mirror of
https://github.com/pese-git/cherrypick.git
synced 2026-01-24 13:47:24 +00:00
doc: update documentations
This commit is contained in:
@@ -1,123 +1,167 @@
|
|||||||
# cherrypick_generator
|
# Cherrypick Generator
|
||||||
|
|
||||||
[](LICENSE)
|
**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.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **Generates DI module extension classes** from Dart classes annotated with `@module()`
|
- **Automatic Binding Generation:**
|
||||||
- **Automatic binding** of methods and dependencies based on `@singleton()`, `@named('...')`, and parameter-level annotations
|
Generates `bind<Type>()` registration code for every method in a DI module marked with `@module()`.
|
||||||
- **Optimized for readability/maintainability:** code output follows best practices for Dart and DI
|
|
||||||
- **Integrated with build_runner** for seamless incremental builds
|
- **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<T>` return types).
|
||||||
|
|
||||||
|
- **Named Bindings:**
|
||||||
|
Allows registration of named services via the `@named()` annotation.
|
||||||
|
|
||||||
|
- **Singletons:**
|
||||||
|
Registers singletons via the `@singleton` annotation.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## How It Works
|
## How It Works
|
||||||
|
|
||||||
1. You annotate your abstract classes with `@module()` and your provider methods inside with `@singleton()` or `@named()`.
|
1. **Annotations**
|
||||||
2. Run `build_runner` to trigger code generation.
|
Annotate your module classes and methods using `@module()`, `@instance`, `@provide`, `@singleton`, and `@named` as needed.
|
||||||
3. The generator creates a class (prefixed with `$`) extending your module, overriding the `builder()` method to register your dependencies with `bind<T>().toProvide(...)`, `.singleton()`, `.withName()`, etc.
|
|
||||||
|
|
||||||
**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
|
```dart
|
||||||
import 'package:cherrypick_annotations/cherrypick_annotations.dart';
|
import 'package:cherrypick_annotations/cherrypick_annotations.dart';
|
||||||
import 'package:cherrypick/cherrypick.dart';
|
|
||||||
|
|
||||||
part 'app_module.cherrypick.g.dart';
|
|
||||||
|
|
||||||
@module()
|
@module()
|
||||||
abstract class AppModule extends Module {
|
class MyModule {
|
||||||
@singleton()
|
@singleton
|
||||||
Dio dio() => Dio();
|
@instance
|
||||||
|
SomeService provideService(ApiClient client);
|
||||||
|
|
||||||
@named('apiBaseUrl')
|
@provide
|
||||||
String baseUrl() => 'https://api.example.com';
|
@named('special')
|
||||||
|
Future<Handler> createHandler(@params Map<String, dynamic> params);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Generates:
|
The generator will output (simplified):
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
final class $AppModule extends AppModule {
|
final class $MyModule extends MyModule {
|
||||||
@override
|
@override
|
||||||
void builder(Scope currentScope) {
|
void builder(Scope currentScope) {
|
||||||
bind<Dio>().toProvide(() => dio()).singleton();
|
bind<SomeService>()
|
||||||
bind<String>().toProvide(() => baseUrl()).withName('apiBaseUrl');
|
.toInstance(provideService(currentScope.resolve<ApiClient>()))
|
||||||
|
.singleton();
|
||||||
|
|
||||||
|
bind<Handler>()
|
||||||
|
.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<Type>()`.
|
||||||
|
- Named dependency: resolved via `currentScope.resolve<Type>(named: 'name')`.
|
||||||
|
- Runtime parameter (`@params`): passed through as-is (e.g., `args`).
|
||||||
|
|
||||||
```yaml
|
- **Binding Types:**
|
||||||
dependencies:
|
Supports both `.toInstance()` and `.toProvide()` (including async variants).
|
||||||
cherrypick_annotations: ^latest
|
|
||||||
|
|
||||||
dev_dependencies:
|
- **Singleton/Named:**
|
||||||
cherrypick_generator: ^latest
|
Appends `.singleton()` and/or `.withName('name')` as appropriate.
|
||||||
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.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Advanced Usage
|
## Usage
|
||||||
|
|
||||||
**Parameter Injection with @named:**
|
1. **Add dependencies**
|
||||||
|
In your `pubspec.yaml`:
|
||||||
|
```yaml
|
||||||
|
dependencies:
|
||||||
|
cherrypick_annotations: ^x.y.z
|
||||||
|
|
||||||
```dart
|
dev_dependencies:
|
||||||
@module()
|
build_runner: ^2.1.0
|
||||||
abstract class NetworkModule {
|
cherrypick_generator: ^x.y.z
|
||||||
@singleton()
|
```
|
||||||
Dio dio(@named('baseUrl') String url) => Dio(BaseOptions(baseUrl: url));
|
|
||||||
}
|
|
||||||
```
|
|
||||||
Which will be generated as:
|
|
||||||
|
|
||||||
```dart
|
2. **Apply annotations**
|
||||||
bind<Dio>().toProvide(() => dio(
|
Annotate your DI modules and provider methods as shown above.
|
||||||
currentScope.resolve<String>(named: 'baseUrl')
|
|
||||||
)).singleton();
|
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<T>` 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
|
## 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 (<sergey.penkovsky@gmail.com>)
|
|
||||||
Reference in New Issue
Block a user