Compare commits

...

10 Commits

Author SHA1 Message Date
Sergey Penkovsky
81f14f5231 chore(release): publish packages
- cherrypick@3.0.0
 - cherrypick_annotations@3.0.0
 - cherrypick_flutter@3.0.0
 - cherrypick_generator@3.0.0
 - talker_cherrypick_logger@3.0.0
2025-09-08 17:17:50 +03:00
Sergey Penkovsky
a9101513e1 Add CI/CD badges to package README files
- Added Melos + FVM CI badges to all package README.md files
- Standardized badge formatting across all packages
- Improved project visibility with build status indicators
2025-09-08 17:16:51 +03:00
Sergey Penkovsky
f1cf1d054f Merge pull request #22 from pese-git/develop
# Release - CherryPick 3.x

> **CherryPick** — a lightweight and modular DI framework for Dart and Flutter that solves dependency injection through strong typing, code generation, and dependency control.

Version **3.x** was recently released with significant improvements.

## Main Changes in 3.x

* **O(1) dependency resolution** — thanks to Map indexing of bindings, performance does not depend on the size of the scope in the DI graph. This provides noticeable speedup in large projects.
* **Protection against circular dependencies** — checking works both within a single scope and across the entire hierarchy. When a cycle is detected, an informative exception with the dependency chain is thrown.
* **Integration with Talker** — all DI events (registration, creation, deletion, errors) are logged and can be displayed in the console or UI.
* **Automatic resource cleanup** — objects implementing `Disposable` are properly released when the scope is closed.
* **Stabilized declarative approach support** — annotations and code generation now work more reliably and are more convenient for use in projects.

## Resource Cleanup Example

```dart
class MyServiceWithSocket implements Disposable {
  @override
  Future<void> dispose() async {
    await socket.close();
    print('Socket closed!');
  }
}

class AppModule extends Module {
  @override
  void builder(Scope currentScope) {
    // singleton Api
    bind<MyServiceWithSocket>()
      .toProvide(() => MyServiceWithSocket())
      .singleton();
  }
}

scope.installModules([AppModule()]);

await CherryPick.closeRootScope(); // will wait for async dispose to complete
```

## Circular Dependency Checking

One of the new features in CherryPick 3.x is built-in cycle protection.
This helps catch situations early where services start depending on each other recursively.

### How to Enable Checking

For checking within a single scope:

```dart
final scope = CherryPick.openRootScope();
scope.enableCycleDetection();
```

For global checking across the entire hierarchy:

```dart
CherryPick.enableGlobalCycleDetection();
CherryPick.enableGlobalCrossScopeCycleDetection();
final rootScope = CherryPick.openRootScope();
```

### How a Cycle Can Occur

Suppose we have two services that depend on each other:

```dart
class UserService {
  final OrderService orderService;
  UserService(this.orderService);
}

class OrderService {
  final UserService userService;
  OrderService(this.userService);
}
```

If we register them in the same scope:

```dart
class AppModule extends Module {
  @override
  void builder(Scope currentScope) {
    bind<UserService>().toProvide(() => UserService(scope.resolve()));
    bind<OrderService>().toProvide(() => OrderService(scope.resolve()));
  }
}

final scope = CherryPick.openRootScope()
  ..enableCycleDetection()
  ..installModules([AppModule()]);

scope.resolve<UserService>();
```

Then when trying to resolve the dependency, an exception will be thrown:

```bash
 Circular dependency detected for UserService
Dependency chain: UserService -> OrderService -> UserService
```

This way, the error is detected immediately, not "somewhere in runtime".

## Integration with Talker

