addFieldMethodPart static method

Future<CompiledFieldMethodPart?> addFieldMethodPart(
  1. TypeInfo type,
  2. MethodElement compiledMethod,
  3. MethodElement fieldMethodPart,
  4. FieldElement field,
  5. String thisReplace,
)

analyse fieldMethodPart if fits compiledMethod

Implementation

static Future<CompiledFieldMethodPart?> addFieldMethodPart(
  TypeInfo type,
  MethodElement compiledMethod,
  MethodElement fieldMethodPart,
  FieldElement field,
  String thisReplace,
) async {
  FormalParameterFragment fieldParameter = fieldMethodPart
      .firstFragment
      .formalParameters
      .where((element) => element.name == 'field')
      .first;

  if (!type.typeMap.typeSystem.isSubtypeOf(
        field.type,
        fieldParameter.element.type,
      ) ||
      //dynamic is nullable but returns empty suffix
      !(fieldParameter.element.type is DynamicType ||
          field.type.nullabilitySuffix ==
              fieldParameter.element.type.nullabilitySuffix)) {
    return null;
  }

  String? requireAnnotation;
  for (var m in fieldMethodPart.metadata.annotations) {
    if (m.toSource().startsWith('@AnnotatedWith(')) {
      requireAnnotation =
          '@${m.toSource().substring(15, m.toSource().length - 1)}';
    }
  }

  if (requireAnnotation != null) {
    bool pass = false;
    for (var m in field.metadata.annotations) {
      //support for parametrised required annotations
      if (m.toSource() == requireAnnotation ||
          m.toSource().startsWith('$requireAnnotation('))
        pass = true;
    }
    if (!pass) return null;
  }

  var enclosingType = (field.enclosingElement is ClassElement)
      ? type.typeMap.fromDartType(
          (field.enclosingElement as ClassElement).thisType,
          context: type.typeArgumentsMap(),
        )
      : (field.enclosingElement is MixinElement)
      ? type.typeMap.fromDartType(
          (field.enclosingElement as MixinElement).thisType,
          context: type.typeArgumentsMap(),
        )
      : null;

  if (enclosingType == null) {
    return null;
  }
  CompiledFieldMethodPart compiledPart;
  if (!type.typeMap.compiledMethodsByType[compiledMethod]!.containsKey(
    enclosingType.uniqueName,
  )) {
    type.typeMap.compiledMethodsByType[compiledMethod]![enclosingType
        .uniqueName] = compiledPart = CompiledFieldMethodPart(
      type.typeMap,
      compiledMethod,
      enclosingType,
    );
  } else {
    compiledPart = type
        .typeMap
        .compiledMethodsByType[compiledMethod]![enclosingType.uniqueName]!;
  }

  if (!compiledPart.stubs.containsKey(field) ||
      !compiledPart.stubs[field]!.containsKey(fieldMethodPart)) {
    //generate stub;
    if (!compiledPart.stubs.containsKey(field)) {
      compiledPart.stubs[field] = {};
    }
    List<String> stubLines = compiledPart.stubs[field]![fieldMethodPart] = [];

    var compiledFieldType = type.typeMap.fromDartType(
      field.type,
      context: type.typeArgumentsMap(),
    );

    stubLines.add('{');
    //magic parameter match
    for (var methodParameter
        in fieldMethodPart.firstFragment.formalParameters) {
      if (compiledMethod.firstFragment.formalParameters
          .where((element) => element.name == methodParameter.name)
          .isNotEmpty) {
        //this parameter comes from compiled method
        continue;
      }
      if (methodParameter.name == fieldParameter.name) {
        //this is a special param
        continue;
      }
      var methodParameterValue = 'null';
      //var methodParameterType = methodParameter.type.toString();
      if (methodParameter.name == 'name') {
        methodParameterValue = '"${field.name}"';
      } else if (methodParameter.name == 'className') {
        methodParameterValue = '"${compiledFieldType.uniqueName}"';
      } else if (fieldParameter.element.type.isDartCoreEnum &&
          methodParameter.name == 'values') {
        methodParameterValue = '${compiledFieldType.uniqueName}.values';
      } else if (methodParameter.element.isOptional) {
        methodParameterValue =
            methodParameter.element.defaultValueCode ?? 'null';
        var nameParts = methodParameter.name!.split('_');
        String annotationName =
            '@${nameParts[0][0].toUpperCase()}${nameParts[0].substring(1)}';
        if (nameParts.length == 1) {
          methodParameterValue = 'false';
          for (var fieldMeta in field.metadata.annotations) {
            if (fieldMeta.toSource() == annotationName) {
              methodParameterValue = 'true';
            }
          }
        } else {
          for (var fieldMeta in field.metadata.annotations) {
            if (fieldMeta.toSource().startsWith('$annotationName(') ||
                fieldMeta.toSource().startsWith('$annotationName.t(')) {
              var constantValue = fieldMeta.computeConstantValue();
              if (constantValue == null) {
                methodParameterValue = '"COMPUTATION ERROR"';
                break;
              }
              DartObject annotationField = constantValue.getField(
                nameParts[1],
              )!;
              var annotationValue = annotationField.type!.getDisplayString();
              switch (annotationValue) {
                case 'Type':
                  //allow passing type as annotation
                  String typeName = fieldMeta.toSource();
                  typeName = typeName.substring(
                    typeName.indexOf('(') + 1,
                    typeName.indexOf(')'),
                  );
                  if (compiledPart.typeMap.allTypes.containsKey(typeName)) {
                    methodParameterValue = compiledPart.typeMap
                        .generateTypeGetter(
                          compiledPart.typeMap.allTypes[typeName]!,
                        );
                  } else {
                    methodParameterValue = "null";
                  }
                  break;
                case 'String':
                  //todo toDartVariable?
                  methodParameterValue =
                      '"${annotationField.toStringValue()!.replaceAll('\$', '\\\$').replaceAll('"', '\\"')}"';
                  break;
                case 'int':
                  methodParameterValue = annotationField
                      .toIntValue()
                      .toString();
                  break;
                default:
                  methodParameterValue = annotationField.toString();
              }
            }
          }
        }
      }
      if (methodParameterValue.startsWith('\$')) {
        stubLines.add('var ${methodParameter.name} = $methodParameterValue;');
      } else {
        stubLines.add(
          'const ${methodParameter.name} = $methodParameterValue;',
        );
      }
    }
    String part = await fieldMethodPart.getSourceCode(type.typeMap.step);

    if (fieldMethodPart.firstFragment.formalParameters.indexWhere(
          (element) => element.name == 'field',
        ) >
        -1) {
      part = part.replaceAll(fieldParameter.name!, 'dis.${field.name}');
    }
    //TODO
    part = part.replaceAll('this', thisReplace);

    String paramClass = fieldParameter.element.type.getDisplayString();
    String fieldClass = compiledFieldType.uniqueName;
    part = part.replaceAll('as $paramClass', 'as $fieldClass');
    if (paramClass.contains('<') && fieldClass.contains('<')) {
      //TODO support many parameters?
      String paramGenericParam = paramClass.substring(
        paramClass.indexOf('<') + 1,
        paramClass.length - 1,
      );
      String fieldGenericParam = fieldClass.substring(
        fieldClass.indexOf('<') + 1,
        fieldClass.length - 1,
      );
      part = part.replaceAll(
        'as $paramGenericParam',
        'as $fieldGenericParam',
      );
    }
    //part = "// ${paramClass} \n" + part;
    //part = "// ${fieldClass} \n" + part;
    stubLines.add(part);
    stubLines.add('}');
  }
  return compiledPart;
}