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;
}