Dart构建运行器生成一个包含内容的Dart文件

时间:2019-07-10 14:23:28

标签: dart

我正在处理一个包含200多个模型的dart程序包,此刻,我必须为每个模型手动编写一行“导出”,以使使用该程序包的每个人都可以使用这些模型。

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

因此,我将创建一个注释“ ExportModel”。构建器应搜索每个带有此注释的类。

我尝试创建一些生成器,但是它们将为每个带注释的类生成一个* .g.dart文件。我只想要一个文件。

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

1 个答案:

答案 0 :(得分:0)

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

我要用2个构建器编写该文件,一个用于搜索ExportModel批注,另一个用于编写导出文件。这是一个粗略的草图,其中省略了细节-我在这里没有测试任何代码,但是它应该可以帮助您开始正确的道路。

构建器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(','));
    }
  }
}

此构建器应为build_to: cache,并且您可能希望拥有一个PostProcessBuilder来清理其产生的所有输出,这些输出将用applies_builder指定。您可以使用FileDeletingBuilder廉价地执行清理。有关临时输出,请参见the FAQ,例如,请参见angular cleanup

Builder 2-查找.exports文件并生成Dart文件

使用findAssets来跟踪所有这些.exports文件,并为每个文件编写一个export语句。在文件内容中使用show,其中应包含被注释成员的名称。

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'));
    }
  }
}

如果您想将此文件发布在pub上,则此构建器可能应该为build_to: source。它应该有一个required_inputs: [".exports"]以确保它在先前的构建器之后运行。

为什么需要这么复杂?

可以将其实现为使用findAssets查找所有Dart文件的单个生成器。缺点是:

  • 由于analyzer不起作用,您需要使用Resolver API直接解析此代码-解析器仅在主要输入是Dart库时才起作用,然后仅对Dart库起作用。从该库中导入的代码。
  • 重建会慢得多,因为任何Dart文件中的任何内容更改都将使重建无效,并且您最终将解析 all Dart代码以更改 any Dart代码。使用2构建器方法时,仅需要解析来自更改后的Dart文件的单个.exports并根据更改进行重建,然后只有导出更改时exports.dart文件才会失效。 / li>