diff --git a/example/.packages b/example/.packages index 5bb5c20..017a6d0 100644 --- a/example/.packages +++ b/example/.packages @@ -1,4 +1,4 @@ -# Generated by pub on 2020-04-28 23:59:20.333515. +# Generated by pub on 2020-05-11 23:01:07.204920. _fe_analyzer_shared:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-1.0.3/lib/ analyzer:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-0.39.4/lib/ args:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/args-1.5.3/lib/ @@ -21,7 +21,6 @@ crypto:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/cr csslib:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/csslib-0.16.1/lib/ dart_style:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/dart_style-1.3.3/lib/ fixnum:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/fixnum-0.10.11/lib/ -flutter:file:///Users/milad/dev/sdk/flutter/packages/flutter/lib/ get_it:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/get_it-4.0.0/lib/ glob:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/glob-1.2.0/lib/ graphs:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/graphs-0.2.0/lib/ @@ -29,7 +28,6 @@ html:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/html http:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/http-0.12.0+4/lib/ http_multi_server:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/http_multi_server-2.2.0/lib/ http_parser:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/http_parser-3.1.3/lib/ -i18n_extension:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/i18n_extension-1.3.5/lib/ injectable:../injectable/lib/ injectable_generator:../injectable_generator/lib/ io:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/io-0.3.3/lib/ @@ -52,10 +50,8 @@ pubspec_parse:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang quiver:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/quiver-2.1.3/lib/ shelf:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/shelf-0.7.5/lib/ shelf_web_socket:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-0.2.3/lib/ -sky_engine:file:///Users/milad/dev/sdk/flutter/bin/cache/pkg/sky_engine/lib/ source_gen:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/source_gen-0.9.5/lib/ source_span:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/source_span-1.6.0/lib/ -sprintf:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/sprintf-4.0.2/lib/ stack_trace:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.9.3/lib/ stream_channel:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.0.0/lib/ stream_transform:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/stream_transform-1.2.0/lib/ @@ -64,7 +60,6 @@ term_glyph:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.or test_api:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/test_api-0.2.15/lib/ timing:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/timing-0.1.1+2/lib/ typed_data:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.1.6/lib/ -vector_math:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.0.8/lib/ watcher:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/watcher-0.9.7+13/lib/ web_socket_channel:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-1.1.0/lib/ yaml:file:///Users/milad/dev/sdk/flutter/.pub-cache/hosted/pub.dartlang.org/yaml-2.2.0/lib/ diff --git a/example/bin/main.dart b/example/bin/main.dart index b74327e..bf2219f 100644 --- a/example/bin/main.dart +++ b/example/bin/main.dart @@ -1,6 +1,5 @@ import 'package:example/injector.dart'; void main(List arguments) { - configure(); - print('x'); + configureDependecies(); } diff --git a/example/lib/injector.dart b/example/lib/injector.dart index 34f3643..bc7ae08 100644 --- a/example/lib/injector.dart +++ b/example/lib/injector.dart @@ -6,6 +6,4 @@ import 'injector.iconfig.dart'; final getIt = GetIt.instance; @injectableInit -Future configure() async { - return $initGetIt(getIt); -} +void configureDependecies() => $initGetIt(getIt); diff --git a/example/lib/injector.iconfig.dart b/example/lib/injector.iconfig.dart index 07e976b..7808d7f 100644 --- a/example/lib/injector.iconfig.dart +++ b/example/lib/injector.iconfig.dart @@ -5,30 +5,17 @@ // ************************************************************************** import 'package:example/register_module.dart'; -import 'package:example/user.dart'; -import 'package:example/generic.dart'; -import 'package:example/services.dart'; import 'package:get_it/get_it.dart'; -Future $initGetIt(GetIt g, {String environment}) async { +void $initGetIt(GetIt g, {String environment}) { final registerModule = _$RegisterModule(); - final apiClient = await registerModule.apiClient; - g.registerFactory(() => apiClient); - g.registerFactoryParam, int>( - (x, y) => registerModule.testSing(x, y)); - g.registerFactory(() => CategoriesService()); - g.registerFactoryParam( - (varName, varTwo) => ProductService.create(varName, varTwo)); - g.registerFactory(() => ServiceA()); - g.registerFactory(() => ServiceB(g())); - g.registerFactory(() => Service3(g())); - - //Eager singletons must be registered in the right order - if (environment == 'dev') { - g.registerSingleton(TestClass()); - } - g.registerSingleton( - ComponentBloc(g(), g())); + g.registerFactory(() => ApiClient.named(g())); + g.registerFactoryParam( + (url, x) => registerModule.apiClient( + url, + g(), + x, + )); } class _$RegisterModule extends RegisterModule {} diff --git a/example/lib/register_module.dart b/example/lib/register_module.dart index 04e4e8c..23314b5 100644 --- a/example/lib/register_module.dart +++ b/example/lib/register_module.dart @@ -1,55 +1,26 @@ -import 'package:example/user.dart'; import 'package:injectable/injectable.dart'; -import 'package:i18n_extension/default.i18n.dart'; -import 'generic.dart'; - -@registerModule +@module abstract class RegisterModule { - // AbsService get absS; - // Future genIml(String x, int y) async => ServiceX(); - // @singleton - // ServiceX ser(); - // @singleton - // TestClass get testClass; - // TestSingleton2 get testSing33; - - BackendService testSing(User x, int y) => - BackendService("Title".i18n); - - // BackendService getService(String url) => BackendService(url); - // @preResolve - // @Singleton(dependsOn: [TestClass]) - // Future get futureSing => TestSingleton.create(); - - // TestSingleton2 get test; - @preResolve - Future get apiClient => ApiClient.create(); -} + // @Singleton(as: LocalStorage) + LocalStorage apiClient( + @factoryParam String url, + LocalStorage localStorage, + @factoryParam int x, + ) => + ApiClient.named(url); -// // @Named("class") -// // @injectable -// class TestSingleton2 { -// TestSingleton2(AbsService service); -// } - -// abstract class AbsService {} - -// @injectable -class BackendService { - final String title; - - BackendService(this.title); + // @singleton + // ApiClient api(String x) => ApiClient.named(x); } -// @RegisterAs(BackendService, env: 'test') -// @injectable -// class BackendServiceMock extends Mock implements BackendService {} - -// @injectable -class ApiClient { +// @singleton +// @RegisterAs(LocalStorage) +// @test +@Injectable(as: LocalStorage) +class ApiClient extends LocalStorage { @factoryMethod - static Future create() async { - return ApiClient(); - } + ApiClient.named(String url); } + +abstract class LocalStorage {} diff --git a/example/lib/services.dart b/example/lib/services.dart deleted file mode 100644 index edc000c..0000000 --- a/example/lib/services.dart +++ /dev/null @@ -1,72 +0,0 @@ -import 'package:injectable/injectable.dart'; - -// @injectable -// abstract class Service { -// @factoryMethod -// static create(Service11 s11) => ServiceImpl2(); -// } - -// @named -// @RegisterAs(Service, env: 'test') -// @injectable -// class ServiceImpl2 implements Service { -// ServiceImpl2(); -// } - -// @injectable -// @RegisterAs(Service, env: 'dev') -// class ServiceImpl extends Service {} - -// @injectable -// @dev -// class MyRepository { -// @factoryMethod -// MyRepository.from(Service ss); -// } - -@injectable -class ServiceA {} - -@injectable -class ServiceB { - ServiceB(ServiceA sa); -} - -@injectable -class Service3 { - Service3(ServiceB s2s); -} - -@singleton -class ComponentBloc { - ComponentBloc(ProductService s1, - CategoriesService s2,); -} - -@injectable -class ProductService { - @factoryMethod - static ProductService create(@factoryParam String varName, - @factoryParam int varTwo,) => - ProductService(); -} - -@injectable -class CategoriesService {} - -@dev -@singleton -class TestClass { - TestClass(); - - // @factoryMethod - static Future create() async => TestClass(); -} - -// @prod -// @Singleton(dependsOn: [TestClass]) -// class TestSingleton { -// TestSingleton(); -// @factoryMethod -// static Future create(TestClass claxx) async => TestSingleton(); -// } diff --git a/example/pubspec.lock b/example/pubspec.lock index e29d62f..c302198 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -155,11 +155,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.10.11" - flutter: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" get_it: dependency: "direct main" description: @@ -209,13 +204,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.1.3" - i18n_extension: - dependency: "direct main" - description: - name: i18n_extension - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.5" injectable: dependency: "direct main" description: @@ -229,7 +217,7 @@ packages: path: "../injectable_generator" relative: true source: path - version: "0.3.4" + version: "0.3.5" io: dependency: transitive description: @@ -370,11 +358,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.2.3" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" source_gen: dependency: transitive description: @@ -389,13 +372,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.6.0" - sprintf: - dependency: transitive - description: - name: sprintf - url: "https://pub.dartlang.org" - source: hosted - version: "4.0.2" stack_trace: dependency: transitive description: @@ -452,13 +428,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.6" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.8" watcher: dependency: transitive description: diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 432c5d4..7ca7360 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -11,7 +11,6 @@ dependencies: # sdk: flutter get_it: 4.0.0 mockito: ^4.1.1 - i18n_extension: injectable: path: ../injectable # path: ^1.6.0 diff --git a/injectable/lib/src/injectable_annotations.dart b/injectable/lib/src/injectable_annotations.dart index 2252b30..af5ea12 100644 --- a/injectable/lib/src/injectable_annotations.dart +++ b/injectable/lib/src/injectable_annotations.dart @@ -5,31 +5,38 @@ class InjectableInit { const injectableInit = const InjectableInit._(); class Injectable { - const Injectable._(); + final Type as; + final String env; + const Injectable({this.as, this.env}); } -const injectable = const Injectable._(); +const injectable = const Injectable(); /// Classes annotated with @Singleton -/// will generate registerSingleton or -/// registerLazySingleton if [_lazy] is true +/// will generate registerSingleton func class Singleton extends Injectable { final bool signalsReady; - final bool _lazy; final List dependsOn; - const Singleton({this.signalsReady, this.dependsOn}) - : _lazy = false, - super._(); + const Singleton({ + this.signalsReady, + this.dependsOn, + Type as, + String env, + }) : super(as: as, env: env); +} - const Singleton.lazy({this.signalsReady}) - : _lazy = true, - dependsOn = null, - super._(); +/// Classes annotated with @LazySingleton +/// will generate registerLazySingleton func +class LazySingleton extends Injectable { + const LazySingleton({ + Type as, + String env, + }) : super(as: as, env: env); } const singleton = const Singleton(); -const lazySingleton = const Singleton.lazy(); +const lazySingleton = const LazySingleton(); // Used to annotate a constructor dependency // that's registered with an instance names; @@ -102,8 +109,11 @@ class RegisterModule { const RegisterModule._(); } +@Deprecated('Use module instead') const registerModule = const RegisterModule._(); +const module = const RegisterModule._(); + /// Futures annotated with [preResolv] /// will be pre-awaited before they're /// registered inside of GetIt diff --git a/injectable_generator/lib/builder.dart b/injectable_generator/lib/builder.dart index 3459e28..8a7f677 100644 --- a/injectable_generator/lib/builder.dart +++ b/injectable_generator/lib/builder.dart @@ -7,6 +7,7 @@ import 'injectable_generator.dart'; Builder injectableBuilder(BuilderOptions options) { return LibraryBuilder( InjectableGenerator(options.config), + formatOutput: (generated) => generated.replaceAll(RegExp(r'//.*|\s'), ''), generatedExtension: '.injectable.json', ); } diff --git a/injectable_generator/lib/dependency_config.dart b/injectable_generator/lib/dependency_config.dart index 0f41215..676b00b 100644 --- a/injectable_generator/lib/dependency_config.dart +++ b/injectable_generator/lib/dependency_config.dart @@ -8,23 +8,29 @@ class DependencyConfig { int injectableType; String instanceName; bool signalsReady; - String bindTo; + String typeImpl; String environment; + String initializerName; String constructorName; bool isAsync; - RegisterModuleItem moduleConfig; List dependsOn; - bool preResolve; + bool isAbstract = false; + bool isModuleMethod = false; + // String name; + String moduleName; + DependencyConfig(); DependencyConfig.fromJson(Map json) { type = json['type']; - bindTo = json['bindTo']; + typeImpl = json['typeImpl']; instanceName = json['instanceName']; signalsReady = json['signalsReady']; + initializerName = json['initializerName'] ?? ''; constructorName = json['constructorName'] ?? ''; + isAsync = json['isAsync'] ?? false; preResolve = json['preResolve'] ?? preResolve; imports = json['imports']?.cast(); @@ -35,18 +41,20 @@ class DependencyConfig { }); } - if (json['moduleConfig'] != null) { - moduleConfig = RegisterModuleItem.fromJson(json['moduleConfig']); - } injectableType = json['injectableType']; environment = json['environment']; + + isAbstract = json['isAbstract'] ?? false; + isModuleMethod = json['isModuleMethod'] ?? false; + moduleName = json['moduleName']; } + bool get isFromModule => moduleName != null; bool get registerAsInstance => isAsync && preResolve; Map toJson() => { "type": type, - "bindTo": bindTo, + "typeImpl": typeImpl, "isAsync": isAsync, "preResolve": preResolve, "injectableType": injectableType, @@ -56,13 +64,15 @@ class DependencyConfig { if (instanceName != null) "instanceName": instanceName, if (signalsReady != null) "signalsReady": signalsReady, if (environment != null) "environment": environment, + if (initializerName != null) "initializerName": initializerName, if (constructorName != null) "constructorName": constructorName, - if (moduleConfig != null) "moduleConfig": moduleConfig.toJson(), + if (isAbstract != null) 'isAbstract': isAbstract, + if (isModuleMethod != null) 'isModuleMethod': isModuleMethod, + if (moduleName != null) 'moduleName': moduleName, }; Set get allImports => { ...imports.where((i) => i != null), - if (moduleConfig != null) moduleConfig.import }; } diff --git a/injectable_generator/lib/dependency_resolver.dart b/injectable_generator/lib/dependency_resolver.dart index bc61a63..d164f68 100644 --- a/injectable_generator/lib/dependency_resolver.dart +++ b/injectable_generator/lib/dependency_resolver.dart @@ -10,6 +10,8 @@ import 'injectable_types.dart'; const TypeChecker namedChecker = TypeChecker.fromRuntime(Named); const TypeChecker singletonChecker = TypeChecker.fromRuntime(Singleton); +const TypeChecker injectableChecker = TypeChecker.fromRuntime(Injectable); + const TypeChecker envChecker = TypeChecker.fromRuntime(Environment); const TypeChecker registerAsChecker = TypeChecker.fromRuntime(RegisterAs); const TypeChecker preResolveChecker = TypeChecker.fromRuntime(PreResolve); @@ -48,30 +50,37 @@ class DependencyResolver { } } - throwBoxedIf(returnType.element is! ClassElement, - '${returnType.getDisplayString()} is not a class element'); + throwIf( + returnType.element is! ClassElement, + '${returnType.getDisplayString()} is not a class element', + element: returnType.element, + ); await _checkForParameterizedTypes(returnType); - final registerModuleItem = RegisterModuleItem(); - registerModuleItem.moduleName = moduleClazz.name; - registerModuleItem.import = getImport(moduleClazz); + _dep.moduleName = moduleClazz.name; + _dep.initializerName = executableElement.name; + _dep.imports.add(getImport(moduleClazz)); + + ExecutableElement executableModuleMember; if (executableElement is MethodElement) { - throwBoxedIf(executableElement.parameters.length > 2, - 'Error generating [$returnType]! Max number of factory params is 2'); - registerModuleItem.isMethod = true; + _dep.isModuleMethod = true; - for (var param in executableElement.parameters) { - await _resolveAndAddImport(param.type.element); - await _checkForParameterizedTypes(param.type); - registerModuleItem.params[param.name] = param.type.getDisplayString(); + if (!executableElement.isAbstract) { + executableModuleMember = executableElement; + } else { + throwIf( + executableElement.parameters.isNotEmpty, + 'Abstract methods can not have injectable or factory paramters', + element: executableElement, + ); } } ClassElement clazz; if (executableElement.isAbstract) { clazz = returnType.element; - registerModuleItem.isAbstract = true; + _dep.isAbstract = true; } else { if (returnType.isDartAsyncFuture) { final typeArg = returnType as ParameterizedType; @@ -82,37 +91,68 @@ class DependencyResolver { clazz = returnType.element; } } - registerModuleItem.name = executableElement.name; - _dep.moduleConfig = registerModuleItem; await _resolveAndAddImport(clazz); - return _resolveActualType(clazz, typeName); + return _resolveActualType(clazz, typeName, executableModuleMember); } - Future _resolveActualType(ClassElement clazz, - [String typeName]) async { + Future _resolveActualType( + ClassElement clazz, [ + String typeName, + ExecutableElement executbaleModuleMemeber, + ]) async { _dep.type = typeName ?? clazz.name; - _dep.bindTo = typeName ?? clazz.name; + _dep.typeImpl = typeName ?? clazz.name; + final injectableAnnotation = injectableChecker + .firstAnnotationOf(_annotatedElement, throwOnUnresolved: false); + + var abstractType; var inlineEnv; - final registerAsAnnotation = - registerAsChecker.firstAnnotationOf(_annotatedElement); - if (registerAsAnnotation != null) { - ConstantReader registerAsReader = ConstantReader(registerAsAnnotation); - final abstractType = registerAsReader.peek('abstractType').typeValue; - final abstractChecker = TypeChecker.fromStatic(abstractType); + // set default injectable type to factory + _dep.injectableType = InjectableType.factory; + + if (injectableAnnotation != null) { + final injectable = ConstantReader(injectableAnnotation); + if (injectable.instanceOf(TypeChecker.fromRuntime(LazySingleton))) { + _dep.injectableType = InjectableType.lazySingleton; + } else if (injectable.instanceOf(TypeChecker.fromRuntime(Singleton))) { + _dep.injectableType = InjectableType.singleton; + _dep.signalsReady = injectable.peek('signalsReady')?.boolValue; + _dep.dependsOn = injectable + .peek('dependsOn') + ?.listValue + ?.map((v) => v.toTypeValue().getDisplayString()) + ?.toList(); + } + abstractType = injectable.peek('as')?.typeValue; + inlineEnv = injectable.peek('env')?.stringValue; + } + + if (abstractType == null) { + final registerAsAnnotation = + registerAsChecker.firstAnnotationOf(_annotatedElement); + if (registerAsAnnotation != null) { + final registerAsReader = ConstantReader(registerAsAnnotation); + abstractType = registerAsReader.peek('abstractType').typeValue; + inlineEnv = registerAsReader.peek('env')?.stringValue; + } + } + + if (abstractType != null) { + final abstractChecker = TypeChecker.fromStatic(abstractType); final abstractSubtype = clazz.allSupertypes.firstWhere( (type) => abstractChecker.isExactly(type.element), orElse: () { - throwBoxed( - '[${clazz.name}] is not a subtype of [${abstractType.getDisplayString()}]'); + throwError( + '[${clazz.name}] is not a subtype of [${abstractType.getDisplayString()}]', + element: clazz, + ); return null; }); _dep.type = abstractSubtype.getDisplayString(); - inlineEnv = registerAsReader.peek('env')?.stringValue; - - _dep.bindTo = clazz.name; + _dep.typeImpl = clazz.name; await _resolveAndAddImport(abstractSubtype.element); await _checkForParameterizedTypes(abstractSubtype); } @@ -124,6 +164,7 @@ class DependencyResolver { ?.toStringValue(); _dep.preResolve = preResolveChecker.hasAnnotationOfExact(_annotatedElement); + final name = namedChecker .firstAnnotationOfExact(_annotatedElement) ?.getField('name') @@ -136,46 +177,32 @@ class DependencyResolver { } } - final singletonAnnotation = singletonChecker - .firstAnnotationOf(_annotatedElement, throwOnUnresolved: false); - if (singletonAnnotation != null) { - if (singletonAnnotation.getField('_lazy').toBoolValue()) { - _dep.injectableType = InjectableType.lazySingleton; - } else { - _dep.injectableType = InjectableType.singleton; - _dep.dependsOn = singletonAnnotation - .getField('dependsOn') - ?.toListValue() - ?.map((v) => v.toTypeValue().getDisplayString()) - ?.toList(); - } - - _dep.signalsReady = - singletonAnnotation.getField('signalsReady')?.toBoolValue(); - } else { - _dep.injectableType = InjectableType.factory; - } + ExecutableElement excutableInitilizer; - ExecutableElement constructor; - if (_dep.moduleConfig == null || _dep.moduleConfig.isAbstract) { + if (executbaleModuleMemeber != null) { + excutableInitilizer = executbaleModuleMemeber; + } else if (!_dep.isFromModule || _dep.isAbstract) { final possibleFactories = [ ...clazz.methods.where((m) => m.isStatic), ...clazz.constructors ]; - constructor = possibleFactories - .firstWhere((m) => constructorChecker.hasAnnotationOf(m), orElse: () { - throwBoxedIf(clazz.isAbstract, - '''[${clazz.name}] is abstract and can not be registered directly! - \n if it has a factory or a create method annotate it with @factoryMethod'''); + excutableInitilizer = possibleFactories.firstWhere( + (m) => constructorChecker.hasAnnotationOfExact(m), orElse: () { + throwIf( + clazz.isAbstract, + '''[${clazz.name}] is abstract and can not be registered directly! + if it has a factory or a create method annotate it with @factoryMethod''', + element: clazz, + ); return clazz.unnamedConstructor; }); + _dep.isAsync = excutableInitilizer.returnType.isDartAsyncFuture; } - if (constructor != null) { - _dep.isAsync = constructor.returnType.isDartAsyncFuture; - _dep.constructorName = constructor.name; - for (ParameterElement param in constructor.parameters) { + if (excutableInitilizer != null) { + _dep.constructorName = excutableInitilizer.name; + for (ParameterElement param in excutableInitilizer.parameters) { final namedAnnotation = namedChecker.firstAnnotationOf(param); final instanceName = namedAnnotation ?.getField('type') @@ -188,35 +215,51 @@ class DependencyResolver { var typeName = param.type.getDisplayString(); if (param.type is TypeParameterType) { typeName = _typeArgsMap[param.type.getDisplayString()]; - throwBoxedIf(typeName == null, - 'Error generating [${clazz.name}]! Can not resolve dependency of type ${param.type.getDisplayString()}'); + throwIf( + typeName == null, + 'Can not resolve dependency of type ${param.type.getDisplayString()}', + element: param, + ); } _dep.dependencies.add(InjectedDependency( type: typeName, name: instanceName, - isFactoryParam: _dep.moduleConfig == null && - factoryParamChecker.hasAnnotationOf(param), + isFactoryParam: factoryParamChecker.hasAnnotationOfExact(param), paramName: param.name, isPositional: param.isPositional, )); - - throwBoxedIf( - _dep.dependencies.where((d) => d.isFactoryParam).length > 2, - 'Error generating [${clazz.name}]! Max number of factory params is 2'); } - } + final factoryParamsCount = + _dep.dependencies.where((d) => d.isFactoryParam).length; + + throwIf( + _dep.preResolve && factoryParamsCount != 0, + 'Factories with params can not be pre-resolved', + element: clazz, + ); - throwBoxedIf( + throwIf( _dep.injectableType != InjectableType.factory && - (_dep.dependencies.where((d) => d.isFactoryParam).isNotEmpty || - _dep.moduleConfig?.params?.isNotEmpty == true), - 'Error generating [${clazz.name}]! only factories can have parameters'); + factoryParamsCount != 0, + 'only factories can have parameters', + element: clazz, + ); + + throwIf( + factoryParamsCount > 2, + 'Max number of factory params supported by get_it is 2', + element: clazz, + ); + } + return _dep; } Future _resolveLibImport(Element element) async { - if (element.source == null || isCoreDartType(element.source)) { + if (element == null || + element.source == null || + isCoreDartType(element.source)) { return null; } //if element from a system library but not from dart:core @@ -224,12 +267,10 @@ class DependencyResolver { return getImport(element); } final assetId = await _resolver.assetIdForElement(element); - final lib = await _resolver.findLibraryByName(assetId.package); - if (lib != null) { - return getImport(lib); - } else { - return getImport(element); - } + + final toBeImported = + await _resolver.findLibraryByName(assetId.package) ?? element; + return getImport(toBeImported); } Future _checkForParameterizedTypes(DartType paramType) async { diff --git a/injectable_generator/lib/generator/config_code_generator.dart b/injectable_generator/lib/generator/config_code_generator.dart index ed9137b..2b144b4 100644 --- a/injectable_generator/lib/generator/config_code_generator.dart +++ b/injectable_generator/lib/generator/config_code_generator.dart @@ -9,7 +9,6 @@ import 'package:injectable_generator/injectable_types.dart'; import 'package:injectable_generator/utils.dart'; import 'factory_generator.dart'; -import 'module_factory_param_generator.dart'; // holds all used var names // to make sure we don't have duplicate var names @@ -37,10 +36,8 @@ class ConfigCodeGenerator { final Set sorted = {}; _sortByDependents(allDeps.toSet(), sorted); - final modules = sorted - .where((d) => d.moduleConfig != null) - .map((d) => d.moduleConfig.moduleName) - .toSet(); + final modules = + sorted.where((d) => d.isFromModule).map((d) => d.moduleName).toSet(); final Set eagerDeps = sorted .where((d) => d.injectableType == InjectableType.singleton) @@ -122,11 +119,8 @@ class ConfigCodeGenerator { void _generateDeps(Set deps) { deps.forEach((dep) { if (dep.injectableType == InjectableType.factory) { - if (dep.moduleConfig == null && - dep.dependencies.where((d) => d.isFactoryParam).isNotEmpty) { + if (dep.dependencies.any((d) => d.isFactoryParam)) { _writeln(FactoryParamGenerator().generate(dep)); - } else if (dep.moduleConfig?.params?.isNotEmpty == true) { - _writeln(ModuleFactoryParamGenerator().generate(dep)); } else { _writeln(FactoryGenerator().generate(dep)); } @@ -171,10 +165,8 @@ class ConfigCodeGenerator { Iterable _getAbstractModuleDeps( Set deps, String m) { - return deps.where((d) => - d.moduleConfig != null && - d.moduleConfig.moduleName == m && - d.moduleConfig.isAbstract); + return deps + .where((d) => d.isFromModule && d.moduleName == m && d.isAbstract); } void _generateModuleItems(List moduleDeps) { diff --git a/injectable_generator/lib/generator/factory_generator.dart b/injectable_generator/lib/generator/factory_generator.dart index 9462437..f7ae9bf 100644 --- a/injectable_generator/lib/generator/factory_generator.dart +++ b/injectable_generator/lib/generator/factory_generator.dart @@ -4,16 +4,17 @@ import 'package:injectable_generator/generator/register_func_generator.dart'; class FactoryGenerator extends RegisterFuncGenerator { @override String generate(DependencyConfig dep) { - final constructBody = dep.moduleConfig == null - ? generateConstructor(dep) - : generateConstructorForModule(dep); + final initializer = generateInitializer(dep); - var constructor = constructBody; + var constructor = initializer; if (dep.registerAsInstance) { - constructor = generateAwaitSetup(dep, constructBody); + constructor = generateAwaitSetup(dep, initializer); } + final asyncStr = dep.isAsync && !dep.preResolve ? 'Async' : ''; + writeln("g.registerFactory$asyncStr<${dep.type}>(()=> $constructor"); + closeRegisterFunc(dep); return buffer.toString(); } diff --git a/injectable_generator/lib/generator/factory_param_generator.dart b/injectable_generator/lib/generator/factory_param_generator.dart index a024acb..9e3d568 100644 --- a/injectable_generator/lib/generator/factory_param_generator.dart +++ b/injectable_generator/lib/generator/factory_param_generator.dart @@ -4,9 +4,7 @@ import 'package:injectable_generator/generator/register_func_generator.dart'; class FactoryParamGenerator extends RegisterFuncGenerator { @override String generate(DependencyConfig dep) { - final constructBody = dep.moduleConfig == null - ? generateConstructor(dep) - : generateConstructorForModule(dep); + final initializer = generateInitializer(dep); var asyncStr = dep.isAsync && !dep.preResolve ? 'Async' : ''; @@ -21,7 +19,7 @@ class FactoryParamGenerator extends RegisterFuncGenerator { final methodParams = typeArgs.keys.join(','); writeln( - "g.registerFactoryParam$asyncStr$argsDeclaration(($methodParams)=> $constructBody"); + "g.registerFactoryParam$asyncStr$argsDeclaration(($methodParams)=> $initializer"); closeRegisterFunc(dep); return buffer.toString(); diff --git a/injectable_generator/lib/generator/lazy_singleton_generator.dart b/injectable_generator/lib/generator/lazy_singleton_generator.dart index 0547421..99129c5 100644 --- a/injectable_generator/lib/generator/lazy_singleton_generator.dart +++ b/injectable_generator/lib/generator/lazy_singleton_generator.dart @@ -4,13 +4,11 @@ import 'package:injectable_generator/generator/factory_generator.dart'; class LazySingletonGenerator extends FactoryGenerator { @override String generate(DependencyConfig dep) { - final constructBody = dep.moduleConfig == null - ? generateConstructor(dep) - : generateConstructorForModule(dep); + final initializer = generateInitializer(dep); - var constructor = constructBody; + var constructor = initializer; if (dep.registerAsInstance) { - constructor = generateAwaitSetup(dep, constructBody); + constructor = generateAwaitSetup(dep, initializer); } final asyncStr = dep.isAsync && !dep.preResolve ? 'Async' : ''; diff --git a/injectable_generator/lib/generator/module_factory_generator.dart b/injectable_generator/lib/generator/module_factory_generator.dart index c642c28..157217c 100644 --- a/injectable_generator/lib/generator/module_factory_generator.dart +++ b/injectable_generator/lib/generator/module_factory_generator.dart @@ -1,20 +1,26 @@ import 'package:injectable_generator/dependency_config.dart'; import 'package:injectable_generator/generator/register_func_generator.dart'; -import 'package:injectable_generator/utils.dart'; class ModuleFactoryGenerator extends RegisterFuncGenerator { @override - String generate(DependencyConfig dep) { - final constructor = generateConstructor(dep, getIt: '_g'); - if (dep.moduleConfig.isMethod) { - throwBoxedIf( - dep.moduleConfig.params.isNotEmpty, - 'Error generating [${dep.type}]! Dependencies with factoryParam methods must have a custom initializer.' - '\nDependency getDep(String p1,int p2) => Dependency(p1,p2);'); + String generateInitializer(DependencyConfig dep, {String getIt = 'g'}) { + final flattenedParams = flattenParams(dep.dependencies, getIt); + + final constructorName = + dep.constructorName != null && dep.constructorName.isNotEmpty + ? '.${dep.constructorName}' + : ''; + + return '${dep.typeImpl}$constructorName($flattenedParams)'; + } - return '${dep.bindTo} ${dep.moduleConfig.name}() => $constructor;'; + @override + String generate(DependencyConfig dep) { + final constructor = generateInitializer(dep, getIt: '_g'); + if (dep.isModuleMethod) { + return '${dep.typeImpl} ${dep.initializerName}() => $constructor;'; } else { - return '${dep.bindTo} get ${dep.moduleConfig.name} => $constructor ;'; + return '${dep.typeImpl} get ${dep.initializerName} => $constructor ;'; } } } diff --git a/injectable_generator/lib/generator/module_factory_param_generator.dart b/injectable_generator/lib/generator/module_factory_param_generator.dart deleted file mode 100644 index 411913b..0000000 --- a/injectable_generator/lib/generator/module_factory_param_generator.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:injectable_generator/dependency_config.dart'; -import 'package:injectable_generator/generator/register_func_generator.dart'; -import 'package:injectable_generator/utils.dart'; - -class ModuleFactoryParamGenerator extends RegisterFuncGenerator { - @override - String generate(DependencyConfig dep) { - throwBoxedIf(dep.preResolve, - 'Error generating [${dep.type}]! FactoryParams can not be pre resolved'); - - final constructBody = generateConstructorForModule(dep); - var asyncStr = dep.isAsync && !dep.preResolve ? 'Async' : ''; - - var typeArgs = dep.moduleConfig.params; - if (typeArgs.length < 2) { - typeArgs['_'] = 'dynamic'; - } - - final argsDeclaration = '<${dep.type},${typeArgs.values.join(',')} >'; - - final methodParams = typeArgs.keys.join(','); - - writeln( - "g.registerFactoryParam$asyncStr$argsDeclaration(($methodParams)=> $constructBody"); - - closeRegisterFunc(dep); - return buffer.toString(); - } -} diff --git a/injectable_generator/lib/generator/register_func_generator.dart b/injectable_generator/lib/generator/register_func_generator.dart index 6689d43..fede6bb 100644 --- a/injectable_generator/lib/generator/register_func_generator.dart +++ b/injectable_generator/lib/generator/register_func_generator.dart @@ -1,3 +1,4 @@ +import 'package:injectable/injectable.dart'; import 'package:injectable_generator/dependency_config.dart'; import 'package:injectable_generator/generator/config_code_generator.dart'; import 'package:injectable_generator/utils.dart'; @@ -8,13 +9,41 @@ abstract class RegisterFuncGenerator { write(Object o) => buffer.write(o); writeln(Object o) => buffer.writeln(o); String generate(DependencyConfig dep); - String generateConstructor(DependencyConfig dep, {String getIt = 'g'}) { - final params = dep.dependencies.map((injectedDep) { + + String generateInitializer(DependencyConfig dep, {String getIt = 'g'}) { + final flattenedParams = flattenParams(dep.dependencies, getIt); + + if (dep.isFromModule) { + final moduleName = toCamelCase(dep.moduleName); + if (!dep.isModuleMethod) { + return '$moduleName.${dep.initializerName}'; + } else { + if (dep.isAbstract) { + return '$moduleName.${dep.initializerName}()'; + } else { + return '${moduleName}.${dep.initializerName}($flattenedParams)'; + } + } + } + + final typeName = stripGenericTypes(dep.typeImpl); + final constructorName = + dep.constructorName != null && dep.constructorName.isNotEmpty + ? '.${dep.constructorName}' + : ''; + + return '${typeName}$constructorName($flattenedParams)'; + } + + String flattenParams(List deps, String getIt) { + final params = deps.map((injectedDep) { var type = injectedDep.type == 'dynamic' ? '' : '<${injectedDep.type}>'; var instanceName = ''; + if (injectedDep.name != null) { instanceName = "instanceName:'${injectedDep.name}'"; } + final paramName = (!injectedDep.isPositional) ? '${injectedDep.paramName}:' : ''; @@ -25,12 +54,10 @@ abstract class RegisterFuncGenerator { } }).toList(); - final constructName = - dep.constructorName.isEmpty ? "" : ".${dep.constructorName}"; if (params.length > 2) { params.add(''); } - return '${stripGenericTypes(dep.bindTo)}$constructName(${params.join(',')})'; + return params.join(','); } String generateAwaitSetup(DependencyConfig dep, String constructBody) { @@ -45,20 +72,6 @@ abstract class RegisterFuncGenerator { return awaitedVar; } - String generateConstructorForModule(DependencyConfig dep) { - final mConfig = dep.moduleConfig; - final mName = toCamelCase(mConfig.moduleName); - - var initializer = StringBuffer()..write(mConfig.name); - if (mConfig.isMethod) { - initializer.write('('); - initializer.write(mConfig.params.keys.join(',')); - initializer.write(')'); - } - - return '$mName.${initializer.toString()}'; - } - void closeRegisterFunc(DependencyConfig dep) { if (dep.signalsReady != null) { write(',signalsReady: ${dep.signalsReady}'); diff --git a/injectable_generator/lib/generator/singleton_generator.dart b/injectable_generator/lib/generator/singleton_generator.dart index b51f2d9..8d71aa1 100644 --- a/injectable_generator/lib/generator/singleton_generator.dart +++ b/injectable_generator/lib/generator/singleton_generator.dart @@ -4,13 +4,11 @@ import 'package:injectable_generator/generator/register_func_generator.dart'; class SingletonGenerator extends RegisterFuncGenerator { @override String generate(DependencyConfig dep) { - final constructBody = dep.moduleConfig == null - ? generateConstructor(dep) - : generateConstructorForModule(dep); + final initializer = generateInitializer(dep); - var constructor = constructBody; + var constructor = initializer; if (dep.registerAsInstance) { - constructor = generateAwaitSetup(dep, constructBody); + constructor = generateAwaitSetup(dep, initializer); } final typeArg = '<${dep.type}>'; diff --git a/injectable_generator/lib/injectable_config_generator.dart b/injectable_generator/lib/injectable_config_generator.dart index 89b2be0..8096a19 100644 --- a/injectable_generator/lib/injectable_config_generator.dart +++ b/injectable_generator/lib/injectable_config_generator.dart @@ -40,7 +40,7 @@ class InjectableConfigGenerator extends GeneratorForAnnotation { final strippedClassName = stripGenericTypes(iDep.type); if (!registeredDeps.contains(strippedClassName)) { messages.add( - "[${dep.bindTo}] depends on [$strippedClassName] which is not injectable!"); + "[${dep.typeImpl}] depends on [$strippedClassName] which is not injectable!"); } }); }); diff --git a/injectable_generator/lib/injectable_generator.dart b/injectable_generator/lib/injectable_generator.dart index ff5c37a..52ee0c3 100644 --- a/injectable_generator/lib/injectable_generator.dart +++ b/injectable_generator/lib/injectable_generator.dart @@ -34,8 +34,11 @@ class InjectableGenerator implements Generator { for (var clazz in library.classes) { if (moduleChecker.hasAnnotationOfExact(clazz)) { - throwBoxedIf( - !clazz.isAbstract, '[${clazz.name}] must be an abstract class!'); + throwIf( + !clazz.isAbstract, + '[${clazz.name}] must be an abstract class!', + element: clazz, + ); final executables = [ ...clazz.accessors, ...clazz.methods, @@ -52,12 +55,7 @@ class InjectableGenerator implements Generator { } } - if (allDepsInStep.isNotEmpty) { - final inputID = buildStep.inputId.changeExtension(".injectable.json"); - - buildStep.writeAsString(inputID, json.encode(allDepsInStep)); - } - return null; + return allDepsInStep.isNotEmpty ? json.encode(allDepsInStep) : null; } bool _hasInjectable(ClassElement element) { diff --git a/injectable_generator/lib/utils.dart b/injectable_generator/lib/utils.dart index cef51c9..f5e8508 100644 --- a/injectable_generator/lib/utils.dart +++ b/injectable_generator/lib/utils.dart @@ -1,6 +1,7 @@ // general utils import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/src/generated/source.dart'; +import 'package:source_gen/source_gen.dart'; // Checks if source is from dart:core library bool isCoreDartType(Source source) { @@ -19,7 +20,7 @@ String getImport(Element element) { // we don't need to import core dart types if (!isCoreDartType(source)) { - final path = source.uri.toString(); + final path = resolveAssetUri(source.uri).toString(); return path; } return null; @@ -44,9 +45,24 @@ void throwBoxed(String message) { throw ("\n${pre.padRight(72, '-')}\n$message\n${''.padRight(72, '-')} \n"); } -void throwBoxedIf(bool condition, String message) { - if (condition) { - throwBoxed(message); +void throwSourceError(String message) { + final pre = 'Injectable Generator '; + throw ("\n${pre.padRight(72, '-')}\n$message\n${''.padRight(72, '-')} \n"); +} + +void throwError(String message, {Element element}) { + throw InvalidGenerationSourceError( + message, + element: element, + ); +} + +void throwIf(bool condition, String message, {Element element}) { + if (condition == true) { + throw InvalidGenerationSourceError( + message, + element: element, + ); } } @@ -56,3 +72,13 @@ void printBoxed(String message) { } String stripGenericTypes(String type) => RegExp('^([^<]*)').stringMatch(type); + +Uri resolveAssetUri(Uri url) => url.scheme == 'asset' && + url.pathSegments.isNotEmpty && + url.pathSegments[1] == 'bin' || + url.pathSegments[1] == 'test' + ? url.replace( + scheme: '', + pathSegments: url.pathSegments.skip(2), + ) + : url; diff --git a/injectable_generator/pubspec.lock b/injectable_generator/pubspec.lock index 7545286..8866213 100644 --- a/injectable_generator/pubspec.lock +++ b/injectable_generator/pubspec.lock @@ -72,7 +72,7 @@ packages: source: hosted version: "5.1.0" built_collection: - dependency: transitive + dependency: "direct main" description: name: built_collection url: "https://pub.dartlang.org" @@ -100,7 +100,7 @@ packages: source: hosted version: "1.0.2" code_builder: - dependency: transitive + dependency: "direct main" description: name: code_builder url: "https://pub.dartlang.org" @@ -186,9 +186,9 @@ packages: injectable: dependency: "direct main" description: - name: injectable - url: "https://pub.dartlang.org" - source: hosted + path: "../injectable" + relative: true + source: path version: "0.3.0" io: dependency: transitive diff --git a/injectable_generator/pubspec.yaml b/injectable_generator/pubspec.yaml index c7cf44c..f84a4a6 100644 --- a/injectable_generator/pubspec.yaml +++ b/injectable_generator/pubspec.yaml @@ -11,10 +11,11 @@ dependencies: source_gen: ^0.9.0 glob: ^1.1.7 analyzer: ">=0.39.2 <0.40.0" - + code_builder: ^3.2.1 + built_collection: injectable: - ^0.3.0 -# path: ../injectable + # ^0.3.0 + path: ../injectable dev_dependencies: build_runner: ^1.0.0