generate method

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

Implementation

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

  for (var member in members) {
    if (!(member is FieldDeclaration)) continue;

    final fieldType = member.fields.type;
    final namedType = fieldType is NamedType ? fieldType : null;
    final typeArgs = namedType?.typeArguments?.arguments;
    final isNullable = member.fields.type?.question != null;
    final dot = isNullable ? '?.' : '.';
    final type = member.fields.type
        .toString()
        .replaceAll('\$', '')
        .replaceAll('?', '');
    final name = member.fields.variables.first.name.lexeme;

    if (primitives.contains(type)) {
      serialize += "'$name': $name,";
    } else if (type == 'Type') {
      serialize += "'$name': 'Type<$name>',";
    } else if (type == 'double') {
      serialize += "'$name': $name,";
    } else if (type == 'Decimal') {
      serialize += "'$name': $name${dot}toDouble(),";
    } else if (enums.contains(type)) {
      serialize += "'$name': $name${dot}value,";
    } else if (type.contains('Map<')) {
      final keyType = _cleanType(typeArgs?.elementAtOrNull(0));
      final originalValueType = typeArgs?.elementAtOrNull(1);
      final valueType = _cleanType(originalValueType);
      final isValueNullable = originalValueType?.question != null;
      final valueDot = isValueNullable ? '?.' : '.';

      // Determine if key needs string conversion for JSON serialization
      final isKeyString = keyType == 'String';
      final needsKeyConversion =
          !isKeyString && ['num', 'bool', 'int', 'double'].contains(keyType);
      final keyExpr = needsKeyConversion ? 'k.toString()' : 'k';

      // Check if value is a generic type parameter from class declaration
      final isGenericValueType = typeParams.contains(valueType);

      var valueExpr = isGenericValueType
          ? '(v as dynamic)?.serialize()'
          : 'v${valueDot}serialize()';

      if (primitives.contains(valueType)) {
        valueExpr = 'v';
      } else if (enums.contains(valueType)) {
        valueExpr = 'v${valueDot}value';
      } else if (valueType.startsWith('List<')) {
        final valueNamedType =
            originalValueType is NamedType ? originalValueType : null;
        final listValueType =
            valueNamedType?.typeArguments?.arguments.elementAtOrNull(0);
        final listPrimitive = _cleanType(listValueType);
        final listItemDot = listValueType?.question == null ? '.' : '?.';
        final isGenericListType = typeParams.contains(listPrimitive);
        if (primitives.contains(listPrimitive)) {
          valueExpr = 'v';
        } else if (enums.contains(listPrimitive)) {
          valueExpr = 'v${valueDot}map((i) => i${listItemDot}value).toList()';
        } else if (isGenericListType) {
          valueExpr =
              'v${valueDot}map((i) => (i as dynamic)?.serialize()).toList()';
        } else {
          valueExpr =
              'v${valueDot}map((i) => i${listItemDot}serialize()).toList()';
        }
      }

      if (!needsKeyConversion && valueExpr == 'v') {
        serialize += "'$name': $name,";
      } else {
        serialize +=
            "'$name': $name${dot}map<String, dynamic>((k, v) => MapEntry($keyExpr, $valueExpr)),";
      }
    } else if (type == 'Map') {
      serialize += "'$name': $name,";
    } else if (type.contains('List<')) {
      final dotMap = isNullable ? '?.map' : '.map';
      final listValueType = typeArgs?.elementAtOrNull(0);
      final listPrimitive = _cleanType(listValueType);
      final listItemDot = listValueType?.question == null ? '.' : '?.';

      // Check if it's a generic type parameter from class declaration
      final isGenericType = typeParams.contains(listPrimitive);

      if (primitives.contains(listPrimitive)) {
        serialize += "'$name': $name,";
      } else if (enums.contains(listPrimitive)) {
        serialize +=
            "'$name': $name$dotMap((i) => i${listItemDot}value).toList(),";
      } else if (isGenericType) {
        // For generic types, use dynamic with null-safe call since T might not have serialize()
        serialize +=
            "'$name': $name$dotMap((i) => (i as dynamic)?.serialize()).toList(),";
      } else {
        serialize +=
            "'$name': $name$dotMap((i) => i${listItemDot}serialize()).toList(),";
      }
    } else {
      if (isNullable) {
        serialize += "'$name': $name?.serialize(),";
      } else {
        serialize += "'$name': $name.serialize(),";
      }
    }
  }

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