generateSourceFieldAssignment function

Expression generateSourceFieldAssignment(
  1. SourceAssignment sourceAssignment,
  2. ClassElement abstractMapper,
  3. VariableElement targetField
)

Generates an assignment of a reference to a sourcefield.

The assignment is the property {sourceField} of the given Reference {sourceReference}. If a method in the given ClassElement exists, whose returntype matches the type of the targetField, and its first parameter type matches the sourceField type, then this method will be used for the assignment instead, and passing the sourceField property of the given Reference as the argument of the method.

Returns the Expression of the sourceField assignment, such as:

model.id;
fromSub(model.sub);

Implementation

Expression generateSourceFieldAssignment(SourceAssignment sourceAssignment,
    ClassElement abstractMapper, VariableElement targetField) {
  Expression sourceFieldAssignment;

  if (sourceAssignment.shouldUseFunction()) {
    final sourceFunction = sourceAssignment.function!;
    final references = sourceAssignment.params!
        .map((sourceParam) => refer(sourceParam.displayName));
    Expression expr = refer(sourceFunction.name);
    if (sourceFunction.isStatic &&
        sourceFunction.enclosingElement3.name != null) {
      expr = refer(sourceFunction.enclosingElement3.name!)
          .property(sourceFunction.name);
    }
    sourceFieldAssignment = expr.call(
        [...references], makeNamedArgumentForStaticFunction(sourceFunction));

    // The return of the function may be needed a nested mapping.
    sourceFieldAssignment = invokeNestedMappingForStaticFunction(
        sourceFunction, abstractMapper, targetField, sourceFieldAssignment);
  } else {
    // final sourceClass = sourceAssignment.sourceClass!;
    final sourceField = sourceAssignment.field!;
    final sourceReference = refer(sourceAssignment.sourceName!);
    sourceFieldAssignment = sourceReference.property(sourceField.name);
    // list support
    if (sourceAssignment.shouldAssignList(targetField.type)) {
      final sourceListType = _getGenericTypes(sourceField.type).first;
      final targetListType = _getGenericTypes(targetField.type).first;
      final matchingMappingListMethods = _findMatchingMappingMethod(
          abstractMapper, targetListType, sourceListType);

      // mapping expression, default is just the identity,
      // for example for primitive types or objects that do not have their own mapping method
      var expr = refer('(e) => e');
      var sourceIsNullable =
          sourceListType.nullabilitySuffix == NullabilitySuffix.question;
      var targetIsNullable =
          targetListType.nullabilitySuffix == NullabilitySuffix.question;

      var needTargetFilter = sourceIsNullable && !targetIsNullable;
      if (matchingMappingListMethods.isNotEmpty) {
        final nestedMapping = matchingMappingListMethods.first;
        // expr = refer(nestedMapping.name);
        final invokeStr = invokeNestedMappingFunction(
          nestedMapping,
          sourceIsNullable,
          refer("x"),
          refer("x"),
        ).accept(DartEmitter()).toString();
        expr = refer('''
          (x) => $invokeStr
        ''');
        final returnIsNullable =
            checkNestMappingReturnNullable(nestedMapping, sourceIsNullable);
        needTargetFilter = !targetIsNullable && returnIsNullable;
      }

      if (sourceField.type.nullabilitySuffix == NullabilitySuffix.question) {
        sourceFieldAssignment =
            // source.{field}.map
            sourceReference.property(sourceField.name).nullSafeProperty('map')
                // (expr)
                .call([expr]);
      } else {
        sourceFieldAssignment =
            // source.{field}.map
            sourceReference.property(sourceField.name).property('map')
                // (expr)
                .call([expr]);
      }

      if (needTargetFilter) {
        sourceFieldAssignment = sourceFieldAssignment
            .property("where")
            .call([refer("(x) => x != null")]);
      }

      if (sourceAssignment.needCollect(targetField.type)) {
        sourceFieldAssignment = sourceFieldAssignment
                //.toList() .toSet()
                .property(sourceAssignment.collectInvoke(targetField.type))
            // .property('toList')
            // .call([])
            ;

        if (targetField.type.nullabilitySuffix == NullabilitySuffix.none &&
            sourceField.type.nullabilitySuffix == NullabilitySuffix.question) {
          sourceFieldAssignment = sourceFieldAssignment.ifNullThen(refer('[]'));
        }
      }

      if (needTargetFilter) {
        sourceFieldAssignment = sourceFieldAssignment.asA(
            refer(targetField.type.getDisplayString(withNullability: true)));
      }
    } else {
      // found a mapping method in the class which will map the source to target
      final matchingMappingMethods = _findMatchingMappingMethod(
          abstractMapper, targetField.type, sourceField.type);

      // nested classes can be mapped with their own mapping methods
      if (matchingMappingMethods.isNotEmpty) {
        sourceFieldAssignment = invokeNestedMappingFunction(
          matchingMappingMethods.first,
          sourceAssignment.refChain!.isNullable,
          refer(sourceAssignment.refChain!.refWithQuestion),
          refer(sourceAssignment.refChain!.ref),
        );
      }
    }
  }
  return sourceFieldAssignment;
}