mirror of
https://github.com/pese-git/cherrypick.git
synced 2026-01-24 05:25:19 +00:00
doc: update documentations
This commit is contained in:
@@ -18,49 +18,76 @@ import 'package:cherrypick_annotations/cherrypick_annotations.dart' as ann;
|
|||||||
|
|
||||||
import 'src/generated_class.dart';
|
import 'src/generated_class.dart';
|
||||||
|
|
||||||
|
/// ---------------------------------------------------------------------------
|
||||||
|
/// ModuleGenerator for code generation of dependency-injected modules.
|
||||||
///
|
///
|
||||||
|
/// ENGLISH
|
||||||
|
/// This generator scans for Dart classes annotated with `@module()` and
|
||||||
|
/// automatically generates boilerplate code for dependency injection
|
||||||
|
/// (DI) based on the public methods in those classes. Each method can be
|
||||||
|
/// annotated to describe how an object should be provided to the DI container.
|
||||||
|
/// The generated code registers those methods as bindings. This automates the
|
||||||
|
/// creation of factories, singletons, and named instances, reducing repetitive
|
||||||
|
/// manual code.
|
||||||
|
///
|
||||||
|
/// RUSSIAN
|
||||||
/// Генератор зависимостей для DI-контейнера на основе аннотаций.
|
/// Генератор зависимостей для DI-контейнера на основе аннотаций.
|
||||||
///
|
|
||||||
/// Данный генератор автоматически создаёт код для внедрения зависимостей (DI)
|
/// Данный генератор автоматически создаёт код для внедрения зависимостей (DI)
|
||||||
/// на основе аннотаций в вашем исходном коде. Когда вы отмечаете класс
|
/// на основе аннотаций в вашем исходном коде. Когда вы отмечаете класс
|
||||||
/// аннотацией `@module()`, этот генератор обработает все его публичные методы
|
/// аннотацией `@module()`, этот генератор обработает все его публичные методы
|
||||||
/// и автоматически сгенерирует класс с биндингами (регистрациями зависимостей)
|
/// и автоматически сгенерирует класс с биндингами (регистрациями зависимостей)
|
||||||
/// для DI-контейнера. Это избавляет от написания однообразного шаблонного кода.
|
/// для DI-контейнера. Это избавляет от написания однообразного шаблонного кода.
|
||||||
///
|
/// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
class ModuleGenerator extends GeneratorForAnnotation<ann.module> {
|
class ModuleGenerator extends GeneratorForAnnotation<ann.module> {
|
||||||
/// Генерирует исходный код для класса-модуля с аннотацией `@module()`.
|
/// -------------------------------------------------------------------------
|
||||||
|
/// ENGLISH
|
||||||
|
/// Generates the Dart source for a class marked with the `@module()` annotation.
|
||||||
|
/// - [element]: the original Dart class element.
|
||||||
|
/// - [annotation]: the annotation parameters (not usually used here).
|
||||||
|
/// - [buildStep]: the current build step info.
|
||||||
///
|
///
|
||||||
|
/// RUSSIAN
|
||||||
|
/// Генерирует исходный код для класса-модуля с аннотацией `@module()`.
|
||||||
/// [element] — исходный класс, помеченный аннотацией.
|
/// [element] — исходный класс, помеченный аннотацией.
|
||||||
/// [annotation] — значения параметров аннотации.
|
/// [annotation] — значения параметров аннотации.
|
||||||
/// [buildStep] — информация о текущем шаге генерации.
|
/// [buildStep] — информация о текущем шаге генерации.
|
||||||
|
/// -------------------------------------------------------------------------
|
||||||
@override
|
@override
|
||||||
String generateForAnnotatedElement(
|
String generateForAnnotatedElement(
|
||||||
Element element,
|
Element element,
|
||||||
ConstantReader annotation,
|
ConstantReader annotation,
|
||||||
BuildStep buildStep,
|
BuildStep buildStep,
|
||||||
) {
|
) {
|
||||||
// Генератор обрабатывает только классы (остальное — ошибка)
|
// Only classes are supported for @module() annotation
|
||||||
|
// Обрабатываются только классы (другие элементы — ошибка)
|
||||||
if (element is! ClassElement) {
|
if (element is! ClassElement) {
|
||||||
throw InvalidGenerationSourceError(
|
throw InvalidGenerationSourceError(
|
||||||
'@module() может быть применён только к классам.',
|
'@module() can only be applied to classes. / @module() может быть применён только к классам.',
|
||||||
element: element,
|
element: element,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final classElement = element;
|
final classElement = element;
|
||||||
|
|
||||||
|
// Build a representation of the generated bindings based on class methods /
|
||||||
// Создаёт объект, описывающий, какие биндинги нужно сгенерировать на основании методов класса
|
// Создаёт объект, описывающий, какие биндинги нужно сгенерировать на основании методов класса
|
||||||
final generatedClass = GeneratedClass.fromClassElement(classElement);
|
final generatedClass = GeneratedClass.fromClassElement(classElement);
|
||||||
|
|
||||||
// Генерирует итоговый Dart-код
|
// Generate the resulting Dart code / Генерирует итоговый Dart-код
|
||||||
return generatedClass.generate();
|
return generatedClass.generate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ---------------------------------------------------------------------------
|
||||||
|
/// ENGLISH
|
||||||
|
/// Entry point for build_runner. Returns a Builder used to generate code for
|
||||||
|
/// every file with a @module() annotation.
|
||||||
///
|
///
|
||||||
|
/// RUSSIAN
|
||||||
/// Точка входа для генератора build_runner.
|
/// Точка входа для генератора build_runner.
|
||||||
/// Возвращает Builder, используемый build_runner для генерации кода для всех
|
/// Возвращает Builder, используемый build_runner для генерации кода для всех
|
||||||
/// файлов, где встречается @module().
|
/// файлов, где встречается @module().
|
||||||
///
|
/// ---------------------------------------------------------------------------
|
||||||
Builder moduleBuilder(BuilderOptions options) =>
|
Builder moduleBuilder(BuilderOptions options) =>
|
||||||
PartBuilder([ModuleGenerator()], '.cherrypick.g.dart');
|
PartBuilder([ModuleGenerator()], '.cherrypick.g.dart');
|
||||||
|
|||||||
@@ -11,25 +11,58 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
/// ----------------------------------------------------------------------------
|
||||||
|
/// BindParameterSpec - describes a single method parameter and how to resolve it.
|
||||||
///
|
///
|
||||||
/// Описывает один параметр метода и возможность его разрешения из контейнера.
|
/// ENGLISH
|
||||||
|
/// Describes a single parameter for a provider/binding method in the DI system.
|
||||||
|
/// Stores the parameter type, its optional `@named` key for named resolution,
|
||||||
|
/// and whether it is a runtime "params" argument. Used to generate code that
|
||||||
|
/// resolves dependencies from the DI scope:
|
||||||
|
/// - If the parameter is a dependency type (e.g. SomeDep), emits:
|
||||||
|
/// currentScope.resolve<SomeDep>()
|
||||||
|
/// - If the parameter is named, emits:
|
||||||
|
/// currentScope.resolve<SomeDep>(named: 'yourName')
|
||||||
|
/// - If it's a runtime parameter (e.g. via @params()), emits:
|
||||||
|
/// args
|
||||||
///
|
///
|
||||||
/// Например, если метод принимает SomeDep dep, то
|
/// RUSSIAN
|
||||||
/// BindParameterSpec хранит тип SomeDep, а generateArg отдаст строку
|
/// Описывает один параметр метода в DI, и его способ разрешения из контейнера.
|
||||||
|
/// Сохраняет имя типа, дополнительное имя (если параметр аннотирован через @named),
|
||||||
|
/// и признак runtime-параметра (@params).
|
||||||
|
/// Для обычной зависимости типа (например, SomeDep) генерирует строку вида:
|
||||||
/// currentScope.resolve<SomeDep>()
|
/// currentScope.resolve<SomeDep>()
|
||||||
///
|
/// Для зависимости с именем:
|
||||||
|
/// currentScope.resolve<SomeDep>(named: 'имя')
|
||||||
|
/// Для runtime-параметра:
|
||||||
|
/// args
|
||||||
|
/// ----------------------------------------------------------------------------
|
||||||
class BindParameterSpec {
|
class BindParameterSpec {
|
||||||
|
/// Type name of the parameter (e.g. SomeService)
|
||||||
/// Имя типа параметра (например, SomeService)
|
/// Имя типа параметра (например, SomeService)
|
||||||
final String typeName;
|
final String typeName;
|
||||||
|
|
||||||
|
/// Optional name for named resolution (from @named)
|
||||||
/// Необязательное имя для разрешения по имени (если аннотировано через @named)
|
/// Необязательное имя для разрешения по имени (если аннотировано через @named)
|
||||||
final String? named;
|
final String? named;
|
||||||
|
|
||||||
|
/// True if this parameter uses @params and should be provided from runtime args
|
||||||
|
/// Признак, что параметр — runtime (через @params)
|
||||||
final bool isParams;
|
final bool isParams;
|
||||||
|
|
||||||
BindParameterSpec(this.typeName, this.named, {this.isParams = false});
|
BindParameterSpec(this.typeName, this.named, {this.isParams = false});
|
||||||
|
|
||||||
/// Генерирует строку для получения зависимости из DI scope (с учётом имени)
|
/// --------------------------------------------------------------------------
|
||||||
|
/// generateArg
|
||||||
|
///
|
||||||
|
/// ENGLISH
|
||||||
|
/// Generates Dart code for resolving the dependency from the DI scope,
|
||||||
|
/// considering type, named, and param-argument.
|
||||||
|
///
|
||||||
|
/// RUSSIAN
|
||||||
|
/// Генерирует строку для получения зависимости из DI scope (с учётом имени
|
||||||
|
/// и типа параметра или runtime-режима @params).
|
||||||
|
/// --------------------------------------------------------------------------
|
||||||
String generateArg([String paramsVar = 'args']) {
|
String generateArg([String paramsVar = 'args']) {
|
||||||
if (isParams) {
|
if (isParams) {
|
||||||
return paramsVar;
|
return paramsVar;
|
||||||
|
|||||||
@@ -17,33 +17,57 @@ import 'package:source_gen/source_gen.dart';
|
|||||||
import 'bind_parameters_spec.dart';
|
import 'bind_parameters_spec.dart';
|
||||||
import 'metadata_utils.dart';
|
import 'metadata_utils.dart';
|
||||||
|
|
||||||
|
/// ---------------------------------------------------------------------------
|
||||||
|
/// BindSpec -- describes a binding specification generated for a dependency.
|
||||||
///
|
///
|
||||||
|
/// ENGLISH
|
||||||
|
/// Represents all the data necessary to generate a DI binding for a single
|
||||||
|
/// method in a module class. Each BindSpec corresponds to one public method
|
||||||
|
/// and contains information about its type, provider method, lifecycle (singleton),
|
||||||
|
/// parameters (with their annotations), binding strategy (instance/provide),
|
||||||
|
/// asynchronous mode, and named keys. It is responsible for generating the
|
||||||
|
/// correct Dart code to register this binding with the DI container, in both
|
||||||
|
/// sync and async cases, with and without named or runtime arguments.
|
||||||
|
///
|
||||||
|
/// RUSSIAN
|
||||||
/// Описывает параметры для создания одного биндинга зависимости (binding spec).
|
/// Описывает параметры для создания одного биндинга зависимости (binding spec).
|
||||||
///
|
/// Каждый биндинг соответствует одному публичному методу класса-модуля и
|
||||||
/// Каждый биндинг соответствует одному публичному методу класса-модуля.
|
/// содержит всю информацию для генерации кода регистрации этого биндинга в
|
||||||
///
|
/// DI-контейнере: тип возвращаемой зависимости, имя метода, параметры, аннотации
|
||||||
|
/// (@singleton, @named, @instance, @provide), асинхронность, признак runtime
|
||||||
|
/// аргументов и др. Генерирует правильный Dart-код для регистрации биндера.
|
||||||
|
/// ---------------------------------------------------------------------------
|
||||||
class BindSpec {
|
class BindSpec {
|
||||||
|
/// The type this binding provides (e.g. SomeService)
|
||||||
/// Тип, который предоставляет биндинг (например, SomeService)
|
/// Тип, который предоставляет биндинг (например, SomeService)
|
||||||
final String returnType;
|
final String returnType;
|
||||||
|
|
||||||
|
/// Method name that implements the binding
|
||||||
/// Имя метода, который реализует биндинг
|
/// Имя метода, который реализует биндинг
|
||||||
final String methodName;
|
final String methodName;
|
||||||
|
|
||||||
|
/// Optional name for named dependency (from @named)
|
||||||
/// Необязательное имя, для именованной зависимости (используется с @named)
|
/// Необязательное имя, для именованной зависимости (используется с @named)
|
||||||
final String? named;
|
final String? named;
|
||||||
|
|
||||||
|
/// Whether the dependency is a singleton (@singleton annotation)
|
||||||
/// Является ли зависимость синглтоном (имеется ли аннотация @singleton)
|
/// Является ли зависимость синглтоном (имеется ли аннотация @singleton)
|
||||||
final bool isSingleton;
|
final bool isSingleton;
|
||||||
|
|
||||||
|
/// List of method parameters to inject dependencies with
|
||||||
/// Список параметров, которые требуются методу для внедрения зависимостей
|
/// Список параметров, которые требуются методу для внедрения зависимостей
|
||||||
final List<BindParameterSpec> parameters;
|
final List<BindParameterSpec> parameters;
|
||||||
|
|
||||||
|
/// Binding type: 'instance' or 'provide' (@instance or @provide)
|
||||||
final String bindingType; // 'instance' | 'provide'
|
final String bindingType; // 'instance' | 'provide'
|
||||||
|
|
||||||
|
/// True if the method is asynchronous and uses instance binding (Future)
|
||||||
final bool isAsyncInstance;
|
final bool isAsyncInstance;
|
||||||
|
|
||||||
|
/// True if the method is asynchronous and uses provide binding (Future)
|
||||||
final bool isAsyncProvide;
|
final bool isAsyncProvide;
|
||||||
|
|
||||||
|
/// True if the binding method accepts runtime "params" argument (@params)
|
||||||
final bool hasParams;
|
final bool hasParams;
|
||||||
|
|
||||||
BindSpec({
|
BindSpec({
|
||||||
@@ -58,10 +82,20 @@ class BindSpec {
|
|||||||
required this.hasParams,
|
required this.hasParams,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// -------------------------------------------------------------------------
|
||||||
|
/// generateBind
|
||||||
|
///
|
||||||
|
/// ENGLISH
|
||||||
|
/// Generates a line of Dart code registering the binding with the DI framework.
|
||||||
|
/// Produces something like:
|
||||||
|
/// bind<Type>().toProvide(() => method(args)).withName('name').singleton();
|
||||||
|
/// Indent parameter allows formatted multiline output.
|
||||||
|
///
|
||||||
|
/// RUSSIAN
|
||||||
/// Формирует dart-код для биндинга, например:
|
/// Формирует dart-код для биндинга, например:
|
||||||
/// bind<Type>().toProvide(() => method(args)).withName('name').singleton();
|
/// bind<Type>().toProvide(() => method(args)).withName('name').singleton();
|
||||||
///
|
|
||||||
/// Параметр [indent] задаёт отступ для красивого форматирования кода.
|
/// Параметр [indent] задаёт отступ для красивого форматирования кода.
|
||||||
|
/// -------------------------------------------------------------------------
|
||||||
String generateBind(int indent) {
|
String generateBind(int indent) {
|
||||||
final indentStr = ' ' * indent;
|
final indentStr = ' ' * indent;
|
||||||
final provide = _generateProvideClause(indent);
|
final provide = _generateProvideClause(indent);
|
||||||
@@ -72,13 +106,15 @@ class BindSpec {
|
|||||||
'$postfix;';
|
'$postfix;';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Internal method: decides how the provide clause should be generated by param kind.
|
||||||
String _generateProvideClause(int indent) {
|
String _generateProvideClause(int indent) {
|
||||||
if (hasParams) return _generateWithParamsProvideClause(indent);
|
if (hasParams) return _generateWithParamsProvideClause(indent);
|
||||||
return _generatePlainProvideClause(indent);
|
return _generatePlainProvideClause(indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// EN / RU: Supports runtime parameters (@params).
|
||||||
String _generateWithParamsProvideClause(int indent) {
|
String _generateWithParamsProvideClause(int indent) {
|
||||||
// Безопасное имя для параметра
|
// Safe variable name for parameters.
|
||||||
const paramVar = 'args';
|
const paramVar = 'args';
|
||||||
final fnArgs = parameters
|
final fnArgs = parameters
|
||||||
.map((p) => p.isParams ? paramVar : p.generateArg(paramVar))
|
.map((p) => p.isParams ? paramVar : p.generateArg(paramVar))
|
||||||
@@ -103,6 +139,7 @@ class BindSpec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// EN / RU: Supports only injected dependencies, not runtime (@params).
|
||||||
String _generatePlainProvideClause(int indent) {
|
String _generatePlainProvideClause(int indent) {
|
||||||
final argsStr = parameters.map((p) => p.generateArg()).join(', ');
|
final argsStr = parameters.map((p) => p.generateArg()).join(', ');
|
||||||
final multiLine = argsStr.length > 60 || argsStr.contains('\n');
|
final multiLine = argsStr.length > 60 || argsStr.contains('\n');
|
||||||
@@ -125,24 +162,37 @@ class BindSpec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// EN / RU: Adds .withName and .singleton if needed.
|
||||||
String _generatePostfix() {
|
String _generatePostfix() {
|
||||||
final namePart = named != null ? ".withName('$named')" : '';
|
final namePart = named != null ? ".withName('$named')" : '';
|
||||||
final singletonPart = isSingleton ? '.singleton()' : '';
|
final singletonPart = isSingleton ? '.singleton()' : '';
|
||||||
return '$namePart$singletonPart';
|
return '$namePart$singletonPart';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Создаёт спецификацию биндинга (BindSpec) из метода класса-модуля
|
/// -------------------------------------------------------------------------
|
||||||
|
/// fromMethod
|
||||||
|
///
|
||||||
|
/// ENGLISH
|
||||||
|
/// Creates a BindSpec from a module class method by analyzing its return type,
|
||||||
|
/// annotations, list of parameters (with their own annotations), and async-ness.
|
||||||
|
/// Throws if a method does not have the required @instance() or @provide().
|
||||||
|
///
|
||||||
|
/// RUSSIAN
|
||||||
|
/// Создаёт спецификацию биндинга (BindSpec) из метода класса-модуля, анализируя
|
||||||
|
/// возвращаемый тип, аннотации, параметры (и их аннотации), а также факт
|
||||||
|
/// асинхронности. Если нет @instance или @provide — кидает ошибку.
|
||||||
|
/// -------------------------------------------------------------------------
|
||||||
static BindSpec fromMethod(MethodElement method) {
|
static BindSpec fromMethod(MethodElement method) {
|
||||||
var returnType = method.returnType.getDisplayString();
|
var returnType = method.returnType.getDisplayString();
|
||||||
|
|
||||||
final methodName = method.displayName;
|
final methodName = method.displayName;
|
||||||
// Проверим, помечен ли метод аннотацией @singleton
|
// Check for @singleton annotation.
|
||||||
final isSingleton = MetadataUtils.anyMeta(method.metadata, 'singleton');
|
final isSingleton = MetadataUtils.anyMeta(method.metadata, 'singleton');
|
||||||
|
|
||||||
// Получаем имя из @named(), если есть
|
// Get @named value if present.
|
||||||
final named = MetadataUtils.getNamedValue(method.metadata);
|
final named = MetadataUtils.getNamedValue(method.metadata);
|
||||||
|
|
||||||
// Для каждого параметра метода
|
// Parse each method parameter.
|
||||||
final params = <BindParameterSpec>[];
|
final params = <BindParameterSpec>[];
|
||||||
bool hasParams = false;
|
bool hasParams = false;
|
||||||
for (final p in method.parameters) {
|
for (final p in method.parameters) {
|
||||||
@@ -153,18 +203,18 @@ class BindSpec {
|
|||||||
params.add(BindParameterSpec(typeStr, paramNamed, isParams: isParams));
|
params.add(BindParameterSpec(typeStr, paramNamed, isParams: isParams));
|
||||||
}
|
}
|
||||||
|
|
||||||
// определяем bindingType
|
// Determine bindingType: @instance or @provide.
|
||||||
final hasInstance = MetadataUtils.anyMeta(method.metadata, 'instance');
|
final hasInstance = MetadataUtils.anyMeta(method.metadata, 'instance');
|
||||||
final hasProvide = MetadataUtils.anyMeta(method.metadata, 'provide');
|
final hasProvide = MetadataUtils.anyMeta(method.metadata, 'provide');
|
||||||
if (!hasInstance && !hasProvide) {
|
if (!hasInstance && !hasProvide) {
|
||||||
throw InvalidGenerationSourceError(
|
throw InvalidGenerationSourceError(
|
||||||
'Метод $methodName класса-модуля должен быть помечен либо @instance(), либо @provide().',
|
'Method $methodName must be marked with @instance() or @provide().',
|
||||||
element: method,
|
element: method,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
final bindingType = hasInstance ? 'instance' : 'provide';
|
final bindingType = hasInstance ? 'instance' : 'provide';
|
||||||
|
|
||||||
// --- Новый участок: извлекаем внутренний тип из Future<> и выставляем флаги
|
// -- Extract inner type for Future<T> and set async flags.
|
||||||
bool isAsyncInstance = false;
|
bool isAsyncInstance = false;
|
||||||
bool isAsyncProvide = false;
|
bool isAsyncProvide = false;
|
||||||
final futureInnerType = _extractFutureInnerType(returnType);
|
final futureInnerType = _extractFutureInnerType(returnType);
|
||||||
@@ -187,6 +237,7 @@ class BindSpec {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// EN / RU: Extracts inner type from Future<T>, returns e.g. "T" or null.
|
||||||
static String? _extractFutureInnerType(String typeName) {
|
static String? _extractFutureInnerType(String typeName) {
|
||||||
final match = RegExp(r'^Future<(.+)>$').firstMatch(typeName);
|
final match = RegExp(r'^Future<(.+)>$').firstMatch(typeName);
|
||||||
return match?.group(1)?.trim();
|
return match?.group(1)?.trim();
|
||||||
|
|||||||
@@ -15,17 +15,37 @@ import 'package:analyzer/dart/element/element.dart';
|
|||||||
|
|
||||||
import 'bind_spec.dart';
|
import 'bind_spec.dart';
|
||||||
|
|
||||||
|
/// ---------------------------------------------------------------------------
|
||||||
|
/// GeneratedClass -- represents the result of processing a single module class.
|
||||||
///
|
///
|
||||||
/// Результат обработки одного класса-модуля: имя класса, его биндинги,
|
/// ENGLISH
|
||||||
/// имя генерируемого класса и т.д.
|
/// Encapsulates all the information produced from analyzing a DI module class:
|
||||||
|
/// - The original class name,
|
||||||
|
/// - Its generated class name (e.g., `$SomeModule`),
|
||||||
|
/// - The collection of bindings (BindSpec) for all implemented provider methods.
|
||||||
///
|
///
|
||||||
|
/// Also provides code generation functionality, allowing to generate the source
|
||||||
|
/// code for the derived DI module class, including all binding registrations.
|
||||||
|
///
|
||||||
|
/// RUSSIAN
|
||||||
|
/// Описывает результат обработки одного класса-модуля DI:
|
||||||
|
/// - Имя оригинального класса,
|
||||||
|
/// - Имя генерируемого класса (например, `$SomeModule`),
|
||||||
|
/// - Список всех бидингов (BindSpec) — по публичным методам модуля.
|
||||||
|
///
|
||||||
|
/// Также содержит функцию генерации исходного кода для этого класса и
|
||||||
|
/// регистрации всех зависимостей через bind(...).
|
||||||
|
/// ---------------------------------------------------------------------------
|
||||||
class GeneratedClass {
|
class GeneratedClass {
|
||||||
|
/// The name of the original module class.
|
||||||
/// Имя исходного класса-модуля
|
/// Имя исходного класса-модуля
|
||||||
final String className;
|
final String className;
|
||||||
|
|
||||||
|
/// The name of the generated class (e.g., $SomeModule).
|
||||||
/// Имя генерируемого класса (например, $SomeModule)
|
/// Имя генерируемого класса (например, $SomeModule)
|
||||||
final String generatedClassName;
|
final String generatedClassName;
|
||||||
|
|
||||||
|
/// List of all discovered bindings for the class.
|
||||||
/// Список всех обнаруженных биндингов
|
/// Список всех обнаруженных биндингов
|
||||||
final List<BindSpec> binds;
|
final List<BindSpec> binds;
|
||||||
|
|
||||||
@@ -35,13 +55,24 @@ class GeneratedClass {
|
|||||||
this.binds,
|
this.binds,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Обрабатывает объект ClassElement (отображение класса в AST)
|
/// -------------------------------------------------------------------------
|
||||||
/// и строит структуру _GeneratedClass для генерации кода.
|
/// fromClassElement
|
||||||
|
///
|
||||||
|
/// ENGLISH
|
||||||
|
/// Static factory: creates a GeneratedClass from a Dart ClassElement (AST representation).
|
||||||
|
/// Discovers all non-abstract methods, builds BindSpec for each, and computes the
|
||||||
|
/// generated class name by prefixing `$`.
|
||||||
|
///
|
||||||
|
/// RUSSIAN
|
||||||
|
/// Строит объект класса по элементу AST (ClassElement): имя класса,
|
||||||
|
/// сгенерированное имя, список BindSpec по всем не абстрактным методам.
|
||||||
|
/// Имя ген-класса строится с префиксом `$`.
|
||||||
|
/// -------------------------------------------------------------------------
|
||||||
static GeneratedClass fromClassElement(ClassElement element) {
|
static GeneratedClass fromClassElement(ClassElement element) {
|
||||||
final className = element.displayName;
|
final className = element.displayName;
|
||||||
// Имя с префиксом $ (стандартная практика для ген-кода)
|
// Generated class name with '$' prefix (standard for generated Dart code).
|
||||||
final generatedClassName = r'$' + className;
|
final generatedClassName = r'$' + className;
|
||||||
// Собираем биндинги по всем методам класса, игнорируем абстрактные (без реализации)
|
// Collect bindings for all non-abstract methods.
|
||||||
final binds = element.methods
|
final binds = element.methods
|
||||||
.where((m) => !m.isAbstract)
|
.where((m) => !m.isAbstract)
|
||||||
.map(BindSpec.fromMethod)
|
.map(BindSpec.fromMethod)
|
||||||
@@ -50,9 +81,19 @@ class GeneratedClass {
|
|||||||
return GeneratedClass(className, generatedClassName, binds);
|
return GeneratedClass(className, generatedClassName, binds);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Генерирует исходный Dart-код для созданного класса DI-модуля.
|
/// -------------------------------------------------------------------------
|
||||||
|
/// generate
|
||||||
///
|
///
|
||||||
/// Внутри builder(Scope currentScope) регистрируются все bind-методы.
|
/// ENGLISH
|
||||||
|
/// Generates Dart source code for the DI module class. The generated class
|
||||||
|
/// inherits from the original, overrides the 'builder' method, and registers
|
||||||
|
/// all bindings in the DI scope.
|
||||||
|
///
|
||||||
|
/// RUSSIAN
|
||||||
|
/// Генерирует исходный Dart-код для класса-модуля DI.
|
||||||
|
/// Новая версия класса наследует оригинальный, переопределяет builder(Scope),
|
||||||
|
/// и регистрирует все зависимости через методы bind<Type>()...
|
||||||
|
/// -------------------------------------------------------------------------
|
||||||
String generate() {
|
String generate() {
|
||||||
final buffer = StringBuffer();
|
final buffer = StringBuffer();
|
||||||
|
|
||||||
@@ -60,6 +101,7 @@ class GeneratedClass {
|
|||||||
buffer.writeln(' @override');
|
buffer.writeln(' @override');
|
||||||
buffer.writeln(' void builder(Scope currentScope) {');
|
buffer.writeln(' void builder(Scope currentScope) {');
|
||||||
|
|
||||||
|
// For each binding, generate bind<Type>() code string.
|
||||||
// Для каждого биндинга — генерируем строку bind<Type>()...
|
// Для каждого биндинга — генерируем строку bind<Type>()...
|
||||||
for (final bind in binds) {
|
for (final bind in binds) {
|
||||||
buffer.writeln(bind.generateBind(4));
|
buffer.writeln(bind.generateBind(4));
|
||||||
|
|||||||
@@ -13,13 +13,31 @@
|
|||||||
|
|
||||||
import 'package:analyzer/dart/element/element.dart';
|
import 'package:analyzer/dart/element/element.dart';
|
||||||
|
|
||||||
|
/// ---------------------------------------------------------------------------
|
||||||
|
/// MetadataUtils -- utilities for analyzing method and parameter annotations.
|
||||||
///
|
///
|
||||||
|
/// ENGLISH
|
||||||
|
/// Provides static utility methods to analyze Dart annotations on methods or
|
||||||
|
/// parameters. For instance, helps to find if an element is annotated with
|
||||||
|
/// `@named()`, `@singleton()`, or other meta-annotations used in this DI framework.
|
||||||
|
///
|
||||||
|
/// RUSSIAN
|
||||||
/// Утилиты для разбора аннотаций методов и параметров.
|
/// Утилиты для разбора аннотаций методов и параметров.
|
||||||
/// Позволяют найти @named() и @singleton() у метода/параметра.
|
/// Позволяют находить наличие аннотаций, например, @named() и @singleton(),
|
||||||
///
|
/// у методов и параметров. Используется для анализа исходного кода при генерации.
|
||||||
|
/// ---------------------------------------------------------------------------
|
||||||
class MetadataUtils {
|
class MetadataUtils {
|
||||||
|
/// -------------------------------------------------------------------------
|
||||||
|
/// anyMeta
|
||||||
|
///
|
||||||
|
/// ENGLISH
|
||||||
|
/// Checks if any annotation in the list has a type name that contains
|
||||||
|
/// [typeName] (case insensitive).
|
||||||
|
///
|
||||||
|
/// RUSSIAN
|
||||||
/// Проверяет: есть ли среди аннотаций метка, имя которой содержит [typeName]
|
/// Проверяет: есть ли среди аннотаций метка, имя которой содержит [typeName]
|
||||||
/// (регистр не учитывается)
|
/// (регистр не учитывается).
|
||||||
|
/// -------------------------------------------------------------------------
|
||||||
static bool anyMeta(List<ElementAnnotation> meta, String typeName) {
|
static bool anyMeta(List<ElementAnnotation> meta, String typeName) {
|
||||||
return meta.any((m) =>
|
return meta.any((m) =>
|
||||||
m
|
m
|
||||||
@@ -31,8 +49,17 @@ class MetadataUtils {
|
|||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// -------------------------------------------------------------------------
|
||||||
|
/// getNamedValue
|
||||||
|
///
|
||||||
|
/// ENGLISH
|
||||||
|
/// Retrieves the value from a `@named('value')` annotation if present.
|
||||||
|
/// Returns the string value or null if not found.
|
||||||
|
///
|
||||||
|
/// RUSSIAN
|
||||||
/// Находит значение из аннотации @named('значение').
|
/// Находит значение из аннотации @named('значение').
|
||||||
/// Возвращает строку значения, если аннотация присутствует; иначе null.
|
/// Возвращает строку значения, если аннотация присутствует; иначе null.
|
||||||
|
/// -------------------------------------------------------------------------
|
||||||
static String? getNamedValue(List<ElementAnnotation> meta) {
|
static String? getNamedValue(List<ElementAnnotation> meta) {
|
||||||
for (final m in meta) {
|
for (final m in meta) {
|
||||||
final cv = m.computeConstantValue();
|
final cv = m.computeConstantValue();
|
||||||
|
|||||||
Reference in New Issue
Block a user