From a771530e226fa2926de39d955e094f7bd804dd23 Mon Sep 17 00:00:00 2001 From: Petr Nymsa Date: Mon, 27 Feb 2023 16:42:33 +0100 Subject: [PATCH] Ignore getter --- example/lib/complete/complete.dart | 19 +- example/lib/complete/complete.mapper.g.dart | 26 ++- .../lib/constructor/constructor.mapper.g.dart | 15 +- .../field_mapping/field_mapping.mapper.g.dart | 6 +- .../lib/freezed/freezed_mapper.mapper.g.dart | 11 +- .../function_mapping.mapper.g.dart | 7 +- .../function_mapping_more.dart | 8 +- .../function_mapping_more.mapper.g.dart | 7 +- ...function_mapping_with_mapper.mapper.g.dart | 6 +- example/lib/getter/getter_mapper.dart | 40 +++++ .../lib/getter/getter_mapper.mapper.g.dart | 21 +++ .../lib/inheritance/inheritance.mapper.g.dart | 6 +- .../lib/injection/service_locator.config.dart | 13 +- example/lib/list/list.mapper.g.dart | 6 +- example/lib/list/nullable_list.mapper.g.dart | 5 +- .../mapper_inheritance.mapper.g.dart | 10 +- .../multi_constructor.mapper.g.dart | 5 +- .../multiple_sources.mapper.g.dart | 18 +- .../lib/nested/nested_mapping.mapper.g.dart | 7 +- .../static_mapping.mapper.g.dart | 10 +- .../static_mapping/static_proxy.mapper.g.dart | 5 +- example/pubspec.lock | 32 ++-- .../lib/code_builders/method_builder.dart | 165 +++++------------- .../lib/generators/mapper_generator.dart | 15 +- generator/lib/models/NestMapping.dart | 11 +- generator/test/mapper_test.dart | 3 +- .../test/src/getter_field_mapper_input.dart | 53 ++++++ generator/test/src/mapper_test_input.dart | 1 + 28 files changed, 312 insertions(+), 219 deletions(-) create mode 100644 example/lib/getter/getter_mapper.dart create mode 100644 example/lib/getter/getter_mapper.mapper.g.dart create mode 100644 generator/test/src/getter_field_mapper_input.dart diff --git a/example/lib/complete/complete.dart b/example/lib/complete/complete.dart index 4b2f6a2..2c9b033 100644 --- a/example/lib/complete/complete.dart +++ b/example/lib/complete/complete.dart @@ -40,18 +40,8 @@ class FooSource extends SuperFooSource { final List list; @override final String superGet; - FooSource( - this.number, - this.text, - this.truthy, - this.named, - this.setterNumber, - this.property, - this.propertyTwo, - this.namedTwo, - this.list, - this.superGet, - String superText) + FooSource(this.number, this.text, this.truthy, this.named, this.setterNumber, this.property, this.propertyTwo, + this.namedTwo, this.list, this.superGet, String superText) : super(superText); } @@ -92,10 +82,7 @@ class BarTarget { } BarTarget(this.numberDiff, this.text, this.truthy, this.superText, - {required this.named, - required this.namedTwoDiff, - required this.list, - required this.secondTextOther}); + {required this.named, required this.namedTwoDiff, required this.list, required this.secondTextOther}); } class BarNestedTarget { diff --git a/example/lib/complete/complete.mapper.g.dart b/example/lib/complete/complete.mapper.g.dart index da3c2d5..7e327f9 100644 --- a/example/lib/complete/complete.mapper.g.dart +++ b/example/lib/complete/complete.mapper.g.dart @@ -11,26 +11,34 @@ class ExampleMapperImpl extends ExampleMapper { ExampleMapperImpl() : super(); @override - BarTarget fromFoo(FooSource source, FooSourceTheSecond second) { + BarTarget fromFoo( + FooSource source, + FooSourceTheSecond second, + ) { final bartarget = BarTarget( - source.number, source.text, source.truthy, source.superText, - named: source.named, - namedTwoDiff: source.namedTwo, - list: source.list.map((x) => fromFooSub(x)).toList(), - secondTextOther: second.secondTextOther); + source.number, + source.text, + source.truthy, + source.superText, + named: source.named, + namedTwoDiff: source.namedTwo, + list: source.list.map((x) => fromFooSub(x)).toList(), + secondTextOther: second.secondTextOther, + ); bartarget.property = source.property; bartarget.propertyTwoDiff = source.propertyTwo; bartarget.nested = fromFooSub(source.nested); bartarget.superPropertySet = source.superPropertySet; bartarget.secondText = second.secondText; - bartarget.setterTextDiff = source.setterText; - bartarget.setterNumber = source.setterNumber; return bartarget; } @override BarNestedTarget fromFooSub(FooNestedSource source) { - final barnestedtarget = BarNestedTarget(source.text, source.number); + final barnestedtarget = BarNestedTarget( + source.text, + source.number, + ); return barnestedtarget; } } diff --git a/example/lib/constructor/constructor.mapper.g.dart b/example/lib/constructor/constructor.mapper.g.dart index a65bef5..cfc30b8 100644 --- a/example/lib/constructor/constructor.mapper.g.dart +++ b/example/lib/constructor/constructor.mapper.g.dart @@ -7,10 +7,17 @@ part of 'constructor.dart'; // ************************************************************************** class ConstructorMapperImpl extends ConstructorMapper { - ConstructorMapperImpl(String? optionalPos, String requiredPos, - {required String requiredNamed, String? optionalNamed}) - : super(optionalPos, requiredPos, - requiredNamed: requiredNamed, optionalNamed: optionalNamed); + ConstructorMapperImpl( + String? optionalPos, + String requiredPos, { + required String requiredNamed, + String? optionalNamed, + }) : super( + optionalPos, + requiredPos, + requiredNamed: requiredNamed, + optionalNamed: optionalNamed, + ); ConstructorMapperImpl.foo(String text) : super.foo(text); diff --git a/example/lib/field_mapping/field_mapping.mapper.g.dart b/example/lib/field_mapping/field_mapping.mapper.g.dart index 73a433b..69239a8 100644 --- a/example/lib/field_mapping/field_mapping.mapper.g.dart +++ b/example/lib/field_mapping/field_mapping.mapper.g.dart @@ -12,7 +12,11 @@ class DogMapperImpl extends DogMapper { @override Dog fromDogModel(DogModel model) { final dog = Dog( - model.dogName, model.breed, model.dogAge, DogMapper._mapDogType(model)); + model.dogName, + model.breed, + model.dogAge, + DogMapper._mapDogType(model), + ); return dog; } } diff --git a/example/lib/freezed/freezed_mapper.mapper.g.dart b/example/lib/freezed/freezed_mapper.mapper.g.dart index 7e7e561..e5c7eaf 100644 --- a/example/lib/freezed/freezed_mapper.mapper.g.dart +++ b/example/lib/freezed/freezed_mapper.mapper.g.dart @@ -11,7 +11,10 @@ class FreezedMapperImpl extends FreezedMapper { @override FreezedTarget fromModel(FreezedSource model) { - final freezedtarget = FreezedTarget(model.name, model.age); + final freezedtarget = FreezedTarget( + model.name, + model.age, + ); return freezedtarget; } } @@ -21,8 +24,10 @@ class FreezedNamedMapperImpl extends FreezedNamedMapper { @override FreezedNamedTarget fromModel(FreezedNamedSource model) { - final freezednamedtarget = - FreezedNamedTarget(name: model.name, age: model.age); + final freezednamedtarget = FreezedNamedTarget( + name: model.name, + age: model.age, + ); return freezednamedtarget; } } diff --git a/example/lib/function_mapping/function_mapping.mapper.g.dart b/example/lib/function_mapping/function_mapping.mapper.g.dart index 3dcc84c..ea61a75 100644 --- a/example/lib/function_mapping/function_mapping.mapper.g.dart +++ b/example/lib/function_mapping/function_mapping.mapper.g.dart @@ -11,8 +11,11 @@ class DogMapperImpl extends DogMapper { @override Dog fromDogModel(DogModel model) { - final dog = Dog(fullNameWithAge(model), DogMapper.breedCustom(model), - FunctionUtils.mapAge(model)); + final dog = Dog( + fullNameWithAge(model), + DogMapper.breedCustom(model), + FunctionUtils.mapAge(model), + ); return dog; } } diff --git a/example/lib/function_mapping/function_mapping_more.dart b/example/lib/function_mapping/function_mapping_more.dart index c8efc30..db5d903 100644 --- a/example/lib/function_mapping/function_mapping_more.dart +++ b/example/lib/function_mapping/function_mapping_more.dart @@ -1,5 +1,5 @@ import 'package:smartstruct/smartstruct.dart'; -import 'package:smartstruct_example/function_mapping/function_utils.dart'; + part 'function_mapping_more.mapper.g.dart'; // TARGET @@ -33,14 +33,14 @@ class AgeHolderTarget { // This is a more complex example. // The toAgeHolderSource may return a "null" and the nested mapping "fromDogModel" -// is not accept "null". +// is not accept "null". // So we need to invoke "toAgeHolderSource" and assign the // return the a variable "tmp". And determine whether use the "nested mapping" by // case that the value of "tmp" is null or not. @Mapper() abstract class DogMapper { static String breedCustom(DogModel model) => 'customBreed'; - + @Mapping(source: fullNameWithAge, target: 'name') @Mapping(source: breedCustom, target: 'breed') @Mapping(source: toAgeHolderSource, target: 'model') @@ -50,4 +50,4 @@ abstract class DogMapper { } String fullNameWithAge(DogModel model) => model.name + '${model.age}'; -AgeHolderSource? toAgeHolderSource(DogModel model) => AgeHolderSource(model.age); \ No newline at end of file +AgeHolderSource? toAgeHolderSource(DogModel model) => AgeHolderSource(model.age); diff --git a/example/lib/function_mapping/function_mapping_more.mapper.g.dart b/example/lib/function_mapping/function_mapping_more.mapper.g.dart index 22473e9..00ed438 100644 --- a/example/lib/function_mapping/function_mapping_more.mapper.g.dart +++ b/example/lib/function_mapping/function_mapping_more.mapper.g.dart @@ -11,8 +11,11 @@ class DogMapperImpl extends DogMapper { @override Dog fromDogModel(DogModel model) { - final dog = - Dog(fullNameWithAge(model), DogMapper.breedCustom(model), model.age); + final dog = Dog( + fullNameWithAge(model), + DogMapper.breedCustom(model), + model.age, + ); dog.model = () { final tmp = toAgeHolderSource(model); return tmp == null ? null : fromAgeHolderSource(tmp); diff --git a/example/lib/function_mapping/function_mapping_with_mapper.mapper.g.dart b/example/lib/function_mapping/function_mapping_with_mapper.mapper.g.dart index 47b8353..e519e97 100644 --- a/example/lib/function_mapping/function_mapping_with_mapper.mapper.g.dart +++ b/example/lib/function_mapping/function_mapping_with_mapper.mapper.g.dart @@ -11,8 +11,10 @@ class PassOnMapperFunctionMapperImpl extends PassOnMapperFunctionMapper { @override ComplexFunctionTarget fromSource(ComplexFunctionSource source) { - final complexfunctiontarget = - ComplexFunctionTarget(mapComplexSubSource(source, mapper: this)); + final complexfunctiontarget = ComplexFunctionTarget(mapComplexSubSource( + source, + mapper: this, + )); return complexfunctiontarget; } diff --git a/example/lib/getter/getter_mapper.dart b/example/lib/getter/getter_mapper.dart new file mode 100644 index 0000000..b58ca8f --- /dev/null +++ b/example/lib/getter/getter_mapper.dart @@ -0,0 +1,40 @@ +import 'package:smartstruct/smartstruct.dart'; + +part 'getter_mapper.mapper.g.dart'; + +class GetterTarget { + final String name; + final int age; + + int foo = 0; + + GetterTarget({ + required this.name, + required this.age, + }); + + List get props => [name, age]; + + bool get sample => false; +} + +class GetterSource { + final String name; + final int age; + + int foo = 1; + + GetterSource({ + required this.name, + required this.age, + }); + + List get props => [name, age]; + + bool get sample => true; +} + +@Mapper() +abstract class GetterMapper { + GetterTarget fromModel(GetterSource source); +} diff --git a/example/lib/getter/getter_mapper.mapper.g.dart b/example/lib/getter/getter_mapper.mapper.g.dart new file mode 100644 index 0000000..6533dbe --- /dev/null +++ b/example/lib/getter/getter_mapper.mapper.g.dart @@ -0,0 +1,21 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'getter_mapper.dart'; + +// ************************************************************************** +// MapperGenerator +// ************************************************************************** + +class GetterMapperImpl extends GetterMapper { + GetterMapperImpl() : super(); + + @override + GetterTarget fromModel(GetterSource source) { + final gettertarget = GetterTarget( + name: source.name, + age: source.age, + ); + gettertarget.foo = source.foo; + return gettertarget; + } +} diff --git a/example/lib/inheritance/inheritance.mapper.g.dart b/example/lib/inheritance/inheritance.mapper.g.dart index a15924c..cf6ae21 100644 --- a/example/lib/inheritance/inheritance.mapper.g.dart +++ b/example/lib/inheritance/inheritance.mapper.g.dart @@ -12,7 +12,11 @@ class InheritanceMapperImpl extends InheritanceMapper { @override BarTarget fromFoo(FooSource source) { final bartarget = BarTarget( - source.subFoo, source.superFoo, source.mappable, source.superProp); + source.subFoo, + source.superFoo, + source.mappable, + source.superProp, + ); return bartarget; } } diff --git a/example/lib/injection/service_locator.config.dart b/example/lib/injection/service_locator.config.dart index 6da0eba..50254bf 100644 --- a/example/lib/injection/service_locator.config.dart +++ b/example/lib/injection/service_locator.config.dart @@ -13,9 +13,16 @@ import 'injectable_mapper.dart' as _i4; // ignore_for_file: unnecessary_lambdas // ignore_for_file: lines_longer_than_80_chars /// initializes the registration of provided dependencies inside of [GetIt] -_i1.GetIt $initGetIt(_i1.GetIt get, - {String? environment, _i2.EnvironmentFilter? environmentFilter}) { - final gh = _i2.GetItHelper(get, environment, environmentFilter); +_i1.GetIt $initGetIt( + _i1.GetIt get, { + String? environment, + _i2.EnvironmentFilter? environmentFilter, +}) { + final gh = _i2.GetItHelper( + get, + environment, + environmentFilter, + ); gh.lazySingleton<_i3.ExampleMapper>(() => _i3.ExampleMapperImpl()); gh.lazySingleton<_i4.InjectableNestedMapper>( () => _i4.InjectableNestedMapperImpl()); diff --git a/example/lib/list/list.mapper.g.dart b/example/lib/list/list.mapper.g.dart index ca7c2de..e2d8a31 100644 --- a/example/lib/list/list.mapper.g.dart +++ b/example/lib/list/list.mapper.g.dart @@ -11,8 +11,10 @@ class ListMapperImpl extends ListMapper { @override Target fromSource(Source source) { - final target = Target(source.intList.map((e) => e).toList(), - source.entryList.map((x) => fromSourceEntry(x)).toList()); + final target = Target( + source.intList.map((e) => e).toList(), + source.entryList.map((x) => fromSourceEntry(x)).toList(), + ); return target; } diff --git a/example/lib/list/nullable_list.mapper.g.dart b/example/lib/list/nullable_list.mapper.g.dart index 2b55257..cab0428 100644 --- a/example/lib/list/nullable_list.mapper.g.dart +++ b/example/lib/list/nullable_list.mapper.g.dart @@ -12,8 +12,9 @@ class NullableListMapperImpl extends NullableListMapper { @override NullableListTarget fromSource(NullableListSource source) { final nullablelisttarget = NullableListTarget( - source.list?.map(fromSubSource).toList(), - source.list2?.map(fromSubSource).toList() ?? []); + source.list?.map((x) => fromSubSource(x)).toList(), + source.list2?.map((x) => fromSubSource(x)).toList() ?? [], + ); return nullablelisttarget; } diff --git a/example/lib/mapper_inheritance/mapper_inheritance.mapper.g.dart b/example/lib/mapper_inheritance/mapper_inheritance.mapper.g.dart index c37770b..df7d535 100644 --- a/example/lib/mapper_inheritance/mapper_inheritance.mapper.g.dart +++ b/example/lib/mapper_inheritance/mapper_inheritance.mapper.g.dart @@ -16,7 +16,10 @@ class UserLoginContractFromEntityMapperImpl return null; } ; - final userlogincontract = UserLoginContract(entity.age, entity.id); + final userlogincontract = UserLoginContract( + entity.age, + entity.id, + ); return userlogincontract; } } @@ -31,7 +34,10 @@ class UserLoginContractFromEntityMapper2Impl return null; } ; - final userlogincontract2 = UserLoginContract2(entity.age, entity.id); + final userlogincontract2 = UserLoginContract2( + entity.age, + entity.id, + ); return userlogincontract2; } } diff --git a/example/lib/multi_constructor/multi_constructor.mapper.g.dart b/example/lib/multi_constructor/multi_constructor.mapper.g.dart index f2e0a02..03cca09 100644 --- a/example/lib/multi_constructor/multi_constructor.mapper.g.dart +++ b/example/lib/multi_constructor/multi_constructor.mapper.g.dart @@ -11,7 +11,10 @@ class MultiConMapperImpl extends MultiConMapper { @override MultiConTarget fromSource(MultiConSource source) { - final multicontarget = MultiConTarget.multi(source.text, source.number); + final multicontarget = MultiConTarget.multi( + source.text, + source.number, + ); return multicontarget; } } diff --git a/example/lib/multiple_sources/multiple_sources.mapper.g.dart b/example/lib/multiple_sources/multiple_sources.mapper.g.dart index 2c22145..c83c3cf 100644 --- a/example/lib/multiple_sources/multiple_sources.mapper.g.dart +++ b/example/lib/multiple_sources/multiple_sources.mapper.g.dart @@ -10,9 +10,21 @@ class MultipleSourcesMapperImpl extends MultipleSourcesMapper { MultipleSourcesMapperImpl() : super(); @override - Target fromSource(Source source, Source2 source2, Source3 source3) { - final target = Target(source.text1, source2.text2, source3.text3, - allText(source, source2, source3)); + Target fromSource( + Source source, + Source2 source2, + Source3 source3, + ) { + final target = Target( + source.text1, + source2.text2, + source3.text3, + allText( + source, + source2, + source3, + ), + ); return target; } } diff --git a/example/lib/nested/nested_mapping.mapper.g.dart b/example/lib/nested/nested_mapping.mapper.g.dart index 1b7e995..b0e445f 100644 --- a/example/lib/nested/nested_mapping.mapper.g.dart +++ b/example/lib/nested/nested_mapping.mapper.g.dart @@ -11,8 +11,11 @@ class UserMapperImpl extends UserMapper { @override User fromResponse(UserResponse response) { - final user = User(response.username, response.address.zipcode, - response.address.street.streetName); + final user = User( + response.username, + response.address.zipcode, + response.address.street.streetName, + ); return user; } } diff --git a/example/lib/static_mapping/static_mapping.mapper.g.dart b/example/lib/static_mapping/static_mapping.mapper.g.dart index 0750f5c..5ad5d06 100644 --- a/example/lib/static_mapping/static_mapping.mapper.g.dart +++ b/example/lib/static_mapping/static_mapping.mapper.g.dart @@ -11,12 +11,18 @@ class StaticMappingMapperImpl extends StaticMappingMapper { @override StaticMappingTarget fromSourceNormal(StaticMappingSource source) { - final staticmappingtarget = StaticMappingTarget(source.text, source.number); + final staticmappingtarget = StaticMappingTarget( + source.text, + source.number, + ); return staticmappingtarget; } } StaticMappingTarget _$fromSourceStatic(StaticMappingSource source) { - final staticmappingtarget = StaticMappingTarget(source.text, source.number); + final staticmappingtarget = StaticMappingTarget( + source.text, + source.number, + ); return staticmappingtarget; } diff --git a/example/lib/static_mapping/static_proxy.mapper.g.dart b/example/lib/static_mapping/static_proxy.mapper.g.dart index 5f559dd..a3fbcb8 100644 --- a/example/lib/static_mapping/static_proxy.mapper.g.dart +++ b/example/lib/static_mapping/static_proxy.mapper.g.dart @@ -11,7 +11,10 @@ class StaticMappingMapperImpl extends StaticMappingMapper { @override StaticProxyTarget fromSourceNormal(StaticMappingSource source) { - final staticproxytarget = StaticProxyTarget(source.text, source.number); + final staticproxytarget = StaticProxyTarget( + source.text, + source.number, + ); return staticproxytarget; } } diff --git a/example/pubspec.lock b/example/pubspec.lock index 238eee3..aab439a 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,14 +7,14 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "47.0.0" + version: "50.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "4.7.0" + version: "5.2.0" args: dependency: transitive description: @@ -42,7 +42,7 @@ packages: name: build_config url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.1.1" build_daemon: dependency: transitive description: @@ -63,7 +63,7 @@ packages: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "2.1.11" + version: "2.3.3" build_runner_core: dependency: transitive description: @@ -105,7 +105,7 @@ packages: name: code_builder url: "https://pub.dartlang.org" source: hosted - version: "4.1.0" + version: "4.4.0" collection: dependency: transitive description: @@ -154,7 +154,7 @@ packages: name: freezed url: "https://pub.dartlang.org" source: hosted - version: "2.1.0+1" + version: "2.1.1" freezed_annotation: dependency: "direct main" description: @@ -168,7 +168,7 @@ packages: name: frontend_server_client url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "3.2.0" get_it: dependency: transitive description: @@ -210,14 +210,14 @@ packages: name: injectable url: "https://pub.dartlang.org" source: hosted - version: "1.5.3" + version: "1.5.4" injectable_generator: dependency: "direct dev" description: name: injectable_generator url: "https://pub.dartlang.org" source: hosted - version: "1.5.4" + version: "1.5.5" io: dependency: transitive description: @@ -238,7 +238,7 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.4.0" + version: "4.8.0" logging: dependency: transitive description: @@ -326,17 +326,17 @@ packages: smartstruct: dependency: "direct main" description: - name: smartstruct - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" + path: "../smartstruct" + relative: true + source: path + version: "1.4.0" smartstruct_generator: dependency: "direct dev" description: name: smartstruct_generator url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.4.0" source_gen: dependency: transitive description: @@ -422,4 +422,4 @@ packages: source: hosted version: "3.1.0" sdks: - dart: ">=2.17.0 <3.0.0" + dart: ">=2.18.0 <3.0.0" diff --git a/generator/lib/code_builders/method_builder.dart b/generator/lib/code_builders/method_builder.dart index 8a6b6ef..8eda415 100644 --- a/generator/lib/code_builders/method_builder.dart +++ b/generator/lib/code_builders/method_builder.dart @@ -3,55 +3,46 @@ import 'dart:collection'; import 'package:analyzer/dart/element/element.dart'; import 'package:code_builder/code_builder.dart'; import 'package:smartstruct_generator/code_builders/parameter_copy.dart'; +import 'package:smartstruct_generator/mapper_config.dart'; import 'package:smartstruct_generator/models/RefChain.dart'; import 'package:smartstruct_generator/models/source_assignment.dart'; -import 'package:smartstruct_generator/mapper_config.dart'; import 'package:source_gen/source_gen.dart'; import 'assignment_builder.dart'; /// Generates the implemented mapper method by the given abstract [MethodElement]. -Method buildMapperImplementation(Map config, - MethodElement method, ClassElement abstractMapper) { - if (method.returnType.element2 == null) { - throw InvalidGenerationSourceError( - '${method.returnType} is not a valid return type', - element: method, - todo: 'Add valid return type to mapping method'); +Method buildMapperImplementation(Map config, MethodElement method, ClassElement abstractMapper) { + if (method.returnType.element == null) { + throw InvalidGenerationSourceError('${method.returnType} is not a valid return type', + element: method, todo: 'Add valid return type to mapping method'); } return Method((b) => b ..annotations.add(CodeExpression(Code('override'))) ..name = method.displayName ..requiredParameters.addAll(method.parameters.map((e) => copyParameter(e))) ..body = _generateBody(config, method, abstractMapper) - ..returns = - refer(method.returnType.getDisplayString(withNullability: true))); + ..returns = refer(method.returnType.getDisplayString(withNullability: true))); } - /// Generates the implemented mapper method by the given abstract [MethodElement]. -Method buildStaticMapperImplementation(Map config, - MethodElement method, ClassElement abstractMapper) { +Method buildStaticMapperImplementation(Map config, MethodElement method, ClassElement abstractMapper) { return Method( - (b) => b + (b) => b ..name = '_\$${method.name}' ..requiredParameters.addAll(method.parameters.map((e) => copyParameter(e))) ..body = _generateBody(config, method, abstractMapper) - ..returns = - refer(method.returnType.getDisplayString(withNullability: true)), + ..returns = refer(method.returnType.getDisplayString(withNullability: true)), ); } - /// Generates the body for the mapping method. /// /// Uses the default constructor of the target mapping class to populate optional and required named and positional parameters. /// If the target class has any properties which were not set in the constructor, and are mappable by the source, they will be also mapped after initializing the target instance. -Code _generateBody(Map config, MethodElement method, - ClassElement abstractMapper) { +Code _generateBody(Map config, MethodElement method, ClassElement abstractMapper) { final blockBuilder = BlockBuilder(); - final targetClass = method.returnType.element2 as ClassElement; + final targetClass = method.returnType.element as ClassElement; final sourceParams = method.parameters; @@ -69,8 +60,7 @@ Code _generateBody(Map config, MethodElement method, .where((targetField) => targetToSource.containsKey(targetField.name)) .forEach((targetField) { final sourceAssignment = targetToSource[targetField.name]!; - var sourceFieldAssignment = generateSourceFieldAssignment( - sourceAssignment, abstractMapper, targetField); + var sourceFieldAssignment = generateSourceFieldAssignment(sourceAssignment, abstractMapper, targetField); if (targetField.isNamed) { namedArgs.putIfAbsent(targetField.name, () => sourceFieldAssignment); @@ -84,31 +74,23 @@ Code _generateBody(Map config, MethodElement method, // source.isOptional does not work for (final sourceParam in sourceParams) { - if (sourceParam.type - .getDisplayString(withNullability: true) - .endsWith('?')) { - blockBuilder.addExpression( - refer('if (${sourceParam.displayName} == null) { return null; }')); + if (sourceParam.type.getDisplayString(withNullability: true).endsWith('?')) { + blockBuilder.addExpression(refer('if (${sourceParam.displayName} == null) { return null; }')); } } // final output = Output(positionalArgs, {namedArgs}); - blockBuilder.addExpression(refer(targetConstructor.displayName) - .newInstance(positionalArgs, namedArgs) - .assignFinal(targetVarName)); + blockBuilder.addExpression( + refer(targetConstructor.displayName).newInstance(positionalArgs, namedArgs).assignFinal(targetVarName)); // non final properties (implicit and explicit setters) final fields = _findFields(targetClass); fields // .where((field) => !field.isFinal) // - .where( - (targetField) => targetToSource.containsKey(targetField.displayName)) + .where((targetField) => targetToSource.containsKey(targetField.displayName)) .map((targetField) { var sourceAssignment = targetToSource[targetField.displayName]!; - var sourceFieldAssignment = generateSourceFieldAssignment( - sourceAssignment, abstractMapper, targetField); - return refer(targetVarName) - .property(targetField.displayName) - .assign(sourceFieldAssignment); + var sourceFieldAssignment = generateSourceFieldAssignment(sourceAssignment, abstractMapper, targetField); + return refer(targetVarName).property(targetField.displayName).assign(sourceFieldAssignment); }).forEach((expr) => blockBuilder.addExpression(expr)); blockBuilder.addExpression(refer(targetVarName).returned); @@ -117,8 +99,7 @@ Code _generateBody(Map config, MethodElement method, /// Chooses the constructor which will be used to instantiate the target class. ConstructorElement _chooseConstructor(ClassElement outputClass) { - ConstructorElement chosen = - outputClass.constructors.where((element) => !element.isFactory).first; + ConstructorElement chosen = outputClass.constructors.where((element) => !element.isFactory).first; for (var con in outputClass.constructors) { if (con.parameters.length >= chosen.parameters.length) { // choose the one with the most parameters @@ -129,10 +110,8 @@ ConstructorElement _chooseConstructor(ClassElement outputClass) { } List _findFields(ClassElement clazz) { - final allSuperclasses = clazz.allSupertypes - .where((element) => !element.isDartCoreObject) - .map((e) => e.element) - .toList(); + final allSuperclasses = + clazz.allSupertypes.where((element) => !element.isDartCoreObject).map((e) => e.element).toList(); final allAccessors = allSuperclasses.map((e) => e.accessors).expand((e) => e); final accessorMap = {for (var e in allAccessors) e.displayName: e}; @@ -148,25 +127,20 @@ List _findFields(ClassElement clazz) { return !field.isStatic && !field.isConst && !isAbstract; }; - final allSuperFields = allSuperclasses - .map((e) => e.fields) - .expand((e) => e) - .where(fieldFilter) - .toList(); - return [...clazz.fields, ...allSuperFields]; + final allSuperFields = allSuperclasses.map((e) => e.fields).expand((e) => e).where(fieldFilter).toList(); + return [ + ...clazz.fields.where((x) => !x.isSynthetic), + ...allSuperFields.where((x) => !x.isSynthetic || (x.getter != null)), + ]; } List> _targetToSource( - List sources, - ClassElement target, - MethodElement method, - Map config) { - final sourceMap = {for (var e in sources) e.type.element2 as ClassElement: e}; + List sources, ClassElement target, MethodElement method, Map config) { + final sourceMap = {for (var e in sources) e.type.element as ClassElement: e}; final caseSensitiveFields = config['caseSensitiveFields']; final fieldMapper = caseSensitiveFields ? (a) => a : (a) => a.toUpperCase(); - final equalsHashCode = - caseSensitiveFields ? (a) => a.hashCode : (a) => a.toUpperCase().hashCode; + final equalsHashCode = caseSensitiveFields ? (a) => a.hashCode : (a) => a.toUpperCase().hashCode; final mappingConfig = MapperConfig.readMappingConfig(method); // final customMappingConfig = MapperConfig.readCustomMappingConfig(method); @@ -174,42 +148,33 @@ List> _targetToSource( /// It is very usefull when you want to have caseInsensitive keys /// Contains data from @Mapping annotations var targetToSource = HashMap( - equals: (a, b) => fieldMapper(a) == fieldMapper(b), - hashCode: (a) => equalsHashCode(a)); + equals: (a, b) => fieldMapper(a) == fieldMapper(b), hashCode: (a) => equalsHashCode(a)); /// Contains data from @CustomMapping annotations var customTargetToSource = HashMap( - equals: (a, b) => fieldMapper(a) == fieldMapper(b), - hashCode: (a) => equalsHashCode(a)); + equals: (a, b) => fieldMapper(a) == fieldMapper(b), hashCode: (a) => equalsHashCode(a)); final mappingStringConfig = _extractStringMappingConfig(mappingConfig); for (final sourceEntry in sourceMap.entries) { Map> matchedSourceClazzInSourceMapping = - _findMatchingSourceClazzInMappingMap( - mappingStringConfig, sourceEntry.value.displayName); + _findMatchingSourceClazzInMappingMap(mappingStringConfig, sourceEntry.value.displayName); for (var f in _findFields(sourceEntry.key)) { if (targetToSource.containsKey(f.name) && !caseSensitiveFields) { - final duplicatedKey = targetToSource.keys - .toList() - .firstWhere((k) => k.toUpperCase() == f.name.toUpperCase()); + final duplicatedKey = targetToSource.keys.toList().firstWhere((k) => k.toUpperCase() == f.name.toUpperCase()); throw InvalidGenerationSourceError( 'Mapper got case insensitive fields and contains fields: ${f.name} and $duplicatedKey. If you use a case-sensitive mapper, make sure the fields are unique in a case insensitive way.', todo: "Use case sensitive mapper or change field's names"); } - if (matchedSourceClazzInSourceMapping.isNotEmpty && - _shouldSearchMoreFields(f)) { + if (matchedSourceClazzInSourceMapping.isNotEmpty && _shouldSearchMoreFields(f)) { for (var matchedTarget in matchedSourceClazzInSourceMapping.keys) { - final sourceValueList = - matchedSourceClazzInSourceMapping[matchedTarget]!; - final fieldClazz = f.type.element2 as ClassElement; - + final sourceValueList = matchedSourceClazzInSourceMapping[matchedTarget]!; + final refChain = RefChain.byPropNames(sourceEntry.value, sourceValueList.sublist(1)); targetToSource[matchedTarget] = SourceAssignment.fromRefChain(refChain); } } else { - targetToSource[f.name] = - SourceAssignment.fromRefChain(RefChain([sourceEntry.value, f])); + targetToSource[f.name] = SourceAssignment.fromRefChain(RefChain([sourceEntry.value, f])); } } } @@ -220,15 +185,13 @@ List> _targetToSource( final sourceField = mappingConfig.source; if (sourceField != null) { if (sourceField.toFunctionValue() != null) { - targetToSource[targetField] = SourceAssignment.fromFunction( - sourceField.toFunctionValue()!, [...sources]); + targetToSource[targetField] = SourceAssignment.fromFunction(sourceField.toFunctionValue()!, [...sources]); } else if (sourceField.toStringValue() != null) { final sourceFieldString = sourceField.toStringValue()!; // sourceField exists in any sourceParam if (targetToSource.containsKey(sourceFieldString)) { // replace mapping target with mapping - targetToSource.putIfAbsent( - targetField, () => targetToSource[sourceFieldString]!); + targetToSource.putIfAbsent(targetField, () => targetToSource[sourceFieldString]!); targetToSource.remove(sourceFieldString); } } @@ -243,8 +206,7 @@ List> _targetToSource( } /// Extracts all Mapping Config Entries in [mappingConfig] which contains source mappings of type string -Map _extractStringMappingConfig( - Map mappingConfig) { +Map _extractStringMappingConfig(Map mappingConfig) { final mappingStringConfig = {}; mappingConfig.forEach((key, value) { if (value.source != null && value.source!.toStringValue() != null) { @@ -254,27 +216,8 @@ Map _extractStringMappingConfig( return mappingStringConfig; } -/// Searches for a matching class for every given [MappingConfig] in [mappingStringConfig], matched against the given [matchingSourceClazzName] -/// For MappingConfigs including dot seperated clazz attributes, the first value before the first dot is matched against the given matchingSourceClazzName. -/// Example: A MappingConfig containing "user.address.zipcode" would try to match against user -List> _findMatchingSourceClazzInMapping( - Map mappingStringConfig, - String matchingSourceClazzName) { - List> matchedSourceClazzInSourceMapping = []; - mappingStringConfig.forEach((key, value) { - // clazz.attribute1.attribute1_1 - final sourceValueList = value.source!.toStringValue()!.split("."); - final sourceClass = sourceValueList[0]; - if (sourceClass == matchingSourceClazzName) { - matchedSourceClazzInSourceMapping.add(sourceValueList); - } - }); - return matchedSourceClazzInSourceMapping; -} - Map> _findMatchingSourceClazzInMappingMap( - Map mappingStringConfig, - String matchingSourceClazzName) { + Map mappingStringConfig, String matchingSourceClazzName) { Map> ret = {}; mappingStringConfig.forEach((key, value) { // clazz.attribute1.attribute1_1 @@ -287,30 +230,6 @@ Map> _findMatchingSourceClazzInMappingMap( return ret; } -/// Finds the matching field, matching the last source of [sources] to any field of [fields] -/// If no field was found, null is returned -/// -/// Example: [sources]="user,address,zipcode" with [fields]=address would identify address as a field, then continue searching in the address field for the zipcode field. -/// If the address contains a field zipcode, the zipcode field is returned. -FieldElement? _findMatchingField( - List sources, List fields) { - for (var source in sources) { - final potentielFinds = fields.where((element) => element.name == source); - if (potentielFinds.isEmpty) { - continue; - } - final foundField = potentielFinds.first; - // foundField is not string - if (_shouldSearchMoreFields(foundField)) { - final searchClazz = foundField.type.element2 as ClassElement; - return _findMatchingField( - sources.skip(1).toList(), _findFields(searchClazz)); - } else { - return foundField; - } - } -} - /// A search for a potential underlying should only be continued, if the field is not a primitive type (string, int, double etc) bool _shouldSearchMoreFields(FieldElement field) { return !field.type.isDartCoreString && diff --git a/generator/lib/generators/mapper_generator.dart b/generator/lib/generators/mapper_generator.dart index dfeb1f8..e8b2bbb 100644 --- a/generator/lib/generators/mapper_generator.dart +++ b/generator/lib/generators/mapper_generator.dart @@ -1,24 +1,19 @@ -import 'dart:collection'; - -import 'package:analyzer/dart/element/type.dart'; -import 'package:build/src/builder/build_step.dart'; import 'package:analyzer/dart/element/element.dart'; +import 'package:build/src/builder/build_step.dart'; import 'package:code_builder/code_builder.dart'; import 'package:smartstruct/smartstruct.dart'; import 'package:smartstruct_generator/code_builders/class_builder.dart'; import 'package:source_gen/source_gen.dart'; + import '../mapper_config.dart'; /// Codegenerator to generate implemented mapping classes class MapperGenerator extends GeneratorForAnnotation { @override - dynamic generateForAnnotatedElement( - Element element, ConstantReader annotation, BuildStep buildStep) { + dynamic generateForAnnotatedElement(Element element, ConstantReader annotation, BuildStep buildStep) { if (element is! ClassElement) { - throw InvalidGenerationSourceError( - '${element.displayName} is not a class and cannot be annotated with @Mapper', - element: element, - todo: 'Add Mapper annotation to a class'); + throw InvalidGenerationSourceError('${element.displayName} is not a class and cannot be annotated with @Mapper', + element: element, todo: 'Add Mapper annotation to a class'); } var config = MapperConfig.readMapperConfig(annotation, element); diff --git a/generator/lib/models/NestMapping.dart b/generator/lib/models/NestMapping.dart index 3ccb134..652217a 100644 --- a/generator/lib/models/NestMapping.dart +++ b/generator/lib/models/NestMapping.dart @@ -1,9 +1,7 @@ - import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/nullability_suffix.dart'; class NestMapping { - final MethodElement method; final VariableElement input; late final bool returnNullable; @@ -17,9 +15,8 @@ class NestMapping { inputNullable = input.type.nullabilitySuffix == NullabilitySuffix.question; methodParamterNullable = method.parameters.first.type.nullabilitySuffix == NullabilitySuffix.question; - returnNullable = - (inputNullable && !methodParamterNullable) || // 'a == null ? null : call(a)'. So the output is nullable. - (inputNullable && methodReturnNullable); // if input is not null, the method return is not + returnNullable = + (inputNullable && !methodParamterNullable) || // 'a == null ? null : call(a)'. So the output is nullable. + (inputNullable && methodReturnNullable); // if input is not null, the method return is not } - -} \ No newline at end of file +} diff --git a/generator/test/mapper_test.dart b/generator/test/mapper_test.dart index c1a0b82..1abade6 100644 --- a/generator/test/mapper_test.dart +++ b/generator/test/mapper_test.dart @@ -1,6 +1,6 @@ +import 'package:path/path.dart' as p; import 'package:smartstruct_generator/generators/mapper_generator.dart'; import 'package:source_gen_test/source_gen_test.dart'; -import 'package:path/path.dart' as p; Future main() async { initializeBuildLogTracking(); @@ -43,4 +43,5 @@ const _expectedAnnotatedTests = { 'PassOnMapperFunctionMapper', 'StaticProxyMapper', 'MapperInheritanceMapper', + 'ExplicitGetterMapper', }; diff --git a/generator/test/src/getter_field_mapper_input.dart b/generator/test/src/getter_field_mapper_input.dart new file mode 100644 index 0000000..24b81eb --- /dev/null +++ b/generator/test/src/getter_field_mapper_input.dart @@ -0,0 +1,53 @@ +part of 'mapper_test_input.dart'; + +class GetterTarget { + final String name; + final int age; + + int foo = 0; + + GetterTarget({ + required this.name, + required this.age, + }); + + List get props => [name, age]; + + bool get sample => false; +} + +class GetterSource { + final String name; + final int age; + + int foo = 1; + + GetterSource({ + required this.name, + required this.age, + }); + + List get props => [name, age]; + + bool get sample => true; +} + +@Mapper() +@ShouldGenerate(r''' +class ExplicitGetterMapperImpl extends ExplicitGetterMapper { + ExplicitGetterMapperImpl() : super(); + + @override + GetterTarget fromModel(GetterSource source) { + final gettertarget = GetterTarget( + name: source.name, + age: source.age, + ); + gettertarget.foo = source.foo; + return gettertarget; + } +} +''') +abstract class ExplicitGetterMapper { + GetterTarget fromModel(GetterSource source); +} diff --git a/generator/test/src/mapper_test_input.dart b/generator/test/src/mapper_test_input.dart index bfe9c22..d1dd393 100644 --- a/generator/test/src/mapper_test_input.dart +++ b/generator/test/src/mapper_test_input.dart @@ -8,6 +8,7 @@ part 'collection_mapper_input.dart'; part 'constructor_mapper_input.dart'; part 'explicit_field_mapper_input.dart'; part 'function_mapper_input.dart'; +part 'getter_field_mapper_input.dart'; part 'ignore_field_mapper_input.dart'; part 'inheritance_mapper_input.dart'; part 'injectable_mapper_input.dart';