Files
cherrypick/cherrypick_generator/lib/module_generator.dart
2025-05-19 16:12:45 +03:00

125 lines
4.1 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:analyzer/dart/element/element.dart';
import 'package:build/build.dart';
import 'package:source_gen/source_gen.dart';
import 'package:cherrypick_annotations/cherrypick_annotations.dart' as ann;
class ModuleGenerator extends GeneratorForAnnotation<ann.module> {
@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;
final generatedClassName = r'$' + className;
final buffer = StringBuffer();
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)) {
final hasSingleton = method.metadata.any(
(m) =>
m
.computeConstantValue()
?.type
?.getDisplayString(withNullability: false)
.toLowerCase()
.contains('singleton') ??
false,
);
ElementAnnotation? namedMeta;
try {
namedMeta = method.metadata.firstWhere(
(m) =>
m
.computeConstantValue()
?.type
?.getDisplayString(withNullability: false)
.toLowerCase()
.contains('named') ??
false,
);
} catch (_) {
namedMeta = null;
}
String? nameArg;
if (namedMeta != null) {
final cv = namedMeta.computeConstantValue();
if (cv != null) {
nameArg = cv.getField('value')?.toStringValue();
}
}
// ЗДЕСЬ ЛОГИКА ДЛЯ ПАРАМЕТРОВ МЕТОДА
final args = method.parameters.map((p) {
ElementAnnotation? paramNamed;
try {
paramNamed = p.metadata.firstWhere(
(m) =>
m
.computeConstantValue()
?.type
?.getDisplayString(withNullability: false)
.toLowerCase()
.contains('named') ??
false,
);
} catch (_) {
paramNamed = null;
}
String argExpr;
if (paramNamed != null) {
final cv = paramNamed.computeConstantValue();
final namedValue = cv?.getField('value')?.toStringValue();
if (namedValue != null) {
argExpr =
"currentScope.resolve<${p.type.getDisplayString(withNullability: false)}>(named: '$namedValue')";
} else {
argExpr =
"currentScope.resolve<${p.type.getDisplayString(withNullability: false)}>()";
}
} else {
argExpr =
"currentScope.resolve<${p.type.getDisplayString(withNullability: false)}>()";
}
return argExpr;
}).join(', ');
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'
' .toProvide(\n () => $methodName($args))');
} else {
buffer.write(' bind<$returnType>()'
'.toProvide(() => $methodName($args))');
}
if (nameArg != null) {
buffer.write(".withName('$nameArg')");
}
if (hasSingleton) {
buffer.write('.singleton()');
}
buffer.write(';\n');
}
buffer.writeln(' }');
buffer.writeln('}');
return buffer.toString();
}
}
Builder moduleBuilder(BuilderOptions options) =>
PartBuilder([ModuleGenerator()], '.cherrypick.g.dart');