### Minimal Inject.dart DI Component Setup Source: https://github.com/ralph-bergmann/inject.dart/blob/master/packages/inject_annotation/skills/inject_annotation-setup-di/SKILL.md This snippet demonstrates a full, minimal example of setting up dependency injection using inject.dart. It includes an injectable class, a component definition, and the main function to create and use the component. ```dart // lib/main.dart import 'package:inject_annotation/inject_annotation.dart'; import 'main.inject.dart' as g; @inject class Greeter { const Greeter(); String greet(String name) => 'Hello, $name!'; } @component abstract class AppComponent { static const create = g.AppComponent$Component.create; @inject Greeter get greeter; } void main() { final component = AppComponent.create(); print(component.greeter.greet('Dart')); // Hello, Dart! } ``` -------------------------------- ### Running inject.dart Example Source: https://github.com/ralph-bergmann/inject.dart/blob/master/examples/example/README.md Commands to set up and run the inject.dart example. Ensure dependencies are fetched, the build runner is executed to generate necessary files, and then the Flutter application is run. ```shell dart pub get dart run build_runner build flutter run ``` -------------------------------- ### Install Agent Skills with Dart Tool Source: https://github.com/ralph-bergmann/inject.dart/blob/master/README.md Installs agent skills using the Dart tool, activating it globally and then getting available skills. ```shell # Dart tool (https://pub.dev/packages/skills) — discovers skills from your # dependency tree and configured GitHub registries, into your IDE's skills dir dart pub global activate skills skills get ``` -------------------------------- ### Install Agent Skills with Node Tool Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/book/chapter_7_ai_assisted_development.html Installs Agent Skills directly from the GitHub repository using the Node.js tool. Use the '--skill *' flag to install all skills and '--agent universal' for broad compatibility. ```bash npx skills add https://github.com/ralph-bergmann/inject.dart/tree/master/packages/inject_annotation/skills --skill "*" --agent universal ``` -------------------------------- ### Example Dependency Graph Output Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/src/chapter_4_core_concepts.md An example of the formatted dependency-graph tree printed per component during the build when debug_graph is enabled. ```text [inject_generator] Dependency graph for MainComponent: MainComponent ├── CounterRepository (@singleton) │ └── Database (@singleton) │ ├── String (@databaseName) │ └── String (@databasePath) ├── CreationLogListener (@singleton) ├── MyAppFactory │ └── HomePageFactory │ └── ViewModelFactory │ └── CounterViewModel │ ├── Future (@singleton) │ └── IncrementCounterUseCase (@singleton) │ └── CounterRepository (@singleton) │ └── Database (@singleton) │ ├── String (@databaseName) │ └── String (@databasePath) └── String (@welcome, @singleton, @async) └── AppInfo (@singleton, @async) ``` -------------------------------- ### Install Agent Skills with Dart Tool Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/book/chapter_7_ai_assisted_development.html Installs Agent Skills using the Dart tool. First, activate the 'skills' package globally, then run 'skills get' to discover and install skills from your dependency tree and configured GitHub registries into your IDE's skills directory. ```bash dart pub global activate skills skills get ``` -------------------------------- ### Install Agent Skills with Node Tool Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/src/chapter_7_ai_assisted_development.md Installs all Agent Skills directly from the GitHub repository using the Node.js tool. ```shell npx skills add https://github.com/ralph-bergmann/inject.dart/tree/master/packages/inject_annotation/skills --skill '*' --agent universal ``` -------------------------------- ### Code Generation Example: NetworkModule Source: https://github.com/ralph-bergmann/inject.dart/blob/master/packages/inject_annotation/README.md This example shows how an @module class with @provides methods is wired into the component's constructor. ```dart @module class NetworkModule { @provides ... } ``` -------------------------------- ### Install Agent Skills with Node Tool Source: https://github.com/ralph-bergmann/inject.dart/blob/master/README.md Installs all agent skills from the inject.dart GitHub repository using the Node.js tool. ```shell # Node tool — installs straight from the GitHub repo npx skills add https://github.com/ralph-bergmann/inject.dart/tree/master/packages/inject_annotation/skills --skill '*' --agent universal ``` -------------------------------- ### Writing Unit Tests with Test Component Source: https://github.com/ralph-bergmann/inject.dart/blob/master/rules/rules.md Demonstrates a typical test case using the TestComponent to inject dependencies and test repository functionality. It includes setup using `setUp` and assertions. ```dart void main() { late TestComponent component; setUp(() { component = TestComponent.create(); }); test('UserRepository saves and loads users', () async { final repo = component.userRepository; final user = User(id: '1', name: 'Alice'); await repo.save(user); final loaded = await repo.load('1'); expect(loaded?.name, equals('Alice')); }); } ``` -------------------------------- ### Environment Swap Example Source: https://github.com/ralph-bergmann/inject.dart/blob/master/README.md Illustrates how to declare separate components for different environments (e.g., production, staging) that share a common base module. The correct component is wired up at the build entry point. ```dart @Component([BaseModule, ProdModule]) abstract class ProdComponent { static const create = g.ProdComponent$Component.create; // ... } @Component([BaseModule, StagingModule]) abstract class StagingComponent { static const create = g.StagingComponent$Component.create; // ... } ``` -------------------------------- ### Constructor Injection Example Source: https://github.com/ralph-bergmann/inject.dart/blob/master/rules/rules.md Demonstrates correct constructor injection for dependencies in Dart. Avoids service locator patterns. ```dart // ✅ CORRECT — constructor injection class OrderService { @inject const OrderService(this._repository, this._logger); final OrderRepository _repository; final Logger _logger; } // ❌ WRONG — service locator (not inject.dart pattern) class OrderService { final _repository = GetIt.I(); } ``` -------------------------------- ### Module Organization with Providers Source: https://github.com/ralph-bergmann/inject.dart/blob/master/rules/rules.md Illustrates how to organize providers into modules for better code structure. Examples include a NetworkModule for Dio and a DatabaseModule for an asynchronous Database. ```dart @module class NetworkModule { @provides @singleton Dio provideDio() => Dio(BaseOptions(baseUrl: 'https://api.example.com')); } @module class DatabaseModule { @provides @singleton @asynchronous Future provideDatabase() => openDatabase('app.db'); } @Component([NetworkModule, DatabaseModule]) abstract class AppComponent { static const create = g.AppComponent$Component.create; @inject AppService get appService; } ``` -------------------------------- ### Module Override Example: Environment Swap Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/src/chapter_4_core_concepts.md Illustrates how to use separate components that share a base module to manage environment-specific configurations. This pattern is useful for swapping between production and staging environments. ```dart @Component([BaseModule, ProdModule]) abstract class ProdComponent { ... } ``` ```dart @Component([BaseModule, StagingModule]) abstract class StagingComponent { ... } ``` -------------------------------- ### File Setup for @assistedInject Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/src/chapter_4_core_concepts.md Files containing @assistedInject constructors require a 'part' directive to allow the factory builder to write into them. ```dart part 'home_page.factory.dart'; ``` -------------------------------- ### Enable Playground Copy Functionality Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/book/404.html Enables the copy-to-clipboard functionality for code examples within the playground. ```javascript window.playground_copyable = true; ``` -------------------------------- ### Code Generation Example: UserService Source: https://github.com/ralph-bergmann/inject.dart/blob/master/packages/inject_annotation/README.md This example shows how an @inject class is transformed into a provider within the generated component file. ```dart @inject class UserService { ... } ``` -------------------------------- ### Inject.dart Dependency Graph Example Source: https://github.com/ralph-bergmann/inject.dart/blob/master/examples/flutter_demo/README.md This is a verbatim capture of the dependency graph from build_runner output for a MainComponent. It illustrates singleton instances, async propagation, and repeated subtrees. ```text [inject_generator] Dependency graph for MainComponent: MainComponent ├── CounterRepository (@singleton) │ └── Database (@singleton) │ ├── String (@databaseName) │ └── String (@databasePath) │ │ ├── CreationLogListener (@singleton) ├── MyAppFactory │ └── HomePageFactory │ └── ViewModelFactory │ └── CounterViewModel │ ├── Future (@singleton) │ └── IncrementCounterUseCase │ └── CounterRepository (@singleton) │ └── Database (@singleton) │ ├── String (@databaseName) │ └── String (@databasePath) │ │ └── String (@welcome, @singleton, @async) └── AppInfo (@singleton, @async) ``` -------------------------------- ### Service Locator Call Example Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/book/index.html Demonstrates how to retrieve an instance of a registered service using the service locator pattern. This is a common pattern for accessing dependencies in application code. ```dart GetIt.I() ``` -------------------------------- ### Add inject.dart to Flutter Project Source: https://github.com/ralph-bergmann/inject.dart/blob/master/README.md Install the necessary packages for Flutter projects using the Flutter CLI. ```shell flutter pub add inject_flutter inject_annotation dev:inject_generator dev:build_runner ``` -------------------------------- ### Inject Generator Builder Configuration Source: https://github.com/ralph-bergmann/inject.dart/blob/master/README.md Configures the inject_generator via build.yaml. This example sets the nullable_duplicate_binding_policy to 'error'. ```yaml targets: $default: builders: inject_generator|inject_builder: options: nullable_duplicate_binding_policy: error # error (default) | warn | allow ``` -------------------------------- ### Module Override Example Source: https://github.com/ralph-bergmann/inject.dart/blob/master/README.md Demonstrates how later modules override earlier ones when providing the same type and qualifier. This behavior is consistent with Dagger 2 and Hilt. ```dart @Component([ModuleA, ModuleB]) // ModuleB overrides ModuleA for shared keys ``` -------------------------------- ### Test Case for UserRepository Source: https://github.com/ralph-bergmann/inject.dart/blob/master/packages/inject_annotation/skills/inject_annotation-write-tests/SKILL.md A basic test case demonstrating how to use the TestComponent to test UserRepository functionality. It creates a fresh component in setUp and asserts save/load operations. ```dart void main() { late TestComponent component; setUp(() => component = TestComponent.create()); test('UserRepository saves and loads users', () async { final repo = component.userRepository; await repo.save(User(id: '1', name: 'Alice')); final loaded = await repo.load('1'); expect(loaded?.name, equals('Alice')); }); } ``` -------------------------------- ### Build and Analyze Project Source: https://github.com/ralph-bergmann/inject.dart/blob/master/packages/inject_annotation/skills/inject_annotation-add-assisted-injection/SKILL.md Run the build runner to generate the factory implementation and then analyze the code for errors. ```bash dart run build_runner build --delete-conflicting-outputs dart analyze ``` -------------------------------- ### Main Application Entry Point Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/book/chapter_5_state_management.html The main function creates the root component, asynchronously retrieves a welcome message, and then runs the application using the injected app factory. ```dart void main() async { final component = MainComponent.create(); debugPrint(await component.welcomeMessage); runApp(component.myAppFactory.create()); } ``` -------------------------------- ### Component Entry Point with Provider Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/book/chapter_4_core_concepts.html Demonstrates using Provider as a component entry point to defer creation until first use. The provider reference can be passed to non-DI code, and it supports multiple independent instances for non-@singleton bindings. ```dart @Component([AppModule, DatabaseModule]) abstract class MainComponent { @inject Provider get counterRepositoryProvider; } // In app code: final repo = component.counterRepositoryProvider.get(); ``` -------------------------------- ### Initialize Theme and Sidebar Settings Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/book/404.html This script attempts to retrieve and clean theme and sidebar settings from local storage. It handles potential errors during storage access and sets default themes based on system preferences. ```javascript try { let theme = localStorage.getItem('mdbook-theme'); let sidebar = localStorage.getItem('mdbook-sidebar'); if (theme.startsWith('"') && theme.endsWith('"')) { localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1)); } if (sidebar.startsWith('"') && sidebar.endsWith('"')) { localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1)); } } catch (e) { } ``` -------------------------------- ### Add inject_flutter Dependency Source: https://github.com/ralph-bergmann/inject.dart/blob/master/packages/inject_annotation/skills/inject_annotation-flutter-view-model/SKILL.md Install the inject_flutter package to enable integration between inject.dart and Flutter for view model management. ```bash flutter pub add inject_flutter ``` -------------------------------- ### Main Application Entry Point Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/src/chapter_3_quickstart.md The main function that sets up the dependency injection component and runs the Flutter application. It creates the component and uses the injected factory to create the root widget. ```dart void main() { final component = MainComponent.create(); runApp(component.myAppFactory.create()); } ``` -------------------------------- ### Add inject.dart to Flutter Project Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/src/chapter_3_quickstart.md Installs the necessary inject.dart packages for a Flutter project. Ensure you are in the project's root directory. ```bash flutter create counter_app cd counter_app flutter pub add inject_annotation inject_flutter dev:inject_generator dev:build_runner ``` -------------------------------- ### Provide Third-Party Type with Module Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/src/chapter_3_quickstart.md Demonstrates how to provide a third-party type (Database) and configuration values using a module. Uses @provides for factory methods and @singleton for a shared instance. ```dart import 'package:inject_annotation/inject_annotation.dart'; const databasePath = Qualifier(#databasePath); const databaseName = Qualifier(#databaseName); @module class DatabaseModule { @provides @databasePath String provideDatabasePath() => '/data/counter.db'; @provides @databaseName String provideDatabaseName() => 'counter_db'; @provides @singleton Database provideDatabase( @databasePath String path, @databaseName String name, ) => Database(path: path, name: name); } class Database { Database({required this.path, required this.name}); final String path; final String name; int _count = 0; Future updateCount(int count) async => _count = count; Future selectCount() => Future.value(_count); } ``` -------------------------------- ### Synthesized Factory for @assistedInject Source: https://github.com/ralph-bergmann/inject.dart/blob/master/README.md Example of a factory automatically generated by inject.dart for classes using @assistedInject. The factory allows supplying runtime parameters during creation. ```dart abstract class DetailPageFactory { DetailPage create({Key? key, required String itemId}); } ``` -------------------------------- ### Flutter Widget with Assisted Injection Source: https://github.com/ralph-bergmann/inject.dart/blob/master/packages/inject_annotation/skills/inject_annotation-add-assisted-injection/SKILL.md Example of a Flutter widget using assisted injection for both injected services and runtime parameters like `key` and `title`. ```dart part 'home_page.factory.dart'; class HomePage extends StatelessWidget { @assistedInject const HomePage({ @assisted super.key, @assisted required this.title, required this.viewModelFactory, // injected from the graph }); final String title; final ViewModelFactory viewModelFactory; // ... } // Synthesized: HomePageFactory.create({Key? key, required String title}) ``` -------------------------------- ### Database Service and Module Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/book/chapter_5_state_management.html Demonstrates providing a simulated third-party Database type using a module. It also shows the two-line @Qualifier form to distinguish String config values. ```dart const databasePath = Qualifier(#databasePath); const databaseName = Qualifier(#databaseName); @module class DatabaseModule { @provides @databasePath String provideDatabasePath() => '/data/counter.db'; @provides @databaseName String provideDatabaseName() => 'counter_db'; @provides @singleton Database provideDatabase( @databasePath String path, @databaseName String name, ) => Database(path: path, name: name); } ``` -------------------------------- ### Assisted Injection with Factory Source: https://github.com/ralph-bergmann/inject.dart/blob/master/rules/rules.md Demonstrates how to use @assistedInject, @assisted, and @assistedFactory for creating objects with runtime parameters. The factory interface, the injectable class constructor, and the component exposing the factory are shown. ```dart // 1. Define the factory interface @assistedFactory abstract class ProductCardFactory { ProductCard create(Product product); } // 2. Annotate the class constructor class ProductCard extends StatelessWidget { @assistedInject const ProductCard( this._analyticsService, // injected from the graph @assisted this.product, // provided at call time {@assisted super.key}, ); final AnalyticsService _analyticsService; final Product product; // ... } // 3. Expose the factory from the component @Component([AppModule]) abstract class AppComponent { static const create = g.AppComponent$Component.create; @inject ProductCardFactory get productCardFactory; } // 4. Use the factory final card = component.productCardCardFactory.create(product); ``` -------------------------------- ### Clean and Build with Build Runner Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/src/chapter_4_core_concepts.md Commands to clean the build cache and then rebuild the project using the build_runner tool. Run these if sources haven't changed and no output is printed. ```bash dart run build_runner clean ``` ```bash dart run build_runner build ``` -------------------------------- ### Module Override Example: Test-Mock Swap Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/book/chapter_4_core_concepts.html Demonstrates how to override a production module with a test module in a component. TestDatabaseModule overrides DatabaseModule's Database binding for testing purposes. ```dart @Component([DatabaseModule]) abstract class AppComponent { ... } ``` ```dart @Component([DatabaseModule, TestDatabaseModule]) abstract class TestRepositoryComponent { static const create = g.TestRepositoryComponent$Component.create; @inject CounterRepository get counterRepository; } @module class TestDatabaseModule { @provides @singleton Database provideDatabase( @databasePath String path, @databaseName String name, ) => FakeDatabase(); } ``` -------------------------------- ### Regenerate Code and Analyze Project Source: https://github.com/ralph-bergmann/inject.dart/blob/master/packages/inject_annotation/skills/inject_annotation-flutter-view-model/SKILL.md After making changes to your DI setup or view models, regenerate the necessary code using build_runner and then analyze your Flutter project for potential issues. ```bash dart run build_runner build --delete-conflicting-outputs flutter analyze ``` -------------------------------- ### MyApp with Assisted Injection and HomePageFactory Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/book/chapter_3_quickstart.html Shows how the root MyApp widget uses assisted injection and injects the synthesized HomePageFactory. It also requires its own 'part' directive for factory generation. ```dart // lib/src/features/app/my_app.dart import 'package:flutter/material.dart'; import 'package:inject_annotation/inject_annotation.dart'; import '../home/home_page.dart'; part 'my_app.factory.dart'; class MyApp extends StatelessWidget { @assistedInject const MyApp({@assisted super.key, required this.homePageFactory}); final HomePageFactory homePageFactory; @override Widget build(BuildContext context) => MaterialApp( home: homePageFactory.create(title: 'Flutter Counter Demo'), ); } ``` -------------------------------- ### Provision Listener for Observing Provisions Source: https://github.com/ralph-bergmann/inject.dart/blob/master/README.md Demonstrates implementing ProvisionListener to observe dependency creations for logging or resource management. The generic parameter can narrow the scope of observed types. ```dart class CreationLogListener implements ProvisionListener { int _count = 0; @override void onProvision(ChangeNotifier instance) { _count++; debugPrint('inject.dart -> $instance (#$_count)'); } } @module class AppModule { @provides @singleton @provisionListener CreationLogListener provideListener() => CreationLogListener(); } ``` -------------------------------- ### Implement Catch-all ProvisionListener Source: https://github.com/ralph-bergmann/inject.dart/blob/master/packages/inject_annotation/skills/inject_annotation-add-provision-listener/SKILL.md Implement ProvisionListener for a listener that fires for every provisioned instance. The onProvision method takes 'dynamic' which Object cannot validly override. ```dart class LoggingListener implements ProvisionListener { @override void onProvision(Object instance) => print('Provisioned: $instance'); } ``` -------------------------------- ### Module Override Example: Test-Mock Swap Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/src/chapter_4_core_concepts.md Demonstrates how to override a production module binding with a test-specific binding in a separate test component. This allows for swapping out dependencies like databases for testing purposes. ```dart @Component([DatabaseModule]) abstract class AppComponent { ... } ``` ```dart @Component([DatabaseModule, TestDatabaseModule]) abstract class TestRepositoryComponent { static const create = g.TestRepositoryComponent$Component.create; @inject CounterRepository get counterRepository; } ``` ```dart @module class TestDatabaseModule { @provides @singleton Database provideDatabase( @databasePath String path, @databaseName String name, ) => FakeDatabase(); } ``` -------------------------------- ### Interpreting inject.dart Debug Graph Output Source: https://github.com/ralph-bergmann/inject.dart/blob/master/packages/inject_flutter/README.md Example of the dependency graph output for a 'CoffeeShop' component, illustrating shared dependencies like 'Heater'. Annotations explain the graph's structure and symbols. ```text [inject_generator] Dependency graph for CoffeeShop: CoffeeShop ├── Brewer (@singleton, @async) │ └── Heater... └── Grinder └── Heater... (shared bindings — each appears in the tree above as ...) Heater (@singleton, injected by: Brewer, Grinder) ``` -------------------------------- ### Add Dependencies for Flutter Projects (Single Command) Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/src/chapter_2_installation.md A consolidated command to add all required inject.dart dependencies for Flutter projects. ```bash flutter pub add inject_annotation inject_flutter dev:inject_generator dev:build_runner ``` -------------------------------- ### AppModule for Initial Count Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/book/chapter_3_quickstart.html A simple module that provides a singleton Future for the initial count of a CounterViewModel. This demonstrates how to provide asynchronous values. ```dart // lib/src/app_module.dart @module class AppModule { @provides @singleton Future provideInitialCount() => Future.value(0); } ``` -------------------------------- ### Provide Catch-all Listener from Module Source: https://github.com/ralph-bergmann/inject.dart/blob/master/packages/inject_annotation/skills/inject_annotation-add-provision-listener/SKILL.md Provide a LoggingListener from a module using @provides and @provisionListener. The return type can be the concrete listener class. ```dart @module class AppModule { // Concrete return type — the catch-all listened-to type is read from the // `ProvisionListener` that LoggingListener implements. @provides @provisionListener LoggingListener provideLoggingListener() => LoggingListener(); // Interface return type also works; here it scopes to Closeable. @provides @provisionListener ProvisionListener provideCloseableListener() => CloseableListener(); } ``` -------------------------------- ### HomePage with Assisted Injection Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/book/chapter_3_quickstart.html Demonstrates how to use @assistedInject for a widget that needs both DI-managed dependencies and runtime parameters. Each file with @assistedInject requires a 'part' directive for factory generation. ```dart // lib/src/features/home/home_page.dart import 'package:flutter/material.dart'; import 'package:inject_annotation/inject_annotation.dart'; import 'package:inject_flutter/inject_flutter.dart'; import 'counter_view_model.dart'; part 'home_page.factory.dart'; class HomePage extends StatelessWidget { @assistedInject const HomePage({ @assisted super.key, @assisted required this.title, required this.viewModelFactory, }); final String title; final ViewModelFactory viewModelFactory; @override Widget build(BuildContext context) { return viewModelFactory( init: (vm) => vm.init(), loading: const Center(child: CircularProgressIndicator()), builder: (context, vm, _) => Scaffold( appBar: AppBar(title: Text(title)), body: Center(child: Text('${vm.counter.value}')), floatingActionButton: FloatingActionButton( onPressed: vm.increment, child: const Icon(Icons.add), ), ), ); } } ``` -------------------------------- ### Build Runner Commands Source: https://github.com/ralph-bergmann/inject.dart/blob/master/rules/rules.md Provides essential commands for running the build runner, including one-time builds, watch mode for development, and cleaning generated files. ```bash # One-time build dart run build_runner build --delete-conflicting-outputs # Watch mode for development dart run build_runner watch --delete-conflicting-outputs # Clean generated files dart run build_runner clean ``` -------------------------------- ### Run build_runner for code generation Source: https://github.com/ralph-bergmann/inject.dart/blob/master/packages/inject_annotation/skills/inject_annotation-setup-di/SKILL.md Run build_runner to generate the dependency injection implementation. Use 'build' for a one-time generation or 'watch' for continuous generation during development. The --delete-conflicting-outputs flag is recommended. ```bash dart run build_runner build --delete-conflicting-outputs ``` ```bash dart run build_runner watch --delete-conflicting-outputs ``` -------------------------------- ### Dart Linting Configuration Source: https://github.com/ralph-bergmann/inject.dart/blob/master/rules/rules.md Provides recommended rules for the `analysis_options.yaml` file to improve code quality. Always run `dart analyze` to verify. ```yaml include: package:lints/recommended.yaml linter: rules: - prefer_const_constructors - prefer_final_fields - prefer_single_quotes - require_trailing_commas ``` -------------------------------- ### Run All Tests Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/src/chapter_6_testing.md Execute all tests in the project using the flutter test command. ```bash flutter test ``` -------------------------------- ### Run the Code Generator Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/src/chapter_2_installation.md Execute the build_runner to generate inject.dart wiring code after annotating your classes. ```bash dart run build_runner build ``` -------------------------------- ### Define Component Root with Dependencies Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/book/chapter_5_state_management.html Defines the root component 'MainComponent' with its associated modules and injected factories/providers. The 'create' static method is used for component instantiation. ```dart import 'main.inject.dart' as g; @Component([AppModule, DatabaseModule]) abstract class MainComponent { static const create = g.MainComponent$Component.create; @inject MyAppFactory get myAppFactory; @welcome @inject Future get welcomeMessage; @inject Provider get counterRepositoryProvider; @inject CreationLogListener get creationLogListener; } ``` -------------------------------- ### Implement Asynchronous Initialization with Loading and Error States Source: https://github.com/ralph-bergmann/inject.dart/blob/master/packages/inject_annotation/skills/inject_annotation-flutter-view-model/SKILL.md Configure the ViewModelBuilder to handle asynchronous initialization using the 'init', 'loading', and 'error' parameters. The 'init' callback runs once when the view model is created. 'loading' displays a progress indicator while 'init' is running, and 'error' shows an error message if initialization fails. ```dart return factory( init: (vm) => vm.init(), // async: awaited before builder runs loading: const Center(child: CircularProgressIndicator()), error: (context, error, stackTrace) => Center(child: Text('Failed: $error')), builder: (context, vm, child) => Text('Count: ${vm.count}'), ); ``` -------------------------------- ### ViewModelFactory with One-Shot Initialization Source: https://github.com/ralph-bergmann/inject.dart/blob/master/README.md This pattern supports a one-shot initialization that can be synchronous or asynchronous. An async init is awaited, showing a loading widget until completion. ```dart viewModelFactory( init: (viewModel) => viewModel.load(), loading: const Center(child: CircularProgressIndicator()), builder: (context, viewModel, _) => /* widget */, ); ``` -------------------------------- ### Annotating and Using ViewModelFactory Source: https://github.com/ralph-bergmann/inject.dart/blob/master/rules/rules.md Demonstrates how to annotate a ChangeNotifier ViewModel, expose a ViewModelFactory from a component, and use the factory within a StatelessWidget to obtain a ViewModelBuilder. ```dart // 1. Annotate the view model constructor class CounterViewModel extends ChangeNotifier { @inject CounterViewModel(this._repository); final CounterRepository _repository; int count = 0; // Optional: an initializer that ViewModelBuilder runs once. May be async. Future init() async { count = await _repository.current(); notifyListeners(); } Future increment() async { count = await _repository.increment(); notifyListeners(); } } // 2. Expose a ViewModelFactory from the component @Component([AppModule]) abstract class AppComponent { static const create = g.AppComponent$Component.create; @inject ViewModelFactory get counterViewModelFactory; } // 3. Call the injected factory in the widget — it returns a ViewModelBuilder. // The widget can stay a StatelessWidget; the factory owns the stateful parts. class CounterPage extends StatelessWidget { const CounterPage({super.key, required this.factory}); final ViewModelFactory factory; @override Widget build(BuildContext context) { return factory( // init may be sync or async. An async init is awaited: // `loading` shows while it runs, `error` shows if it throws. init: (vm) => vm.init(), loading: const Center(child: CircularProgressIndicator()), error: (context, error, stackTrace) => Text('Failed: $error'), builder: (context, vm, child) => Text('Count: ${vm.count}'), ); } } ``` -------------------------------- ### Inject Builder Configuration in build.yaml Source: https://github.com/ralph-bergmann/inject.dart/blob/master/book/src/chapter_4_core_concepts.md Shows how to configure the inject_generator|inject_builder options within a build.yaml file. This includes setting policies for handling duplicate bindings and enabling debug logging for the dependency graph. ```yaml targets: $default: builders: inject_generator|inject_builder: options: nullable_duplicate_binding_policy: error # default debug_graph: false # default ``` -------------------------------- ### Build Runner Commands Source: https://github.com/ralph-bergmann/inject.dart/blob/master/packages/inject_generator/README.md Commands to build the project with build_runner. If source files haven't changed, a clean build might be necessary to see output. ```bash dart run build_runner build ``` ```bash dart run build_runner clean dart run build_runner build ``` -------------------------------- ### Component Entry Point with @asynchronous Source: https://github.com/ralph-bergmann/inject.dart/blob/master/examples/flutter_demo/README.md The component entry point for an @asynchronous provider is a Future because async-ness propagates to the boundary. You must await at the entry point. ```dart // In main(): final welcome = await component.welcomeMessage; // Future ``` -------------------------------- ### Define a Network Module with Providers Source: https://github.com/ralph-bergmann/inject.dart/blob/master/packages/inject_annotation/skills/inject_annotation-create-module/SKILL.md This snippet shows how to define a module class with @provides methods for Dio and ApiClient. Parameters for provider methods are automatically injected from the graph. ```dart @module class NetworkModule { @provides @singleton Dio provideDio() => Dio(BaseOptions(baseUrl: 'https://api.example.com')); // Parameters are injected from the graph automatically. @provides ApiClient provideApiClient(Dio dio) => ApiClient(dio); } ```