diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..bfa6a22a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +# Created by .ignore support plugin (hsz.mobi) diff --git a/angel_serialize_generator/lib/angel_serialize_generator.dart b/angel_serialize_generator/lib/angel_serialize_generator.dart index 9f871831..ee4e51b5 100644 --- a/angel_serialize_generator/lib/angel_serialize_generator.dart +++ b/angel_serialize_generator/lib/angel_serialize_generator.dart @@ -5,25 +5,25 @@ import 'package:angel_serialize/angel_serialize.dart'; import 'package:build/build.dart'; import 'package:code_builder/code_builder.dart'; import 'package:code_builder/dart/core.dart'; -import 'package:source_gen/src/annotation.dart'; -import 'package:source_gen/source_gen.dart'; +import 'package:source_gen/source_gen.dart' hide LibraryBuilder; import 'build_context.dart'; import 'context.dart'; class JsonModelGenerator extends GeneratorForAnnotation { final bool autoSnakeCaseNames; final bool autoIdAndDateFields; + const JsonModelGenerator( {this.autoSnakeCaseNames: true, this.autoIdAndDateFields: true}); @override Future generateForAnnotatedElement( - Element element, Serializable annotation, BuildStep buildStep) async { + Element element, ConstantReader reader, BuildStep buildStep) async { if (element.kind != ElementKind.CLASS) throw 'Only classes can be annotated with a @Serializable() annotation.'; var ctx = buildContext( element, - annotation, + serializable, buildStep, await buildStep.resolver, autoSnakeCaseNames != false, @@ -73,6 +73,12 @@ class JsonModelGenerator extends GeneratorForAnnotation { literal(null), reference(field.name).invoke('toIso8601String', [])); } + // Serialize models + else if (serializableTypeChecker.firstAnnotationOf(field.type.element) != + null) { + value = reference(field.name).invoke('toJson', []); + } + // Anything else else { value = reference(field.name); @@ -126,8 +132,7 @@ class JsonModelGenerator extends GeneratorForAnnotation { fromJsonClassName = genericClass.displayName; } else { // If it has a serializable annotation, act accordingly. - if (genericClass.metadata - .any((ann) => matchAnnotation(Serializable, ann))) { + if (serializableTypeChecker.firstAnnotationOf(genericClass) != null) { fromJsonClassName = genericClass.displayName.substring(1); hasFromJson = true; } @@ -166,8 +171,7 @@ class JsonModelGenerator extends GeneratorForAnnotation { fromJsonClassName = type.displayName; } else { // If it has a serializable annotation, act accordingly. - if (genericClass.metadata - .any((ann) => matchAnnotation(Serializable, ann))) { + if (serializableTypeChecker.firstAnnotationOf(genericClass) != null) { fromJsonClassName = type.displayName.substring(1); hasFromJson = true; } @@ -202,8 +206,7 @@ class JsonModelGenerator extends GeneratorForAnnotation { fromJsonClassName = targetType.displayName; } else { // If it has a serializable annotation, act accordingly. - if (genericClass.metadata - .any((ann) => matchAnnotation(Serializable, ann))) { + if (serializableTypeChecker.firstAnnotationOf(genericClass) != null) { fromJsonClassName = targetType.displayName.substring(1); hasFromJson = true; } @@ -242,6 +245,17 @@ class JsonModelGenerator extends GeneratorForAnnotation { } } + // Deerialize models + if (!done && + serializableTypeChecker.firstAnnotationOf(field.type.element) != + null) { + var typeName = field.type.name; + typeName.startsWith('_') ? typeName = typeName.substring(1) : null; + var typeBuilder = new TypeBuilder(typeName); + value = mapKey.isInstanceOf(typeBuilder).ternary( + mapKey, typeBuilder.newInstance([mapKey], constructor: 'fromJson')); + } + return out..[field.name] = value; }); fromJson diff --git a/angel_serialize_generator/lib/build_context.dart b/angel_serialize_generator/lib/build_context.dart index 0c7cfae5..7b300297 100644 --- a/angel_serialize_generator/lib/build_context.dart +++ b/angel_serialize_generator/lib/build_context.dart @@ -5,10 +5,16 @@ import 'package:angel_serialize/angel_serialize.dart'; import 'package:build/build.dart'; import 'package:path/path.dart' as p; import 'package:recase/recase.dart'; -import 'package:source_gen/src/annotation.dart'; -import 'src/find_annotation.dart'; +import 'package:source_gen/source_gen.dart'; import 'context.dart'; +const TypeChecker aliasTypeChecker = const TypeChecker.fromRuntime(Alias); + +const TypeChecker excludeTypeChecker = const TypeChecker.fromRuntime(Exclude); + +const TypeChecker serializableTypeChecker = +const TypeChecker.fromRuntime(Serializable); + // TODO: Should add id, createdAt, updatedAt... BuildContext buildContext( ClassElement clazz, @@ -28,12 +34,15 @@ BuildContext buildContext( if (field.getter != null && field.setter != null) { fieldNames.add(field.name); // Skip if annotated with @exclude - var excludeAnnotation = field.metadata.firstWhere( - (ann) => matchAnnotation(Exclude, ann), - orElse: () => null); + var excludeAnnotation = excludeTypeChecker.firstAnnotationOf(field); if (excludeAnnotation != null) continue; // Check for alias - var alias = findAnnotation(field, Alias); + Alias alias; + var aliasAnn = aliasTypeChecker.firstAnnotationOf(field); + + if (aliasAnn != null) { + alias = new Alias(aliasAnn.getField('name').toStringValue()); + } if (alias?.name?.isNotEmpty == true) { ctx.aliases[field.name] = alias.name; diff --git a/angel_serialize_generator/lib/src/find_annotation.dart b/angel_serialize_generator/lib/src/find_annotation.dart deleted file mode 100644 index c7b65d2a..00000000 --- a/angel_serialize_generator/lib/src/find_annotation.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:analyzer/dart/element/element.dart'; -import 'package:source_gen/src/annotation.dart'; - -T findAnnotation(FieldElement field, Type outType) { - var first = field.metadata - .firstWhere((ann) => matchAnnotation(outType, ann), orElse: () => null); - return first == null ? null : instantiateAnnotation(first); -} diff --git a/angel_serialize_generator/pubspec.yaml b/angel_serialize_generator/pubspec.yaml index 5691b1c9..d3b5e0ef 100644 --- a/angel_serialize_generator/pubspec.yaml +++ b/angel_serialize_generator/pubspec.yaml @@ -1,5 +1,5 @@ name: angel_serialize_generator -version: 1.0.0-alpha+1 +version: 1.0.0-alpha+2 description: Model serialization generators, designed for use with Angel. author: Tobe O homepage: https://github.com/angel-dart/serialize @@ -7,11 +7,10 @@ environment: sdk: ">=1.19.0" dependencies: angel_serialize: ^1.0.0-alpha - build: ^0.9.0 code_builder: ^1.0.0 id: ^1.0.0 recase: ^1.0.0 - source_gen: ^0.6.0 + source_gen: ^0.7.0 dev_dependencies: angel_framework: ^1.0.0 build_runner: ^0.3.0 diff --git a/angel_serialize_generator/test/models/book.g.dart b/angel_serialize_generator/test/models/book.g.dart index 9f3a46cb..47ceab7c 100644 --- a/angel_serialize_generator/test/models/book.g.dart +++ b/angel_serialize_generator/test/models/book.g.dart @@ -4,7 +4,6 @@ part of angel_serialize.test.models.book; // ************************************************************************** // Generator: JsonModelGenerator -// Target: abstract class _Book // ************************************************************************** class Book extends _Book { @@ -74,11 +73,6 @@ class Book extends _Book { } } -// ************************************************************************** -// Generator: JsonModelGenerator -// Target: abstract class _Author -// ************************************************************************** - class Author extends _Author { @override String id; @@ -121,11 +115,9 @@ class Author extends _Author { x == null ? null : (x is Book ? x : new Book.fromJson(x))) .toList() : null, - newestBook: data['newest_book'] == null - ? null - : (data['newest_book'] is Book - ? data['newest_book'] - : new Book.fromJson(data['newest_book'])), + newestBook: data['newest_book'] is Book + ? data['newest_book'] + : new Book.fromJson(data['newest_book']), createdAt: data['created_at'] is DateTime ? data['created_at'] : (data['created_at'] is String @@ -143,7 +135,7 @@ class Author extends _Author { 'name': name, 'age': age, 'books': books, - 'newest_book': newestBook, + 'newest_book': newestBook.toJson(), 'created_at': createdAt == null ? null : createdAt.toIso8601String(), 'updated_at': updatedAt == null ? null : updatedAt.toIso8601String() }; @@ -155,11 +147,6 @@ class Author extends _Author { } } -// ************************************************************************** -// Generator: JsonModelGenerator -// Target: abstract class _Library -// ************************************************************************** - class Library extends _Library { @override String id; diff --git a/angel_serialize_generator/tool/phases.dart b/angel_serialize_generator/tool/phases.dart index a5a0cbb3..1e49270f 100644 --- a/angel_serialize_generator/tool/phases.dart +++ b/angel_serialize_generator/tool/phases.dart @@ -3,5 +3,5 @@ import 'package:source_gen/source_gen.dart'; import 'package:angel_serialize_generator/angel_serialize_generator.dart'; final PhaseGroup PHASES = new PhaseGroup.singleAction( - new GeneratorBuilder([const JsonModelGenerator()]), + new PartBuilder([const JsonModelGenerator()]), new InputSet('angel_serialize_generator', const ['test/models/*.dart']));