From bd5b656689f3acb57d03b309e2688b34c88fcadc Mon Sep 17 00:00:00 2001 From: Eric Schneller Date: Mon, 17 Sep 2018 19:37:51 +0200 Subject: [PATCH] Further refactorings, moving generator code into separate folder --- README.md | 141 +++++------ changelog.md | 6 + lib/builder.dart | 4 +- lib/src/annotations.dart | 8 +- lib/src/generator.dart | 220 ------------------ lib/src/generator/entity_generator.dart | 114 +++++++++ .../{ => generator}/entity_type_helper.dart | 4 +- lib/src/generator/field_context.dart | 42 ++++ lib/src/generator/generator.dart | 42 ++++ .../{ => generator}/generator_settings.dart | 10 +- lib/src/generator/identifier.dart | 15 ++ lib/src/generator/serializer_generator.dart | 38 +++ .../transformer_generator.dart | 6 +- lib/src/{ => generator}/utils.dart | 2 +- lib/src/identifier.dart | 4 - lib/src/serializer.dart | 6 +- lib/transformers/date_time.dart | 1 + test/generator_test.dart | 2 +- 18 files changed, 356 insertions(+), 309 deletions(-) delete mode 100644 lib/src/generator.dart create mode 100644 lib/src/generator/entity_generator.dart rename lib/src/{ => generator}/entity_type_helper.dart (81%) create mode 100644 lib/src/generator/field_context.dart create mode 100644 lib/src/generator/generator.dart rename lib/src/{ => generator}/generator_settings.dart (87%) create mode 100644 lib/src/generator/identifier.dart create mode 100644 lib/src/generator/serializer_generator.dart rename lib/src/{ => generator}/transformer_generator.dart (93%) rename lib/src/{ => generator}/utils.dart (100%) delete mode 100644 lib/src/identifier.dart diff --git a/README.md b/README.md index 7cc9e27..2a2e0c5 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,77 @@ import 'my_class.dart'; final Dartson serializer = _serializer$dartson.useCodec(json); ``` + +### Encoding / decoding lists + +As of dartson `>1.0.0` there are specific `encodeList` and `decodeList` methods. Because of type restrictions +`encodeList` returns an `Object` and `decodeList` expects an `Object`. This should not cause any further actions when +using `json` codec, however when working with the default serializer without any Codec, than a cast to +`List>` might be necessary when using the `encodeList` result. + +```dart +main() { + final result = serializer.encodeList([ + MyClass()..name = 'test1', + MyClass()..name = 'test2', + ]) as List>; + + expect(result, allOf(isList, hasLength(2))); + expect(result[0]['name'], 'test1'); + expect(result[1]['name'], 'test2'); +} +``` + +### Replacing entities + +Sometimes entities are automatically generated and as such cannot contain any handwritten code, which could provide +further logic and reduce complexity. This is where the `replacement` feature of dartson can help. + +Here an example of an entity called `Money` which is replaced using `MoneyImpl` for replacing the operators. + +```dart +import 'package:dartson/dartson.dart'; +import 'package:dartson/transformers/date_time.dart'; + +// Imagine Money and Product couldn't be touched. +class Money { + double net; + double gross; +} + +class Product { + Money price; + String name; +} + + +class MoneyImpl extends Money { + operator +(dynamic ob) { + if (obj is! Money) { + throw TypeError(); + } + + net += ob.net; + gross += ob.gross; + } +} + + +@Serializer( + entities: [ + Money, + Product, + ], + replacements: { + Money: MoneyImpl, + }, + transformers: [ + DateTimeParser, + ], +) +final Dartson serializer = _serializer$dartson; +``` + ### Extending the serializer Dartson supports extending serializers to provide a module approach. This is necessary to support functionality @@ -137,76 +208,6 @@ import 'my_class.dart'; final Dartson serializer = _serializer$dartson; ``` -## Encoding / decoding lists - -As of dartson `>1.0.0` there are specific `encodeList` and `decodeList` methods. Because of type restrictions -`encodeList` returns an `Object` and `decodeList` expects an `Object`. This should not cause any further actions when -using `json` codec, however when working with the default serializer without any Codec, than a cast to -`List>` might be necessary when using the `encodeList` result. - -```dart -main() { - final result = serializer.encodeList([ - MyClass()..name = 'test1', - MyClass()..name = 'test2', - ]) as List>; - - expect(result, allOf(isList, hasLength(2))); - expect(result[0]['name'], 'test1'); - expect(result[1]['name'], 'test2'); -} -``` - -## Replacing entities - -Sometimes entities are automatically generated and as such cannot contain any handwritten code, which could provide -further logic and reduce complexity. This is where the `replacement` feature of dartson can help. - -Here an example of an entity called `Money` which is replaced using `MoneyImpl` for replacing the operators. - -```dart -import 'package:dartson/dartson.dart'; -import 'package:dartson/transformers/date_time.dart'; - -// Imagine Money and Product couldn't be touched. -class Money { - double net; - double gross; -} - -class Product { - Money price; - String name; -} - - -class MoneyImpl extends Money { - operator +(dynamic ob) { - if (obj is! Money) { - throw TypeError(); - } - - net += ob.net; - gross += ob.gross; - } -} - - -@Serializer( - entities: [ - Money, - Product, - ], - replacements: { - Money: MoneyImpl, - }, - transformers: [ - DateTimeParser, - ], -) -final Dartson serializer = _serializer$dartson; -``` - ## Roadmap for 1.0.0 alpha/beta - First alpha release evaluates and tests the reuse of `json_serializable` diff --git a/changelog.md b/changelog.md index 1bd7fe8..3664e66 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,11 @@ # Changelog +## 1.0.0-alpha+3 + +**Breaking changes** +- `DateTimeParser` is deprecated. The default is now the `json_serializable` implementation and it's no longer necessary + to register a transformer at all. + ## 1.0.0-alpha+2 (09/17/2018) - Add replacement functionality diff --git a/lib/builder.dart b/lib/builder.dart index 977c663..286dd79 100644 --- a/lib/builder.dart +++ b/lib/builder.dart @@ -3,7 +3,9 @@ library dartson.builder; import 'package:build/build.dart'; import 'package:source_gen/source_gen.dart'; -import 'src/generator.dart'; +import 'src/generator/generator.dart'; +/// Provides a [SharedPartBuilder] for the dartson generator. See README.md for +/// usage. Builder dartsonBuilder(_) => SharedPartBuilder([SerializerGenerator()], 'dartson'); diff --git a/lib/src/annotations.dart b/lib/src/annotations.dart index f3ec84c..b5f1d8d 100644 --- a/lib/src/annotations.dart +++ b/lib/src/annotations.dart @@ -19,8 +19,12 @@ class Property { /// Defines the generation of a serializer. Assign the variable name as private /// with a suffix "$dartson" to the annotated variable. /// -/// @Serializer(entities: [MyClass]) -/// final serializer = _serializer$dartson; +/// @Serializer( +/// entities: [MyClass], +/// replacements: {MyInterface: MyImplementation}, +/// transformers: [MyCustomTransformer], +/// ) +/// final Dartson serializer = _serializer$dartson.useCodec(json); /// class Serializer { /// A list of entities which will be serialized by the [Serializer]. diff --git a/lib/src/generator.dart b/lib/src/generator.dart deleted file mode 100644 index 1a9def4..0000000 --- a/lib/src/generator.dart +++ /dev/null @@ -1,220 +0,0 @@ -import 'dart:async'; - -import 'package:analyzer/dart/element/element.dart'; -import 'package:analyzer/dart/element/type.dart'; -import 'package:code_builder/code_builder.dart'; -import 'package:build/src/builder/build_step.dart'; -import 'package:source_gen/source_gen.dart'; -import 'package:dart_style/dart_style.dart'; -import 'package:json_serializable/type_helper.dart'; -import 'package:json_serializable/src/type_helpers/value_helper.dart'; -import 'package:json_serializable/src/type_helpers/enum_helper.dart'; -import 'package:json_serializable/src/type_helpers/iterable_helper.dart'; -import 'package:json_serializable/src/type_helpers/map_helper.dart'; - -import 'annotations.dart'; -import 'transformer_generator.dart'; -import 'utils.dart'; -import 'generator_settings.dart'; -import 'identifier.dart'; -import 'entity_type_helper.dart'; - -// TODO: Properly separate the generators. - -class SerializerGenerator extends GeneratorForAnnotation { - @override - FutureOr generateForAnnotatedElement( - Element element, ConstantReader annotation, BuildStep buildStep) { - final settings = GeneratorSettings.fromConstant(annotation); - final trans = TransformerGenerator(settings.transformers); - final entityHelper = EntityTypeHelper(settings.entities); - - final emitter = DartEmitter(); - final str = StringBuffer(); - - str.write(trans.build(emitter)); - str.writeAll(settings.entities.values - .map((e) => _EntityGenerator(e, trans, entityHelper).build(emitter))); - - str.write( - _DartsonGenerator(settings.entities.values.toSet()).build(emitter)); - str.write(refer(implementationIdentifier) - .newInstance([]) - .assignFinal('_${element.name}$serializerIdentifier') - .statement - .accept(emitter)); - - final formatter = DartFormatter(); - return formatter.format(str.toString()); - } -} - -class _DartsonGenerator { - final Set objects; - - _DartsonGenerator(this.objects); - - String build(DartEmitter emitter) => - _buildDartson().accept(emitter).toString(); - - Spec _buildDartson() { - final mapValues = {}; - - objects.forEach((t) => - mapValues[refer(t.displayName)] = refer('DartsonEntity').constInstance([ - refer('_${t.displayName}$encodeMethodIdentifier'), - refer('_${t.displayName}$decodeMethodIdentifier'), - ], {}, [ - refer(t.displayName) - ])); - - final lookupMap = literalMap(mapValues, refer('Type', 'dart:core'), - refer('DartsonEntity', 'package:dartson/dartson.dart')); - - String dartsonTypeArguments = 'Map'; - - final constr = Constructor( - (mb) => mb..initializers.add(refer('super').call([lookupMap]).code)); - - return Class((cb) => cb - ..name = implementationIdentifier - ..extend = refer( - 'Dartson<$dartsonTypeArguments>', 'package:dartson/dartson.dart') - ..constructors.add(constr)); - } -} - -class _EntityGenerator { - final ClassElement _element; - final Set _fields; - final Iterable _helpers; - final _fieldContexts = []; - - _EntityGenerator(this._element, TransformerGenerator _transformers, - EntityTypeHelper entities) - : _fields = sortedFieldSet(_element), - _helpers = [_transformers, entities].followedBy([ - ValueHelper(), - UriHelper(), - EnumHelper(), - IterableHelper(), - MapHelper(), - ]); - - String build(DartEmitter emitter) { - final buffer = StringBuffer(); - buffer.write(_buildEncoder(_element).accept(emitter)); - buffer.write(_buildDecoder(_element).accept(emitter)); - Set() - ..addAll(_fieldContexts.expand((f) => f.members)) - ..forEach(buffer.write); - - return buffer.toString(); - } - - Method _buildEncoder(ClassElement classElement) { - final obj = refer('obj'); - final block = BlockBuilder() - ..statements.add(Code('if (object == null) { return null; }')) - ..addExpression(refer('Map', 'dart:core') - .newInstance([]).assignFinal('obj')); - - for (var field in _fields) { - final fieldProperty = propertyAnnotation(field); - if (fieldProperty.ignore) { - continue; - } - - final fieldContext = FieldContext(true, field.metadata, _helpers); - _fieldContexts.add(fieldContext); - - block.addExpression(obj - .index(literalString(fieldProperty.name ?? field.name)) - .assign(CodeExpression(Code( - fieldContext.serialize(field.type, 'object.${field.name}'))))); - } - - block.addExpression(obj.returned); - - return Method((b) => b - ..name = '_${classElement.name}$encodeMethodIdentifier' - ..returns = refer('Map') - ..requiredParameters.addAll([ - Parameter((pb) => pb - ..name = 'object' - ..type = refer(classElement.name)), - Parameter((pb) => pb - ..name = 'inst' - ..type = refer('Dartson')) - ]) - ..body = block.build()); - } - - Method _buildDecoder(ClassElement classElement) { - final block = BlockBuilder() - ..statements.add(Code('if (data == null) { return null; }')) - ..addExpression( - refer(classElement.name).newInstance([]).assignFinal('obj')); - - for (var field in _fields) { - final fieldProperty = propertyAnnotation(field); - if (fieldProperty.ignore) { - continue; - } - final fieldContext = FieldContext(true, field.metadata, _helpers); - _fieldContexts.add(fieldContext); - - block.addExpression(refer('obj').property(field.name).assign( - CodeExpression(Code(fieldContext.deserialize( - field.type, 'data[\'${fieldProperty.name ?? field.name}\']'))))); - } - - block.addExpression(refer('obj').returned); - - return Method((b) => b - ..name = '_${classElement.name}$decodeMethodIdentifier' - ..returns = refer(classElement.name) - ..requiredParameters.addAll([ - Parameter((pb) => pb - ..name = 'data' - ..type = refer('Map')), - Parameter((pb) => pb - ..name = 'inst' - ..type = refer('Dartson')) - ]) - ..body = block.build()); - } -} - -class FieldContext implements DeserializeContext, SerializeContext { - final bool nullable; - final List metadata; - final Iterable helpers; - final List members = []; - - FieldContext(this.nullable, this.metadata, this.helpers); - - @override - void addMember(String memberContent) { - members.add(memberContent); - } - - // TODO: Proper error message. - @override - String deserialize(DartType fieldType, String expression) => helpers - .map((h) => h.deserialize(fieldType, expression, this)) - .firstWhere((r) => r != null, - orElse: () => throw UnsupportedTypeError( - fieldType, expression, 'Unable to detect helper.')); - - @override - String serialize(DartType fieldType, String expression) => helpers - .map((h) => h.serialize(fieldType, expression, this)) - .firstWhere((r) => r != null, - orElse: () => throw UnsupportedTypeError( - fieldType, expression, 'Unable to detect type.')); - - // TODO: Add proper implementation. - @override - bool get useWrappers => false; -} diff --git a/lib/src/generator/entity_generator.dart b/lib/src/generator/entity_generator.dart new file mode 100644 index 0000000..1775346 --- /dev/null +++ b/lib/src/generator/entity_generator.dart @@ -0,0 +1,114 @@ +import 'package:analyzer/dart/element/element.dart'; +import 'package:code_builder/code_builder.dart'; +import 'package:json_serializable/type_helper.dart'; +import 'package:json_serializable/src/type_helpers/value_helper.dart'; +import 'package:json_serializable/src/type_helpers/enum_helper.dart'; +import 'package:json_serializable/src/type_helpers/iterable_helper.dart'; +import 'package:json_serializable/src/type_helpers/map_helper.dart'; + +import 'entity_type_helper.dart'; +import 'field_context.dart'; +import 'identifier.dart'; +import 'transformer_generator.dart'; +import 'utils.dart'; + +class EntityGenerator { + final ClassElement _element; + final Set _fields; + final Iterable _helpers; + final _fieldContexts = []; + + EntityGenerator(this._element, TransformerGenerator transformers, + EntityTypeHelper entities) + : _fields = sortedFieldSet(_element), + _helpers = [ + transformers, + entities, + ].followedBy([ + ValueHelper(), + UriHelper(), + EnumHelper(), + IterableHelper(), + MapHelper(), + DateTimeHelper(), + ]); + + String build(DartEmitter emitter) => (StringBuffer() + ..write(_buildEncoder(_element).accept(emitter)) + ..write(_buildDecoder(_element).accept(emitter)) + ..writeAll(_fieldContexts.expand((f) => f.members).toSet())) + .toString(); + + Method _buildEncoder(ClassElement classElement) { + final obj = refer('obj'); + final block = BlockBuilder() + ..statements.add(Code('if (object == null) { return null; }')) + ..addExpression(refer('Map', 'dart:core') + .newInstance([]).assignFinal('obj')); + + for (var field in _fields) { + final fieldProperty = propertyAnnotation(field); + if (fieldProperty.ignore) { + continue; + } + + final fieldContext = FieldContext(true, field.metadata, _helpers); + _fieldContexts.add(fieldContext); + + block.addExpression(obj + .index(literalString(fieldProperty.name ?? field.name)) + .assign(CodeExpression(Code( + fieldContext.serialize(field.type, 'object.${field.name}'))))); + } + + block.addExpression(obj.returned); + + return Method((b) => b + ..name = encodeMethod(classElement) + ..returns = refer('Map') + ..requiredParameters.addAll([ + Parameter((pb) => pb + ..name = 'object' + ..type = refer(classElement.displayName)), + Parameter((pb) => pb + ..name = 'inst' + ..type = refer('Dartson', dartsonPackage)) + ]) + ..body = block.build()); + } + + Method _buildDecoder(ClassElement classElement) { + final block = BlockBuilder() + ..statements.add(Code('if (data == null) { return null; }')) + ..addExpression( + refer(classElement.displayName).newInstance([]).assignFinal('obj')); + + for (var field in _fields) { + final fieldProperty = propertyAnnotation(field); + if (fieldProperty.ignore) { + continue; + } + final fieldContext = FieldContext(true, field.metadata, _helpers); + _fieldContexts.add(fieldContext); + + block.addExpression(refer('obj').property(field.displayName).assign( + CodeExpression(Code(fieldContext.deserialize(field.type, + 'data[\'${fieldProperty.name ?? field.displayName}\']'))))); + } + + block.addExpression(refer('obj').returned); + + return Method((b) => b + ..name = decodeMethod(classElement) + ..returns = refer(classElement.displayName) + ..requiredParameters.addAll([ + Parameter((pb) => pb + ..name = 'data' + ..type = refer('Map')), + Parameter((pb) => pb + ..name = 'inst' + ..type = refer('Dartson', dartsonPackage)) + ]) + ..body = block.build()); + } +} diff --git a/lib/src/entity_type_helper.dart b/lib/src/generator/entity_type_helper.dart similarity index 81% rename from lib/src/entity_type_helper.dart rename to lib/src/generator/entity_type_helper.dart index c9f3ba2..db088a0 100644 --- a/lib/src/entity_type_helper.dart +++ b/lib/src/generator/entity_type_helper.dart @@ -16,7 +16,7 @@ class EntityTypeHelper implements TypeHelper { return null; } - return '_${entities[target].displayName}$decodeMethodIdentifier($expression, inst)'; + return '${decodeMethod(entities[target])}($expression, inst)'; } @override @@ -27,6 +27,6 @@ class EntityTypeHelper implements TypeHelper { return null; } - return '_${entities[target].displayName}$encodeMethodIdentifier($expression, inst)'; + return '${encodeMethod(entities[target])}($expression, inst)'; } } diff --git a/lib/src/generator/field_context.dart b/lib/src/generator/field_context.dart new file mode 100644 index 0000000..83a7ded --- /dev/null +++ b/lib/src/generator/field_context.dart @@ -0,0 +1,42 @@ +import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/dart/element/type.dart'; +import 'package:json_serializable/type_helper.dart'; + +/// Provides the serialization methods for a field using [TypeHelper]s which are +/// standard [TypeHelper], entities or transformers. +class FieldContext implements DeserializeContext, SerializeContext { + final bool nullable; + final List metadata; + final Iterable helpers; + final List members = []; + + FieldContext(this.nullable, this.metadata, this.helpers); + + @override + void addMember(String memberContent) { + members.add(memberContent); + } + + @override + String deserialize(DartType fieldType, String expression) => helpers + .map((h) => h.deserialize(fieldType, expression, this)) + .firstWhere((r) => r != null, + orElse: () => throw UnsupportedTypeError( + fieldType, expression, _notSupportedTypeMessage)); + + @override + String serialize(DartType fieldType, String expression) => helpers + .map((h) => h.serialize(fieldType, expression, this)) + .firstWhere((r) => r != null, + orElse: () => throw UnsupportedTypeError( + fieldType, expression, _notSupportedTypeMessage)); + + // TODO: Add proper implementation. + @override + bool get useWrappers => false; +} + +final _notSupportedTypeMessage = 'UnsupportedTypeError: None of the provided ' + '`TypeHelper` or defined `entities` and `transformers` support the defined ' + 'type. Please make sure to add the type either to `entities`, define a ' + 'TypeTransformer in `transformers` or define a `replacement`.'; diff --git a/lib/src/generator/generator.dart b/lib/src/generator/generator.dart new file mode 100644 index 0000000..8e22e7b --- /dev/null +++ b/lib/src/generator/generator.dart @@ -0,0 +1,42 @@ +import 'dart:async'; + +import 'package:analyzer/dart/element/element.dart'; +import 'package:code_builder/code_builder.dart'; +import 'package:build/src/builder/build_step.dart'; +import 'package:source_gen/source_gen.dart'; +import 'package:dart_style/dart_style.dart'; + +import '../annotations.dart'; +import 'entity_type_helper.dart'; +import 'entity_generator.dart'; +import 'generator_settings.dart'; +import 'identifier.dart'; +import 'transformer_generator.dart'; +import 'serializer_generator.dart'; + +class SerializerGenerator extends GeneratorForAnnotation { + @override + FutureOr generateForAnnotatedElement( + Element element, ConstantReader annotation, BuildStep buildStep) { + final settings = GeneratorSettings.fromConstant(annotation); + final trans = TransformerGenerator(settings.transformers); + final entityHelper = EntityTypeHelper(settings.entities); + + final emitter = DartEmitter(); + final str = StringBuffer(); + + str.write(trans.build(emitter)); + str.writeAll(settings.entities.values + .map((e) => EntityGenerator(e, trans, entityHelper).build(emitter))); + + str.write( + DartsonGenerator(settings.entities.values.toSet()).build(emitter)); + str.write(refer(implementationIdentifier) + .newInstance([]) + .assignFinal('_${element.name}$serializerIdentifier') + .statement + .accept(emitter)); + + return DartFormatter().format(str.toString()); + } +} diff --git a/lib/src/generator_settings.dart b/lib/src/generator/generator_settings.dart similarity index 87% rename from lib/src/generator_settings.dart rename to lib/src/generator/generator_settings.dart index 3038d39..25736bc 100644 --- a/lib/src/generator_settings.dart +++ b/lib/src/generator/generator_settings.dart @@ -1,6 +1,7 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:source_gen/source_gen.dart'; +/// Helper class to fetch all [Serializer] definitions within the generator. class GeneratorSettings { final Map entities; final Map replacements; @@ -13,12 +14,13 @@ class GeneratorSettings { final entityMap = {} ..addAll(Map.fromIterable( - _fromReader(reader, 'entities'), - key: (v) => v, - value: (v) => v)) + _fromReader(reader, 'entities'), + key: (v) => v, + value: (v) => v, + )) ..addAll(replacements); - return new GeneratorSettings._( + return GeneratorSettings._( entityMap, _fromReader(reader, 'transformers'), replacements, diff --git a/lib/src/generator/identifier.dart b/lib/src/generator/identifier.dart new file mode 100644 index 0000000..083e414 --- /dev/null +++ b/lib/src/generator/identifier.dart @@ -0,0 +1,15 @@ +import 'package:analyzer/dart/element/element.dart'; + +const _encodeMethodIdentifier = r'$encoder'; +const _decodeMethodIdentifier = r'$decoder'; +const serializerIdentifier = r'$dartson'; +const implementationIdentifier = r'_Dartson$impl'; +const dartsonPackage = 'package:dartson/dartson.dart'; + +/// Returns the encode method identifier for a specific entity [ClassElement]. +String encodeMethod(ClassElement element) => + '_${element.displayName}$_encodeMethodIdentifier'; + +/// Returns the decode method identifier for a specific entity [ClassElement]. +String decodeMethod(ClassElement element) => + '_${element.displayName}$_decodeMethodIdentifier'; diff --git a/lib/src/generator/serializer_generator.dart b/lib/src/generator/serializer_generator.dart new file mode 100644 index 0000000..0a29d5e --- /dev/null +++ b/lib/src/generator/serializer_generator.dart @@ -0,0 +1,38 @@ +import 'package:analyzer/dart/element/element.dart'; +import 'package:code_builder/code_builder.dart'; + +import 'identifier.dart'; + +class DartsonGenerator { + final Set objects; + + DartsonGenerator(this.objects); + + String build(DartEmitter emitter) => + _buildDartson().accept(emitter).toString(); + + Spec _buildDartson() { + final mapValues = {}; + + objects.forEach((t) => mapValues[refer(t.displayName)] = + refer('DartsonEntity', dartsonPackage).constInstance([ + refer(encodeMethod(t)), + refer(decodeMethod(t)), + ], {}, [ + refer(t.displayName) + ])); + + final lookupMap = literalMap(mapValues, refer('Type', 'dart:core'), + refer('DartsonEntity', dartsonPackage)); + + String dartsonTypeArguments = 'Map'; + + final constr = Constructor( + (mb) => mb..initializers.add(refer('super').call([lookupMap]).code)); + + return Class((cb) => cb + ..name = implementationIdentifier + ..extend = refer('Dartson<$dartsonTypeArguments>', dartsonPackage) + ..constructors.add(constr)); + } +} diff --git a/lib/src/transformer_generator.dart b/lib/src/generator/transformer_generator.dart similarity index 93% rename from lib/src/transformer_generator.dart rename to lib/src/generator/transformer_generator.dart index 9e8edd1..c3fb225 100644 --- a/lib/src/transformer_generator.dart +++ b/lib/src/generator/transformer_generator.dart @@ -3,7 +3,7 @@ import 'package:analyzer/dart/element/type.dart'; import 'package:code_builder/code_builder.dart'; import 'package:json_serializable/type_helper.dart'; -import 'exceptions.dart'; +import '../exceptions.dart'; class TransformerGenerator implements TypeHelper { final Iterable _transformers; @@ -44,7 +44,7 @@ class TransformerGenerator implements TypeHelper { return null; } - return '${transformer.name}.decode(${expression} as ' + return '${transformer.name}.decode($expression as ' '${transformer.inputType.displayName})'; } @@ -56,7 +56,7 @@ class TransformerGenerator implements TypeHelper { return null; } - return '${transformer.name}.encode(${expression})'; + return '${transformer.name}.encode($expression)'; } } diff --git a/lib/src/utils.dart b/lib/src/generator/utils.dart similarity index 100% rename from lib/src/utils.dart rename to lib/src/generator/utils.dart index 11665b4..797c593 100644 --- a/lib/src/utils.dart +++ b/lib/src/generator/utils.dart @@ -1,7 +1,7 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/src/dart/resolver/inheritance_manager.dart'; -import 'package:dartson/dartson.dart'; import 'package:source_gen/source_gen.dart'; +import 'package:dartson/dartson.dart'; Property propertyAnnotation(FieldElement element) { final annotations = TypeChecker.fromRuntime(Property).annotationsOf(element); diff --git a/lib/src/identifier.dart b/lib/src/identifier.dart deleted file mode 100644 index ac2e65b..0000000 --- a/lib/src/identifier.dart +++ /dev/null @@ -1,4 +0,0 @@ -const encodeMethodIdentifier = r'$encoder'; -const decodeMethodIdentifier = r'$decoder'; -const serializerIdentifier = r'$dartson'; -const implementationIdentifier = r'_Dartson$impl'; diff --git a/lib/src/serializer.dart b/lib/src/serializer.dart index 47b312e..69a5a32 100644 --- a/lib/src/serializer.dart +++ b/lib/src/serializer.dart @@ -103,7 +103,6 @@ class Dartson { new Dartson({}..addAll(instance._entities)..addAll(_entities), codec: _codec); - // TODO: Add test case. /// Returns a new [Dartson] instance using the provided [codec]. Dartson useCodec(Codec codec) => new Dartson({}..addAll(_entities), codec: codec); @@ -117,8 +116,13 @@ class Dartson { } } +/// Simple container for [encoder] and [decoder] methods of an entity. This +/// shouldn't be used and is generated by the builder. class DartsonEntity { + /// The generated encoding function. final Map Function(T obj, Dartson inst) encoder; + + /// The generated decoding function. final T Function(Map data, Dartson inst) decoder; const DartsonEntity(this.encoder, this.decoder); diff --git a/lib/transformers/date_time.dart b/lib/transformers/date_time.dart index aa159dc..fc1d6e9 100644 --- a/lib/transformers/date_time.dart +++ b/lib/transformers/date_time.dart @@ -3,6 +3,7 @@ library dartson.transformers.DateTime; import 'package:dartson/dartson.dart'; /// A simple DateTime transformer which uses the toString() method. +@Deprecated('A default implementation is now available using ISO-8601.') class DateTimeParser implements TypeTransformer { const DateTimeParser(); DateTime decode(String value) => diff --git a/test/generator_test.dart b/test/generator_test.dart index 3ea544b..93cc227 100644 --- a/test/generator_test.dart +++ b/test/generator_test.dart @@ -3,7 +3,7 @@ import 'dart:io'; import 'package:test/test.dart'; import 'package:build_test/build_test.dart'; -import 'package:dartson/src/generator.dart'; +import 'package:dartson/src/generator/generator.dart'; import 'package:source_gen/source_gen.dart'; import 'package:path/path.dart' as p;