首页 > 解决方案 > 如何为字段的注释生成 Dart 代码?

问题描述

我正在使用 为 Dart 编写代码生成器build_runner,但我的构建器不会被调用以在字段中进行注释,尽管它确实适用于类中的注释。

是否也可以在字段(或在任何地方)调用注释生成器?

例如,为以下文件调用构建器:

import 'package:my_annotation/my_annotation.dart';

part 'example.g.dart';

@MyAnnotation()
class Fruit {
  int number;
}

但不适用于这个:

import 'package:my_annotation/my_annotation.dart';

part 'example.g.dart';

class Fruit {
  @MyAnnotation()
  int number;
}

这是注解的定义:

class MyAnnotation {
  const MyAnnotation();
}

这就是生成器的定义方式。目前,它只是在被调用时中止,从而导致打印错误消息。

library my_annotation_generator;

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

Builder generateAnnotation(BuilderOptions options) =>
    SharedPartBuilder([MyAnnotationGenerator()], 'my_annotation');

class MyAnnotationGenerator extends GeneratorForAnnotation<MyAnnotation> {
  @override
  generateForAnnotatedElement(Element element, ConstantReader annotation, _) {
    throw CodeGenError('Generating code for annotation is not implemented yet.');
}

这是build.yaml配置:

targets:
  $default:
    builders:
      my_annotation_generator|my_annotation:
        enabled: true

builders:
  my_annotation:
    target: ":my_annotation_generator"
    import: "package:my_annotation/my_annotation.dart"
    builder_factories: ["generateAnnotation"]
    build_extensions: { ".dart": [".my_annotation.g.part"] }
    auto_apply: dependents
    build_to: cache
    applies_builders: ["source_gen|combining_builder"]

标签: dartbuild-runner

解决方案


至少根据我的经验,您的文件“example.dart”需要在类定义上方至少有一个注释才能由 GeneratorForAnnotation 解析。

例子.dart:

import 'package:my_annotation/my_annotation.dart';

part 'example.g.dart';

@MyAnnotation()
class Fruit {
 @MyFieldAnnotation()
 int number;
}

要访问类字段或类方法上方的注释,您可以使用访问者“访问”每个子元素并提取源代码信息。例如,要获取有关类字段的信息,您可以覆盖方法 visitFieldElement,然后使用 getter:element.metadata 访问任何注释。

builder.dart:

import 'dart:async';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/visitor.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:build/src/builder/build_step.dart';
import 'package:source_gen/source_gen.dart';
import 'package:my_annotation/my_annotation.dart';

class MyAnnotationGenerator extends 
GeneratorForAnnotation<MyAnnotation> {
  @override
  FutureOr<String> generateForAnnotatedElement(
      Element element, 
      ConstantReader annotation,   
      BuildStep buildStep,){
    return _generateSource(element);
  }

  String _generateSource(Element element) {
    var visitor = ModelVisitor();
    element.visitChildren(visitor);
    return '''
      // ${visitor.className}
      // ${visitor.fields}
      // ${visitor.metaData}
    ''';
  }
}

class ModelVisitor extends SimpleElementVisitor {
  DartType className;
  Map<String, DartType> fields = {};
  Map<String, dynamic> metaData = {};

  @override
  visitConstructorElement(ConstructorElement element) {
    className = element.type.returnType;
  }

  @override
  visitFieldElement(FieldElement element) {
    fields[element.name] = element.type;
    metaData[element.name] = element.metadata;
  }
}

注意:在本例中,_generateSource 返回一个注释语句。如果没有注释,您将需要返回格式良好的 dart 源代码,否则,构建器将因错误而终止。

有关更多信息,请参阅:源代码生成和编写自己的包(无聊的 Flutter 开发秀,第 22 集)https://www.youtube.com/watch?v=mYDFOdl-aWM&t=459s


推荐阅读