generateClasses method

String generateClasses(
  1. Map classes, {
  2. void build(
    1. ClassBuilder builder,
    2. Map classData
    )?,
  3. Map serializers = const {},
})

Implementation

String generateClasses(
  Map classes, {
  void Function(ClassBuilder builder, Map classData)? build,
  Map serializers = const {},
}) {
  final classReader = MapReader(classes);
  final serializerReader = MapReader(serializers);
  final library = Library((b) {
    for (final key in classes.keys) {
      final class_ = Class((b) {
        final className = '$key';
        b.name = className;
        final extend =
            classReader.tryRead<String>('$className.extends', false);
        if (extend != null) {
          b.extend = Reference(extend);
        }

        final typeParameters =
            classReader.tryRead<String>('$className.typeParameters', false);
        if (typeParameters != null) {
          final type = _parseType('$className$typeParameters');
          b.types.addAll(type.arguments.map((e) => Reference('$e')));
        }

        final fieldsData = classReader.read<Map>('$className.fields');
        for (final key in fieldsData.keys) {
          final fieldName = '$key';
          b.fields.add(Field((b) {
            var type = classReader.tryRead<String>(
                '$className.fields.$fieldName', false);
            if (type == null) {
              type = classReader
                  .read<String>('$className.fields.$fieldName.type');
              final metadata = classReader.tryRead<List>(
                  '$className.fields.$fieldName.metadata', false);
              if (metadata != null) {
                for (final annotation in metadata) {
                  b.annotations.add(CodeExpression(Code('$annotation')));
                }
              }
            }

            b.name = fieldName;
            b.type = Reference(type);
            b.modifier = FieldModifier.final$;
          }));
        }

        b.constructors.add(Constructor((b) {
          for (final key in fieldsData.keys) {
            final fieldName = '$key';
            b.optionalParameters.add(Parameter((b) {
              b.required = true;
              b.toThis = true;
              b.name = fieldName;
              b.named = true;
            }));
          }
        }));

        b.constructors.add(Constructor((b) {
          b.name = 'fromJson';
          b.factory = true;
          b.requiredParameters.add(Parameter((b) {
            b.name = 'json';
            b.type = Reference('Map');
          }));

          final code = <String>[];
          code.add('return $className(');
          for (final key in fieldsData.keys) {
            final fieldName = '$key';
            var alias = fieldName;
            String? deserialize;
            var type = classReader.tryRead<String>(
                '$className.fields.$fieldName', false);
            if (type == null) {
              type = classReader
                  .read<String>('$className.fields.$fieldName.type');
              alias = (classReader.tryRead<String>(
                          '$className.fields.$fieldName.alias', false) ??
                      fieldName)
                  .trim();
              deserialize = classReader.tryRead(
                  '$className.fields.$fieldName.deserialize', false);
            }

            final typeInfo = _parseType(type);
            var value = "json['$alias']";
            if (deserialize != null) {
              value = '$deserialize($value)';
            } else {
              value = _deserialize(typeInfo, value, serializerReader);
            }

            code.add("$fieldName: $value,");
          }

          code.add(');');
          b.body = Code(code.join('\n'));
        }));

        b.methods.add(Method((b) {
          b.static = true;
          b.returns = Reference('List<$className>');
          b.name = 'fromJsonList';
          b.requiredParameters.add(Parameter((b) {
            b.name = 'json';
            b.type = Reference('List');
          }));

          final code = <String>[];
          code.add(
              'return json.map((e) => $className.fromJson(e as Map)).toList();');
          b.body = Code(code.join('\n'));
        }));

        b.methods.add(Method((b) {
          b.name = 'toJson';
          b.returns = Reference('Map<String, dynamic>');
          final code = <String>[];
          code.add('return {');
          for (final key in fieldsData.keys) {
            final fieldName = '$key';
            var alias = fieldName;
            String? serialize;
            var type = classReader.tryRead<String>(
                '$className.fields.$fieldName', false);
            if (type == null) {
              type = classReader
                  .read<String>('$className.fields.$fieldName.type');
              alias = (classReader.tryRead<String>(
                          '$className.fields.$fieldName.alias', false) ??
                      fieldName)
                  .trim();
              serialize = classReader.tryRead(
                  '$className.fields.$fieldName.serialize', false);
            }

            final typeInfo = _parseType(type);
            var value = fieldName;
            if (serialize != null) {
              value = '$serialize($value)';
            } else {
              value = _serialize(typeInfo, value, serializerReader);
            }

            code.add("'$alias': $value,");
          }

          code.add('};');
          b.body = Code(code.join('\n'));
        }));

        b.methods.add(Method((b) {
          b.static = true;
          b.returns = Reference('List<Map<String, dynamic>>');
          b.name = 'toJsonList';
          b.requiredParameters.add(Parameter((b) {
            b.name = 'list';
            b.type = Reference('List<$className>');
          }));

          final code = <String>[];
          code.add('return list.map((e) => e.toJson()).toList();');
          b.body = Code(code.join('\n'));
        }));
      });

      b.body.add(class_);
    }
  });

  final emitter = DartEmitter();
  final result = library.accept(emitter).toString();
  return result;
}