使用dart中的source_gen为解析文件列表生成一个文件

时间:2017-05-10 20:45:32

标签: dart

我有一个模型列表,我需要创建一个迷你反射系统 我分析了Serializable包,并了解了如何为每个文件创建一个生成的文件,但是,我无法找到如何为大量文件创建一个文件。

那么,如何使用source_gen动态生成一个文件列表?

例:
文件
user.dart
category.dart

生成的


info.dart(包含来自user.dart和category.dart的信息)

2 个答案:

答案 0 :(得分:2)

在Gitter的帮助下找到了如何做到这一点 您必须有一个文件,即使是空的,也可以调用生成器。在我的例子中,它是lib / batch.dart。

source_gen:^ 0.5.8

以下是工作代码:

工具/ build.dart

import 'package:build_runner/build_runner.dart';
import 'package:raoni_global/phase.dart';

main() async {
  PhaseGroup pg = new PhaseGroup()
    ..addPhase(batchModelablePhase(const ['lib/batch.dart']));

  await build(pg,
      deleteFilesByDefault: true);
}

阶段:

batchModelablePhase([Iterable<String> globs =
const ['bin/**.dart', 'web/**.dart', 'lib/**.dart']]) {
  return new Phase()
    ..addAction(
        new GeneratorBuilder(const
        [const BatchGenerator()], isStandalone: true
        ),
        new InputSet(new PackageGraph.forThisPackage().root.name, globs));
}

发电机:

import 'dart:async';

import 'package:analyzer/dart/element/element.dart';
import 'package:build/build.dart';
import 'package:source_gen/source_gen.dart';
import 'package:glob/glob.dart';
import 'package:build_runner/build_runner.dart';

class BatchGenerator extends Generator {
  final String path;

  const BatchGenerator({this.path: 'lib/models/*.dart'});

  @override
  Future<String> generate(Element element, BuildStep buildStep) async {
    // this makes sure we parse one time only
    if (element is! LibraryElement)
      return null;

    String libraryName = 'raoni_global', filePath = 'lib/src/model.dart';
    String className = 'Modelable';

    // find the files at the path designed
    var l = buildStep.findAssets(new Glob(path));

    // get the type of annotation that we will use to search classes
    var resolver = await buildStep.resolver;
    var assetWithAnnotationClass = new AssetId(libraryName, filePath);
    var annotationLibrary = resolver.getLibrary(assetWithAnnotationClass);
    var exposed = annotationLibrary.getType(className).type;

    // the caller library' name
    String libName = new PackageGraph.forThisPackage().root.name;

    await Future.forEach(l.toList(), (AssetId aid) async {
      LibraryElement lib;

      try {
        lib = resolver.getLibrary(aid);
      } catch (e) {}

      if (lib != null && Utils.isNotEmpty(lib.name)) {
        // all objects within the file
        lib.units.forEach((CompilationUnitElement unit) {
          // only the types, not methods
          unit.types.forEach((ClassElement el) {
            // only the ones annotated
            if (el.metadata.any((ElementAnnotation ea) =>
            ea.computeConstantValue().type == exposed)) {
              // use it
            }
          });
        });
      }
    });

    return '''
       $libName
    ''';
  }
}

答案 1 :(得分:-2)

[Günter]的回答对我有所帮助。
埋在该线程中的是另一个线程,该线程链接到聚合构建器的一个很好的示例: 1 https://github.com/matanlurey/build/blob/147083da9b6a6c70c46eb910a3e046239a2a0a6e/docs/writing_an_aggregate_builder.md

要点是:

import 'package:build/build.dart';
import 'package:glob/glob.dart';

class AggregatingBuilder implements Builder {
  /// Glob of all input files
  static final inputFiles = new Glob('lib/**');

  @override
  Map<String, List<String>> get buildExtensions {
    /// '$lib$' is a synthetic input that is used to 
    /// force the builder to build only once.
    return const {'\$lib$': const ['all_files.txt']};
  }

  @override
  Future<void> build(BuildStep buildStep) async {

    /// Do some operation on the files
    final files = <String>[];
    await for (final input in buildStep.findAssets(inputFiles)) {
      files.add(input.path);
    }
    String fileContent = files.join('\n');

    /// Write to the file
    final outputFile = AssetId(buildStep.inputId.package,'lib/all_files.txt');
    return buildStep.writeAsString(outputFile, fileContent);
  }
}