From 884df50a340fa56133a2acfd90da1a1f5497deeb Mon Sep 17 00:00:00 2001 From: Sergey Penkovsky Date: Tue, 12 Aug 2025 16:18:53 +0300 Subject: [PATCH] docs(annotations): unify and improve English DartDoc for all DI annotations - Updated all annotation files with complete English DartDoc, field/class/method usage, practical code samples - Unified documentation style for @inject, @injectable, @instance, @singleton, @named, @scope, @params, @provide, @module - Removed Russian comments for clarity and consistency - Improved discoverability and IDE/autocomplete experience for CherryPick DI users - No functional or API changes; documentation/dev experience only --- cherrypick_annotations/analysis_options.yaml | 3 + cherrypick_annotations/lib/src/inject.dart | 30 +++++--- .../lib/src/injectable.dart | 29 ++++--- cherrypick_annotations/lib/src/instance.dart | 61 ++++++--------- cherrypick_annotations/lib/src/module.dart | 57 +++++--------- cherrypick_annotations/lib/src/named.dart | 75 ++++++++----------- cherrypick_annotations/lib/src/params.dart | 53 +++++-------- cherrypick_annotations/lib/src/provide.dart | 64 +++++----------- cherrypick_annotations/lib/src/scope.dart | 40 +++++++--- cherrypick_annotations/lib/src/singleton.dart | 59 ++++----------- 10 files changed, 190 insertions(+), 281 deletions(-) diff --git a/cherrypick_annotations/analysis_options.yaml b/cherrypick_annotations/analysis_options.yaml index dee8927..ef8bc50 100644 --- a/cherrypick_annotations/analysis_options.yaml +++ b/cherrypick_annotations/analysis_options.yaml @@ -12,6 +12,9 @@ # The core lints are also what is used by pub.dev for scoring packages. include: package:lints/recommended.yaml +analyzer: + errors: + camel_case_types: ignore # Uncomment the following section to specify additional rules. diff --git a/cherrypick_annotations/lib/src/inject.dart b/cherrypick_annotations/lib/src/inject.dart index ca27754..02eedcc 100644 --- a/cherrypick_annotations/lib/src/inject.dart +++ b/cherrypick_annotations/lib/src/inject.dart @@ -13,22 +13,30 @@ import 'package:meta/meta.dart'; -/// Annotation for field injection in CherryPick DI framework. -/// Apply this to a field, and the code generator will automatically inject -/// the appropriate dependency into it. +/// Marks a field for dependency injection by CherryPick's code generator. /// -/// --- +/// Use `@inject()` on fields within a class marked with `@injectable()`. +/// Such fields will be automatically injected from the DI [Scope] +/// when using the generated mixin or calling `.injectFields()`. /// -/// Аннотация для внедрения зависимости в поле через фреймворк CherryPick DI. -/// Поместите её на поле класса — генератор кода автоматически подставит нужную зависимость. -/// -/// Example / Пример: +/// Example: /// ```dart -/// @inject() -/// late final SomeService service; +/// import 'package:cherrypick_annotations/cherrypick_annotations.dart'; +/// +/// @injectable() +/// class LoginScreen with _\$LoginScreen { +/// @inject() +/// late final AuthService authService; +/// +/// @inject() +/// @named('main') +/// late final ApiClient api; +/// } +/// +/// // After running build_runner, call: +/// // LoginScreen().injectFields(); /// ``` @experimental -// ignore: camel_case_types final class inject { const inject(); } diff --git a/cherrypick_annotations/lib/src/injectable.dart b/cherrypick_annotations/lib/src/injectable.dart index 0d0d940..8ce1336 100644 --- a/cherrypick_annotations/lib/src/injectable.dart +++ b/cherrypick_annotations/lib/src/injectable.dart @@ -13,26 +13,31 @@ import 'package:meta/meta.dart'; -/// Marks a class as injectable for the CherryPick dependency injection framework. -/// If a class is annotated with [@injectable()], the code generator will -/// create a mixin to perform automatic injection of fields marked with [@inject]. +/// Marks a class as injectable, enabling automatic field injection by CherryPick's code generator. /// -/// --- +/// Use `@injectable()` on a class whose fields (marked with `@inject`) you want to be automatically injected from the DI [Scope]. +/// When used together with code generation (see cherrypick_generator), a mixin will be generated to inject fields. /// -/// Помечает класс как внедряемый для фреймворка внедрения зависимостей CherryPick. -/// Если класс помечен аннотацией [@injectable()], генератор создаст миксин -/// для автоматического внедрения полей, отмеченных [@inject]. -/// -/// Example / Пример: +/// Example: /// ```dart +/// import 'package:cherrypick_annotations/cherrypick_annotations.dart'; +/// /// @injectable() -/// class MyWidget extends StatelessWidget { +/// class ProfileScreen with _\$ProfileScreen { /// @inject() -/// late final MyService service; +/// late final UserManager manager; +/// +/// @inject() +/// @named('main') +/// late final ApiClient api; /// } +/// +/// // After running build_runner, call: +/// // profileScreen.injectFields(); /// ``` +/// +/// After running the generator, the mixin (`_\$ProfileScreen`) will be available to help auto-inject all [@inject] fields in your widget/service/controller. @experimental -// ignore: camel_case_types final class injectable { const injectable(); } diff --git a/cherrypick_annotations/lib/src/instance.dart b/cherrypick_annotations/lib/src/instance.dart index 7ec5e00..6e32e65 100644 --- a/cherrypick_annotations/lib/src/instance.dart +++ b/cherrypick_annotations/lib/src/instance.dart @@ -11,58 +11,39 @@ // limitations under the License. // -/// ENGLISH: -/// Annotation to specify that a new instance should be provided on each request. +import 'package:meta/meta.dart'; + +/// Marks a provider method or class to always create a new instance (factory) in CherryPick DI. /// -/// Use the `@instance()` annotation for methods or classes in your DI module -/// to declare that the DI container must create a new object every time -/// the dependency is injected (i.e., no singleton behavior). +/// Use `@instance()` to annotate methods or classes in your DI module/class +/// when you want a new object to be created on every injection (no singleton caching). +/// The default DI lifecycle is instance/factory unless otherwise specified. /// -/// Example: +/// ### Example (in a module method) /// ```dart +/// import 'package:cherrypick_annotations/cherrypick_annotations.dart'; +/// /// @module() -/// abstract class AppModule extends Module { +/// abstract class FeatureModule { /// @instance() -/// Foo foo() => Foo(); +/// MyService provideService() => MyService(); +/// +/// @singleton() +/// Logger provideLogger() => Logger(); /// } /// ``` /// -/// This will generate: +/// ### Example (on a class, with @injectable) /// ```dart -/// final class $AppModule extends AppModule { -/// @override -/// void builder(Scope currentScope) { -/// bind().toInstance(() => foo()); -/// } +/// @injectable() +/// @instance() +/// class MyFactoryClass { +/// // ... /// } /// ``` /// -/// RUSSIAN (Русский): -/// Аннотация для создания нового экземпляра при каждом запросе. -/// -/// Используйте `@instance()` для методов или классов в DI-модуле, -/// чтобы указать, что контейнер внедрения зависимостей должен создавать -/// новый объект при каждом обращении к зависимости (то есть, не синглтон). -/// -/// Пример: -/// ```dart -/// @module() -/// abstract class AppModule extends Module { -/// @instance() -/// Foo foo() => Foo(); -/// } -/// ``` -/// -/// Будет сгенерирован следующий код: -/// ```dart -/// final class $AppModule extends AppModule { -/// @override -/// void builder(Scope currentScope) { -/// bind().toInstance(() => foo()); -/// } -/// } -/// ``` -// ignore: camel_case_types +/// See also: [@singleton] +@experimental final class instance { const instance(); } diff --git a/cherrypick_annotations/lib/src/module.dart b/cherrypick_annotations/lib/src/module.dart index 6e3a34e..acf6302 100644 --- a/cherrypick_annotations/lib/src/module.dart +++ b/cherrypick_annotations/lib/src/module.dart @@ -11,59 +11,40 @@ // limitations under the License. // -/// ENGLISH: -/// Annotation for marking Dart classes or libraries as modules. +import 'package:meta/meta.dart'; + +/// Marks an abstract Dart class as a dependency injection module for CherryPick code generation. /// -/// Use the `@module()` annotation on abstract classes (or on a library) -/// to indicate that the class represents a DI (Dependency Injection) module. -/// This is commonly used in code generation tools to automatically register -/// and configure dependencies defined within the module. +/// Use `@module()` on your abstract class to indicate it provides DI bindings (via provider methods). +/// This enables code generation of a concrete module that registers all bindings from your methods. /// -/// Example: +/// Typical usage: /// ```dart +/// import 'package:cherrypick_annotations/cherrypick_annotations.dart'; +/// /// @module() -/// abstract class AppModule extends Module { -/// // Dependency definitions go here. +/// abstract class AppModule { +/// @singleton() +/// Logger provideLogger() => Logger(); +/// +/// @named('mock') +/// ApiClient mockApi() => MockApiClient(); /// } /// ``` /// -/// Generates code like: +/// The generated code will look like: /// ```dart /// final class $AppModule extends AppModule { /// @override /// void builder(Scope currentScope) { -/// // Dependency registration... +/// // Dependency registration code... /// } /// } /// ``` /// -/// RUSSIAN (Русский): -/// Аннотация для пометки классов или библиотек Dart как модуля. -/// -/// Используйте `@module()` для абстрактных классов (или библиотек), чтобы -/// показать, что класс реализует DI-модуль (Dependency Injection). -/// Обычно используется генераторами кода для автоматической регистрации -/// и конфигурирования зависимостей, определённых в модуле. -/// -/// Пример: -/// ```dart -/// @module() -/// abstract class AppModule extends Module { -/// // Определения зависимостей -/// } -/// ``` -/// -/// Будет сгенерирован код: -/// ```dart -/// final class $AppModule extends AppModule { -/// @override -/// void builder(Scope currentScope) { -/// // Регистрация зависимостей... -/// } -/// } -/// ``` -// ignore: camel_case_types +/// See also: [@provide], [@singleton], [@instance], [@named] +@experimental final class module { - /// Creates a [module] annotation. + /// Creates a [module] annotation for use on a DI module class. const module(); } diff --git a/cherrypick_annotations/lib/src/named.dart b/cherrypick_annotations/lib/src/named.dart index e32ed93..8e8b738 100644 --- a/cherrypick_annotations/lib/src/named.dart +++ b/cherrypick_annotations/lib/src/named.dart @@ -11,67 +11,52 @@ // limitations under the License. // -/// ENGLISH: -/// Annotation to assign a name or identifier to a class, method, or other element. +import 'package:meta/meta.dart'; + +/// Assigns a name or key identifier to a class, field, factory method or parameter +/// for use in multi-registration scenarios (named dependencies) in CherryPick DI. /// -/// The `@named('value')` annotation allows you to specify a string name -/// for a dependency, factory, or injectable. This is useful for distinguishing -/// between multiple registrations of the same type in dependency injection, -/// code generation, and for providing human-readable metadata. +/// Use `@named('key')` to distinguish between multiple bindings/implementations +/// of the same type—when registering and when injecting dependencies. /// -/// Example: +/// You can use `@named`: +/// - On provider/factory methods in a module +/// - On fields with `@inject()` to receive a named instance +/// - On function parameters (for method/constructor injection) +/// +/// ### Example: On Provider Method /// ```dart /// @module() -/// abstract class AppModule extends Module { -/// @named('dio') -/// Dio dio() => Dio(); +/// abstract class AppModule { +/// @named('main') +/// ApiClient apiClient() => ApiClient(); +/// +/// @named('mock') +/// ApiClient mockApi() => MockApiClient(); /// } /// ``` /// -/// This will generate: +/// ### Example: On Injectable Field /// ```dart -/// final class $AppModule extends AppModule { -/// @override -/// void builder(Scope currentScope) { -/// bind().toProvide(() => dio()).withName('dio').singleton(); -/// } +/// @injectable() +/// class WidgetModel with _\$WidgetModel { +/// @inject() +/// @named('main') +/// late final ApiClient api; /// } /// ``` /// -/// RUSSIAN (Русский): -/// Аннотация для задания имени или идентификатора классу, методу или другому элементу. -/// -/// Аннотация `@named('значение')` позволяет указать строковое имя для зависимости, -/// фабрики или внедряемого значения. Это удобно для различения нескольких -/// регистраций одного типа в DI, генерации кода. -/// -/// Пример: +/// ### Example: On Parameter /// ```dart -/// @module() -/// abstract class AppModule extends Module { -/// @named('dio') -/// Dio dio() => Dio(); +/// class UserScreen { +/// UserScreen(@named('current') User user); /// } /// ``` -/// -/// Будет сгенерирован следующий код: -/// ```dart -/// final class $AppModule extends AppModule { -/// @override -/// void builder(Scope currentScope) { -/// bind().toProvide(() => dio()).withName('dio').singleton(); -/// } -/// } -/// ``` -// ignore: camel_case_types +@experimental final class named { - /// EN: The assigned name or identifier for the element. - /// - /// RU: Назначенное имя или идентификатор для элемента. + /// The assigned name or identifier for the dependency, provider, or parameter. final String value; - /// EN: Creates a [named] annotation with the given [value]. - /// - /// RU: Создаёт аннотацию [named] с заданным значением [value]. + /// Creates a [named] annotation with the given [value] key or name. const named(this.value); } diff --git a/cherrypick_annotations/lib/src/params.dart b/cherrypick_annotations/lib/src/params.dart index b884000..1b5c055 100644 --- a/cherrypick_annotations/lib/src/params.dart +++ b/cherrypick_annotations/lib/src/params.dart @@ -11,46 +11,33 @@ // limitations under the License. // -/// ENGLISH: -/// Annotation to mark a method parameter for injection with run-time arguments. +import 'package:meta/meta.dart'; + +/// Marks a parameter in a provider method to receive dynamic runtime arguments when resolving a dependency. /// -/// Use the `@params()` annotation to specify that a particular parameter of a -/// provider method should be assigned a value supplied at resolution time, -/// rather than during static dependency graph creation. This is useful in DI -/// when a dependency must receive dynamic data passed by the consumer -/// (via `.withParams(...)` in the generated code). +/// Use `@params()` in a DI module/factory method when the value must be supplied by the user/code at injection time, +/// not during static wiring (such as user input, navigation arguments, etc). +/// +/// This enables CherryPick and its codegen to generate .withParams or .toProvideWithParams bindings — so your provider can access runtime values. /// /// Example: /// ```dart -/// @provide() -/// String greet(@params() dynamic params) => 'Hello $params'; -/// ``` +/// import 'package:cherrypick_annotations/cherrypick_annotations.dart'; /// -/// This will generate: +/// @module() +/// abstract class FeatureModule { +/// @provide +/// UserManager createManager(@params Map runtimeParams) { +/// return UserManager.forUserId(runtimeParams['userId']); +/// } +/// } +/// ``` +/// Usage at injection/resolution: /// ```dart -/// bind().toProvideWithParams((args) => greet(args)); +/// final manager = scope.resolve(params: {'userId': myId}); /// ``` -/// -/// RUSSIAN (Русский): -/// Аннотация для пометки параметра метода, который будет внедряться со значением во время выполнения. -/// -/// Используйте `@params()` чтобы указать, что конкретный параметр метода-провайдера -/// должен получать значение, передаваемое в момент обращения к зависимости, -/// а не на этапе построения графа зависимостей. Это полезно, если зависимость -/// должна получать данные динамически от пользователя или другого процесса -/// через `.withParams(...)` в сгенерированном коде. -/// -/// Пример: -/// ```dart -/// @provide() -/// String greet(@params() dynamic params) => 'Hello $params'; -/// ``` -/// -/// Будет сгенерировано: -/// ```dart -/// bind().toProvideWithParams((args) => greet(args)); -/// ``` -// ignore: camel_case_types +@experimental final class params { + /// Marks a method/constructor parameter as supplied at runtime by the caller. const params(); } diff --git a/cherrypick_annotations/lib/src/provide.dart b/cherrypick_annotations/lib/src/provide.dart index 95acdf2..0f42043 100644 --- a/cherrypick_annotations/lib/src/provide.dart +++ b/cherrypick_annotations/lib/src/provide.dart @@ -11,60 +11,34 @@ // limitations under the License. // -/// ENGLISH: -/// Annotation to declare a factory/provider method or class as a singleton. +import 'package:meta/meta.dart'; + +/// Marks a method or class as a dependency provider (factory/provider) for CherryPick module code generation. /// -/// Use the `@singleton()` annotation on methods in your DI module to specify -/// that only one instance of the resulting object should be created and shared -/// for all consumers. This is especially useful in dependency injection -/// frameworks and service locators. +/// Use `@provide` on any method inside a `@module()` annotated class when you want that method +/// to be used as a DI factory/provider during code generation. +/// +/// This should be used for methods that create dynamic, optional, or complex dependencies, especially +/// if you want to control the codegen/injection pipeline explicitly and support parameters. /// /// Example: /// ```dart +/// import 'package:cherrypick_annotations/cherrypick_annotations.dart'; +/// /// @module() -/// abstract class AppModule extends Module { +/// abstract class FeatureModule { +/// @provide +/// Future provideApi(@params Map args) async => ...; +/// /// @singleton() -/// Dio dio() => Dio(); +/// @provide +/// Logger provideLogger() => Logger(); /// } /// ``` /// -/// This generates the following code: -/// ```dart -/// final class $AppModule extends AppModule { -/// @override -/// void builder(Scope currentScope) { -/// bind().toProvide(() => dio()).singleton(); -/// } -/// } -/// ``` -/// -/// RUSSIAN (Русский): -/// Аннотация для объявления фабричного/провайдерного метода или класса синглтоном. -/// -/// Используйте `@singleton()` для методов внутри DI-модуля, чтобы указать, -/// что соответствующий объект (экземпляр класса) должен быть создан только один раз -/// и использоваться всеми компонентами приложения (единый общий экземпляр). -/// Это характерно для систем внедрения зависимостей и сервис-локаторов. -/// -/// Пример: -/// ```dart -/// @module() -/// abstract class AppModule extends Module { -/// @singleton() -/// Dio dio() => Dio(); -/// } -/// ``` -/// -/// Будет сгенерирован следующий код: -/// ```dart -/// final class $AppModule extends AppModule { -/// @override -/// void builder(Scope currentScope) { -/// bind().toProvide(() => dio()).singleton(); -/// } -/// } -/// ``` -// ignore: camel_case_types +/// See also: [@singleton], [@instance], [@params], [@named] +@experimental final class provide { + /// Creates a [provide] annotation. const provide(); } diff --git a/cherrypick_annotations/lib/src/scope.dart b/cherrypick_annotations/lib/src/scope.dart index 407626d..ecfc054 100644 --- a/cherrypick_annotations/lib/src/scope.dart +++ b/cherrypick_annotations/lib/src/scope.dart @@ -13,25 +13,41 @@ import 'package:meta/meta.dart'; -/// Annotation to specify a scope for dependency injection in CherryPick. -/// Use this on an injected field to indicate from which scope -/// the dependency must be resolved. +/// Specifies the DI scope or region from which a dependency should be resolved. /// -/// --- +/// Use `@scope('scopeName')` on an injected field, parameter, or provider method when you want +/// to resolve a dependency not from the current scope, but from another named scope/subcontainer. /// -/// Аннотация для указания области внедрения (scope) в CherryPick. -/// Используйте её на инъецируемом поле, чтобы определить из какой области -/// должна быть получена зависимость. +/// Useful for advanced DI scenarios: multi-feature/state isolation, navigation stacks, explicit subscopes, or testing. /// -/// Example / Пример: +/// Example (injected field): /// ```dart -/// @inject() -/// @scope('profile') -/// late final ProfileManager profileManager; +/// @injectable() +/// class ProfileScreen with _\$ProfileScreen { +/// @inject() +/// @scope('profile') +/// late final ProfileManager manager; +/// } +/// ``` +/// +/// Example (parameter): +/// ```dart +/// class TabBarModel { +/// TabBarModel(@scope('tabs') TabContext context); +/// } +/// ``` +/// +/// Example (in a module): +/// ```dart +/// @module() +/// abstract class FeatureModule { +/// @provide +/// Service service(@scope('shared') SharedConfig config); +/// } /// ``` @experimental -// ignore: camel_case_types final class scope { + /// The name/key of the DI scope from which to resolve this dependency. final String? name; const scope(this.name); } diff --git a/cherrypick_annotations/lib/src/singleton.dart b/cherrypick_annotations/lib/src/singleton.dart index f614f93..8d6fd24 100644 --- a/cherrypick_annotations/lib/src/singleton.dart +++ b/cherrypick_annotations/lib/src/singleton.dart @@ -11,63 +11,32 @@ // limitations under the License. // -/// ENGLISH: -/// Annotation to declare a dependency as a singleton. +import 'package:meta/meta.dart'; + +/// Marks a provider method or class so its instance is created only once and shared (singleton) for DI in CherryPick. /// -/// Use the `@singleton()` annotation on provider methods inside a module -/// to indicate that only a single instance of this dependency should be -/// created and shared throughout the application's lifecycle. This is -/// typically used in dependency injection frameworks or service locators -/// to guarantee a single shared instance. +/// Use `@singleton()` on provider methods or classes in your DI module to ensure only one instance is ever created +/// and reused across the application's lifetime (or scope lifetime). /// /// Example: /// ```dart +/// import 'package:cherrypick_annotations/cherrypick_annotations.dart'; +/// /// @module() -/// abstract class AppModule extends Module { +/// abstract class AppModule { /// @singleton() -/// Dio dio() => Dio(); +/// ApiClient createApi() => ApiClient(); /// } /// ``` /// -/// This will generate code like: +/// The generated code will ensure: /// ```dart -/// final class $AppModule extends AppModule { -/// @override -/// void builder(Scope currentScope) { -/// bind().toProvide(() => dio()).singleton(); -/// } -/// } +/// bind().toProvide(() => createApi()).singleton(); /// ``` /// -/// RUSSIAN (Русский): -/// Аннотация для объявления зависимости как синглтона. -/// -/// Используйте `@singleton()` для методов-провайдеров внутри модуля, -/// чтобы указать, что соответствующий объект должен быть создан -/// единожды и использоваться во всём приложении (общий синглтон). -/// Это характерно для систем внедрения зависимостей и сервис-локаторов, -/// чтобы гарантировать один общий экземпляр. -/// -/// Пример: -/// ```dart -/// @module() -/// abstract class AppModule extends Module { -/// @singleton() -/// Dio dio() => Dio(); -/// } -/// ``` -/// -/// Будет сгенерирован следующий код: -/// ```dart -/// final class $AppModule extends AppModule { -/// @override -/// void builder(Scope currentScope) { -/// bind().toProvide(() => dio()).singleton(); -/// } -/// } -/// ``` -// ignore: camel_case_types +/// See also: [@instance], [@provide], [@named] +@experimental final class singleton { - /// Creates a [singleton] annotation. + /// Creates a [singleton] annotation for DI providers/classes. const singleton(); }