mirror of
https://github.com/pese-git/cherrypick.git
synced 2026-01-24 05:25:19 +00:00
write comments to code
This commit is contained in:
@@ -3,27 +3,63 @@ import 'package:build/build.dart';
|
|||||||
import 'package:source_gen/source_gen.dart';
|
import 'package:source_gen/source_gen.dart';
|
||||||
import 'package:cherrypick_annotations/cherrypick_annotations.dart' as ann;
|
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<Dio>().toProvide(() => dio()).singleton();
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
class ModuleGenerator extends GeneratorForAnnotation<ann.module> {
|
class ModuleGenerator extends GeneratorForAnnotation<ann.module> {
|
||||||
|
/// Основной метод генерации кода для аннотированного класса-модуля.
|
||||||
|
/// [element] - класс с аннотацией @module.
|
||||||
|
/// [annotation], [buildStep] - служебные параметры build_runner.
|
||||||
|
/// Возвращает сгенерированный Dart-код класса-расширения.
|
||||||
@override
|
@override
|
||||||
String generateForAnnotatedElement(
|
String generateForAnnotatedElement(
|
||||||
Element element,
|
Element element,
|
||||||
ConstantReader annotation,
|
ConstantReader annotation,
|
||||||
BuildStep buildStep,
|
BuildStep buildStep,
|
||||||
) {
|
) {
|
||||||
|
// Убеждаемся, что аннотирован только класс (не функция, не переменная).
|
||||||
if (element is! ClassElement) {
|
if (element is! ClassElement) {
|
||||||
throw InvalidGenerationSourceError(
|
throw InvalidGenerationSourceError(
|
||||||
'@module() может быть применён только к классам.',
|
'@module() может быть применён только к классам.',
|
||||||
element: element,
|
element: element,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final classElement = element;
|
final classElement = element;
|
||||||
final className = classElement.displayName;
|
final className = classElement.displayName;
|
||||||
|
|
||||||
|
// Имя сгенерированного класса (например: $AppModule)
|
||||||
final generatedClassName = r'$' + className;
|
final generatedClassName = r'$' + className;
|
||||||
|
|
||||||
final buffer = StringBuffer();
|
final buffer = StringBuffer();
|
||||||
|
|
||||||
|
// Объявление генерируемого класса как final, который наследуется от исходного модуля
|
||||||
buffer.writeln('final class $generatedClassName extends $className {');
|
buffer.writeln('final class $generatedClassName extends $className {');
|
||||||
buffer.writeln(' @override');
|
buffer.writeln(' @override');
|
||||||
buffer.writeln(' void builder(Scope currentScope) {');
|
buffer.writeln(' void builder(Scope currentScope) {');
|
||||||
|
|
||||||
|
// Обрабатываем все НЕ-абстрактные методы модуля
|
||||||
for (final method in classElement.methods.where((m) => !m.isAbstract)) {
|
for (final method in classElement.methods.where((m) => !m.isAbstract)) {
|
||||||
|
// Проверка на наличие аннотации @singleton() у метода
|
||||||
final hasSingleton = method.metadata.any(
|
final hasSingleton = method.metadata.any(
|
||||||
(m) =>
|
(m) =>
|
||||||
m
|
m
|
||||||
@@ -34,6 +70,8 @@ class ModuleGenerator extends GeneratorForAnnotation<ann.module> {
|
|||||||
.contains('singleton') ??
|
.contains('singleton') ??
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Проверяем, есть ли у метода @named('...')
|
||||||
ElementAnnotation? namedMeta;
|
ElementAnnotation? namedMeta;
|
||||||
try {
|
try {
|
||||||
namedMeta = method.metadata.firstWhere(
|
namedMeta = method.metadata.firstWhere(
|
||||||
@@ -49,6 +87,8 @@ class ModuleGenerator extends GeneratorForAnnotation<ann.module> {
|
|||||||
} catch (_) {
|
} catch (_) {
|
||||||
namedMeta = null;
|
namedMeta = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Извлекаем значение name из @named('value')
|
||||||
String? nameArg;
|
String? nameArg;
|
||||||
if (namedMeta != null) {
|
if (namedMeta != null) {
|
||||||
final cv = namedMeta.computeConstantValue();
|
final cv = namedMeta.computeConstantValue();
|
||||||
@@ -57,8 +97,10 @@ class ModuleGenerator extends GeneratorForAnnotation<ann.module> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ЗДЕСЬ ЛОГИКА ДЛЯ ПАРАМЕТРОВ МЕТОДА
|
// Формируем список аргументов для вызова метода.
|
||||||
|
// Каждый параметр может быть с аннотацией @named, либо без.
|
||||||
final args = method.parameters.map((p) {
|
final args = method.parameters.map((p) {
|
||||||
|
// Проверяем наличие @named('value') на параметре
|
||||||
ElementAnnotation? paramNamed;
|
ElementAnnotation? paramNamed;
|
||||||
try {
|
try {
|
||||||
paramNamed = p.metadata.firstWhere(
|
paramNamed = p.metadata.firstWhere(
|
||||||
@@ -79,14 +121,17 @@ class ModuleGenerator extends GeneratorForAnnotation<ann.module> {
|
|||||||
if (paramNamed != null) {
|
if (paramNamed != null) {
|
||||||
final cv = paramNamed.computeConstantValue();
|
final cv = paramNamed.computeConstantValue();
|
||||||
final namedValue = cv?.getField('value')?.toStringValue();
|
final namedValue = cv?.getField('value')?.toStringValue();
|
||||||
|
// Если указано имя для параметра (@named), пробрасываем его в resolve
|
||||||
if (namedValue != null) {
|
if (namedValue != null) {
|
||||||
argExpr =
|
argExpr =
|
||||||
"currentScope.resolve<${p.type.getDisplayString(withNullability: false)}>(named: '$namedValue')";
|
"currentScope.resolve<${p.type.getDisplayString(withNullability: false)}>(named: '$namedValue')";
|
||||||
} else {
|
} else {
|
||||||
|
// fallback — скобки все равно нужны
|
||||||
argExpr =
|
argExpr =
|
||||||
"currentScope.resolve<${p.type.getDisplayString(withNullability: false)}>()";
|
"currentScope.resolve<${p.type.getDisplayString(withNullability: false)}>()";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Если параметр не @named - просто resolve по типу
|
||||||
argExpr =
|
argExpr =
|
||||||
"currentScope.resolve<${p.type.getDisplayString(withNullability: false)}>()";
|
"currentScope.resolve<${p.type.getDisplayString(withNullability: false)}>()";
|
||||||
}
|
}
|
||||||
@@ -96,7 +141,8 @@ class ModuleGenerator extends GeneratorForAnnotation<ann.module> {
|
|||||||
final returnType =
|
final returnType =
|
||||||
method.returnType.getDisplayString(withNullability: false);
|
method.returnType.getDisplayString(withNullability: false);
|
||||||
final methodName = method.displayName;
|
final methodName = method.displayName;
|
||||||
// С переносом строки, если есть параметры
|
|
||||||
|
// Если список параметров длинный — переносим вызов на новую строку для читаемости.
|
||||||
final hasLongArgs = args.length > 60 || args.contains('\n');
|
final hasLongArgs = args.length > 60 || args.contains('\n');
|
||||||
if (hasLongArgs) {
|
if (hasLongArgs) {
|
||||||
buffer.write(' bind<$returnType>()\n'
|
buffer.write(' bind<$returnType>()\n'
|
||||||
@@ -105,14 +151,17 @@ class ModuleGenerator extends GeneratorForAnnotation<ann.module> {
|
|||||||
buffer.write(' bind<$returnType>()'
|
buffer.write(' bind<$returnType>()'
|
||||||
'.toProvide(() => $methodName($args))');
|
'.toProvide(() => $methodName($args))');
|
||||||
}
|
}
|
||||||
|
// Применяем имя биндера если есть @named
|
||||||
if (nameArg != null) {
|
if (nameArg != null) {
|
||||||
buffer.write(".withName('$nameArg')");
|
buffer.write(".withName('$nameArg')");
|
||||||
}
|
}
|
||||||
|
// Применяем singleton если был @singleton
|
||||||
if (hasSingleton) {
|
if (hasSingleton) {
|
||||||
buffer.write('.singleton()');
|
buffer.write('.singleton()');
|
||||||
}
|
}
|
||||||
buffer.write(';\n');
|
buffer.write(';\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.writeln(' }');
|
buffer.writeln(' }');
|
||||||
buffer.writeln('}');
|
buffer.writeln('}');
|
||||||
|
|
||||||
@@ -120,5 +169,7 @@ class ModuleGenerator extends GeneratorForAnnotation<ann.module> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Фабрика Builder-го класса для build_runner
|
||||||
|
/// Производит .cherrypick.g.dart файл для каждого модуля.
|
||||||
Builder moduleBuilder(BuilderOptions options) =>
|
Builder moduleBuilder(BuilderOptions options) =>
|
||||||
PartBuilder([ModuleGenerator()], '.cherrypick.g.dart');
|
PartBuilder([ModuleGenerator()], '.cherrypick.g.dart');
|
||||||
|
|||||||
Reference in New Issue
Block a user