CherryPick 3.x allows logging all DI events through [Talker](https://pub.dev/packages/talker): registration, object creation, deletion, and errors. This is convenient for debugging and diagnosing the dependency graph.

Connection example:

```dart
final talker = Talker();
final observer = TalkerCherryPickObserver(talker);
CherryPick.setGlobalObserver(observer);
```

After this, DI events will be displayed in the console or UI:

```bash
┌───────────────────────────────────────────────────────────────
│ [info]    9:41:33  | [scope opened][CherryPick] scope_1757054493089_7072
└───────────────────────────────────────────────────────────────
┌───────────────────────────────────────────────────────────────
│ [verbose] 9:41:33  | [diagnostic][CherryPick] Scope created: scope_1757054493089_7072 {type: Scope, name: scope_1757054493089_7072, description: scope created}
└───────────────────────────────────────────────────────────────
```

In the log, you can see when scopes are created, which objects are registered and deleted, and catch errors and cycles in real time.


## Declarative Approach with Annotations

In addition to fully programmatic module descriptions, CherryPick supports **declarative DI style through annotations**.  
This allows minimizing manual code and automatically generating modules and mixins for automatic dependency injection.

Example of a declarative module:

```dart
@module()
abstract class AppModule extends Module {
  @provide()
  @singleton()
  Api api() => Api();

  @provide()
  Repo repo(Api api) => Repo(api);
}
````

After code generation, you can automatically inject dependencies into widgets or services:

```dart
@injectable()
class MyScreen extends StatelessWidget with _$MyScreen {
  @inject()
  late final Repo repo;

  MyScreen() {
    _inject(this);
  }
}
```

This way you can choose a convenient style: either **purely programmatic** or **declarative with annotations**.


## Who Might Find CherryPick Useful?

* Projects where it's important to guarantee **no cycles in the dependency graph**;
* Teams that want to **minimize manual DI code** and use a declarative style with annotations;
* Applications that require **automatic resource cleanup** (sockets, controllers, streams).

## Useful Links

* 📦 Package: [pub.dev/packages/cherrypick](https://pub.dev/packages/cherrypick)
* 💻 Code: [github.com/pese-git/cherrypick](https://github.com/pese-git/cherrypick)
* 📖 Documentation: [cherrypick-di.netlify.app](https://cherrypick-di.netlify.app/)
2025-09-08 17:04:48 +03:00
Sergey Penkovsky
f1ad1c42b5 Add ignore comment for deprecated member warning in binding.dart
- Added // ignore: deprecated_member_use_from_same_package comment
- This suppresses the warning about deprecated toProvideAsync method
- The comment is needed to maintain code quality while keeping backward compatibility
2025-09-08 16:50:45 +03:00
Sergey Penkovsky
be7f3e0392 Add release notes for CherryPick 3.x in both Russian and English
- Added comprehensive release notes for CherryPick 3.x
- Includes new features: O(1) dependency resolution, circular dependency protection
- Added Talker integration and automatic resource cleanup examples
- Added declarative approach with annotations section
- Both Russian and English versions included
2025-09-08 16:48:12 +03:00
Sergey Penkovsky
1b0615810d add presentation 2025-09-08 15:48:58 +03:00
Sergey Penkovsky
ef04f464da Update README.md 2025-09-08 15:40:09 +03:00
Sergey Penkovsky
6826f0f62c chore: synchronize package versions to 3.0.0-dev.X across all packages
- Unified MAJOR.MINOR versioning across all cherrypick ecosystem packages
- Updated cherrypick_annotations from 1.1.2-dev.2 to 3.0.0-dev.0
- Updated cherrypick_generator from 2.0.0-dev.2 to 3.0.0-dev.0
- Updated cherrypick_flutter from 1.1.3-dev.12 to 3.0.0-dev.1
- Updated documentation URLs from .dev to .netlify.app domain
- Maintained semantic versioning consistency for mono-repository management

This change ensures:
- Clear compatibility signaling between interdependent packages
- Simplified dependency management for consumers
- Consistent release versioning across the ecosystem
2025-09-08 15:06:19 +03:00
Sergey Penkovsky
9e517d047f chore(release): publish packages
- cherrypick@3.0.0-dev.13
 - cherrypick_flutter@3.0.0-dev.1
 - talker_cherrypick_logger@3.0.0-dev.1
2025-09-08 14:58:37 +03:00
Sergey Penkovsky
68a16aaa0c chore(release): publish packages
- talker_cherrypick_logger@3.0.0-dev.0
2025-09-08 14:57:29 +03:00
23 changed files with 788 additions and 25 deletions

View File

@@ -3,6 +3,101 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## 2025-09-08
### Changes
---
Packages with breaking changes:
- [`cherrypick` - `v3.0.0`](#cherrypick---v300)
- [`cherrypick_annotations` - `v3.0.0`](#cherrypick_annotations---v300)
- [`cherrypick_flutter` - `v3.0.0`](#cherrypick_flutter---v300)
- [`cherrypick_generator` - `v3.0.0`](#cherrypick_generator---v300)
- [`talker_cherrypick_logger` - `v3.0.0`](#talker_cherrypick_logger---v300)
Packages with other changes:
- There are no other changes in this release.
Packages graduated to a stable release (see pre-releases prior to the stable version for changelog entries):
- `cherrypick` - `v3.0.0`
- `cherrypick_annotations` - `v3.0.0`
- `cherrypick_flutter` - `v3.0.0`
- `cherrypick_generator` - `v3.0.0`
- `talker_cherrypick_logger` - `v3.0.0`
---
#### `cherrypick` - `v3.0.0`
#### `cherrypick_annotations` - `v3.0.0`
#### `cherrypick_flutter` - `v3.0.0`
#### `cherrypick_generator` - `v3.0.0`
#### `talker_cherrypick_logger` - `v3.0.0`
## 2025-09-08
### Changes
---
Packages with breaking changes:
- There are no breaking changes in this release.
Packages with other changes:
- [`cherrypick` - `v3.0.0-dev.13`](#cherrypick---v300-dev13)
- [`cherrypick_flutter` - `v3.0.0-dev.1`](#cherrypick_flutter---v300-dev1)
- [`talker_cherrypick_logger` - `v3.0.0-dev.1`](#talker_cherrypick_logger---v300-dev1)
Packages with dependency updates only:
> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project.
- `cherrypick_flutter` - `v3.0.0-dev.1`
- `talker_cherrypick_logger` - `v3.0.0-dev.1`
---
#### `cherrypick` - `v3.0.0-dev.13`
- **FIX**: fix examples.
- **DOCS**: update contributors list with GitHub links and add new contributor.
- **DOCS**(binding,docs): clarify `.singleton()` with `.toInstance()` behavior in docs and API.
- **DOCS**(binding,docs): explain .singleton() + parametric provider behavior.
- **DOCS**(binding): clarify registration limitation in API doc.
- **DOCS**(di): clarify 'toInstance' binding limitations in builder.
## 2025-09-08
### Changes
---
Packages with breaking changes:
- There are no breaking changes in this release.
Packages with other changes:
- [`talker_cherrypick_logger` - `v3.0.0-dev.0`](#talker_cherrypick_logger---v300-dev0)
---
#### `talker_cherrypick_logger` - `v3.0.0-dev.0`
- chore(talker_cherrypick_logger): sync version with cherrypick 3.0.0-dev.12
## 2025-09-08
### Changes

View File

@@ -1,3 +1,7 @@
[![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)
---
# CherryPick Workspace
CherryPick Workspace is a modular, open-source dependency injection ecosystem for Dart and Flutter, designed to offer lightweight, flexible, and scalable DI suitable for both backend and frontend (Flutter) development. This monorepo contains the main DI runtime library, annotation helpers, code generation for modular bindings, and seamless Flutter integration.
@@ -142,4 +146,4 @@ Please see:
---
**Happy Cherry Picking! 🍒**
**Happy Cherry Picking! 🍒**

View File

@@ -1,3 +1,16 @@
## 3.0.0
- Graduate package to a stable release. See pre-releases prior to this version for changelog entries.
## 3.0.0-dev.13
- **FIX**: fix examples.
- **DOCS**: update contributors list with GitHub links and add new contributor.
- **DOCS**(binding,docs): clarify `.singleton()` with `.toInstance()` behavior in docs and API.
- **DOCS**(binding,docs): explain .singleton() + parametric provider behavior.
- **DOCS**(binding): clarify registration limitation in API doc.
- **DOCS**(di): clarify 'toInstance' binding limitations in builder.
## 3.0.0-dev.12
- **FIX**(scope): prevent concurrent modification in dispose().

View File

@@ -1,3 +1,7 @@
[![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)
---
# CherryPick
`cherrypick` is a flexible and lightweight dependency injection library for Dart and Flutter.

View File

@@ -191,6 +191,7 @@ class Binding<T> {
/// }
/// ```
/// This restriction only applies to [toInstance] bindings.
// ignore: deprecated_member_use_from_same_package
/// With [toProvide]/[toProvideAsync] you may freely use `scope.resolve<T>()` in the builder or provider function.
Binding<T> toInstance(Instance<T> value) {
_resolver = InstanceResolver<T>(value);

View File

@@ -1,8 +1,8 @@
name: cherrypick
description: Cherrypick is a small dependency injection (DI) library for dart/flutter projects.
version: 3.0.0-dev.12
homepage: https://cherrypick-di.dev/
documentation: https://cherrypick-di.dev/docs/intro
version: 3.0.0
homepage: https://cherrypick-di.netlify.app
documentation: https://cherrypick-di.netlify.app/docs/intro
repository: https://github.com/pese-git/cherrypick
issue_tracker: https://github.com/pese-git/cherrypick/issues
topics:

View File

@@ -1,3 +1,7 @@
## 3.0.0
- Graduate package to a stable release. See pre-releases prior to this version for changelog entries.
## 3.0.0-dev.0
- chore(cherrypick_annotations): sync version with cherrypick 3.0.0-dev.0

View File

@@ -1,3 +1,7 @@
[![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)
---
# cherrypick_annotations
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)

View File

@@ -1,9 +1,9 @@
name: cherrypick_annotations
description: |
Set of annotations for CherryPick dependency injection library. Enables code generation and declarative DI for Dart & Flutter projects.
version: 3.0.0-dev.0
homepage: https://cherrypick-di.dev/
documentation: https://cherrypick-di.dev/docs/intro
version: 3.0.0
homepage: https://cherrypick-di.netlify.app
documentation: https://cherrypick-di.netlify.app/docs/intro
repository: https://github.com/pese-git/cherrypick/cherrypick_annotations
issue_tracker: https://github.com/pese-git/cherrypick/issues
topics:

View File

@@ -1,3 +1,11 @@
## 3.0.0
- Graduate package to a stable release. See pre-releases prior to this version for changelog entries.
## 3.0.0-dev.1
- Update a dependency to the latest release.
## 3.0.0-dev.0
- chore(cherrypick_flutter): sync version with cherrypick 3.0.0-dev.12

View File

@@ -1,3 +1,7 @@
[![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)
---
# CherryPick Flutter
`cherrypick_flutter` offers a Flutter integration to access and manage dependency injection scopes using the `CherryPickProvider`. This setup facilitates accessing the root scope directly from the widget tree, providing a straightforward mechanism for dependences management within Flutter applications.

View File

@@ -1,8 +1,8 @@
name: cherrypick_flutter
description: "Flutter library that allows access to the root scope through the context using `CherryPickProvider`."
version: 3.0.0-dev.0
homepage: https://cherrypick-di.dev/
documentation: https://cherrypick-di.dev/docs/intro
version: 3.0.0
homepage: https://cherrypick-di.netlify.app
documentation: https://cherrypick-di.netlify.app/docs/intro
repository: https://github.com/pese-git/cherrypick
issue_tracker: https://github.com/pese-git/cherrypick/issues
topics:
@@ -19,7 +19,7 @@ environment:
dependencies:
flutter:
sdk: flutter
cherrypick: ^3.0.0-dev.12
cherrypick: ^3.0.0
dev_dependencies:
flutter_test:

View File

@@ -1,3 +1,7 @@
## 3.0.0
- Graduate package to a stable release. See pre-releases prior to this version for changelog entries.
## 3.0.0-dev.0
- chore(cherrypick_generator): sync version with cherrypick 3.0.0-dev.12

View File

@@ -1,3 +1,7 @@
[![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)
---
# Cherrypick Generator
**Cherrypick Generator** is a Dart code generation library for automating dependency injection (DI) boilerplate. It processes classes and fields annotated with [cherrypick_annotations](https://pub.dev/packages/cherrypick_annotations) and generates registration code for services, modules, and field injection for classes marked as `@injectable`. It supports advanced DI features such as scopes, named bindings, parameters, and asynchronous dependencies.

View File

@@ -2,9 +2,9 @@ name: cherrypick_generator
description: |
Source code generator for the cherrypick dependency injection system. Processes annotations to generate binding and module code for Dart & Flutter projects.
version: 3.0.0-dev.0
homepage: https://cherrypick-di.dev/
documentation: https://cherrypick-di.dev/docs/intro
version: 3.0.0
homepage: https://cherrypick-di.netlify.app
documentation: https://cherrypick-di.netlify.app/docs/intro
repository: https://github.com/pese-git/cherrypick/cherrypick_generator
issue_tracker: https://github.com/pese-git/cherrypick/issues
topics:
@@ -19,7 +19,7 @@ environment:
# Add regular dependencies here.
dependencies:
cherrypick_annotations: ^3.0.0-dev.0
cherrypick_annotations: ^3.0.0
analyzer: ^7.0.0
dart_style: ^3.0.0
build: ^2.4.1

View File

@@ -0,0 +1,178 @@
# Release - CherryPick 3.x
> **CherryPick** — a lightweight and modular DI framework for Dart and Flutter that solves dependency injection through strong typing, code generation, and dependency control.
Version **3.x** was recently released with significant improvements.
## Main Changes in 3.x
* **O(1) dependency resolution** — thanks to Map indexing of bindings, performance does not depend on the size of the scope in the DI graph. This provides noticeable speedup in large projects.
* **Protection against circular dependencies** — checking works both within a single scope and across the entire hierarchy. When a cycle is detected, an informative exception with the dependency chain is thrown.
* **Integration with Talker** — all DI events (registration, creation, deletion, errors) are logged and can be displayed in the console or UI.
* **Automatic resource cleanup** — objects implementing `Disposable` are properly released when the scope is closed.
* **Stabilized declarative approach support** — annotations and code generation now work more reliably and are more convenient for use in projects.
## Resource Cleanup Example
```dart
class MyServiceWithSocket implements Disposable {
@override
Future<void> dispose() async {
await socket.close();
print('Socket closed!');
}
}
class AppModule extends Module {
@override
void builder(Scope currentScope) {
// singleton Api
bind<MyServiceWithSocket>()
.toProvide(() => MyServiceWithSocket())
.singleton();
}
}
scope.installModules([AppModule()]);
await CherryPick.closeRootScope(); // will wait for async dispose to complete
```
## Circular Dependency Checking
One of the new features in CherryPick 3.x is built-in cycle protection.
This helps catch situations early where services start depending on each other recursively.
### How to Enable Checking
For checking within a single scope:
```dart
final scope = CherryPick.openRootScope();
scope.enableCycleDetection();
```
For global checking across the entire hierarchy:
```dart
CherryPick.enableGlobalCycleDetection();
CherryPick.enableGlobalCrossScopeCycleDetection();
final rootScope = CherryPick.openRootScope();
```
### How a Cycle Can Occur
Suppose we have two services that depend on each other:
```dart
class UserService {
final OrderService orderService;
UserService(this.orderService);
}
class OrderService {
final UserService userService;
OrderService(this.userService);
}
```
If we register them in the same scope:
```dart
class AppModule extends Module {
@override
void builder(Scope currentScope) {
bind<UserService>().toProvide(() => UserService(scope.resolve()));
bind<OrderService>().toProvide(() => OrderService(scope.resolve()));
}
}
final scope = CherryPick.openRootScope()
..enableCycleDetection()
..installModules([AppModule()]);
scope.resolve<UserService>();
```
Then when trying to resolve the dependency, an exception will be thrown:
```bash
❌ Circular dependency detected for UserService
Dependency chain: UserService -> OrderService -> UserService
```
This way, the error is detected immediately, not "somewhere in runtime".
## Integration with Talker
CherryPick 3.x allows logging all DI events through [Talker](https://pub.dev/packages/talker): registration, object creation, deletion, and errors. This is convenient for debugging and diagnosing the dependency graph.
Connection example:
```dart
final talker = Talker();
final observer = TalkerCherryPickObserver(talker);
CherryPick.setGlobalObserver(observer);
```
After this, DI events will be displayed in the console or UI:
```bash
┌───────────────────────────────────────────────────────────────
[info] 9:41:33 | [scope opened][CherryPick] scope_1757054493089_7072
└───────────────────────────────────────────────────────────────
┌───────────────────────────────────────────────────────────────
[verbose] 9:41:33 | [diagnostic][CherryPick] Scope created: scope_1757054493089_7072 {type: Scope, name: scope_1757054493089_7072, description: scope created}
└───────────────────────────────────────────────────────────────
```
In the log, you can see when scopes are created, which objects are registered and deleted, and catch errors and cycles in real time.
## Declarative Approach with Annotations
In addition to fully programmatic module descriptions, CherryPick supports **declarative DI style through annotations**.
This allows minimizing manual code and automatically generating modules and mixins for automatic dependency injection.
Example of a declarative module:
```dart
@module()
abstract class AppModule extends Module {
@provide()
@singleton()
Api api() => Api();
@provide()
Repo repo(Api api) => Repo(api);
}
````
After code generation, you can automatically inject dependencies into widgets or services:
```dart
@injectable()
class MyScreen extends StatelessWidget with _$MyScreen {
@inject()
late final Repo repo;
MyScreen() {
_inject(this);
}
}
```
This way you can choose a convenient style: either **purely programmatic** or **declarative with annotations**.
## Who Might Find CherryPick Useful?
* Projects where it's important to guarantee **no cycles in the dependency graph**;
* Teams that want to **minimize manual DI code** and use a declarative style with annotations;
* Applications that require **automatic resource cleanup** (sockets, controllers, streams).
## Useful Links
* 📦 Package: [pub.dev/packages/cherrypick](https://pub.dev/packages/cherrypick)
* 💻 Code: [github.com/pese-git/cherrypick](https://github.com/pese-git/cherrypick)
* 📖 Documentation: [cherrypick-di.netlify.app](https://cherrypick-di.netlify.app/)

View File

@@ -0,0 +1,180 @@
# Release - CherryPick 3.x
> **CherryPick** — лёгкий и модульный DI-фреймворк для Dart и Flutter, который решает задачу через строгую типизацию, кодогенерацию и контроль за зависимостями.
Недавно вышла версия **3.x**, где появились заметные улучшения.
## Основные изменения в 3.x
* **O(1) разрешение зависимостей** — благодаря Map-индексации биндингов производительность не зависит от размера скоупа в DI графе. На больших проектах это даёт ощутимое ускорение.
* **Защита от циклических зависимостей** — проверка работает как внутри одного scope, так и во всей иерархии. При обнаружении цикла выбрасывается информативное исключение с цепочкой зависимостей.
* **Интеграция с Talker** — все события DI (регистрация, создание, удаление, ошибки) логируются и могут выводиться в консоль или UI.
* **Автоматическая очистка ресурсов** — объекты, реализующие `Disposable`, корректно освобождаются при закрытии scope.
* **Стабилизирована поддержка декларативного подхода** — аннотации и генерация кода теперь работают надёжнее и удобнее для использования в проектах.
## Пример с очисткой ресурсов
```dart
class MyServiceWithSocket implements Disposable {
@override
Future<void> dispose() async {
await socket.close();
print('Socket закрыт!');
}
}
class AppModule extends Module {
@override
void builder(Scope currentScope) {
// singleton Api
bind<MyServiceWithSocket>()
.toProvide(() => MyServiceWithSocket())
.singleton();
}
}
scope.installModules([AppModule()]);
await CherryPick.closeRootScope(); // дождётся завершения async dispose
```
## Проверка циклических зависимостей
Одна из новинок CherryPick 3.x — встроенная защита от циклов.
Это помогает на раннем этапе отлавливать ситуации, когда сервисы начинают зависеть друг от друга рекурсивно.
### Как включить проверку
Для проверки внутри одного scope:
```dart
final scope = CherryPick.openRootScope();
scope.enableCycleDetection();
```
Для глобальной проверки во всей иерархии:
```dart
CherryPick.enableGlobalCycleDetection();
CherryPick.enableGlobalCrossScopeCycleDetection();
final rootScope = CherryPick.openRootScope();
```
### Как может возникнуть цикл
Предположим, у нас есть два сервиса, которые зависят друг от друга:
```dart
class UserService {
final OrderService orderService;
UserService(this.orderService);
}
class OrderService {
final UserService userService;
OrderService(this.userService);
}
```
Если зарегистрировать их в одном scope:
```dart
class AppModule extends Module {
@override
void builder(Scope currentScope) {
bind<UserService>().toProvide(() => UserService(scope.resolve());
bind<OrderService>().toProvide(() => OrderService(scope.resolve()));
}
}
final scope = CherryPick.openRootScope()
..enableCycleDetection()
..installModules([AppModule()]);
scope.resolve<UserService>();
```
То при попытке разрешить зависимость будет выброшено исключение:
```bash
❌ Circular dependency detected for UserService
Dependency chain: UserService -> OrderService -> UserService
```
Таким образом, ошибка выявляется сразу, а не «где-то в runtime».
## Интеграция с Talker
CherryPick 3.x позволяет логировать все события DI через [Talker](https://pub.dev/packages/talker): регистрацию, создание объектов, удаление и ошибки. Это удобно для отладки и диагностики графа зависимостей.
Пример подключения:
```dart
final talker = Talker();
final observer = TalkerCherryPickObserver(talker);
CherryPick.setGlobalObserver(observer);
```
После этого в консоли или UI будут отображаться события DI:
```bash
┌───────────────────────────────────────────────────────────────
[info] 9:41:33 | [scope opened][CherryPick] scope_1757054493089_7072
└───────────────────────────────────────────────────────────────
┌───────────────────────────────────────────────────────────────
[verbose] 9:41:33 | [diagnostic][CherryPick] Scope created: scope_1757054493089_7072 {type: Scope, name: scope_1757054493089_7072, description: scope created}
└───────────────────────────────────────────────────────────────
```
В логе можно увидеть, когда scope создаётся, какие объекты регистрируются и удаляются, а также отлавливать ошибки и циклы в реальном времени.
## Декларативный подход с аннотациями
Помимо полностью программного описания модулей, CherryPick поддерживает **декларативный стиль DI через аннотации**.
Это позволяет минимизировать ручной код и автоматически генерировать модули и mixin для автоподстановки зависимостей.
Пример декларативного модуля:
```dart
@module()
abstract class AppModule extends Module {
@provide()
@singleton()
Api api() => Api();
@provide()
Repo repo(Api api) => Repo(api);
}
````
После генерации кода можно автоматически подтягивать зависимости в виджеты или сервисы:
```dart
@injectable()
class MyScreen extends StatelessWidget with _$MyScreen {
@inject()
late final Repo repo;
MyScreen() {
_inject(this);
}
}
```
Таким образом можно выбрать удобный стиль: либо **чисто программный**, либо **декларативный с аннотациями**.
## Кому может быть полезен CherryPick?
* проектам, где важно гарантировать **отсутствие циклов в графе зависимостей**;
* командам, которые хотят **минимизировать ручной DI-код** и использовать декларативный стиль с аннотациями;
* приложениям, где требуется **автоматическое освобождение ресурсов** (сокеты, контроллеры, потоки).
## Полезные ссылки
* 📦 Пакет: [pub.dev/packages/cherrypick](https://pub.dev/packages/cherrypick)
* 💻 Код: [github.com/pese-git/cherrypick](https://github.com/pese-git/cherrypick)
* 📖 Документация: [cherrypick-di.netlify.app](https://cherrypick-di.netlify.app/)

244
doc/presentation_ru.md Normal file
View File

@@ -0,0 +1,244 @@
---
marp: true
---
<!--
#backgroundImage: url('./doc/assets/image.png')
backgroundSize: cover
-->
# CherryPick 3.x
### Быстро. Безопасно. Просто.
Современный DI-framework для Dart и Flutter
Автор: Сергей Пеньковский
---
<!--
backgroundImage: none
-->
## Что такое CherryPick?
- Лёгкий и модульный framework для внедрения зависимостей (DI)
- Фокус: производительность, безопасность и лаконичный код
- Применяется во frontend, backend, CLI
---
## Эволюция: что нового в 3.x?
- Оптимизация скорости разрешения зависимостей
- Интеграция с Talker для наглядного логирования DI-событий
- Защита от циклических зависимостей на уровне ядра
- Полностью декларативное описание DI через аннотации и генерацию кода
- Автоматическая очистка ресурсов
---
## Быстро
* Мгновенное разрешение зависимостей
---
### Мгновенное разрешение зависимостей
- Операция resolve<T> теперь выполняется за O(1)
- Используется Map-индексация всех биндингов в каждом скоупе (в среднем ускорение в 10x+ на крупных графах)
- Производительность не зависит от размера приложения
---
## Безопасно
* Циклические зависимости больше не страшны
* Интеграция с Talker и расширенное логирование
---
### Циклические зависимости больше не страшны
- CherryPick 3.x автоматически выявляет циклы при разрешении зависимостей.
- Возможна проверка как внутри отдельного scope, так и во всём DI-графе (глобально).
---
#### Как включить проверку циклов
- Для защиты только внутри одного scope:
```dart
// 1. Для текущего scope (локальная проверка)
final scope = CherryPick.openRootScope();
scope.enableCycleDetection();
```
- Для защиты всей иерархии скоупов:
```dart
// 2. Для всей иерархии скоупов (глобальная проверка)
CherryPick.enableGlobalCycleDetection();
CherryPick.enableGlobalCrossScopeCycleDetection();
final rootScope = CherryPick.openRootScope();
```
---
#### Пример обработки ошибки
При обнаружении цикла будет выброшено исключение с подробной трассировкой:
```dart
try {
scope.resolve<A>();
} on CircularDependencyException catch(e) {
print(e.dependencyChain);
}
```
```bash
=== Circular Dependency Detection Example ===
1. Attempt to create a scope with circular dependencies:
❌ Circular dependency detected: CircularDependencyException: Circular dependency detected for UserService
Dependency chain: UserService -> OrderService -> UserService
```
---
### Интеграция с Talker и расширенное логирование
- Всё, что происходит в DI: регистрация, создание, удаление, ошибки ― теперь логируется!
- Достаточно подключить observer:
```dart
final talker = Talker();
final talkerLogger = TalkerCherryPickObserver(talker);
CherryPick.setGlobalObserver(talkerLogger);
```
- Логи сразу видны в консоли, UI
```bash
┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────
[info] | 9:41:33 89ms | [scope opened][CherryPick] scope_1757054493089_7072
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────
┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────
[verbose] | 9:41:33 90ms | [diagnostic][CherryPick] Scope created: scope_1757054493089_7072 {type: Scope, name: scope_1757054493089_7072, description: scope created}
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────
```
---
## Просто
* Декларативный DI
* Автоматическая очистка ресурсов
---
### Декларативный DI: аннотации и генерация кода
- Описывайте зависимости с помощью аннотаций
- Автоматически генерируется модуль DI и mixin для автоподстановки зависимостей
```dart
@module()
abstract class AppModule extends Module {
@provide()
@singleton()
Api api() => Api();
@provide()
Repo repo(Api api) => Repo(api);
}
```
Регистрация модуля
```dart
final scope = openRootScope()
..installModules([$AppModule()]);
```
---
### Field injection: минимум кода — максимум удобства
```dart
@injectable()
class MyScreen extends StatelessWidget with _$MyScreen {
@inject()
late final Repo repo;
MyScreen() {
_inject(this);
}
}
```
- После генерации mixin и вызова `screen._inject()` — зависимости готовы
- Сильная типизация, никаких ручных вызовов resolve
---
## Автоматическая очистка ресурсов
Автоматическая очистка ресурсов (контроллеры, потоки, сокеты, файлы и др.).
Если вы регистрируете объект, реализующий Disposable, через DI-контейнер, CherryPick вызовет его метод dispose() при закрытии скоупа.
```dart
class MyServiceWithSocket implements Disposable {
@override
Future<void> dispose() async {
await socket.close();
print('Socket закрыт!');
}
}
scope.installModules([
Module((bind) => bind<MyServiceWithSocket>().toProvide(() => MyServiceWithSocket()).singleton()),
]);
await CherryPick.closeRootScope(); // дождётся завершения async очистки
```
---
## Почему это удобно?
### Сравнение с ручным DI
|| Аннотации | Ручной DI |
|:---|:-----------|:------------|
|Гибко|✅|✅|
|Кратко|✅|❌|
|Безопасно|✅|❌ (легко ошибиться)|
---
## CherryPick 3.x: ваш DI-фреймворк
- Быстрое разрешение зависимостей
- Гарантия безопасности и тестируемости
- Интеграция с логированием
- Максимально простой и декларативный код
---
<!--
#backgroundImage: url('./doc/assets/image.png')
backgroundSize: cover
-->
## Спасибо за внимание
---
## Вопросы?
- Try CherryPick - [https://pub.dev/packages/cherrypick](https://pub.dev/packages/cherrypick)
- Contributing — [https://github.com/pese-git/cherrypick](https://github.com/pese-git/cherrypick)
- Документация и примеры — [https://cherrypick-di.netlify.app](https://cherrypick-di.netlify.app/)
- Готов помочь — пишите, пробуйте, внедряйте!

View File

@@ -134,21 +134,21 @@ packages:
path: "../../cherrypick_annotations"
relative: true
source: path
version: "1.1.2-dev.2"
version: "3.0.0-dev.0"
cherrypick_flutter:
dependency: "direct main"
description:
path: "../../cherrypick_flutter"
relative: true
source: path
version: "1.1.3-dev.12"
version: "3.0.0-dev.0"
cherrypick_generator:
dependency: "direct dev"
description:
path: "../../cherrypick_generator"
relative: true
source: path
version: "2.0.0-dev.2"
version: "3.0.0-dev.0"
clock:
dependency: transitive
description:

View File

@@ -182,14 +182,14 @@ packages:
path: "../../cherrypick_annotations"
relative: true
source: path
version: "1.1.2-dev.2"
version: "3.0.0-dev.0"
cherrypick_generator:
dependency: "direct main"
description:
path: "../../cherrypick_generator"
relative: true
source: path
version: "2.0.0-dev.2"
version: "3.0.0-dev.0"
cli_launcher:
dependency: transitive
description:
@@ -864,7 +864,7 @@ packages:
path: "../../talker_cherrypick_logger"
relative: true
source: path
version: "1.1.0-dev.7"
version: "3.0.0-dev.0"
talker_dio_logger:
dependency: "direct main"
description:

View File

@@ -1,3 +1,15 @@
## 3.0.0
- Graduate package to a stable release. See pre-releases prior to this version for changelog entries.
## 3.0.0-dev.1
- Update a dependency to the latest release.
## 3.0.0-dev.0
- chore(talker_cherrypick_logger): sync version with cherrypick 3.0.0-dev.12
## 1.1.0-dev.7
- Update a dependency to the latest release.

View File

@@ -1,3 +1,7 @@
[![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)
---
# talker_cherrypick_logger
An integration package that allows you to log [CherryPick](https://github.com/pese-dot-work/cherrypick) Dependency Injection (DI) container events using the [Talker](https://pub.dev/packages/talker) logging system.

View File

@@ -1,8 +1,8 @@
name: talker_cherrypick_logger
description: A Talker logger integration for CherryPick DI to observe and log DI events and errors.
version: 1.1.0-dev.7
homepage: https://cherrypick-di.dev/
documentation: https://cherrypick-di.dev/docs/intro
version: 3.0.0
homepage: https://cherrypick-di.netlify.app
documentation: https://cherrypick-di.netlify.app/docs/intro
repository: https://github.com/pese-git/cherrypick
issue_tracker: https://github.com/pese-git/cherrypick/issues
@@ -18,7 +18,7 @@ environment:
# Add regular dependencies here.
dependencies:
talker: ^4.9.3
cherrypick: ^3.0.0-dev.12
cherrypick: ^3.0.0
dev_dependencies: