structurizeConstructor function

Future<StructurizeResult> structurizeConstructor(
  1. DartType type,
  2. DogsGeneratorSettings settings,
  3. ConstructorElement2 constructorElement,
  4. SubjectGenContext<Element2> context,
  5. CachedAliasCounter counter,
)

Implementation

Future<StructurizeResult> structurizeConstructor(
    DartType type,
    DogsGeneratorSettings settings,
    ConstructorElement2 constructorElement,
    SubjectGenContext<Element2> context,
    CachedAliasCounter counter) async {
  List<AliasImport> imports = [];
  List<IRStructureField> fields = [];
  var element = type.element3! as ClassElement2;
  var serialName = element.displayName;
  serialName = settings.nameCase.recase(serialName);

  // Check for Serializable annotation and override serialName if applicable
  if (serializableChecker.hasAnnotationOf(element)) {
    var annotation = serializableChecker.annotationsOf(element).first;
    var overrideName = annotation.getField("serialName")?.toStringValue();
    if (overrideName != null) {
      serialName = overrideName;
    }
  }

  // Determine used constructor
  var constructorName = "";
  if (element.getNamedConstructor2("dog") != null) {
    constructorElement = element.getNamedConstructor2("dog")!;
    constructorName = ".dog";
  }

  for (var e in constructorElement.formalParameters) {
    String? fieldName;
    DartType? fieldType;
    Element2? fieldElement;

    if (e is FieldFormalParameterElement2) {
      fieldName = e.displayName;
      fieldType = e.type;
      fieldElement = e.field2;
    } else if (e is SuperFormalParameterElement2) {
      FieldFormalParameterElement2 resolveUntilFieldFormal(FormalParameterElement e) {
        if (e is FieldFormalParameterElement2) return e;
        if (e is SuperFormalParameterElement2) {
          return resolveUntilFieldFormal(e.superConstructorParameter2!);
        }
        throw Exception("Can't resolve super formal field");
      }

      var field = resolveUntilFieldFormal(e.superConstructorParameter2!).field2;
      fieldName = field!.displayName;
      fieldType = field.type;
      fieldElement = field;
    } else {
      var parameterType = e.type;
      var namedField = element.getField2(e.displayName);
      var namedGetter = element.lookUpGetter2(name: e.displayName, library: element.library2);
      if (namedField != null && namedGetter == null) {
        fieldName = e.displayName;
        fieldType = namedField.type;
        fieldElement = namedField;
        if (parameterType.nullabilitySuffix == NullabilitySuffix.question) {
          fieldType = parameterType;
        }
      } else {
        if (namedGetter != null) {
          fieldName = e.displayName;
          fieldType = namedGetter.returnType;
          fieldElement = namedGetter;
          if (parameterType.nullabilitySuffix == NullabilitySuffix.question) {
            fieldType = parameterType;
          }
        }
      }
    }
    if (fieldElement == null || fieldName == null || fieldType == null) {
      throw Exception(
          "Constructor fields must have a backing field or getter with the same name and type. Nullability may vary.");
    }
    var serialType = await getSerialType(fieldType, context);
    var iterableType = await getIterableType(fieldType, context);

    var optional = fieldType.nullabilitySuffix == NullabilitySuffix.question;
    if (fieldType is DynamicType) optional = true;

    var propertyName = fieldName;
    propertyName = settings.propertyCase.recase(propertyName);

    if (propertyNameChecker.hasAnnotationOf(fieldElement)) {
      var annotation = propertyNameChecker.annotationsOf(fieldElement).first;
      propertyName = annotation.getField("name")!.toStringValue()!;
    }

    var propertySerializer = "null";
    if (propertySerializerChecker.hasAnnotationOf(fieldElement)) {
      var serializerAnnotation = propertySerializerChecker.annotationsOf(fieldElement).first;
      propertySerializer = counter.get(serializerAnnotation.getField("type")!.toTypeValue()!);
    }

    fields.add(IRStructureField(
        fieldName,
        counter.get(fieldType),
        getTypeTree(fieldType).code(counter),
        propertySerializer,
        counter.get(serialType),
        iterableType,
        propertyName,
        optional,
        !isDogPrimitiveType(serialType),
        getRetainedAnnotationSourceArray(fieldElement, counter),
        mapChecker.isAssignableFrom(fieldType.element3!)));
  }

  // Create proxy arguments
  var getters = fields.map((e) => e.accessor).toList();
  var activator =
      "return ${counter.get(element.thisType)}$constructorName(${constructorElement.formalParameters.mapIndexed((i, e) {
    if (e.isNamed) {
      return "${e.displayName}: list[$i]";
    } else {
      return "list[$i]";
    }
  }).join(", ")});";
  var isDataclass = dataclassChecker.isAssignableFromType(element.thisType);
  var structure = IRStructure(
      counter.get(type),
      isDataclass ? StructureConformity.dataclass : StructureConformity.basic,
      serialName,
      fields,
      getRetainedAnnotationSourceArray(element, counter));
  return StructurizeResult(imports, structure, getters, activator);
}