2018-02-27 19:42:06 +00:00
|
|
|
part of angel_serialize_generator;
|
|
|
|
|
2018-02-28 00:36:53 +00:00
|
|
|
class JsonModelGenerator extends GeneratorForAnnotation<Serializable> {
|
|
|
|
final bool autoIdAndDateFields;
|
|
|
|
|
2018-02-28 00:46:35 +00:00
|
|
|
const JsonModelGenerator({this.autoIdAndDateFields: true});
|
2018-02-28 00:36:53 +00:00
|
|
|
|
|
|
|
@override
|
|
|
|
Future<String> generateForAnnotatedElement(
|
2018-02-28 00:46:35 +00:00
|
|
|
Element element, ConstantReader annotation, BuildStep buildStep) async {
|
2018-02-28 00:36:53 +00:00
|
|
|
if (element.kind != ElementKind.CLASS)
|
|
|
|
throw 'Only classes can be annotated with a @Serializable() annotation.';
|
|
|
|
|
2018-02-28 00:46:35 +00:00
|
|
|
var ctx = await buildContext(element, annotation, buildStep,
|
|
|
|
await buildStep.resolver, true, autoIdAndDateFields != false);
|
2018-02-28 00:36:53 +00:00
|
|
|
|
2018-03-02 21:23:00 +00:00
|
|
|
var lib = new Library((b) {
|
2018-02-28 01:49:14 +00:00
|
|
|
generateClass(ctx, b, annotation);
|
2018-02-28 00:36:53 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
var buf = lib.accept(new DartEmitter());
|
|
|
|
return buf.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Generate an extended model class.
|
2018-02-28 01:49:14 +00:00
|
|
|
void generateClass(
|
2018-03-02 21:23:00 +00:00
|
|
|
BuildContext ctx, LibraryBuilder file, ConstantReader annotation) {
|
2018-02-28 00:36:53 +00:00
|
|
|
file.body.add(new Class((clazz) {
|
|
|
|
clazz
|
|
|
|
..name = ctx.modelClassNameRecase.pascalCase
|
|
|
|
..extend = new Reference(ctx.originalClassName);
|
|
|
|
|
|
|
|
for (var field in ctx.fields) {
|
|
|
|
clazz.fields.add(new Field((b) {
|
|
|
|
b
|
|
|
|
..name = field.name
|
|
|
|
..modifier = FieldModifier.final$
|
2018-03-02 21:23:00 +00:00
|
|
|
..annotations.add(new CodeExpression(new Code('override')))
|
2018-02-28 00:36:53 +00:00
|
|
|
..type = convertTypeReference(field.type);
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
generateConstructor(ctx, clazz, file);
|
|
|
|
generateCopyWithMethod(ctx, clazz, file);
|
2018-02-28 01:49:14 +00:00
|
|
|
|
|
|
|
// Generate toJson() method if necessary
|
|
|
|
var serializers = annotation.peek('serializers')?.listValue ?? [];
|
|
|
|
|
|
|
|
if (serializers.any((o) => o.toIntValue() == Serializers.json)) {
|
|
|
|
clazz.methods.add(new Method((method) {
|
|
|
|
method
|
|
|
|
..name = 'toJson'
|
|
|
|
..returns = new Reference('Map<String, dynamic>')
|
|
|
|
..body = new Code('return ${clazz.name}Serializer.toMap(this);');
|
|
|
|
}));
|
|
|
|
}
|
2018-02-28 00:36:53 +00:00
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Generate a constructor with named parameters.
|
|
|
|
void generateConstructor(
|
2018-03-02 21:23:00 +00:00
|
|
|
BuildContext ctx, ClassBuilder clazz, LibraryBuilder file) {
|
2018-02-28 00:36:53 +00:00
|
|
|
clazz.constructors.add(new Constructor((constructor) {
|
2018-05-13 17:23:40 +00:00
|
|
|
// Add all `super` params
|
|
|
|
if (ctx.constructorParameters.isNotEmpty) {
|
|
|
|
for (var param in ctx.constructorParameters) {
|
|
|
|
constructor.requiredParameters.add(new Parameter((b) => b
|
|
|
|
..name = param.name
|
|
|
|
..type = convertTypeReference(param.type)));
|
|
|
|
}
|
|
|
|
|
|
|
|
constructor.initializers.add(new Code(
|
|
|
|
'super(${ctx.constructorParameters.map((p) => p.name).join(',')})'));
|
|
|
|
}
|
|
|
|
|
2018-02-28 00:36:53 +00:00
|
|
|
for (var field in ctx.fields) {
|
|
|
|
constructor.optionalParameters.add(new Parameter((b) {
|
|
|
|
b
|
|
|
|
..name = field.name
|
|
|
|
..named = true
|
|
|
|
..toThis = true;
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Generate a `copyWith` method.
|
|
|
|
void generateCopyWithMethod(
|
2018-03-02 21:23:00 +00:00
|
|
|
BuildContext ctx, ClassBuilder clazz, LibraryBuilder file) {
|
2018-02-28 00:36:53 +00:00
|
|
|
clazz.methods.add(new Method((method) {
|
|
|
|
method
|
|
|
|
..name = 'copyWith'
|
|
|
|
..returns = ctx.modelClassType;
|
2018-05-13 17:23:40 +00:00
|
|
|
|
|
|
|
// Add all `super` params
|
|
|
|
if (ctx.constructorParameters.isNotEmpty) {
|
|
|
|
for (var param in ctx.constructorParameters) {
|
|
|
|
method.requiredParameters.add(new Parameter((b) => b
|
|
|
|
..name = param.name
|
|
|
|
..type = convertTypeReference(param.type)));
|
|
|
|
}
|
|
|
|
}
|
2018-02-28 00:36:53 +00:00
|
|
|
|
|
|
|
var buf = new StringBuffer('return new ${ctx.modelClassName}(');
|
|
|
|
int i = 0;
|
|
|
|
|
2018-05-13 17:23:40 +00:00
|
|
|
for (var param in ctx.constructorParameters) {
|
|
|
|
if (i++ > 0) buf.write(', ');
|
|
|
|
buf.write(param.name);
|
|
|
|
}
|
|
|
|
|
2018-02-28 00:36:53 +00:00
|
|
|
// Add named parameters
|
|
|
|
for (var field in ctx.fields) {
|
|
|
|
method.optionalParameters.add(new Parameter((b) {
|
|
|
|
b
|
|
|
|
..name = field.name
|
|
|
|
..named = true
|
|
|
|
..type = convertTypeReference(field.type);
|
|
|
|
}));
|
|
|
|
|
|
|
|
if (i++ > 0) buf.write(', ');
|
|
|
|
buf.write('${field.name}: ${field.name} ?? this.${field.name}');
|
|
|
|
}
|
|
|
|
|
|
|
|
buf.write(');');
|
|
|
|
method.body = new Code(buf.toString());
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|