diff --git a/website/blog/2019-05-28-first-blog-post.md b/website/blog/2019-05-28-first-blog-post.md deleted file mode 100644 index d3032ef..0000000 --- a/website/blog/2019-05-28-first-blog-post.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -slug: first-blog-post -title: First Blog Post -authors: [slorber, yangshun] -tags: [hola, docusaurus] ---- - -Lorem ipsum dolor sit amet... - - - -...consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet diff --git a/website/blog/2019-05-29-long-blog-post.md b/website/blog/2019-05-29-long-blog-post.md deleted file mode 100644 index eb4435d..0000000 --- a/website/blog/2019-05-29-long-blog-post.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -slug: long-blog-post -title: Long Blog Post -authors: yangshun -tags: [hello, docusaurus] ---- - -This is the summary of a very long blog post, - -Use a `` comment to limit blog post size in the list view. - - - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet diff --git a/website/blog/2021-08-01-mdx-blog-post.mdx b/website/blog/2021-08-01-mdx-blog-post.mdx deleted file mode 100644 index 0c4b4a4..0000000 --- a/website/blog/2021-08-01-mdx-blog-post.mdx +++ /dev/null @@ -1,24 +0,0 @@ ---- -slug: mdx-blog-post -title: MDX Blog Post -authors: [slorber] -tags: [docusaurus] ---- - -Blog posts support [Docusaurus Markdown features](https://docusaurus.io/docs/markdown-features), such as [MDX](https://mdxjs.com/). - -:::tip - -Use the power of React to create interactive blog posts. - -::: - -{/* truncate */} - -For example, use JSX to create an interactive button: - -```js - -``` - - diff --git a/website/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg b/website/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg deleted file mode 100644 index 11bda09..0000000 Binary files a/website/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg and /dev/null differ diff --git a/website/blog/2021-08-26-welcome/index.md b/website/blog/2021-08-26-welcome/index.md deleted file mode 100644 index 349ea07..0000000 --- a/website/blog/2021-08-26-welcome/index.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -slug: welcome -title: Welcome -authors: [slorber, yangshun] -tags: [facebook, hello, docusaurus] ---- - -[Docusaurus blogging features](https://docusaurus.io/docs/blog) are powered by the [blog plugin](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog). - -Here are a few tips you might find useful. - - - -Simply add Markdown files (or folders) to the `blog` directory. - -Regular blog authors can be added to `authors.yml`. - -The blog post date can be extracted from filenames, such as: - -- `2019-05-30-welcome.md` -- `2019-05-30-welcome/index.md` - -A blog post folder can be convenient to co-locate blog post images: - -![Docusaurus Plushie](./docusaurus-plushie-banner.jpeg) - -The blog supports tags as well! - -**And if you don't want a blog**: just delete this directory, and use `blog: false` in your Docusaurus config. diff --git a/website/blog/authors.yml b/website/blog/authors.yml deleted file mode 100644 index 0fd3987..0000000 --- a/website/blog/authors.yml +++ /dev/null @@ -1,25 +0,0 @@ -yangshun: - name: Yangshun Tay - title: Ex-Meta Staff Engineer, Co-founder GreatFrontEnd - url: https://linkedin.com/in/yangshun - image_url: https://github.com/yangshun.png - page: true - socials: - x: yangshunz - linkedin: yangshun - github: yangshun - newsletter: https://www.greatfrontend.com - -slorber: - name: Sébastien Lorber - title: Docusaurus maintainer - url: https://sebastienlorber.com - image_url: https://github.com/slorber.png - page: - # customize the url of the author page at /blog/authors/ - permalink: '/all-sebastien-lorber-articles' - socials: - x: sebastienlorber - linkedin: sebastienlorber - github: slorber - newsletter: https://thisweekinreact.com diff --git a/website/blog/tags.yml b/website/blog/tags.yml deleted file mode 100644 index bfaa778..0000000 --- a/website/blog/tags.yml +++ /dev/null @@ -1,19 +0,0 @@ -facebook: - label: Facebook - permalink: /facebook - description: Facebook tag description - -hello: - label: Hello - permalink: /hello - description: Hello tag description - -docusaurus: - label: Docusaurus - permalink: /docusaurus - description: Docusaurus tag description - -hola: - label: Hola - permalink: /hola - description: Hola tag description diff --git a/website/docs/additional-modules.md b/website/docs/additional-modules.md new file mode 100644 index 0000000..3fe46aa --- /dev/null +++ b/website/docs/additional-modules.md @@ -0,0 +1,14 @@ +--- +sidebar_position: 9 +--- + +# Additional Modules + +CherryPick provides a set of official add-on modules for advanced use cases and specific platforms: + +| Module name | Description | +|-------------|-------------| +| [**cherrypick_annotations**](https://pub.dev/packages/cherrypick_annotations) | Dart annotations for concise DI definitions and code generation. | +| [**cherrypick_generator**](https://pub.dev/packages/cherrypick_generator) | Code generator to produce DI bindings based on annotations. | +| [**cherrypick_flutter**](https://pub.dev/packages/cherrypick_flutter) | Flutter integration: DI provider widgets and helpers for Flutter. | +| [**talker_cherrypick_logger**](https://pub.dev/packages/talker_cherrypick_logger) | Advanced logger for CherryPick DI events and state. Provides seamless integration with [Talker](https://pub.dev/packages/talker) logger, enabling central and visual tracking of DI events, errors, and diagnostics in both UI and console. | diff --git a/website/docs/advanced-features/_category_.json b/website/docs/advanced-features/_category_.json new file mode 100644 index 0000000..340b0b1 --- /dev/null +++ b/website/docs/advanced-features/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Advanced Features", + "position": 6 + } \ No newline at end of file diff --git a/website/docs/advanced-features/circular-dependency-detection.md b/website/docs/advanced-features/circular-dependency-detection.md new file mode 100644 index 0000000..d50b32d --- /dev/null +++ b/website/docs/advanced-features/circular-dependency-detection.md @@ -0,0 +1,71 @@ +--- +sidebar_position: 3 +--- + +# Circular Dependency Detection + +CherryPick can detect circular dependencies in your DI configuration, helping you avoid infinite loops and hard-to-debug errors. + +## How to use: + +### 1. Enable Cycle Detection for Development + +**Local detection (within one scope):** +```dart +final scope = CherryPick.openSafeRootScope(); // Local detection enabled by default +// or, for an existing scope: +scope.enableCycleDetection(); +``` + +**Global detection (across all scopes):** +```dart +CherryPick.enableGlobalCrossScopeCycleDetection(); +final rootScope = CherryPick.openGlobalSafeRootScope(); +``` + +### 2. Error Example + +If you declare mutually dependent services: +```dart +class A { A(B b); } +class B { B(A a); } + +scope.installModules([ + Module((bind) { + bind().to((s) => A(s.resolve())); + bind().to((s) => B(s.resolve())); + }), +]); + +scope.resolve(); // Throws CircularDependencyException +``` + +### 3. Typical Usage Pattern + +- **Always enable detection** in debug and test environments for maximum safety. +- **Disable detection** in production for performance (after code is tested). + +```dart +import 'package:flutter/foundation.dart'; + +void main() { + if (kDebugMode) { + CherryPick.enableGlobalCycleDetection(); + CherryPick.enableGlobalCrossScopeCycleDetection(); + } + runApp(MyApp()); +} +``` + +### 4. Handling and Debugging Errors + +On detection, `CircularDependencyException` is thrown with a readable dependency chain: +```dart +try { + scope.resolve(); +} on CircularDependencyException catch (e) { + print('Dependency chain: ${e.dependencyChain}'); +} +``` + +**More details:** See [cycle_detection.en.md](doc/cycle_detection.en.md) diff --git a/website/docs/advanced-features/hierarchical-subscopes.md b/website/docs/advanced-features/hierarchical-subscopes.md new file mode 100644 index 0000000..862ac37 --- /dev/null +++ b/website/docs/advanced-features/hierarchical-subscopes.md @@ -0,0 +1,45 @@ +--- +sidebar_position: 1 +--- + +# Hierarchical Subscopes + +CherryPick supports a hierarchical structure of scopes, allowing you to create complex and modular dependency graphs for advanced application architectures. Each subscope inherits from its parent, enabling context-specific overrides while still allowing access to global or shared services. + +## Key Points + +- **Subscopes** are child scopes that can be opened from any existing scope (including the root). +- Dependencies registered in a subscope override those from parent scopes when resolved. +- If a dependency is not found in the current subscope, the resolution process automatically searches parent scopes up the hierarchy. +- Subscopes can have their own modules, lifetime, and disposable objects. +- You can nest subscopes to any depth, modeling features, flows, or components independently. + +## Example + +```dart +final rootScope = CherryPick.openRootScope(); +rootScope.installModules([AppModule()]); + +// Open a hierarchical subscope for a feature or page +final userFeatureScope = rootScope.openSubScope('userFeature'); +userFeatureScope.installModules([UserFeatureModule()]); + +// Dependencies defined in UserFeatureModule will take precedence +final userService = userFeatureScope.resolve(); + +// If not found in the subscope, lookup continues in the parent (rootScope) +final sharedService = userFeatureScope.resolve(); + +// You can nest subscopes +final dialogScope = userFeatureScope.openSubScope('dialog'); +dialogScope.installModules([DialogModule()]); +final dialogManager = dialogScope.resolve(); +``` + +## Use Cases + +- Isolate feature modules, flows, or screens with their own dependencies. +- Provide and override services for specific navigation stacks or platform-specific branches. +- Manage the lifetime and disposal of groups of dependencies independently (e.g., per-user, per-session, per-component). + +**Tip:** Always close subscopes when they are no longer needed to release resources and trigger cleanup of Disposable dependencies. diff --git a/website/docs/advanced-features/logging.md b/website/docs/advanced-features/logging.md new file mode 100644 index 0000000..30c6d79 --- /dev/null +++ b/website/docs/advanced-features/logging.md @@ -0,0 +1,62 @@ +--- +sidebar_position: 2 +--- + +# Logging + +CherryPick lets you log all dependency injection (DI) events and errors using a flexible observer mechanism. + +## Custom Observers +You can pass any implementation of `CherryPickObserver` to your root scope or any sub-scope. +This allows centralized and extensible logging, which you can direct to print, files, visualization frameworks, external loggers, or systems like [Talker](https://pub.dev/packages/talker). + +### Example: Printing All Events + +```dart +import 'package:cherrypick/cherrypick.dart'; + +void main() { + // Use the built-in PrintCherryPickObserver for console logs + final observer = PrintCherryPickObserver(); + final scope = CherryPick.openRootScope(observer: observer); + // All DI actions and errors will now be printed! +} +``` + +### Example: Advanced Logging with Talker + +For richer logging, analytics, or UI overlays, use an advanced observer such as [talker_cherrypick_logger](../talker_cherrypick_logger): + +```dart +import 'package:cherrypick/cherrypick.dart'; +import 'package:talker/talker.dart'; +import 'package:talker_cherrypick_logger/talker_cherrypick_logger.dart'; + +void main() { + final talker = Talker(); + final observer = TalkerCherryPickObserver(talker); + CherryPick.openRootScope(observer: observer); + // All container events go to the Talker log system! +} +``` + +## Default Behavior +- By default, logging is silent (`SilentCherryPickObserver`) for production, with no output unless you supply an observer. +- You can configure observers **per scope** for isolated, test-specific, or feature-specific logging. + +## Observer Capabilities +Events you can observe and log: +- Dependency registration +- Instance requests, creations, disposals +- Module installs/removals +- Scope opening/closing +- Cache hits/misses +- Cycle detection +- Diagnostics, warnings, errors + +Just implement or extend `CherryPickObserver` and direct messages anywhere you want! + +## When to Use +- Enable verbose logging and debugging in development or test builds. +- Route logs to your main log system or analytics. +- Hook into DI lifecycle for profiling or monitoring. \ No newline at end of file diff --git a/website/docs/advanced-features/performance-improvements.md b/website/docs/advanced-features/performance-improvements.md new file mode 100644 index 0000000..4d621fc --- /dev/null +++ b/website/docs/advanced-features/performance-improvements.md @@ -0,0 +1,10 @@ +--- +sidebar_position: 4 +--- + +# Performance Improvements + +> **Performance Note:** +> **Starting from version 3.0.0**, CherryPick uses a Map-based resolver index for dependency lookup. This means calls to `resolve()` and related methods are now O(1) operations, regardless of the number of modules or bindings in your scope. Previously, the library had to iterate over all modules and bindings to locate the requested dependency, which could impact performance as your project grew. +> +> This optimization is internal and does not change any library APIs or usage patterns, but it significantly improves resolution speed in larger applications. diff --git a/website/docs/contributing.md b/website/docs/contributing.md new file mode 100644 index 0000000..7c16874 --- /dev/null +++ b/website/docs/contributing.md @@ -0,0 +1,7 @@ +--- +sidebar_position: 10 +--- + +# Contributing + +Contributions are welcome! Please open issues or submit pull requests on [GitHub](https://github.com/pese-git/cherrypick). diff --git a/website/docs/core-concepts/_category_.json b/website/docs/core-concepts/_category_.json new file mode 100644 index 0000000..2561217 --- /dev/null +++ b/website/docs/core-concepts/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Core Concepts", + "position": 4 +} \ No newline at end of file diff --git a/website/docs/core-concepts/binding.md b/website/docs/core-concepts/binding.md new file mode 100644 index 0000000..a12727f --- /dev/null +++ b/website/docs/core-concepts/binding.md @@ -0,0 +1,41 @@ +--- +sidebar_position: 1 +--- + +# Binding + +A **Binding** acts as a configuration for how to create or provide a particular dependency. Bindings support: + +* Direct instance assignment (`toInstance()`, `toInstanceAsync()`) +* Lazy providers (sync/async functions) +* Provider functions supporting dynamic parameters +* Named instances for resolving by string key +* Optional singleton lifecycle + +## Example + +```dart +// Provide a direct instance +Binding().toInstance("Hello world"); + +// Provide an async direct instance +Binding().toInstanceAsync(Future.value("Hello world")); + +// Provide a lazy sync instance using a factory +Binding().toProvide(() => "Hello world"); + +// Provide a lazy async instance using a factory +Binding().toProvideAsync(() async => "Hello async world"); + +// Provide an instance with dynamic parameters (sync) +Binding().toProvideWithParams((params) => "Hello $params"); + +// Provide an instance with dynamic parameters (async) +Binding().toProvideAsyncWithParams((params) async => "Hello $params"); + +// Named instance for retrieval by name +Binding().toProvide(() => "Hello world").withName("my_string"); + +// Mark as singleton (only one instance within the scope) +Binding().toProvide(() => "Hello world").singleton(); +``` diff --git a/website/docs/core-concepts/disposable.md b/website/docs/core-concepts/disposable.md new file mode 100644 index 0000000..4a61a47 --- /dev/null +++ b/website/docs/core-concepts/disposable.md @@ -0,0 +1,52 @@ +--- +sidebar_position: 4 +--- + +# Disposable + +CherryPick can automatically clean up any dependency that implements the `Disposable` interface. This makes resource management (for controllers, streams, sockets, files, etc.) easy and reliable—especially when scopes or the app are shut down. + +If you bind an object implementing `Disposable` as a singleton or provide it via the DI container, CherryPick will call its `dispose()` method when the scope is closed or cleaned up. + +## Key Points +- Supports both synchronous and asynchronous cleanup (dispose may return `void` or `Future`). +- All `Disposable` instances from the current scope and subscopes will be disposed in the correct order. +- Prevents resource leaks and enforces robust cleanup. +- No manual wiring needed once your class implements `Disposable`. + +## Minimal Sync Example +```dart +class CacheManager implements Disposable { + void dispose() { + cache.clear(); + print('CacheManager disposed!'); + } +} + +final scope = CherryPick.openRootScope(); +scope.installModules([ + Module((bind) => bind().toProvide(() => CacheManager()).singleton()), +]); + +// ...later +await CherryPick.closeRootScope(); // prints: CacheManager disposed! +``` + +## Async Example +```dart +class MyServiceWithSocket implements Disposable { + @override + Future dispose() async { + await socket.close(); + print('Socket closed!'); + } +} + +scope.installModules([ + Module((bind) => bind().toProvide(() => MyServiceWithSocket()).singleton()), +]); + +await CherryPick.closeRootScope(); // awaits async disposal +``` + +**Tip:** Always call `await CherryPick.closeRootScope()` or `await scope.closeSubScope(key)` in your shutdown/teardown logic to ensure all resources are released automatically. diff --git a/website/docs/core-concepts/module.md b/website/docs/core-concepts/module.md new file mode 100644 index 0000000..026c80d --- /dev/null +++ b/website/docs/core-concepts/module.md @@ -0,0 +1,19 @@ +--- +sidebar_position: 2 +--- + +# Module + +A **Module** is a logical collection point for bindings, designed for grouping and initializing related dependencies. Implement the `builder` method to define how dependencies should be bound within the scope. + +## Example + +```dart +class AppModule extends Module { + @override + void builder(Scope currentScope) { + bind().toInstance(ApiClientMock()); + bind().toProvide(() => "Hello world!"); + } +} +``` diff --git a/website/docs/core-concepts/scope.md b/website/docs/core-concepts/scope.md new file mode 100644 index 0000000..1607352 --- /dev/null +++ b/website/docs/core-concepts/scope.md @@ -0,0 +1,31 @@ +--- +sidebar_position: 3 +--- + +# Scope + +A **Scope** manages a tree of modules and dependency instances. Scopes can be nested into hierarchies (parent-child), supporting modular app composition and context-specific overrides. + +You typically work with the root scope, but can also create named subscopes as needed. + +## Example + +```dart +// Open the main/root scope +final rootScope = CherryPick.openRootScope(); + +// Install a custom module +rootScope.installModules([AppModule()]); + +// Resolve a dependency synchronously +final str = rootScope.resolve(); + +// Resolve a dependency asynchronously +final result = await rootScope.resolveAsync(); + +// Recommended: Close the root scope and release all resources +await CherryPick.closeRootScope(); + +// Alternatively, you may manually call dispose on any scope you manage individually +// await rootScope.dispose(); +``` diff --git a/website/docs/dependency-resolution-api.md b/website/docs/dependency-resolution-api.md new file mode 100644 index 0000000..ba09404 --- /dev/null +++ b/website/docs/dependency-resolution-api.md @@ -0,0 +1,15 @@ +--- +sidebar_position: 4 +--- + +# Dependency Resolution API + +- `resolve()` — Locates a dependency instance or throws if missing. +- `resolveAsync()` — Async variant for dependencies requiring async binding. +- `tryResolve()` — Returns `null` if not found (sync). +- `tryResolveAsync()` — Returns `null` async if not found. + +Supports: +- Synchronous and asynchronous dependencies +- Named dependencies +- Provider functions with and without runtime parameters diff --git a/website/docs/documentation-links.md b/website/docs/documentation-links.md new file mode 100644 index 0000000..e03e719 --- /dev/null +++ b/website/docs/documentation-links.md @@ -0,0 +1,7 @@ +--- +sidebar_position: 8 +--- + +# Documentation Links + +* Circular Dependency Detection [(En)](doc/cycle_detection.en.md)[(Ru)](doc/cycle_detection.ru.md) diff --git a/website/docs/example-application.md b/website/docs/example-application.md new file mode 100644 index 0000000..e07bd1b --- /dev/null +++ b/website/docs/example-application.md @@ -0,0 +1,124 @@ +--- +sidebar_position: 6 +--- + +# Example Application + +Below is a complete example illustrating modules, subscopes, async providers, and dependency resolution. + +```dart +import 'dart:async'; +import 'package:meta/meta.dart'; +import 'package:cherrypick/cherrypick.dart'; + +class AppModule extends Module { + @override + void builder(Scope currentScope) { + bind().withName("apiClientMock").toInstance(ApiClientMock()); + bind().withName("apiClientImpl").toInstance(ApiClientImpl()); + } +} + +class FeatureModule extends Module { + final bool isMock; + FeatureModule({required this.isMock}); + @override + void builder(Scope currentScope) { + // Async provider for DataRepository with named dependency selection + bind() + .withName("networkRepo") + .toProvideAsync(() async { + final client = await Future.delayed( + Duration(milliseconds: 100), + () => currentScope.resolve( + named: isMock ? "apiClientMock" : "apiClientImpl", + ), + ); + return NetworkDataRepository(client); + }) + .singleton(); + + // Chained async provider for DataBloc + bind().toProvideAsync( + () async { + final repo = await currentScope.resolveAsync( + named: "networkRepo"); + return DataBloc(repo); + }, + ); + } +} + +void main() async { + final scope = CherryPick.openRootScope().installModules([AppModule()]); + final featureScope = scope.openSubScope("featureScope") + ..installModules([FeatureModule(isMock: true)]); + + final dataBloc = await featureScope.resolveAsync(); + dataBloc.data.listen( + (d) => print('Received data: $d'), + onError: (e) => print('Error: $e'), + onDone: () => print('DONE'), + ); + + await dataBloc.fetchData(); +} + +class DataBloc { + final DataRepository _dataRepository; + Stream get data => _dataController.stream; + final StreamController _dataController = StreamController.broadcast(); + + DataBloc(this._dataRepository); + + Future fetchData() async { + try { + _dataController.sink.add(await _dataRepository.getData()); + } catch (e) { + _dataController.sink.addError(e); + } + } + + void dispose() { + _dataController.close(); + } +} + +abstract class DataRepository { + Future getData(); +} + +class NetworkDataRepository implements DataRepository { + final ApiClient _apiClient; + final _token = 'token'; + NetworkDataRepository(this._apiClient); + + @override + Future getData() async => + await _apiClient.sendRequest( + url: 'www.google.com', + token: _token, + requestBody: {'type': 'data'}, + ); +} + +abstract class ApiClient { + Future sendRequest({@required String? url, String? token, Map? requestBody}); +} + +class ApiClientMock implements ApiClient { + @override + Future sendRequest( + {@required String? url, String? token, Map? requestBody}) async { + return 'Local Data'; + } +} + +class ApiClientImpl implements ApiClient { + @override + Future sendRequest( + {@required String? url, String? token, Map? requestBody}) async { + return 'Network data'; + } +} +``` diff --git a/website/docs/faq.md b/website/docs/faq.md new file mode 100644 index 0000000..509edb7 --- /dev/null +++ b/website/docs/faq.md @@ -0,0 +1,10 @@ +--- +sidebar_position: 7 +--- + +# FAQ + +### Q: Do I need to use `await` with CherryPick.closeRootScope(), CherryPick.closeScope(), or scope.dispose() if I have no Disposable services? + +**A:** +Yes! Even if none of your services currently implement `Disposable`, always use `await` when closing scopes. If you later add resource cleanup (by implementing `dispose()`), CherryPick will handle it automatically without you needing to change your scope cleanup code. This ensures resource management is future-proof, robust, and covers all application scenarios. diff --git a/website/docs/getting-started.md b/website/docs/getting-started.md new file mode 100644 index 0000000..842bc56 --- /dev/null +++ b/website/docs/getting-started.md @@ -0,0 +1,27 @@ +--- +sidebar_position: 3 +--- + +# Getting Started + +Here is a minimal example that registers and resolves a dependency: + +```dart +import 'package:cherrypick/cherrypick.dart'; + +class AppModule extends Module { + @override + void builder(Scope currentScope) { + bind().toInstance(ApiClientMock()); + bind().toProvide(() => "Hello, CherryPick!"); + } +} + +final rootScope = CherryPick.openRootScope(); +rootScope.installModules([AppModule()]); + +final greeting = rootScope.resolve(); +print(greeting); // prints: Hello, CherryPick! + +await CherryPick.closeRootScope(); +``` diff --git a/website/docs/installation.md b/website/docs/installation.md new file mode 100644 index 0000000..80320eb --- /dev/null +++ b/website/docs/installation.md @@ -0,0 +1,18 @@ +--- +sidebar_position: 2 +--- + +# Installation + +Add to your `pubspec.yaml`: + +```yaml +dependencies: + cherrypick: ^ +``` + +Then run: + +```shell +dart pub get +``` diff --git a/website/docs/intro.md b/website/docs/intro.md index 45e8604..a7144ec 100644 --- a/website/docs/intro.md +++ b/website/docs/intro.md @@ -2,46 +2,40 @@ sidebar_position: 1 --- -# Tutorial Intro +# CherryPick — Dependency Injection for Dart & Flutter -Let's discover **Docusaurus in less than 5 minutes**. +Welcome to the documentation for **CherryPick**, a lightweight and flexible dependency injection library for Dart and Flutter. -## Getting Started +--- -Get started by **creating a new site**. +## About CherryPick -Or **try Docusaurus immediately** with **[docusaurus.new](https://docusaurus.new)**. +CherryPick is a modular DI (Dependency Injection) toolkit designed for: +- Clean architecture +- Lightweight and intuitive API +- Powerful hierarchical scopes +- Fast synchronous & asynchronous injections +- Code generation and annotation-based configuration -### What you'll need +Whether you build backend or Flutter apps, CherryPick will help you maintain clear and testable project structure with minimal boilerplate. -- [Node.js](https://nodejs.org/en/download/) version 18.0 or above: - - When installing Node.js, you are recommended to check all checkboxes related to dependencies. +## Quick Links -## Generate a new site +- [Key Features](key-features.md) +- [Getting Started](getting-started.md) +- [Core Concepts](core-concepts/binding.md) +- [Advanced Features](advanced-features/hierarchical-subscopes.md) +- [Using Annotations](using-annotations.md) +- [FAQ](faq.md) +- [Example Application](example-application.md) +- [GitHub Repository](https://github.com/pese-git/cherrypick) -Generate a new Docusaurus site using the **classic template**. +## Installation -The classic template will automatically be added to your project after you run the command: +See [Installation](installation.md) for instructions on adding CherryPick to your Dart/Flutter project. -```bash -npm init docusaurus@latest my-website classic -``` +--- -You can type this command into Command Prompt, Powershell, Terminal, or any other integrated terminal of your code editor. +CherryPick is open-source. Contributions and questions are welcome! -The command also installs all necessary dependencies you need to run Docusaurus. - -## Start your site - -Run the development server: - -```bash -cd my-website -npm run start -``` - -The `cd` command changes the directory you're working with. In order to work with your newly created Docusaurus site, you'll need to navigate the terminal there. - -The `npm run start` command builds your website locally and serves it through a development server, ready for you to view at http://localhost:3000/. - -Open `docs/intro.md` (this page) and edit some lines: the site **reloads automatically** and displays your changes. +--- \ No newline at end of file diff --git a/website/docs/key-features.md b/website/docs/key-features.md new file mode 100644 index 0000000..e4eae74 --- /dev/null +++ b/website/docs/key-features.md @@ -0,0 +1,16 @@ +--- +sidebar_position: 1 +--- + +# Key Features + +- Main Scope and Named Subscopes +- Named Instance Binding and Resolution +- Asynchronous and Synchronous Providers +- Providers Supporting Runtime Parameters +- Singleton Lifecycle Management +- Modular and Hierarchical Composition +- Null-safe Resolution (tryResolve/tryResolveAsync) +- Circular Dependency Detection (Local and Global) +- Comprehensive logging of dependency injection state and actions +- Automatic resource cleanup for all registered Disposable dependencies diff --git a/website/docs/license.md b/website/docs/license.md new file mode 100644 index 0000000..2b44f78 --- /dev/null +++ b/website/docs/license.md @@ -0,0 +1,9 @@ +--- +sidebar_position: 11 +--- + +# License + +Licensed under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). + +**Important:** Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for specific language governing permissions and limitations under the License. diff --git a/website/docs/tutorial-basics/_category_.json b/website/docs/tutorial-basics/_category_.json deleted file mode 100644 index 2e6db55..0000000 --- a/website/docs/tutorial-basics/_category_.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "label": "Tutorial - Basics", - "position": 2, - "link": { - "type": "generated-index", - "description": "5 minutes to learn the most important Docusaurus concepts." - } -} diff --git a/website/docs/tutorial-basics/congratulations.md b/website/docs/tutorial-basics/congratulations.md deleted file mode 100644 index 04771a0..0000000 --- a/website/docs/tutorial-basics/congratulations.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -sidebar_position: 6 ---- - -# Congratulations! - -You have just learned the **basics of Docusaurus** and made some changes to the **initial template**. - -Docusaurus has **much more to offer**! - -Have **5 more minutes**? Take a look at **[versioning](../tutorial-extras/manage-docs-versions.md)** and **[i18n](../tutorial-extras/translate-your-site.md)**. - -Anything **unclear** or **buggy** in this tutorial? [Please report it!](https://github.com/facebook/docusaurus/discussions/4610) - -## What's next? - -- Read the [official documentation](https://docusaurus.io/) -- Modify your site configuration with [`docusaurus.config.js`](https://docusaurus.io/docs/api/docusaurus-config) -- Add navbar and footer items with [`themeConfig`](https://docusaurus.io/docs/api/themes/configuration) -- Add a custom [Design and Layout](https://docusaurus.io/docs/styling-layout) -- Add a [search bar](https://docusaurus.io/docs/search) -- Find inspirations in the [Docusaurus showcase](https://docusaurus.io/showcase) -- Get involved in the [Docusaurus Community](https://docusaurus.io/community/support) diff --git a/website/docs/tutorial-basics/create-a-blog-post.md b/website/docs/tutorial-basics/create-a-blog-post.md deleted file mode 100644 index 550ae17..0000000 --- a/website/docs/tutorial-basics/create-a-blog-post.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -sidebar_position: 3 ---- - -# Create a Blog Post - -Docusaurus creates a **page for each blog post**, but also a **blog index page**, a **tag system**, an **RSS** feed... - -## Create your first Post - -Create a file at `blog/2021-02-28-greetings.md`: - -```md title="blog/2021-02-28-greetings.md" ---- -slug: greetings -title: Greetings! -authors: - - name: Joel Marcey - title: Co-creator of Docusaurus 1 - url: https://github.com/JoelMarcey - image_url: https://github.com/JoelMarcey.png - - name: Sébastien Lorber - title: Docusaurus maintainer - url: https://sebastienlorber.com - image_url: https://github.com/slorber.png -tags: [greetings] ---- - -Congratulations, you have made your first post! - -Feel free to play around and edit this post as much as you like. -``` - -A new blog post is now available at [http://localhost:3000/blog/greetings](http://localhost:3000/blog/greetings). diff --git a/website/docs/tutorial-basics/create-a-document.md b/website/docs/tutorial-basics/create-a-document.md deleted file mode 100644 index c22fe29..0000000 --- a/website/docs/tutorial-basics/create-a-document.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -sidebar_position: 2 ---- - -# Create a Document - -Documents are **groups of pages** connected through: - -- a **sidebar** -- **previous/next navigation** -- **versioning** - -## Create your first Doc - -Create a Markdown file at `docs/hello.md`: - -```md title="docs/hello.md" -# Hello - -This is my **first Docusaurus document**! -``` - -A new document is now available at [http://localhost:3000/docs/hello](http://localhost:3000/docs/hello). - -## Configure the Sidebar - -Docusaurus automatically **creates a sidebar** from the `docs` folder. - -Add metadata to customize the sidebar label and position: - -```md title="docs/hello.md" {1-4} ---- -sidebar_label: 'Hi!' -sidebar_position: 3 ---- - -# Hello - -This is my **first Docusaurus document**! -``` - -It is also possible to create your sidebar explicitly in `sidebars.js`: - -```js title="sidebars.js" -export default { - tutorialSidebar: [ - 'intro', - // highlight-next-line - 'hello', - { - type: 'category', - label: 'Tutorial', - items: ['tutorial-basics/create-a-document'], - }, - ], -}; -``` diff --git a/website/docs/tutorial-basics/create-a-page.md b/website/docs/tutorial-basics/create-a-page.md deleted file mode 100644 index 20e2ac3..0000000 --- a/website/docs/tutorial-basics/create-a-page.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -sidebar_position: 1 ---- - -# Create a Page - -Add **Markdown or React** files to `src/pages` to create a **standalone page**: - -- `src/pages/index.js` → `localhost:3000/` -- `src/pages/foo.md` → `localhost:3000/foo` -- `src/pages/foo/bar.js` → `localhost:3000/foo/bar` - -## Create your first React Page - -Create a file at `src/pages/my-react-page.js`: - -```jsx title="src/pages/my-react-page.js" -import React from 'react'; -import Layout from '@theme/Layout'; - -export default function MyReactPage() { - return ( - -

My React page

-

This is a React page

-
- ); -} -``` - -A new page is now available at [http://localhost:3000/my-react-page](http://localhost:3000/my-react-page). - -## Create your first Markdown Page - -Create a file at `src/pages/my-markdown-page.md`: - -```mdx title="src/pages/my-markdown-page.md" -# My Markdown page - -This is a Markdown page -``` - -A new page is now available at [http://localhost:3000/my-markdown-page](http://localhost:3000/my-markdown-page). diff --git a/website/docs/tutorial-basics/deploy-your-site.md b/website/docs/tutorial-basics/deploy-your-site.md deleted file mode 100644 index 1c50ee0..0000000 --- a/website/docs/tutorial-basics/deploy-your-site.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -sidebar_position: 5 ---- - -# Deploy your site - -Docusaurus is a **static-site-generator** (also called **[Jamstack](https://jamstack.org/)**). - -It builds your site as simple **static HTML, JavaScript and CSS files**. - -## Build your site - -Build your site **for production**: - -```bash -npm run build -``` - -The static files are generated in the `build` folder. - -## Deploy your site - -Test your production build locally: - -```bash -npm run serve -``` - -The `build` folder is now served at [http://localhost:3000/](http://localhost:3000/). - -You can now deploy the `build` folder **almost anywhere** easily, **for free** or very small cost (read the **[Deployment Guide](https://docusaurus.io/docs/deployment)**). diff --git a/website/docs/tutorial-basics/markdown-features.mdx b/website/docs/tutorial-basics/markdown-features.mdx deleted file mode 100644 index 35e0082..0000000 --- a/website/docs/tutorial-basics/markdown-features.mdx +++ /dev/null @@ -1,152 +0,0 @@ ---- -sidebar_position: 4 ---- - -# Markdown Features - -Docusaurus supports **[Markdown](https://daringfireball.net/projects/markdown/syntax)** and a few **additional features**. - -## Front Matter - -Markdown documents have metadata at the top called [Front Matter](https://jekyllrb.com/docs/front-matter/): - -```text title="my-doc.md" -// highlight-start ---- -id: my-doc-id -title: My document title -description: My document description -slug: /my-custom-url ---- -// highlight-end - -## Markdown heading - -Markdown text with [links](./hello.md) -``` - -## Links - -Regular Markdown links are supported, using url paths or relative file paths. - -```md -Let's see how to [Create a page](/create-a-page). -``` - -```md -Let's see how to [Create a page](./create-a-page.md). -``` - -**Result:** Let's see how to [Create a page](./create-a-page.md). - -## Images - -Regular Markdown images are supported. - -You can use absolute paths to reference images in the static directory (`static/img/docusaurus.png`): - -```md -![Docusaurus logo](/img/docusaurus.png) -``` - -![Docusaurus logo](/img/docusaurus.png) - -You can reference images relative to the current file as well. This is particularly useful to colocate images close to the Markdown files using them: - -```md -![Docusaurus logo](./img/docusaurus.png) -``` - -## Code Blocks - -Markdown code blocks are supported with Syntax highlighting. - -````md -```jsx title="src/components/HelloDocusaurus.js" -function HelloDocusaurus() { - return

