generateForAnnotatedElement method

  1. @override
Future<String?> generateForAnnotatedElement(
  1. Element element,
  2. ConstantReader constantReader,
  3. BuildStep buildStep
)

Implement to return source code to generate for element.

This method is invoked based on finding elements annotated with an instance of T. The annotation is provided as a ConstantReader.

Supported return values include a single String or multiple String instances within an Iterable or Stream. It is also valid to return a Future of String, Iterable, or Stream.

Implementations should return null when no content is generated. Empty or whitespace-only String instances are also ignored.

Implementation

@override
Future<String?> generateForAnnotatedElement(Element element,
    ConstantReader constantReader, BuildStep buildStep) async {
  if (element is FunctionElement) {
    return 'const ${element.name}FunctionMirror = ${_renderFunction(element)};';
  }

  if (element is EnumElement) {
    return "const ${element.name}ClassMirror = ClassMirror("
        "name: '${element.name}',"
        "isEnum: true,"
        "values: ${element.name}.values);";
  }

  if (element is ClassElement) {
    var superTypes =
        element.allSupertypes.where((st) => !{'Object', 'SerializableMap', 'Map'}.contains(st.element.name));
    var stAccessors = superTypes.expand((st) => st.accessors);
    var stMethods = superTypes.expand((st) => st.methods);
    var stFields = superTypes.expand((st) => st.element.fields);

    var constructors = element.constructors;
    var className = element.name;

    var elementFields = <FieldElement>[]
      ..addAll(element.fields.toList())
      ..addAll(stFields);
    var fields = _distinctByName(elementFields);

    var accessors = _distinctByName([...element.accessors, ...stAccessors]);
    var getters =
        _distinctByName(accessors.where((a) => a.kind == ElementKind.GETTER));
    var setters =
        _distinctByName(accessors.where((a) => a.kind == ElementKind.SETTER));
    var methods = _distinctByName([...element.methods, ...stMethods]);

    return '''${element.isAbstract ? '' : constructors.map((c) => '_${className}_${c.name}_Constructor([positionalParams, namedParams]) =>'
            '${className}${c.name.isEmpty ? '' : '.${c.name}'}(${_renderConstructorParametersCall(c)});\n').join('')}

${element.fields.map(_renderFieldsDeclarations).join('\n')}

const ${className}ClassMirror = ClassMirror(
name: '${element.name}',
${[
      element.isAbstract
          ? ''
          : '''constructors: {
        ${constructors.map((c) => "'${c.name}': FunctionMirror("
              "name: '${c.name}',"
              "${_renderPositionalParameters(c.parameters)}"
              "${_renderNamedParameters(c.parameters)}"
              "\$call: _${className}_${c.name}_Constructor)").join(',')}
        }''',
      _renderMetadata(element.metadata),
      fields.where((x) => !x.isStatic).isNotEmpty
          ? 'fields: {${fields.where((x) => !x.isStatic).map(_renderFields).join(',')}}'
          : '',
      getters.where((x) => !x.isStatic).isNotEmpty
          ? 'getters: [${getters.where((x) => !x.isStatic).map((g) => "'${_getSerializedNameFromAccessor(g)}'").join(',')}]'
          : '',
      setters.where((x) => !x.isStatic).isNotEmpty
          ? 'setters: [${setters.where((x) => !x.isStatic).map((s) => "'${_getSerializedNameFromAccessor(s)}'").join(',')}]'
          : '',
      methods.where((x) => !x.isStatic).isNotEmpty
          ? 'methods: {${methods.where((x) => !x.isStatic).map(_renderMethods).join(',')}}'
          : '',
      element.isAbstract ? 'isAbstract: true' : '',
      element.supertype?.getDisplayString(withNullability: false) != 'Object'
          ? 'superclass: ${element.supertype?.element.name}'
          : '',
      element.interfaces.isNotEmpty
          ? 'superinterfaces: [${element.interfaces.map((i) => i.element.name).join(',')}]'
          : ''
    ].fold('', _combine)}
);''';
  }
  return null;
}