Files

234 lines
5.5 KiB
Markdown
Raw Permalink Normal View History

[![Melos + FVM CI](https://github.com/pese-git/cherrypick/actions/workflows/pipeline.yml/badge.svg)](https://github.com/pese-git/cherrypick/actions/workflows/pipeline.yml)
[![Netlify Status](https://api.netlify.com/api/v1/badges/3c3e0f98-27a9-4dd4-9eab-4be0b96798b8/deploy-status)](https://app.netlify.com/projects/cherrypick-di/deploys)
---
2025-05-18 14:01:00 +03:00
# cherrypick_annotations
2025-05-14 12:53:51 +03:00
2025-05-18 14:01:00 +03:00
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
2025-05-14 12:53:51 +03:00
2025-05-23 17:27:40 +03:00
A lightweight set of Dart annotations for dependency injection (DI) frameworks and code generation, inspired by modern approaches like Dagger and Injectable. Optimized for use with [`cherrypick_generator`](https://pub.dev/packages/cherrypick_generator).
2025-05-14 12:53:51 +03:00
2025-05-18 14:01:00 +03:00
---
2025-05-14 12:53:51 +03:00
## Features
2025-05-18 14:01:00 +03:00
- **@module** Marks a class as a DI module for service/provider registration.
- **@singleton** Declares that a method or class should be provided as a singleton.
2025-05-23 17:27:40 +03:00
- **@instance** Marks a method or class so that a new instance is provided on each request.
- **@provide** Marks a method whose return value should be registered as a provider, supporting DI into its parameters.
- **@named** Assigns a string name to a binding for keyed resolution and injection.
2025-05-22 15:18:16 +03:00
- **@params** Indicates that a parameter should be injected with runtime-supplied arguments.
2025-05-23 17:27:40 +03:00
- **@injectable** Marks a class as eligible for automatic field injection. Fields annotated with `@inject` will be injected by the code generator.
- **@inject** Marks a field to be automatically injected by the code generator.
- **@scope** Declares the DI scope from which a dependency should be resolved for a field.
2025-05-14 12:53:51 +03:00
2025-05-22 15:18:16 +03:00
These annotations streamline DI configuration and serve as markers for code generation tools such as [`cherrypick_generator`](https://pub.dev/packages/cherrypick_generator).
2025-05-14 12:53:51 +03:00
2025-05-18 14:01:00 +03:00
---
2025-05-14 12:53:51 +03:00
2025-05-18 14:01:00 +03:00
## Getting Started
2025-05-14 12:53:51 +03:00
2025-05-18 14:01:00 +03:00
### 1. Add dependency
```yaml
dependencies:
cherrypick_annotations: ^latest
```
2025-05-22 15:18:16 +03:00
Add as a `dev_dependency` for code generation:
2025-05-18 14:01:00 +03:00
```yaml
dev_dependencies:
2025-05-23 17:27:40 +03:00
cherrypick_generator: ^latest
2025-05-18 14:01:00 +03:00
build_runner: ^latest
```
2025-05-23 17:27:40 +03:00
---
### 2. Annotate your DI modules, providers, and injectable classes
#### **Module and Provider Example**
2025-05-18 14:01:00 +03:00
```dart
import 'package:cherrypick_annotations/cherrypick_annotations.dart';
@module()
2025-05-23 17:27:40 +03:00
abstract class AppModule {
2025-05-18 14:01:00 +03:00
@singleton()
Dio dio() => Dio();
@named('baseUrl')
String baseUrl() => 'https://api.example.com';
2025-05-22 15:18:16 +03:00
@instance()
Foo foo() => Foo();
@provide()
Bar bar(Foo foo) => Bar(foo);
@provide()
String greet(@params() dynamic params) => 'Hello $params';
2025-05-18 14:01:00 +03:00
}
```
2025-05-23 17:27:40 +03:00
With `cherrypick_generator`, code like the following will be generated:
2025-05-18 14:01:00 +03:00
```dart
final class $AppModule extends AppModule {
@override
void builder(Scope currentScope) {
bind<Dio>().toProvide(() => dio()).singleton();
bind<String>().toProvide(() => baseUrl()).withName('baseUrl');
2025-05-22 15:18:16 +03:00
bind<Foo>().toInstance(foo());
bind<Bar>().toProvide(() => bar(currentScope.resolve<Foo>()));
bind<String>().toProvideWithParams((args) => greet(args));
2025-05-18 14:01:00 +03:00
}
}
```
---
2025-05-23 17:27:40 +03:00
#### **Field Injection Example**
```dart
import 'package:cherrypick_annotations/cherrypick_annotations.dart';
@injectable()
class ProfileView with _$ProfileView{
@inject()
late final AuthService auth;
@inject()
@scope('profile')
late final ProfileManager manager;
@inject()
@named('admin')
late final UserService adminUserService;
}
```
The code generator produces a mixin (simplified):
```dart
mixin _$ProfileView {
void _inject(ProfileView instance) {
instance.auth = CherryPick.openRootScope().resolve<AuthService>();
instance.manager = CherryPick.openScope(scopeName: 'profile').resolve<ProfileManager>();
instance.adminUserService = CherryPick.openRootScope().resolve<UserService>(named: 'admin');
}
}
```
---
2025-05-18 14:01:00 +03:00
## Annotation Reference
2025-05-23 17:27:40 +03:00
### `@injectable`
```dart
@injectable()
class MyWidget { ... }
```
Marks a class as injectable for CherryPick DI. The code generator will generate a mixin to perform automatic injection of fields marked with `@inject()`.
---
### `@inject`
```dart
@inject()
late final SomeService service;
```
Applied to a field to request automatic injection of the dependency using the CherryPick DI framework.
---
### `@scope`
```dart
@inject()
@scope('profile')
late final ProfileManager manager;
```
Specifies the scope from which the dependency should be resolved for an injected field.
---
2025-05-18 14:01:00 +03:00
### `@module`
```dart
@module()
2025-05-23 17:27:40 +03:00
abstract class AppModule {}
2025-05-18 14:01:00 +03:00
```
2025-05-22 15:18:16 +03:00
Use on classes to mark them as a DI module. This is the root for registering your dependency providers.
2025-05-18 14:01:00 +03:00
---
### `@singleton`
```dart
@singleton()
Dio dio() => Dio();
```
2025-05-22 15:18:16 +03:00
Use on methods or classes to provide a singleton instance (the same instance is reused).
---
### `@instance`
```dart
@instance()
Foo foo() => Foo();
```
Use on methods or classes to provide a new instance on each request (not a singleton).
---
### `@provide`
```dart
@provide()
Bar bar(Foo foo) => Bar(foo);
```
Use on methods to indicate they provide a dependency to the DI module. Dependencies listed as parameters (e.g., `foo`) are resolved and injected.
2025-05-18 14:01:00 +03:00
---
### `@named`
2025-05-14 12:53:51 +03:00
```dart
2025-05-18 14:01:00 +03:00
@named('token')
String token() => 'abc';
2025-05-14 12:53:51 +03:00
```
2025-05-23 17:27:40 +03:00
Assigns a name to a binding for keyed injection or resolution.
Can be used on both provider methods and fields.
2025-05-22 15:18:16 +03:00
---
### `@params`
```dart
@provide()
String greet(@params() dynamic params) => 'Hello $params';
```
2025-05-23 17:27:40 +03:00
Indicates that this parameter should receive runtime-supplied arguments during dependency resolution.
2025-05-18 14:01:00 +03:00
---
## License
Licensed under the [Apache License 2.0](LICENSE).
---
## Contributing
Pull requests and feedback are welcome!
---
2025-05-14 12:53:51 +03:00
2025-05-18 14:01:00 +03:00
## Author
2025-05-14 12:53:51 +03:00
2025-05-22 15:18:16 +03:00
Sergey Penkovsky (<sergey.penkovsky@gmail.com>)