generateForAnnotatedElement method

  1. @override
dynamic generateForAnnotatedElement(
  1. Element element,
  2. ConstantReader annotation,
  3. BuildStep buildStep,
  4. List<ClassElement> allClasses,
)

Implementation

@override
dynamic generateForAnnotatedElement(
  Element element,
  ConstantReader annotation,
  BuildStep buildStep,
  List<ClassElement> allClasses,
) {
  var sb = StringBuffer();

  if (element is! ClassElement) {
    throw Exception("not a class");
  }

  var classElement = element;
  var className = classElement.name ?? "";
  _allAnnotatedClasses[className] = classElement;

  var hasConstConstructor = classElement.constructors.any((e) => e.isConst);
  var nonSealed = annotation.read('nonSealed').boolValue;
  var isAbstract = className.startsWith("\$\$") && !nonSealed;

  if (classElement.supertype?.element.name != "Object") {
    throw Exception("you must use implements, not extends");
  }

  var docComment = classElement.documentationComment;

  var allInterfaces = <InterfaceType>[];
  var processedInterfaces = <String>{};

  void addInterface(InterfaceType interface) {
    var interfaceName = interface.element.name ?? "";
    if (interfaceName == "Object" || interfaceName == "Enum") return;
    if (processedInterfaces.contains(interfaceName)) return;
    processedInterfaces.add(interfaceName);
    allInterfaces.add(interface);

    for (var supertype in interface.element.allSupertypes) {
      addInterface(supertype);
    }
  }

  for (var supertype in classElement.allSupertypes) {
    addInterface(supertype);
  }

  var interfaces = allInterfaces.map((e) {
    var interfaceName = e.element.name ?? "";
    var implementedName = interfaceName.startsWith("\$\$")
        ? interfaceName.replaceAll("\$\$", "")
        : interfaceName.replaceAll("\$", "");

    return InterfaceWithComment(
      implementedName,
      e.typeArguments.map(typeToString).toList(),
      e.element.typeParameters.map((x) => x.name ?? "").toList(),
      e.element.fields
          .map((f) => NameType(f.name ?? "", typeToString(f.type)))
          .toList(),
      comment: e.element.documentationComment,
      isSealed: interfaceName.startsWith("\$\$"),
      hidePublicConstructor: false,
    );
  }).toList();

  var allFields = getAllFieldsIncludingSubtypes(classElement);
  var allFieldsDistinct = getDistinctFields(allFields, interfaces);

  var classGenerics = classElement.typeParameters.map((e) {
    final bound = e.bound;
    return NameTypeClassComment(
      e.name ?? "",
      bound == null ? null : typeToString(bound),
      null,
    );
  }).toList();

  var typesExplicit = <Interface>[];
  if (!annotation.read('explicitSubTypes').isNull) {
    typesExplicit = annotation.read('explicitSubTypes').listValue.map((x) {
      var typeValue = x.toTypeValue();
      if (typeValue?.element is! ClassElement) {
        throw Exception("each type for the copywith def must all be classes");
      }

      var el = typeValue!.element as ClassElement;
      _allAnnotatedClasses[el.name ?? ""] = el;

      var fields = getAllFieldsIncludingSubtypes(
        el,
      ).where((f) => f.name != "hashCode").toList();
      var nameTypeFields = fields
          .map((f) => NameType(f.name, f.type ?? ""))
          .toList();

      return Interface.fromGenerics(
        el.name ?? "",
        el.typeParameters.map((tp) {
          final bound = tp.bound;
          return NameType(
            tp.name ?? "",
            bound == null ? null : typeToString(bound),
          );
        }).toList(),
        nameTypeFields,
        true,
      );
    }).toList();
  }

  var allValueTInterfaces = allInterfaces
      .map((e) {
        var interfaceName = e.element.name ?? "";
        var fields = getAllFieldsIncludingSubtypes(
          e.element as ClassElement,
        ).where((f) => f.name != "hashCode").toList();
        var nameTypeFields = fields
            .map((f) => NameType(f.name, f.type ?? ""))
            .toList();
        return Interface.fromGenerics(
          interfaceName.startsWith("\$\$")
              ? interfaceName.replaceAll("\$\$", "")
              : interfaceName.replaceAll("\$", ""),
          e.typeArguments.asMap().entries.map((entry) {
            final index = entry.key;
            final typeArg = entry.value;
            final paramName = e.element.typeParameters.length > index
                ? e.element.typeParameters[index].name ??
                      "T" + index.toString()
                : "T" + index.toString();
            return NameType(paramName, typeToString(typeArg));
          }).toList(),
          nameTypeFields,
          false,
          interfaceName.startsWith("\$\$"),
          false,
        );
      })
      .cast<Interface>()
      .toList();

  sb.writeln(
    createZorphy(
      isAbstract,
      allFieldsDistinct,
      className,
      docComment ?? "",
      interfaces,
      allValueTInterfaces,
      classGenerics,
      hasConstConstructor,
      annotation.read('generateJson').boolValue,
      annotation.read('hidePublicConstructor').boolValue,
      typesExplicit,
      nonSealed,
      annotation.read('explicitToJson').boolValue,
      annotation.read('generateCompareTo').boolValue,
      annotation.read('generateCopyWithFn').boolValue,
      [],
      _allAnnotatedClasses,
      {}, // ownFields - empty for builder2
    ),
  );

  return sb.toString();
}