From 76129721f216fd66898ade86ba0f9a9b2d70c0ae Mon Sep 17 00:00:00 2001 From: Tobe O Date: Tue, 15 May 2018 15:33:57 -0400 Subject: [PATCH] Complete @required support --- angel_serialize_generator/CHANGELOG.md | 3 +++ .../lib/build_context.dart | 2 +- angel_serialize_generator/lib/context.dart | 4 +++ angel_serialize_generator/lib/model.dart | 3 +++ angel_serialize_generator/lib/serialize.dart | 27 +++++++++++++++++-- angel_serialize_generator/lib/typescript.dart | 4 ++- .../test/models/author.d.ts | 2 +- .../test/models/author.dart | 3 ++- .../test/models/author.g.dart | 2 +- .../test/models/author.serializer.g.dart | 24 +++++++++++++++++ 10 files changed, 67 insertions(+), 7 deletions(-) diff --git a/angel_serialize_generator/CHANGELOG.md b/angel_serialize_generator/CHANGELOG.md index 2d180d8e..cb6dbf77 100644 --- a/angel_serialize_generator/CHANGELOG.md +++ b/angel_serialize_generator/CHANGELOG.md @@ -1,5 +1,8 @@ # 2.0.7 * Create unmodifiable Lists and Maps. +* Support `@required` on fields. +* Affix an `@immutable` annotation to classes, if +`package:meta` is imported. # 2.0.6 * Support for using `abstract` to create immutable model classes. diff --git a/angel_serialize_generator/lib/build_context.dart b/angel_serialize_generator/lib/build_context.dart index 01d25b25..54d1d5b9 100644 --- a/angel_serialize_generator/lib/build_context.dart +++ b/angel_serialize_generator/lib/build_context.dart @@ -80,7 +80,7 @@ Future buildContext( if (required != null) { var cr = new ConstantReader(required); var reason = cr.peek('reason')?.stringValue ?? - "Missing field '${ctx.resolveFieldName(field.name)}' on ${ctx + "Missing required field '${ctx.resolveFieldName(field.name)}' on ${ctx .modelClassName}."; ctx.requiredFields[field.name] = reason; } diff --git a/angel_serialize_generator/lib/context.dart b/angel_serialize_generator/lib/context.dart index 0debfd3c..6f5dba58 100644 --- a/angel_serialize_generator/lib/context.dart +++ b/angel_serialize_generator/lib/context.dart @@ -59,6 +59,10 @@ class BuildContext { FieldElement get primaryKeyField => fields.firstWhere((f) => f.name == primaryKeyName); + bool get importsPackageMeta { + return clazz.library.imports.any((i) => i.uri == 'package:meta/meta.dart'); + } + /// Get the aliased name (if one is defined) for a field. String resolveFieldName(String name) => aliases.containsKey(name) ? aliases[name] : name; diff --git a/angel_serialize_generator/lib/model.dart b/angel_serialize_generator/lib/model.dart index d7446ab2..90a81513 100644 --- a/angel_serialize_generator/lib/model.dart +++ b/angel_serialize_generator/lib/model.dart @@ -30,6 +30,9 @@ class JsonModelGenerator extends GeneratorForAnnotation { ..name = ctx.modelClassNameRecase.pascalCase ..extend = new Reference(ctx.originalClassName); + //if (ctx.importsPackageMeta) + // clazz.annotations.add(new CodeExpression(new Code('immutable'))); + for (var field in ctx.fields) { clazz.fields.add(new Field((b) { b diff --git a/angel_serialize_generator/lib/serialize.dart b/angel_serialize_generator/lib/serialize.dart index 6c04d39f..b8be7f82 100644 --- a/angel_serialize_generator/lib/serialize.dart +++ b/angel_serialize_generator/lib/serialize.dart @@ -64,7 +64,18 @@ class SerializerGenerator extends GeneratorForAnnotation { ..type = ctx.modelClassType; })); - var buf = new StringBuffer('return {'); + var buf = new StringBuffer(); + + ctx.requiredFields.forEach((key, msg) { + if (ctx.excluded[key]?.canSerialize == false) return; + buf.writeln(''' + if (model.$key == null) { + throw new FormatException("$msg"); + } + '''); + }); + + buf.writeln('return {'); int i = 0; // Add named parameters @@ -134,7 +145,19 @@ class SerializerGenerator extends GeneratorForAnnotation { } } - var buf = new StringBuffer('return new ${ctx.modelClassName}('); + var buf = new StringBuffer(); + + ctx.requiredFields.forEach((key, msg) { + if (ctx.excluded[key]?.canDeserialize == false) return; + var name = ctx.resolveFieldName(key); + buf.writeln(''' + if (map['$name'] == null) { + throw new FormatException("$msg"); + } + '''); + }); + + buf.writeln('return new ${ctx.modelClassName}('); int i = 0; for (var param in ctx.constructorParameters) { diff --git a/angel_serialize_generator/lib/typescript.dart b/angel_serialize_generator/lib/typescript.dart index 5a7ed47e..6737dcb6 100644 --- a/angel_serialize_generator/lib/typescript.dart +++ b/angel_serialize_generator/lib/typescript.dart @@ -151,7 +151,9 @@ class TypeScriptDefinitionBuilder implements Builder { ctx, field.name, field.type, ext, buildStep); // foo: string; - buf.writeln('$alias?: $typeScriptType;'); + if (!ctx.requiredFields.containsKey(field.name)) + alias += '?'; + buf.writeln('$alias: $typeScriptType;'); } buf diff --git a/angel_serialize_generator/test/models/author.d.ts b/angel_serialize_generator/test/models/author.d.ts index b0979f27..9a7b5f24 100644 --- a/angel_serialize_generator/test/models/author.d.ts +++ b/angel_serialize_generator/test/models/author.d.ts @@ -11,7 +11,7 @@ interface LibraryCollection { interface Bookmark { id?: string; history?: number[]; - page?: number; + page: number; comment?: string; created_at?: any; updated_at?: any; diff --git a/angel_serialize_generator/test/models/author.dart b/angel_serialize_generator/test/models/author.dart index ce4695a2..8949c405 100644 --- a/angel_serialize_generator/test/models/author.dart +++ b/angel_serialize_generator/test/models/author.dart @@ -15,7 +15,7 @@ abstract class _Author extends Model { @required String get name; - @required + @Required('Custom message for missing `age`') int get age; List get books; @@ -41,6 +41,7 @@ abstract class _Bookmark extends Model { List get history; + @required int get page; String get comment; diff --git a/angel_serialize_generator/test/models/author.g.dart b/angel_serialize_generator/test/models/author.g.dart index a40b4452..11ec5212 100644 --- a/angel_serialize_generator/test/models/author.g.dart +++ b/angel_serialize_generator/test/models/author.g.dart @@ -136,7 +136,7 @@ class Bookmark extends _Bookmark { Bookmark(Book book, {this.id, List history, - this.page, + @required this.page, this.comment, this.createdAt, this.updatedAt}) diff --git a/angel_serialize_generator/test/models/author.serializer.g.dart b/angel_serialize_generator/test/models/author.serializer.g.dart index 5747c076..6db29c22 100644 --- a/angel_serialize_generator/test/models/author.serializer.g.dart +++ b/angel_serialize_generator/test/models/author.serializer.g.dart @@ -8,6 +8,14 @@ part of angel_serialize.test.models.author; abstract class AuthorSerializer { static Author fromMap(Map map) { + if (map['name'] == null) { + throw new FormatException("Missing required field 'name' on Author."); + } + + if (map['age'] == null) { + throw new FormatException("Custom message for missing `age`"); + } + return new Author( id: map['id'], name: map['name'], @@ -32,6 +40,14 @@ abstract class AuthorSerializer { } static Map toMap(Author model) { + if (model.name == null) { + throw new FormatException("Missing required field 'name' on Author."); + } + + if (model.age == null) { + throw new FormatException("Custom message for missing `age`"); + } + return { 'id': model.id, 'name': model.name, @@ -110,6 +126,10 @@ abstract class LibraryFields { abstract class BookmarkSerializer { static Bookmark fromMap(Map map, Book book) { + if (map['page'] == null) { + throw new FormatException("Missing required field 'page' on Bookmark."); + } + return new Bookmark(book, id: map['id'], history: map['history'], @@ -128,6 +148,10 @@ abstract class BookmarkSerializer { } static Map toMap(Bookmark model) { + if (model.page == null) { + throw new FormatException("Missing required field 'page' on Bookmark."); + } + return { 'id': model.id, 'history': model.history,