diff --git a/cherrypick_annotations/lib/cherrypick_annotations.dart b/cherrypick_annotations/lib/cherrypick_annotations.dart index 6b08e9e..979008a 100644 --- a/cherrypick_annotations/lib/cherrypick_annotations.dart +++ b/cherrypick_annotations/lib/cherrypick_annotations.dart @@ -14,8 +14,8 @@ library; // export 'src/module.dart'; -export 'src/bind.dart'; export 'src/provide.dart'; export 'src/instance.dart'; export 'src/singleton.dart'; export 'src/named.dart'; +export 'src/params.dart'; diff --git a/cherrypick_annotations/lib/src/instance.dart b/cherrypick_annotations/lib/src/instance.dart index 7f638be..d453a23 100644 --- a/cherrypick_annotations/lib/src/instance.dart +++ b/cherrypick_annotations/lib/src/instance.dart @@ -12,6 +12,6 @@ // // ignore: camel_case_types -class instance { +final class instance { const instance(); } diff --git a/cherrypick_annotations/lib/src/bind.dart b/cherrypick_annotations/lib/src/params.dart similarity index 94% rename from cherrypick_annotations/lib/src/bind.dart rename to cherrypick_annotations/lib/src/params.dart index 9df07a0..edb9008 100644 --- a/cherrypick_annotations/lib/src/bind.dart +++ b/cherrypick_annotations/lib/src/params.dart @@ -12,6 +12,6 @@ // // ignore: camel_case_types -class Bind { - const Bind(); +final class params { + const params(); } diff --git a/cherrypick_annotations/lib/src/provide.dart b/cherrypick_annotations/lib/src/provide.dart index 6ad8a75..3b4ec88 100644 --- a/cherrypick_annotations/lib/src/provide.dart +++ b/cherrypick_annotations/lib/src/provide.dart @@ -12,6 +12,6 @@ // // ignore: camel_case_types -class provide { +final class provide { const provide(); } diff --git a/cherrypick_generator/lib/module_generator.dart b/cherrypick_generator/lib/module_generator.dart index d8aeac7..0eb396a 100644 --- a/cherrypick_generator/lib/module_generator.dart +++ b/cherrypick_generator/lib/module_generator.dart @@ -82,6 +82,8 @@ class BindSpec { final bool isAsyncProvide; + final bool hasParams; + BindSpec({ required this.returnType, required this.methodName, @@ -91,6 +93,7 @@ class BindSpec { required this.bindingType, required this.isAsyncInstance, required this.isAsyncProvide, + required this.hasParams, }); /// Формирует dart-код для биндинга, например: @@ -100,6 +103,42 @@ class BindSpec { String generateBind(int indent) { final indentStr = ' ' * indent; + // Если есть @params() + if (hasParams) { + // Параметры метода: все, кроме isParams --> resolve(...) + // последний isParams --> "params" + final paramsArgs = parameters.map((p) => p.generateArg()).join(', '); + + String provide; + if (bindingType == 'instance') { + // По умолчанию instance с @params, делать нельзя — но если нужно, аналогично provide. + provide = isAsyncInstance + ? '.toInstanceAsync(($paramsArgs) => $methodName($paramsArgs))' + : '.toInstance(($paramsArgs) => $methodName($paramsArgs))'; + } else { + final fnArgs = parameters + .map((p) => p.isParams ? 'params' : p.generateArg()) + .join(', '); + if (isAsyncProvide) { + provide = (fnArgs.length > 60 || fnArgs.contains('\n')) + ? '.toProvideAsyncWithParams(\n${' ' * (indent + 2)}(params) => $methodName($fnArgs))' + : '.toProvideAsyncWithParams((params) => $methodName($fnArgs))'; + } else { + provide = (fnArgs.length > 60 || fnArgs.contains('\n')) + ? '.toProvideWithParams(\n${' ' * (indent + 2)}(params) => $methodName($fnArgs))' + : '.toProvideWithParams((params) => $methodName($fnArgs))'; + } + } + + final namePart = named != null ? ".withName('$named')" : ''; + final singletonPart = isSingleton ? '.singleton()' : ''; + return '$indentStr' + 'bind<$returnType>()' + '$provide' + '$namePart' + '$singletonPart;'; + } + // Собираем строку аргументов для вызова метода final argsStr = parameters.map((p) => p.generateArg()).join(', '); @@ -153,10 +192,13 @@ class BindSpec { // Для каждого параметра метода final params = []; + bool hasParams = false; for (final p in method.parameters) { final typeStr = p.type.getDisplayString(); final paramNamed = _MetadataUtils.getNamedValue(p.metadata); - params.add(BindParameterSpec(typeStr, paramNamed)); + final isParams = _MetadataUtils.anyMeta(p.metadata, 'params'); + if (isParams) hasParams = true; + params.add(BindParameterSpec(typeStr, paramNamed, isParams: isParams)); } // определяем bindingType @@ -192,6 +234,7 @@ class BindSpec { bindingType: bindingType, isAsyncInstance: isAsyncInstance, isAsyncProvide: isAsyncProvide, + hasParams: hasParams, ); } } @@ -210,10 +253,15 @@ class BindParameterSpec { /// Необязательное имя для разрешения по имени (если аннотировано через @named) final String? named; - BindParameterSpec(this.typeName, this.named); + final bool isParams; + + BindParameterSpec(this.typeName, this.named, {this.isParams = false}); /// Генерирует строку для получения зависимости из DI scope (с учётом имени) - String generateArg() { + String generateArg([String paramsVar = 'params']) { + if (isParams) { + return paramsVar; + } if (named != null) { return "currentScope.resolve<$typeName>(named: '$named')"; } diff --git a/examples/postly/lib/di/app_module.dart b/examples/postly/lib/di/app_module.dart index 6b45cd7..24c106b 100644 --- a/examples/postly/lib/di/app_module.dart +++ b/examples/postly/lib/di/app_module.dart @@ -45,4 +45,25 @@ abstract class AppModule extends Module { @provide() @named('repo') PostRepository repo(JsonPlaceholderApi api) => PostRepositoryImpl(api); + + @provide() + @named('TestProvideWithParams') + String testProvideWithParams(@params() dynamic params) => "hello $params"; + + @provide() + @named('TestProvideAsyncWithParams') + Future testProvideAsyncWithParams(@params() dynamic params) async => + "hello $params"; + + @provide() + @named('TestProvideWithParams1') + String testProvideWithParams1( + @named('baseUrl') String baseUrl, @params() dynamic params) => + "hello $params"; + + @provide() + @named('TestProvideAsyncWithParams1') + Future testProvideAsyncWithParams1( + @named('baseUrl') String baseUrl, @params() dynamic params) async => + "hello $params"; }