From 0874cbe43af7776661ff63a314da1f797df6bf59 Mon Sep 17 00:00:00 2001 From: Sergey Penkovsky Date: Thu, 22 May 2025 16:06:38 +0300 Subject: [PATCH] doc: update documentations --- cherrypick_generator/README.md | 188 ++++++++++++++++++++------------- 1 file changed, 116 insertions(+), 72 deletions(-) diff --git a/cherrypick_generator/README.md b/cherrypick_generator/README.md index d24494f..1b4cd6d 100644 --- a/cherrypick_generator/README.md +++ b/cherrypick_generator/README.md @@ -1,123 +1,167 @@ -# cherrypick_generator +# Cherrypick Generator -[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE) - -A code generator for dependency injection (DI) modules in Dart, designed to work with [`cherrypick_annotations`](https://pub.dev/packages/cherrypick_annotations). This package generates efficient, boilerplate-free registration code for your annotated module classes—making the provisioning and resolution of dependencies fast, type-safe, and expressive. +**Cherrypick Generator** is a Dart code generation library for automatic boilerplate creation in dependency injection (DI) modules. It processes classes annotated with `@module()` (from [cherrypick_annotations](https://pub.dev/packages/cherrypick_annotations)) and generates code for registering dependencies, handling singletons, named bindings, runtime parameters, and more. --- ## Features -- **Generates DI module extension classes** from Dart classes annotated with `@module()` -- **Automatic binding** of methods and dependencies based on `@singleton()`, `@named('...')`, and parameter-level annotations -- **Optimized for readability/maintainability:** code output follows best practices for Dart and DI -- **Integrated with build_runner** for seamless incremental builds +- **Automatic Binding Generation:** + Generates `bind()` registration code for every method in a DI module marked with `@module()`. + +- **Support for DI Annotations:** + Understands and processes meta-annotations such as `@singleton`, `@named`, `@instance`, `@provide`, and `@params`. + +- **Runtime & Compile-Time Parameters:** + Handles both injected (compile-time) and runtime parameters for provider/binding methods. + +- **Synchronous & Asynchronous Support:** + Correctly distinguishes between synchronous and asynchronous bindings (including `Future` return types). + +- **Named Bindings:** + Allows registration of named services via the `@named()` annotation. + +- **Singletons:** + Registers singletons via the `@singleton` annotation. --- ## How It Works -1. You annotate your abstract classes with `@module()` and your provider methods inside with `@singleton()` or `@named()`. -2. Run `build_runner` to trigger code generation. -3. The generator creates a class (prefixed with `$`) extending your module, overriding the `builder()` method to register your dependencies with `bind().toProvide(...)`, `.singleton()`, `.withName()`, etc. +1. **Annotations** + Annotate your module classes and methods using `@module()`, `@instance`, `@provide`, `@singleton`, and `@named` as needed. -**Example:** +2. **Code Scanning** + During the build process (with `build_runner`), the generator scans your annotated classes. + +3. **Code Generation** + For each `@module()` class, a new class (with a `$` prefix) is generated. + This class overrides the `builder(Scope)` method to register all bindings. + +4. **Binding Logic** + Each binding method's signature and annotations are analyzed. Registration code is generated according to: + - Return type (sync/async) + - Annotations (`@singleton`, `@named`, etc.) + - Parameter list (DI dependencies, `@named`, or `@params` for runtime values) + +--- + +## Example + +Given the following annotated Dart code: ```dart import 'package:cherrypick_annotations/cherrypick_annotations.dart'; -import 'package:cherrypick/cherrypick.dart'; - -part 'app_module.cherrypick.g.dart'; @module() -abstract class AppModule extends Module { - @singleton() - Dio dio() => Dio(); +class MyModule { + @singleton + @instance + SomeService provideService(ApiClient client); - @named('apiBaseUrl') - String baseUrl() => 'https://api.example.com'; + @provide + @named('special') + Future createHandler(@params Map params); } ``` -Generates: +The generator will output (simplified): ```dart -final class $AppModule extends AppModule { +final class $MyModule extends MyModule { @override void builder(Scope currentScope) { - bind().toProvide(() => dio()).singleton(); - bind().toProvide(() => baseUrl()).withName('apiBaseUrl'); + bind() + .toInstance(provideService(currentScope.resolve())) + .singleton(); + + bind() + .toProvideAsyncWithParams((args) => createHandler(args)) + .withName('special'); } } ``` --- -## Getting Started +## Generated Code Overview -### 1. Add dependencies +- **Constructor Registration:** + All non-abstract methods are considered as providers and processed for DI registration. -Add to your `pubspec.yaml`: +- **Parameter Handling:** + Each method parameter is analyzed: + - Standard DI dependency: resolved via `currentScope.resolve()`. + - Named dependency: resolved via `currentScope.resolve(named: 'name')`. + - Runtime parameter (`@params`): passed through as-is (e.g., `args`). -```yaml -dependencies: - cherrypick_annotations: ^latest +- **Binding Types:** + Supports both `.toInstance()` and `.toProvide()` (including async variants). -dev_dependencies: - cherrypick_generator: ^latest - build_runner: ^latest -``` - -### 2. Annotate modules - -See the example above. Use -- `@module()` on abstract classes -- `@singleton()` on methods for singleton bindings -- `@named('name')` on methods or method parameters to indicate named resolvers - -### 3. Build - -```shell -dart run build_runner build -``` - -This generates `.cherrypick.g.dart` files containing the `$YourModule` classes. +- **Singleton/Named:** + Appends `.singleton()` and/or `.withName('name')` as appropriate. --- -## Advanced Usage +## Usage -**Parameter Injection with @named:** +1. **Add dependencies** + In your `pubspec.yaml`: + ```yaml + dependencies: + cherrypick_annotations: ^x.y.z -```dart -@module() -abstract class NetworkModule { - @singleton() - Dio dio(@named('baseUrl') String url) => Dio(BaseOptions(baseUrl: url)); -} -``` -Which will be generated as: + dev_dependencies: + build_runner: ^2.1.0 + cherrypick_generator: ^x.y.z + ``` -```dart -bind().toProvide(() => dio( - currentScope.resolve(named: 'baseUrl') -)).singleton(); -``` +2. **Apply annotations** + Annotate your DI modules and provider methods as shown above. + +3. **Run the generator** + ``` + dart run build_runner build + # or with Flutter: + flutter pub run build_runner build + ``` + +4. **Import and use the generated code** + The generated files (suffix `.cherrypick.g.dart`) contain your `$YourModule` classes ready for use with your DI framework. + +--- + +## Advanced + +- **Customizing Parameter Names:** + Use the `@named('value')` annotation on methods and parameters for named bindings. + +- **Runtime Arguments:** + Use `@params` to designate parameters as runtime arguments that are supplied at injection time. + +- **Async Factories:** + Methods returning `Future` generate the appropriate `.toProvideAsync()` or `.toInstanceAsync()` bindings. + +--- + +## Developer Notes + +- The generator relies on Dart's analyzer, source_gen, and build packages. +- Each class and method is parsed for annotations; missing required annotations (like `@instance` or `@provide`) will result in a generation error. +- The generated code is designed to extend your original module classes while injecting all binding logic. --- ## License -Licensed under the [Apache License 2.0](LICENSE). +``` +Licensed under the Apache License, Version 2.0 +``` --- -## Contributing +## Contribution -PRs and issues welcome! Please file bugs or feature requests via GitHub. +Pull requests and issues are welcome! Please open git issues or submit improvements as needed. ---- - -## Author - -Sergey Penkovsky () \ No newline at end of file +--- \ No newline at end of file