generate method

  1. @override
String generate(
  1. List<ClassMember> members
)

Implementation

@override
String generate(List<ClassMember> members) {
  var toMap = '';
  var patcher = '';

  var usingToDouble = false;
  var usingToDecimal = false;
  final toDouble =
      'final toDouble = (val) => val == null ? null : val * 1.0;\n';
  final toDecimal =
      'final toDecimal = (val) => val == null ? null : Decimal.parse(val.toString());\n';

  for (var member in members) {
    if (!(member is FieldDeclaration)) continue;
    if (!getTag(member).contains('json')) continue;

    final key = getTag(member).split(':')[1].replaceAll('"', '');
    final isNullable = member.fields.type?.question != null;
    final dot = isNullable ? '?.' : '.';
    final typeName = (member.fields.type as NamedType).name.toString();
    final typeArgs =
        (member.fields.type as NamedType).typeArguments?.arguments;
    final leftType = (typeArgs?.elementAtOrNull(0) as NamedType?);
    final leftName = leftType?.name.toString() ?? 'dynamic';
    final leftDot = (leftType?.question?.toString() ?? '') + '.';
    final leftExcl = leftType?.question == null ? '!' : '';
    final rightType = (typeArgs?.elementAtOrNull(1) as NamedType?);
    final rightName = rightType?.name.toString() ?? 'dynamic';
    final rightDot = (rightType?.question?.toString() ?? '') + '.';
    final rightExcl = rightType?.question == null ? '!' : '';

    final type = member.fields.type
        .toString()
        .replaceAll('\$', '')
        .replaceAll('?', '');
    final name = member.fields.variables.first.name.lexeme;
    final initializer = member.fields.variables.first.initializer;

    if ([
      'String',
      'num',
      'bool',
      'int',
      'dynamic',
      'Map<String, dynamic>',
      'List<dynamic>'
    ].contains(type)) {
      toMap += "'$key': $name,\n";
      patcher += "$name = _data['$key']";
    } else if (type == 'double') {
      toMap += "'$key': $name,\n";
      patcher += "$name = toDouble(_data['$key'])";
      usingToDouble = true;
    } else if (type == 'Decimal') {
      toMap += "'$key': $name${dot}toDouble(),\n";
      patcher += "$name = toDecimal(_data['$key'])";
      usingToDecimal = true;
    } else if (enums.contains(type)) {
      toMap += "'$key': $name${dot}value,\n";
      patcher += "$name = $type.parse(_data['$key'])";
    } else if (typeName == 'Map') {
      // Determine if key needs string conversion for JSON serialization
      final isKeyString = leftName == 'String';
      final needsKeyConversion =
          !isKeyString && ['num', 'bool', 'int', 'double'].contains(leftName);

      // Helper to convert key to string in toMap
      final keyToString = needsKeyConversion ? 'k.toString()' : 'k';

      // Helper to parse key from string in patcher
      String parseKey(String keyType) {
        switch (keyType) {
          case 'int':
            return 'int.parse(k)';
          case 'double':
            return 'double.parse(k)';
          case 'num':
            return 'num.parse(k)';
          case 'bool':
            return "k == 'true'";
          default:
            return 'k as $keyType';
        }
      }

      final parsedKey =
          needsKeyConversion ? parseKey(leftName) : 'k as $leftName';

      if (['String', 'num', 'bool', 'dynamic'].contains(rightName)) {
        // For primitive values
        if (needsKeyConversion || leftName == 'dynamic') {
          toMap +=
              "'$key': $name${dot}map<String, dynamic>((k,v) => MapEntry($keyToString, v)),\n";
        } else {
          toMap += "'$key': $name,\n";
        }
        patcher +=
            "$name = (_data['$key'] as Map?)?.map<$leftName, $rightName>((k, v) => MapEntry($parsedKey, v as $rightName))";
      } else if (rightName == 'int') {
        if (needsKeyConversion || leftName == 'dynamic') {
          toMap +=
              "'$key': $name${dot}map<String, dynamic>((k,v) => MapEntry($keyToString, v)),\n";
        } else {
          toMap += "'$key': $name,\n";
        }
        patcher +=
            "$name = (_data['$key'] as Map?)?.map<$leftName, $rightName>((k, v) => MapEntry($parsedKey, v ~/ 1))";
      } else if (rightName == 'double') {
        if (needsKeyConversion || leftName == 'dynamic') {
          toMap +=
              "'$key': $name${dot}map<String, dynamic>((k,v) => MapEntry($keyToString, v)),\n";
        } else {
          toMap += "'$key': $name,\n";
        }
        patcher +=
            "$name = (_data['$key'] as Map?)?.map<$leftName, $rightName>((k, v) => MapEntry($parsedKey, v * 1.0))";
      } else if (enums.contains(rightName)) {
        toMap +=
            "'$key': $name${dot}map<String, dynamic>((k,v) => MapEntry($keyToString, v${rightDot}value)),\n";
        patcher +=
            "$name = (_data['$key'] as Map?)?.map<$leftName, $rightName>((k, v) => MapEntry($parsedKey, $rightName.parse(v)$rightExcl))";
      } else if (rightName == 'List') {
        // Handle Map<K, List<V>> types
        final listValueType = (rightType?.typeArguments?.arguments
            .elementAtOrNull(0) as NamedType?);
        final listValueName = listValueType?.name.toString() ?? 'dynamic';
        final listValueDot =
            (listValueType?.question?.toString() ?? '') + '.';
        final listValueExcl = listValueType?.question == null ? '!' : '';
        // Get the full type string for the List (e.g., "List<Address>")
        final fullListType =
            rightType.toString().replaceAll('\$', '').replaceAll('?', '');

        if (['String', 'num', 'bool', 'dynamic', 'int', 'double']
            .contains(listValueName)) {
          if (needsKeyConversion || leftName == 'dynamic') {
            toMap +=
                "'$key': $name${dot}map<String, dynamic>((k,v) => MapEntry($keyToString, v)),\n";
          } else {
            toMap += "'$key': $name,\n";
          }
          patcher +=
              "$name = (_data['$key'] as Map?)?.map<$leftName, $fullListType>((k, v) => MapEntry($parsedKey, (v as List?)?.cast<$listValueName>() ?? []))";
        } else if (enums.contains(listValueName)) {
          toMap +=
              "'$key': $name${dot}map<String, dynamic>((k,v) => MapEntry($keyToString, v${rightDot}map((i) => i${listValueDot}value).toList())),\n";
          patcher +=
              "$name = (_data['$key'] as Map?)?.map<$leftName, $fullListType>((k, v) => MapEntry($parsedKey, (v as List?)?.map((i) => $listValueName.parse(i)$listValueExcl).toList().cast<$listValueName>() ?? []))";
        } else {
          toMap +=
              "'$key': $name${dot}map<String, dynamic>((k,v) => MapEntry($keyToString, v${rightDot}map((i) => i${listValueDot}toMap()).toList())),\n";
          patcher +=
              "$name = (_data['$key'] as Map?)?.map<$leftName, $fullListType>((k, v) => MapEntry($parsedKey, (v as List?)?.map((i) => $listValueName.fromMap(i)$listValueExcl).toList().cast<$listValueName>() ?? []))";
        }
      } else {
        toMap +=
            "'$key': $name${dot}map<String, dynamic>((k,v) => MapEntry($keyToString, v${rightDot}toMap())),\n";
        patcher +=
            "$name = (_data['$key'] as Map?)?.map<$leftName, $rightName>((k, v) => MapEntry($parsedKey, $rightName.fromMap(v)$rightExcl))";
      }
    } else if (typeName == 'List') {
      if (['String', 'num', 'bool', 'dynamic'].contains(leftName)) {
        toMap += "'$key': $name,\n";
        patcher += "$name = _data['$key']?.cast<$leftName>()";
      } else if (leftName == 'int') {
        toMap += "'$key': $name,\n";
        patcher +=
            "$name = _data['$key']?.map((i) => i ~/ 1).toList().cast<int>()";
      } else if (leftName == 'double') {
        toMap += "'$key': $name,\n";
        patcher +=
            "$name = _data['$key']?.map((i) => i * 1.0).toList().cast<double>()";
      } else if (enums.contains(leftName)) {
        toMap +=
            "'$key': $name${dot}map((i) => i${leftDot}value).toList(),\n";
        patcher +=
            "$name = _data['$key']?.map((i) => $leftName.parse(i)$leftExcl).toList().cast<$leftName>()";
      } else {
        toMap +=
            "'$key': $name${dot}map((i) => i${leftDot}toMap()).toList(),\n";
        patcher +=
            "$name = _data['$key']?.map((i) => $leftName.fromMap(i)$leftExcl).toList().cast<$leftName>()";
      }
    } else {
      toMap += "'$key': $name${dot}toMap(),";
      patcher += "$name = $type.fromMap(_data['$key'])";
    }

    patcher += ' ?? ${initializer ?? name};\n';
  }

  return '''
  void patch(Map? _data) { if(_data == null) return;
    ${usingToDouble ? toDouble : ''}
    ${usingToDecimal ? toDecimal : ''}
    $patcher
  }

  static $className? fromMap(Map? data) { if(data == null) return null; return $className()..patch(data); }

  Map<String, dynamic> toMap() => {
    $toMap
  };
  ''';
}