Files
cherrypick/cherrypick_generator/lib/inject_generator.dart

85 lines
2.8 KiB
Dart
Raw Normal View History

2025-05-23 12:21:23 +03:00
import 'dart:async';
2025-05-23 14:08:08 +03:00
import 'package:analyzer/dart/constant/value.dart';
2025-05-23 15:26:09 +03:00
import 'package:analyzer/dart/element/type.dart';
2025-05-23 12:21:23 +03:00
import 'package:build/build.dart';
import 'package:source_gen/source_gen.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:cherrypick_annotations/cherrypick_annotations.dart' as ann;
class InjectGenerator extends GeneratorForAnnotation<ann.injectable> {
const InjectGenerator();
@override
FutureOr<String> generateForAnnotatedElement(
Element element, ConstantReader annotation, BuildStep buildStep) {
if (element is! ClassElement) {
throw InvalidGenerationSourceError(
'@injectable() can only be applied to classes.',
element: element,
);
}
final classElement = element;
final className = classElement.name;
final mixinName = '_\$$className';
final injectedFields = classElement.fields.where((field) => field.metadata
.any((m) =>
m.computeConstantValue()?.type?.getDisplayString() == 'inject'));
final buffer = StringBuffer();
buffer.writeln('mixin $mixinName {');
buffer.writeln(' void _inject($className instance) {');
for (final field in injectedFields) {
2025-05-23 14:08:08 +03:00
String? scopeName;
String? namedValue;
for (final m in field.metadata) {
final DartObject? obj = m.computeConstantValue();
final type = obj?.type?.getDisplayString();
if (type == 'scope') {
scopeName = obj?.getField('name')?.toStringValue();
} else if (type == 'named') {
namedValue = obj?.getField('value')?.toStringValue();
2025-05-23 12:21:23 +03:00
}
}
2025-05-23 14:08:08 +03:00
2025-05-23 15:26:09 +03:00
// --- Фикс: определяем resolveAsync для Future<T> ---
final DartType type = field.type;
String genericType;
String resolveMethod;
2025-05-23 14:08:08 +03:00
2025-05-23 15:26:09 +03:00
if (type.isDartAsyncFuture) {
// Если поле Future<T>
final typeArg = (type as ParameterizedType).typeArguments.first;
genericType = typeArg.getDisplayString();
resolveMethod = 'resolveAsync<$genericType>';
} else {
genericType = type.getDisplayString();
resolveMethod = 'resolve<$genericType>';
}
// Вызываем openScope или openRootScope
2025-05-23 14:08:08 +03:00
String accessor = (scopeName != null && scopeName.isNotEmpty)
2025-05-23 15:26:09 +03:00
? "CherryPick.openScope(scopeName: '$scopeName').$resolveMethod"
: "CherryPick.openRootScope().$resolveMethod";
2025-05-23 14:08:08 +03:00
2025-05-23 15:26:09 +03:00
// Аргументы resolve
2025-05-23 14:08:08 +03:00
String params = (namedValue != null && namedValue.isNotEmpty)
? "(named: '$namedValue')"
: '()';
2025-05-23 15:26:09 +03:00
buffer.writeln(" instance.${field.name} = $accessor$params;");
2025-05-23 12:21:23 +03:00
}
buffer.writeln(' }');
buffer.writeln('}');
return buffer.toString();
}
}
Builder injectBuilder(BuilderOptions options) =>
PartBuilder([InjectGenerator()], '.inject.cherrypick.g.dart');