mirror of
https://github.com/pese-git/cherrypick.git
synced 2026-01-24 05:25:19 +00:00
feat(generator): support output_dir and build_extensions config for generated files
Now the code generator supports specifying a custom output directory and extension/name template for generated DI files via build.yaml ( and ). This allows placing all generated code in custom folders and using flexible naming schemes. docs: update all user docs and tutorials to explain new output_dir/build_extensions config - Added detailed usage and YAML examples to cherrypick_generator/README.md - Synced full_tutorial_en.md and full_tutorial_ru.md (advanced codegen section) with explanation of new configuration and impact on imports - Updated quick_start_en.md and quick_start_ru.md to mention advanced customization and point to tutorials - Added troubleshooting and tips for custom output/imports in docs
This commit is contained in:
76
cherrypick_generator/lib/cherrypick_custom_builders.dart
Normal file
76
cherrypick_generator/lib/cherrypick_custom_builders.dart
Normal file
@@ -0,0 +1,76 @@
|
||||
import 'dart:async';
|
||||
import 'package:build/build.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:source_gen/source_gen.dart';
|
||||
import 'inject_generator.dart';
|
||||
import 'module_generator.dart';
|
||||
|
||||
/// Универсальный Builder для генераторов Cherrypick с поддержкой кастомного output_dir
|
||||
/// (указывает директорию для складывания сгенерированных файлов через build.yaml)
|
||||
class CustomOutputBuilder extends Builder {
|
||||
final Generator generator;
|
||||
final String extension;
|
||||
final String outputDir;
|
||||
final Map<String, List<String>> customBuildExtensions;
|
||||
|
||||
CustomOutputBuilder(this.generator, this.extension, this.outputDir, this.customBuildExtensions);
|
||||
|
||||
@override
|
||||
Map<String, List<String>> get buildExtensions {
|
||||
if (customBuildExtensions.isNotEmpty) {
|
||||
return customBuildExtensions;
|
||||
}
|
||||
// Дефолт: рядом с исходником, как PartBuilder
|
||||
return {
|
||||
'.dart': [extension],
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> build(BuildStep buildStep) async {
|
||||
final inputId = buildStep.inputId;
|
||||
print('[CustomOutputBuilder] build() called for input: \\${inputId.path}');
|
||||
final library = await buildStep.resolver.libraryFor(inputId);
|
||||
print('[CustomOutputBuilder] resolved library for: \\${inputId.path}');
|
||||
final generated = await generator.generate(LibraryReader(library), buildStep);
|
||||
print('[CustomOutputBuilder] gen result for input: \\${inputId.path}, isNull: \\${generated == null}, isEmpty: \\${generated?.isEmpty}');
|
||||
if (generated == null || generated.isEmpty) return;
|
||||
String outputPath;
|
||||
if (customBuildExtensions.isNotEmpty) {
|
||||
// Кастомная директория/шаблон
|
||||
final inputPath = inputId.path;
|
||||
final relativeInput = p.relative(inputPath, from: 'lib/');
|
||||
final parts = p.split(relativeInput);
|
||||
String subdir = '';
|
||||
String baseName = parts.last.replaceAll('.dart', '');
|
||||
if (parts.length > 1) {
|
||||
subdir = parts.first; // Например, 'di'
|
||||
}
|
||||
outputPath = subdir.isEmpty
|
||||
? p.join('lib', 'generated', '$baseName$extension')
|
||||
: p.join('lib', 'generated', subdir, '$baseName$extension');
|
||||
} else {
|
||||
// Дефолт: рядом с исходником
|
||||
outputPath = p.setExtension(inputId.path, extension);
|
||||
}
|
||||
final outputId = AssetId(inputId.package, outputPath);
|
||||
// part of - всегда авто!
|
||||
final partOfPath = p.relative(inputId.path, from: p.dirname(outputPath));
|
||||
final codeWithPartOf = "part of '$partOfPath';\n\n$generated";
|
||||
print('[CustomOutputBuilder] writing to output: \\${outputId.path}');
|
||||
await buildStep.writeAsString(outputId, codeWithPartOf);
|
||||
print('[CustomOutputBuilder] successfully written for input: \\${inputId.path}');
|
||||
}
|
||||
}
|
||||
|
||||
Builder injectCustomBuilder(BuilderOptions options) {
|
||||
final outputDir = options.config['output_dir'] as String? ?? '';
|
||||
final buildExtensions = (options.config['build_extensions'] as Map?)?.map((k,v)=>MapEntry(k.toString(), (v as List).map((item)=>item.toString()).toList())) ?? {};
|
||||
return CustomOutputBuilder(InjectGenerator(), '.inject.cherrypick.g.dart', outputDir, buildExtensions);
|
||||
}
|
||||
|
||||
Builder moduleCustomBuilder(BuilderOptions options) {
|
||||
final outputDir = options.config['output_dir'] as String? ?? '';
|
||||
final buildExtensions = (options.config['build_extensions'] as Map?)?.map((k,v)=>MapEntry(k.toString(), (v as List).map((item)=>item.toString()).toList())) ?? {};
|
||||
return CustomOutputBuilder(ModuleGenerator(), '.module.cherrypick.g.dart', outputDir, buildExtensions);
|
||||
}
|
||||
@@ -19,6 +19,7 @@ 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;
|
||||
import 'cherrypick_custom_builders.dart' as custom;
|
||||
|
||||
/// InjectGenerator generates a mixin for a class marked with @injectable()
|
||||
/// and injects all fields annotated with @inject(), using CherryPick DI.
|
||||
@@ -204,4 +205,4 @@ class _ParsedInjectField {
|
||||
///
|
||||
/// Фабрика билдера. Используется build_runner.
|
||||
Builder injectBuilder(BuilderOptions options) =>
|
||||
PartBuilder([InjectGenerator()], '.inject.cherrypick.g.dart');
|
||||
custom.injectCustomBuilder(options);
|
||||
|
||||
@@ -15,9 +15,8 @@ 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;
|
||||
|
||||
import 'src/generated_class.dart';
|
||||
|
||||
import 'cherrypick_custom_builders.dart' as custom;
|
||||
/// ---------------------------------------------------------------------------
|
||||
/// ModuleGenerator for code generation of dependency-injected modules.
|
||||
///
|
||||
@@ -89,5 +88,8 @@ class ModuleGenerator extends GeneratorForAnnotation<ann.module> {
|
||||
/// Возвращает Builder, используемый build_runner для генерации кода для всех
|
||||
/// файлов, где встречается @module().
|
||||
/// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
Builder moduleBuilder(BuilderOptions options) =>
|
||||
PartBuilder([ModuleGenerator()], '.module.cherrypick.g.dart');
|
||||
custom.moduleCustomBuilder(options);
|
||||
Reference in New Issue
Block a user