Hello, Docusaurus!

; -} -``` -```` - -```jsx title="src/components/HelloDocusaurus.js" -function HelloDocusaurus() { - return

Hello, Docusaurus!

; -} -``` - -## Admonitions - -Docusaurus has a special syntax to create admonitions and callouts: - -```md -:::tip My tip - -Use this awesome feature option - -::: - -:::danger Take care - -This action is dangerous - -::: -``` - -:::tip My tip - -Use this awesome feature option - -::: - -:::danger Take care - -This action is dangerous - -::: - -## MDX and React Components - -[MDX](https://mdxjs.com/) can make your documentation more **interactive** and allows using any **React components inside Markdown**: - -```jsx -export const Highlight = ({children, color}) => ( - { - alert(`You clicked the color ${color} with label ${children}`) - }}> - {children} - -); - -This is Docusaurus green ! - -This is Facebook blue ! -``` - -export const Highlight = ({children, color}) => ( - { - alert(`You clicked the color ${color} with label ${children}`); - }}> - {children} - -); - -This is Docusaurus green ! - -This is Facebook blue ! diff --git a/website/docs/tutorial-extras/_category_.json b/website/docs/tutorial-extras/_category_.json deleted file mode 100644 index a8ffcc1..0000000 --- a/website/docs/tutorial-extras/_category_.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "label": "Tutorial - Extras", - "position": 3, - "link": { - "type": "generated-index" - } -} diff --git a/website/docs/tutorial-extras/img/docsVersionDropdown.png b/website/docs/tutorial-extras/img/docsVersionDropdown.png deleted file mode 100644 index 97e4164..0000000 Binary files a/website/docs/tutorial-extras/img/docsVersionDropdown.png and /dev/null differ diff --git a/website/docs/tutorial-extras/img/localeDropdown.png b/website/docs/tutorial-extras/img/localeDropdown.png deleted file mode 100644 index e257edc..0000000 Binary files a/website/docs/tutorial-extras/img/localeDropdown.png and /dev/null differ diff --git a/website/docs/tutorial-extras/manage-docs-versions.md b/website/docs/tutorial-extras/manage-docs-versions.md deleted file mode 100644 index ccda0b9..0000000 --- a/website/docs/tutorial-extras/manage-docs-versions.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -sidebar_position: 1 ---- - -# Manage Docs Versions - -Docusaurus can manage multiple versions of your docs. - -## Create a docs version - -Release a version 1.0 of your project: - -```bash -npm run docusaurus docs:version 1.0 -``` - -The `docs` folder is copied into `versioned_docs/version-1.0` and `versions.json` is created. - -Your docs now have 2 versions: - -- `1.0` at `http://localhost:3000/docs/` for the version 1.0 docs -- `current` at `http://localhost:3000/docs/next/` for the **upcoming, unreleased docs** - -## Add a Version Dropdown - -To navigate seamlessly across versions, add a version dropdown. - -Modify the `docusaurus.config.js` file: - -```js title="docusaurus.config.js" -export default { - themeConfig: { - navbar: { - items: [ - // highlight-start - { - type: 'docsVersionDropdown', - }, - // highlight-end - ], - }, - }, -}; -``` - -The docs version dropdown appears in your navbar: - -![Docs Version Dropdown](./img/docsVersionDropdown.png) - -## Update an existing version - -It is possible to edit versioned docs in their respective folder: - -- `versioned_docs/version-1.0/hello.md` updates `http://localhost:3000/docs/hello` -- `docs/hello.md` updates `http://localhost:3000/docs/next/hello` diff --git a/website/docs/tutorial-extras/translate-your-site.md b/website/docs/tutorial-extras/translate-your-site.md deleted file mode 100644 index b5a644a..0000000 --- a/website/docs/tutorial-extras/translate-your-site.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -sidebar_position: 2 ---- - -# Translate your site - -Let's translate `docs/intro.md` to French. - -## Configure i18n - -Modify `docusaurus.config.js` to add support for the `fr` locale: - -```js title="docusaurus.config.js" -export default { - i18n: { - defaultLocale: 'en', - locales: ['en', 'fr'], - }, -}; -``` - -## Translate a doc - -Copy the `docs/intro.md` file to the `i18n/fr` folder: - -```bash -mkdir -p i18n/fr/docusaurus-plugin-content-docs/current/ - -cp docs/intro.md i18n/fr/docusaurus-plugin-content-docs/current/intro.md -``` - -Translate `i18n/fr/docusaurus-plugin-content-docs/current/intro.md` in French. - -## Start your localized site - -Start your site on the French locale: - -```bash -npm run start -- --locale fr -``` - -Your localized site is accessible at [http://localhost:3000/fr/](http://localhost:3000/fr/) and the `Getting Started` page is translated. - -:::caution - -In development, you can only use one locale at a time. - -::: - -## Add a Locale Dropdown - -To navigate seamlessly across languages, add a locale dropdown. - -Modify the `docusaurus.config.js` file: - -```js title="docusaurus.config.js" -export default { - themeConfig: { - navbar: { - items: [ - // highlight-start - { - type: 'localeDropdown', - }, - // highlight-end - ], - }, - }, -}; -``` - -The locale dropdown now appears in your navbar: - -![Locale Dropdown](./img/localeDropdown.png) - -## Build your localized site - -Build your site for a specific locale: - -```bash -npm run build -- --locale fr -``` - -Or build your site to include all the locales at once: - -```bash -npm run build -``` diff --git a/website/docs/using-annotations.md b/website/docs/using-annotations.md new file mode 100644 index 0000000..46039b1 --- /dev/null +++ b/website/docs/using-annotations.md @@ -0,0 +1,131 @@ +--- +sidebar_position: 5 +--- + +# Using Annotations & Code Generation + +CherryPick provides best-in-class developer ergonomics and type safety through **Dart annotations** and code generation. This lets you dramatically reduce boilerplate: simply annotate your classes, fields, and modules, run the code generator, and enjoy auto-wired dependency injection! + +## How It Works + +1. **Annotate** your services, providers, and fields using `cherrypick_annotations`. +2. **Generate** code using `cherrypick_generator` with `build_runner`. +3. **Use** generated modules and mixins for fully automated DI (dependency injection). + +--- + +## Supported Annotations + +| Annotation | Target | Description | +|-------------------|---------------|--------------------------------------------------------------------------------| +| `@injectable()` | class | Enables automatic field injection for this class (mixin will be generated) | +| `@inject()` | field | Field will be injected using DI (works with @injectable classes) | +| `@module()` | class | Declares a DI module; its methods can provide services/providers | +| `@provide` | method | Registers as a DI provider method (may have dependencies as parameters) | +| `@instance` | method/class | Registers an instance (new object on each resolution, i.e. factory) | +| `@singleton` | method/class | Registers as a singleton (one instance per scope) | +| `@named` | field/param | Use named instance (bind/resolve by name or apply to field/param) | +| `@scope` | field/param | Inject or resolve from a specific named scope | +| `@params` | param | Marks method parameter as filled by user-supplied runtime params at resolution | + +You can easily **combine** these annotations for advanced scenarios! + +--- + +## Field Injection Example + +```dart +import 'package:cherrypick_annotations/cherrypick_annotations.dart'; + +@injectable() +class ProfilePage with _\$ProfilePage { + @inject() + late final AuthService auth; + + @inject() + @scope('profile') + late final ProfileManager manager; + + @inject() + @named('admin') + late final UserService adminUserService; +} +``` + +- After running build_runner, the mixin `_ProfilePage` will be generated for field injection. +- Call `myProfilePage.injectFields();` or use the mixin's auto-inject feature, and all dependencies will be set up for you. + +## Module and Provider Example + +```dart +@module() +abstract class AppModule { + @singleton + AuthService provideAuth(Api api) => AuthService(api); + + @named('logging') + @provide + Future provideLogger(@params Map args) async => ...; +} +``` + +- Mark class as `@module`, write provider methods. +- Use `@singleton`, `@named`, `@provide`, `@params` to control lifecycle, key names, and parameters. +- The generator will produce a class like `$AppModule` with the proper DI bindings. + +## Usage Steps + +1. **Add to your pubspec.yaml**: + + ```yaml + dependencies: + cherrypick: any + cherrypick_annotations: any + + dev_dependencies: + cherrypick_generator: any + build_runner: any + ``` + +2. **Annotate** your classes and modules as above. + +3. **Run code generation:** + + ```shell + dart run build_runner build --delete-conflicting-outputs + # or in Flutter: + flutter pub run build_runner build --delete-conflicting-outputs + ``` + +4. **Register modules and use auto-injection:** + + ```dart + final scope = CherryPick.openRootScope() + ..installModules([\$AppModule()]); + + final profile = ProfilePage(); + profile.injectFields(); // injects all @inject fields + ``` + +## Advanced: Parameters, Named Instances, and Scopes + +- Use `@named` for key-based multi-implementation injection. +- Use `@scope` when dependencies live in a non-root scope. +- Use `@params` for runtime arguments passed during resolution. + +--- + +## Troubleshooting & Tips + +- After modifying DI-related code, always re-run `build_runner`. +- Do not manually edit `.g.dart` files—let the generator manage them. +- Errors in annotation usage (e.g., using `@singleton` on wrong target) are shown at build time. + +--- + +## References + +- [Full annotation reference (en)](doc/annotations_en.md) +- [cherrypick_annotations/README.md](../cherrypick_annotations/README.md) +- [cherrypick_generator/README.md](../cherrypick_generator/README.md) +- See the [`examples/postly`](../examples/postly) for a full working DI+annotations app. diff --git a/website/docusaurus.config.ts b/website/docusaurus.config.ts index 95cb36c..a2a79c0 100644 --- a/website/docusaurus.config.ts +++ b/website/docusaurus.config.ts @@ -5,8 +5,8 @@ import type * as Preset from '@docusaurus/preset-classic'; // This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) const config: Config = { - title: 'My Site', - tagline: 'Dinosaurs are cool', + title: 'CherryPick', + tagline: 'CherryPick are cool', favicon: 'img/favicon.ico', // Future flags, see https://docusaurus.io/docs/api/docusaurus-config#future @@ -22,8 +22,8 @@ const config: Config = { // GitHub pages deployment config. // If you aren't using GitHub pages, you don't need these. - organizationName: 'facebook', // Usually your GitHub org/user name. - projectName: 'docusaurus', // Usually your repo name. + organizationName: 'CherryPick', // Usually your GitHub org/user name. + projectName: 'CherryPick', // Usually your repo name. onBrokenLinks: 'throw', onBrokenMarkdownLinks: 'warn', @@ -33,7 +33,11 @@ const config: Config = { // may want to replace "en" with "zh-Hans". i18n: { defaultLocale: 'en', - locales: ['en'], + locales: ['en', 'ru'], + localeConfigs: { + en: { label: 'English' }, + ru: { label: 'Русский' } + } }, presets: [ @@ -73,21 +77,20 @@ const config: Config = { // Replace with your project's social card image: 'img/docusaurus-social-card.jpg', navbar: { - title: 'My Site', + title: 'CherryPick', logo: { - alt: 'My Site Logo', + alt: 'CherryPick Logo', src: 'img/logo.svg', }, items: [ { type: 'docSidebar', sidebarId: 'tutorialSidebar', - position: 'left', - label: 'Tutorial', + position: 'right', + label: 'Docs', }, - {to: '/blog', label: 'Blog', position: 'left'}, { - href: 'https://github.com/facebook/docusaurus', + href: 'https://github.com/pese-git/cherrypick', label: 'GitHub', position: 'right', }, @@ -100,7 +103,7 @@ const config: Config = { title: 'Docs', items: [ { - label: 'Tutorial', + label: 'Docs', to: '/docs/intro', }, ], @@ -126,17 +129,17 @@ const config: Config = { title: 'More', items: [ { - label: 'Blog', - to: '/blog', + label: 'PubDev', + href: 'https://pub.dev/packages/cherrypick', }, { label: 'GitHub', - href: 'https://github.com/facebook/docusaurus', + href: 'https://github.com/pese-git/cherrypick', }, ], }, ], - copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`, + copyright: `Copyright © ${new Date().getFullYear()} CherryPick, Inc. Built with Docusaurus.`, }, prism: { theme: prismThemes.github, diff --git a/website/src/components/HomepageFeatures/index.tsx b/website/src/components/HomepageFeatures/index.tsx index c2551fb..b202c32 100644 --- a/website/src/components/HomepageFeatures/index.tsx +++ b/website/src/components/HomepageFeatures/index.tsx @@ -11,32 +11,29 @@ type FeatureItem = { const FeatureList: FeatureItem[] = [ { - title: 'Easy to Use', + title: 'Modular & Hierarchical', Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, description: ( <> - Docusaurus was designed from the ground up to be easily installed and - used to get your website up and running quickly. + CherryPick supports modular DI bindings and true hierarchical scopes. Build scalable apps by composing advanced dependency trees with clean separation of concerns. ), }, { - title: 'Focus on What Matters', + title: 'Sync & Async DI, Zero Boilerplate', Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default, description: ( <> - Docusaurus lets you focus on your docs, and we'll do the chores. Go - ahead and move your docs into the docs directory. + Register synchronous or asynchronous providers, named and singleton dependencies, and enjoy null-safe, testable resolution. Annotation-based code generation removes all manual “wiring”. ), }, { - title: 'Powered by React', + title: 'For Dart & Flutter', Svg: require('@site/static/img/undraw_docusaurus_react.svg').default, description: ( <> - Extend or customize your website layout by reusing React. Docusaurus can - be extended while reusing the same header and footer. + Use CherryPick in backend, CLI, server or Flutter widget trees equally well. Deep Flutter integration for provider injection, async scope lifecycles, and easy testing. ), }, diff --git a/website/src/pages/index.tsx b/website/src/pages/index.tsx index 2e006d1..1eb1224 100644 --- a/website/src/pages/index.tsx +++ b/website/src/pages/index.tsx @@ -21,7 +21,7 @@ function HomepageHeader() { - Docusaurus Tutorial - 5min ⏱️ + Explore CherryPick Documentation 🍒 @@ -33,8 +33,8 @@ export default function Home(): ReactNode { const {siteConfig} = useDocusaurusContext(); return ( + title={siteConfig.title} + description="CherryPick: Modular and lightweight dependency injection for Dart & Flutter. Fast, powerful, easy to integrate.">