From 7bad0c09c0b59e8c552309d6b90831ae28ec911f Mon Sep 17 00:00:00 2001 From: Sergey Penkovsky Date: Sat, 17 May 2025 22:29:37 +0300 Subject: [PATCH] write comments to code --- .../lib/module_generator.dart | 55 ++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/cherrypick_generator/lib/module_generator.dart b/cherrypick_generator/lib/module_generator.dart index 2021264..9ac5bed 100644 --- a/cherrypick_generator/lib/module_generator.dart +++ b/cherrypick_generator/lib/module_generator.dart @@ -3,27 +3,63 @@ import 'package:build/build.dart'; import 'package:source_gen/source_gen.dart'; import 'package:cherrypick_annotations/cherrypick_annotations.dart' as ann; +/// Генератор DI-модулей для фреймворка cherrypick. +/// Генерирует расширение для класса с аннотацией @module, +/// автоматически создавая биндинги для зависимостей, определённых в модуле. +/// +/// Пример: +/// ```dart +/// @module() +/// abstract class AppModule extends Module { +/// @singleton() +/// Dio dio() => Dio(); +/// } +/// ``` +/// +/// Сгенерирует код: +/// ```dart +/// final class $AppModule extends AppModule { +/// @override +/// void builder(Scope currentScope) { +/// bind().toProvide(() => dio()).singleton(); +/// } +/// } +/// ``` class ModuleGenerator extends GeneratorForAnnotation { + /// Основной метод генерации кода для аннотированного класса-модуля. + /// [element] - класс с аннотацией @module. + /// [annotation], [buildStep] - служебные параметры build_runner. + /// Возвращает сгенерированный Dart-код класса-расширения. @override String generateForAnnotatedElement( Element element, ConstantReader annotation, BuildStep buildStep, ) { + // Убеждаемся, что аннотирован только класс (не функция, не переменная). if (element is! ClassElement) { throw InvalidGenerationSourceError( '@module() может быть применён только к классам.', element: element, ); } + final classElement = element; final className = classElement.displayName; + + // Имя сгенерированного класса (например: $AppModule) final generatedClassName = r'$' + className; + final buffer = StringBuffer(); + + // Объявление генерируемого класса как final, который наследуется от исходного модуля buffer.writeln('final class $generatedClassName extends $className {'); buffer.writeln(' @override'); buffer.writeln(' void builder(Scope currentScope) {'); + + // Обрабатываем все НЕ-абстрактные методы модуля for (final method in classElement.methods.where((m) => !m.isAbstract)) { + // Проверка на наличие аннотации @singleton() у метода final hasSingleton = method.metadata.any( (m) => m @@ -34,6 +70,8 @@ class ModuleGenerator extends GeneratorForAnnotation { .contains('singleton') ?? false, ); + + // Проверяем, есть ли у метода @named('...') ElementAnnotation? namedMeta; try { namedMeta = method.metadata.firstWhere( @@ -49,6 +87,8 @@ class ModuleGenerator extends GeneratorForAnnotation { } catch (_) { namedMeta = null; } + + // Извлекаем значение name из @named('value') String? nameArg; if (namedMeta != null) { final cv = namedMeta.computeConstantValue(); @@ -57,8 +97,10 @@ class ModuleGenerator extends GeneratorForAnnotation { } } - // ЗДЕСЬ ЛОГИКА ДЛЯ ПАРАМЕТРОВ МЕТОДА + // Формируем список аргументов для вызова метода. + // Каждый параметр может быть с аннотацией @named, либо без. final args = method.parameters.map((p) { + // Проверяем наличие @named('value') на параметре ElementAnnotation? paramNamed; try { paramNamed = p.metadata.firstWhere( @@ -79,14 +121,17 @@ class ModuleGenerator extends GeneratorForAnnotation { if (paramNamed != null) { final cv = paramNamed.computeConstantValue(); final namedValue = cv?.getField('value')?.toStringValue(); + // Если указано имя для параметра (@named), пробрасываем его в resolve if (namedValue != null) { argExpr = "currentScope.resolve<${p.type.getDisplayString(withNullability: false)}>(named: '$namedValue')"; } else { + // fallback — скобки все равно нужны argExpr = "currentScope.resolve<${p.type.getDisplayString(withNullability: false)}>()"; } } else { + // Если параметр не @named - просто resolve по типу argExpr = "currentScope.resolve<${p.type.getDisplayString(withNullability: false)}>()"; } @@ -96,7 +141,8 @@ class ModuleGenerator extends GeneratorForAnnotation { final returnType = method.returnType.getDisplayString(withNullability: false); final methodName = method.displayName; - // С переносом строки, если есть параметры + + // Если список параметров длинный — переносим вызов на новую строку для читаемости. final hasLongArgs = args.length > 60 || args.contains('\n'); if (hasLongArgs) { buffer.write(' bind<$returnType>()\n' @@ -105,14 +151,17 @@ class ModuleGenerator extends GeneratorForAnnotation { buffer.write(' bind<$returnType>()' '.toProvide(() => $methodName($args))'); } + // Применяем имя биндера если есть @named if (nameArg != null) { buffer.write(".withName('$nameArg')"); } + // Применяем singleton если был @singleton if (hasSingleton) { buffer.write('.singleton()'); } buffer.write(';\n'); } + buffer.writeln(' }'); buffer.writeln('}'); @@ -120,5 +169,7 @@ class ModuleGenerator extends GeneratorForAnnotation { } } +/// Фабрика Builder-го класса для build_runner +/// Производит .cherrypick.g.dart файл для каждого модуля. Builder moduleBuilder(BuilderOptions options) => PartBuilder([ModuleGenerator()], '.cherrypick.g.dart');