From 14dce2aafaa926c43bf1464fa9c91d306c482e68 Mon Sep 17 00:00:00 2001 From: Sergey Penkovsky Date: Wed, 21 May 2025 00:50:57 +0300 Subject: [PATCH] feat: implement instance/provide annotations --- .../lib/cherrypick_annotations.dart | 1 + cherrypick_annotations/lib/src/instance.dart | 17 ++++++++++++ .../lib/module_generator.dart | 26 ++++++++++++++++--- examples/postly/lib/di/app_module.dart | 18 +++++++++---- 4 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 cherrypick_annotations/lib/src/instance.dart diff --git a/cherrypick_annotations/lib/cherrypick_annotations.dart b/cherrypick_annotations/lib/cherrypick_annotations.dart index 684779e..6b08e9e 100644 --- a/cherrypick_annotations/lib/cherrypick_annotations.dart +++ b/cherrypick_annotations/lib/cherrypick_annotations.dart @@ -16,5 +16,6 @@ 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'; diff --git a/cherrypick_annotations/lib/src/instance.dart b/cherrypick_annotations/lib/src/instance.dart new file mode 100644 index 0000000..7f638be --- /dev/null +++ b/cherrypick_annotations/lib/src/instance.dart @@ -0,0 +1,17 @@ +// +// Copyright 2021 Sergey Penkovsky (sergey.penkovsky@gmail.com) +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// ignore: camel_case_types +class instance { + const instance(); +} diff --git a/cherrypick_generator/lib/module_generator.dart b/cherrypick_generator/lib/module_generator.dart index cd88a85..c1fd4d0 100644 --- a/cherrypick_generator/lib/module_generator.dart +++ b/cherrypick_generator/lib/module_generator.dart @@ -76,12 +76,15 @@ class BindSpec { /// Список параметров, которые требуются методу для внедрения зависимостей final List parameters; + final String bindingType; // 'instance' | 'provide' + BindSpec({ required this.returnType, required this.methodName, required this.isSingleton, required this.parameters, this.named, + required this.bindingType, }); /// Формирует dart-код для биндинга, например: @@ -95,11 +98,14 @@ class BindSpec { final argsStr = parameters.map((p) => p.generateArg()).join(', '); // Если аргументов много или они длинные — разбиваем вызов на несколько строк - final needMultiline = argsStr.length > 60 || argsStr.contains('\n'); + //final needMultiline = argsStr.length > 60 || argsStr.contains('\n'); - final provide = needMultiline - ? '.toProvide(\n${' ' * (indent + 2)}() => $methodName($argsStr))' - : '.toProvide(() => $methodName($argsStr))'; + // Важно: для .toInstance всегда просто method(), для .toProvide нужна лямбда + final provide = bindingType == 'instance' + ? '.toInstance($methodName($argsStr))' + : (argsStr.length > 60 || argsStr.contains('\n') + ? '.toProvide(\n${' ' * (indent + 2)}() => $methodName($argsStr))' + : '.toProvide(() => $methodName($argsStr))'); final namePart = named != null ? ".withName('$named')" : ''; final singletonPart = isSingleton ? '.singleton()' : ''; @@ -132,12 +138,24 @@ class BindSpec { params.add(BindParameterSpec(typeStr, paramNamed)); } + // определяем bindingType + final hasInstance = _MetadataUtils.anyMeta(method.metadata, 'instance'); + final hasProvide = _MetadataUtils.anyMeta(method.metadata, 'provide'); + if (!hasInstance && !hasProvide) { + throw InvalidGenerationSourceError( + 'Метод $methodName класса-модуля должен быть помечен либо @instance(), либо @provide().', + element: method, + ); + } + final bindingType = hasInstance ? 'instance' : 'provide'; + return BindSpec( returnType: returnType, methodName: methodName, isSingleton: isSingleton, named: named, parameters: params, + bindingType: bindingType, ); } } diff --git a/examples/postly/lib/di/app_module.dart b/examples/postly/lib/di/app_module.dart index cd47100..9b61ae0 100644 --- a/examples/postly/lib/di/app_module.dart +++ b/examples/postly/lib/di/app_module.dart @@ -9,16 +9,24 @@ part 'app_module.cherrypick.g.dart'; @module() abstract class AppModule extends Module { + @instance() + int timeout() => 1000; + + @instance() + @named('baseUrl') + String baseUrl() => "https://google.com"; + + @provide() @singleton() @named('dio') - Dio dio() => Dio(); + Dio dio(@named('baseUrl') String baseUrl) => + Dio(BaseOptions(baseUrl: baseUrl)); + @provide() @singleton() - @named('api') JsonPlaceholderApi api(@named('dio') Dio dio) => JsonPlaceholderApi(dio); + @provide() @named('repo') - @singleton() - PostRepository repo(@named('api') JsonPlaceholderApi api) => - PostRepositoryImpl(api); + PostRepository repo(JsonPlaceholderApi api) => PostRepositoryImpl(api); }