Dart build runner 生成一个包含内容的 dart 文件

Eph*_*rom 5 dart

我正在开发一个包含 200 多个模型的 dart 包,目前我必须为每个模型手动编写一行“导出”,以使使用此包的每个人都可以使用这些模型。

我希望构建运行程序生成一个包含每个导出定义的 dart 文件。

因此,我会创建一个注释“ExportModel”。构建器应搜索使用此注释注释的每个类。

我尝试创建一些构建器,但它们会为每个被注释的类生成一个 *.g.dart 文件。我只想拥有一个文件。

在哪里可以创建只运行一次并在最后创建文件的构建器?

Nat*_*sch 8

对仅运行一次并在包中创建单个文件的构建器问题的简短回答是r'$lib$'用作输入扩展名。长答案是,要找到被注释的类,您可能需要一个中间输出来跟踪它们。

我会用 2 个构建器来编写它,一个用于搜索ExportModel注释,另一个用于编写导出文件。这是一个省略了细节的粗略草图 - 我没有测试这里的任何代码,但它应该让你开始走上正确的道路。

Builder 1 - 找到用@ExportModel().

可以使用 中的一些实用程序编写package:source_gen,但不能使用,LibraryBuilder因为它不输出 Dart 代码...

目标是在.exports每个文件旁边写一个文件.dart,作为所有用@ExportModel().

class ExportLocatingBuilder implements Builder {
  @override
  final buildExtensions = const {
    '.dart': ['.exports']
  };

  @override
  Future<void> build(BuildStep buildStep) async {
    final resolver = buildStep.resolver;
    if (!await resolver.isLibrary(buildStep.inputId)) return;
    final lib = LibraryReader(await buildStep.inputLibrary);
    final exportAnnotation = TypeChecker.fromRuntime(ExportModel);
    final annotated = [
      for (var member in lib.annotatedWith(exportAnnotation)) element.name,
    ];
    if (annotated.isNotEmpty) {
      buildStep.writeAsString(
          buildStep.inputId.changeExtension('.exports'), annotated.join(','));
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这个构建器应该是build_to: cache,你可能想要PostProcessBuilder清理它产生的所有输出,这些输出将被指定为applies_builder. 您可以使用FileDeletingBuilder来廉价地实施清理。例如,请参阅有关临时输出和角度清理的常见问题解答

Builder 2 - 找到.exports文件并生成一个 Dart 文件

使用findAssets追查所有这些.exports文件,并就export为每一个语句。将 ashow与文件内容一起使用,该文件内容应包含被注释的成员的名称。

class ExportsBuilder implements Builder {
  @override
  final buildExtensions = const {
    r'$lib$': ['exports.dart']
  };

  @override
  Future<void> build(BuildStep buildStep) async {
    final exports = buildStep.findAssets(Glob('**/*.exports'));
    final content = [
      await for (var exportLibrary in exports)
        'export \'${exportLibrary.changeExtension('.dart').uri}\' '
            'show ${await buildStep.readAsString(exportLibrary)};',
    ];
    if (content.isNotEmpty) {
      buildStep.writeAsString(
          AssetId(buildStep.inputId.package, 'lib/exports.dart'),
          content.join('\n'));
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

build_to: source如果你想在 pub 上发布这个文件,这个构建器应该是。它应该有一个required_inputs: [".exports"]以确保它在前一个构建器之后运行。

为什么需要这么复杂?

可以将其实现为findAssets用于查找所有 Dart 文件的单个构建器。缺点是重建会慢得多,因为它会因任何 Dart 文件中的任何内容更改而失效,并且您最终会解析所有Dart 代码以查找任何Dart 代码中的更改。使用 2 构建器方法,则只有.exports来自更改的 Dart 文件的个体需要被解析并在更改时重建,然后只有当导出更改时,exports.dart文件才会失效。

的旧版本build_runner也不支持使用Resolver来解析不是从输入库中传递导入的代码。最近的版本build_runner已经放宽了这个限制。