From cc1a73a5a8f7862beefff63ef6c751cee31499b3 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Mon, 4 Sep 2023 17:06:44 +0200 Subject: [PATCH 01/42] #130: removed unused code --- example/lib/model/user/person/gender.dart | 22 +- lib/config/yml_generator_config.dart | 121 +++----- lib/model/model/enum_model.dart | 33 +- lib/writer/enum_model_writer.dart | 80 +---- .../yml_generator_config/enum-normal.txt | 8 + test/config/yml_generator_config_test.dart | 27 +- test/model/model/enum_model_test.dart | 48 ++- .../output.txt} | 0 .../output.txt} | 0 .../output.txt} | 0 .../{no-fields.txt => no-fields/output.txt} | 0 .../output.txt} | 0 .../{normal.txt => normal/output.txt} | 0 .../output.txt} | 0 .../output.txt} | 0 .../output.txt} | 0 .../output.txt} | 0 .../output.txt} | 0 .../output.txt} | 0 .../{null-value.txt => null-value/output.txt} | 0 test/writer/enum_model_writer_test.dart | 293 +----------------- test/writer/writer_test_helper.dart | 16 - 22 files changed, 140 insertions(+), 508 deletions(-) rename test/writer/enum_model_writer/{custom-value-map-extension.txt => custom-value-map-extension/output.txt} (100%) rename test/writer/enum_model_writer/{custom-value-map.txt => custom-value-map/output.txt} (100%) rename test/writer/enum_model_writer/{custom-value.txt => custom-value/output.txt} (100%) rename test/writer/enum_model_writer/{no-fields.txt => no-fields/output.txt} (100%) rename test/writer/enum_model_writer/{normal-description.txt => normal-description/output.txt} (100%) rename test/writer/enum_model_writer/{normal.txt => normal/output.txt} (100%) rename test/writer/enum_model_writer/{normal_with_double_type.txt => normal_with_double_type/output.txt} (100%) rename test/writer/enum_model_writer/{normal_with_double_type_map.txt => normal_with_double_type_map/output.txt} (100%) rename test/writer/enum_model_writer/{normal_with_double_type_map_extension.txt => normal_with_double_type_map_extension/output.txt} (100%) rename test/writer/enum_model_writer/{normal_with_int_type.txt => normal_with_int_type/output.txt} (100%) rename test/writer/enum_model_writer/{normal_with_int_type_map.txt => normal_with_int_type_map/output.txt} (100%) rename test/writer/enum_model_writer/{normal_with_int_type_map_extension.txt => normal_with_int_type_map_extension/output.txt} (100%) rename test/writer/enum_model_writer/{null-value.txt => null-value/output.txt} (100%) delete mode 100644 test/writer/writer_test_helper.dart diff --git a/example/lib/model/user/person/gender.dart b/example/lib/model/user/person/gender.dart index 687ae82..a82ca2d 100644 --- a/example/lib/model/user/person/gender.dart +++ b/example/lib/model/user/person/gender.dart @@ -4,21 +4,25 @@ import 'package:json_annotation/json_annotation.dart'; enum Gender { @JsonValue('_mAl3') - MALE, + MALE(name: 'brian'), @JsonValue('femAle') - FEMALE, + FEMALE(name: 'brian'), @JsonValue('X') - X, + X(name: 'brian'), @JsonValue('GENDER_X') - GENDER_X, + GENDER_X(name: 'brian'), @JsonValue('null') - GENDER_Y, + GENDER_Y(name: 'brian'), @JsonValue('gender_z') - GENDER_Z, + GENDER_Z(name: 'brian'), @JsonValue('GENDER_abC') - GENDER_ABC, + GENDER_ABC(name: 'brian'), @JsonValue('null') - GENDER_DEF, + GENDER_DEF(name: 'brian'), @JsonValue('GENDER_lap') - GENDER_LAP, + GENDER_LAP(name: 'brian'); + + final String name; + + const Gender({required this.name}); } diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index 3a9e3e6..07988ab 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -27,20 +27,16 @@ class YmlGeneratorConfig { List get models => _models; - YmlGeneratorConfig( - PubspecConfig pubspecConfig, String configContent, this.fileName) { + YmlGeneratorConfig(PubspecConfig pubspecConfig, String configContent, this.fileName) { final yamlContent = loadYaml(configContent); if (yamlContent == null) return; // Ignore empty file yamlContent.forEach((key, value) { - final String baseDirectory = - value['base_directory'] ?? pubspecConfig.baseDirectory; + final String baseDirectory = value['base_directory'] ?? pubspecConfig.baseDirectory; final String? path = value['path']; final String? extendsModel = value['extends']; - final bool generateForGenerics = - value['generate_for_generics'] ?? pubspecConfig.generateForGenerics; + final bool generateForGenerics = value['generate_for_generics'] ?? pubspecConfig.generateForGenerics; - final extraImports = - value.containsKey('extra_imports') ? [] : null; + final extraImports = value.containsKey('extra_imports') ? [] : null; final extraImportsVal = value['extra_imports']; extraImportsVal?.forEach((e) { if (e != null) { @@ -48,8 +44,7 @@ class YmlGeneratorConfig { } }); - final extraAnnotations = - value.containsKey('extra_annotations') ? [] : null; + final extraAnnotations = value.containsKey('extra_annotations') ? [] : null; final extraAnnotationsVal = value['extra_annotations']; extraAnnotationsVal?.forEach((e) { if (e != null) { @@ -93,69 +88,54 @@ class YmlGeneratorConfig { throw Exception('Properties can not be null. model: $key'); } if (properties is! YamlMap) { - throw Exception( - 'Properties should be a map, right now you are using a ${properties.runtimeType}. model: $key'); + throw Exception('Properties should be a map, right now you are using a ${properties.runtimeType}. model: $key'); } if (type == 'enum') { - final uppercaseEnums = - (value['uppercase_enums'] ?? pubspecConfig.uppercaseEnums) == true; - final itemType = value['item_type'] == null - ? const StringType() - : _parseSimpleType(value['item_type']); - - if (itemType is! StringType && - itemType is! IntegerType && - itemType is! DoubleType) { - throw Exception( - 'item_type should be a string or integer. model: $key'); - } + final uppercaseEnums = (value['uppercase_enums'] ?? pubspecConfig.uppercaseEnums) == true; final fields = []; properties.forEach((propertyKey, propertyValue) { if (propertyValue != null && propertyValue is! YamlMap) { throw Exception('$propertyKey should be an object'); } + final propertiesYaml = propertyValue as YamlMap; + final properties = []; + propertiesYaml.forEach((propertyKey, propertyValue) { + properties.add(EnumProperty( + value: propertyValue, + name: propertyKey, + )); + }); fields.add(EnumField( name: uppercaseEnums ? propertyKey.toUpperCase() : propertyKey, rawName: propertyKey, - value: propertyValue == null - ? null - : propertyValue['value'].toString(), - description: - propertyValue == null ? null : propertyValue['description'], + enumProperties: properties, )); }); models.add(EnumModel( name: key, path: path, - generateMap: value['generate_map'] == true, - generateExtensions: value['generate_extensions'] == true, + keyProperty: value['key_property'], baseDirectory: baseDirectory, fields: fields, - itemType: itemType, extraImports: extraImports, extraAnnotations: extraAnnotations, description: description, )); } else { final staticCreate = (value['static_create'] ?? false) == true; - final disallowNullForDefaults = - value.containsKey('disallow_null_for_defaults') - ? (value['disallow_null_for_defaults'] == true) - : pubspecConfig.disallowNullForDefaults; + final disallowNullForDefaults = value.containsKey('disallow_null_for_defaults') ? (value['disallow_null_for_defaults'] == true) : pubspecConfig.disallowNullForDefaults; final fields = []; properties.forEach((propertyKey, propertyValue) { if (propertyValue is YamlMap) { - fields.add(getField(propertyKey, propertyValue, - disallowNullForDefaults: disallowNullForDefaults)); + fields.add(getField(propertyKey, propertyValue, disallowNullForDefaults: disallowNullForDefaults)); } else if (propertyValue is String) { fields.add(getSimpleField(name: propertyKey, value: propertyValue)); } else { throw Exception('$propertyKey should be an object'); } }); - final mappedConverters = - converters?.map((element) => element.toString()).toList(); + final mappedConverters = converters?.map((element) => element.toString()).toList(); models.add(ObjectModel( name: key, path: path, @@ -177,36 +157,25 @@ class YmlGeneratorConfig { }); } - Field getField(String name, YamlMap property, - {required bool disallowNullForDefaults}) { + Field getField(String name, YamlMap property, {required bool disallowNullForDefaults}) { try { if (property.containsKey('required')) { - throw ArgumentError( - 'required is removed, follow the migration to version 7.0.0'); + throw ArgumentError('required is removed, follow the migration to version 7.0.0'); } - final ignored = - property.containsKey('ignore') && property['ignore'] == true; - final includeFromJson = !property.containsKey('includeFromJson') || - property['includeFromJson'] == true; - final includeToJson = !property.containsKey('includeToJson') || - property['includeToJson'] == true; - final nonFinal = ignored || - property.containsKey('non_final') && property['non_final'] == true; - final includeIfNull = property.containsKey('include_if_null') && - property['include_if_null'] == true; + final ignored = property.containsKey('ignore') && property['ignore'] == true; + final includeFromJson = !property.containsKey('includeFromJson') || property['includeFromJson'] == true; + final includeToJson = !property.containsKey('includeToJson') || property['includeToJson'] == true; + final nonFinal = ignored || property.containsKey('non_final') && property['non_final'] == true; + final includeIfNull = property.containsKey('include_if_null') && property['include_if_null'] == true; final unknownEnumValue = property['unknown_enum_value']; final jsonKey = property['jsonKey'] ?? property['jsonkey']; final fromJson = property['fromJson']; final toJson = property['toJson']; - final description = property.containsKey('description') - ? property['description']!.toString() - : null; + final description = property.containsKey('description') ? property['description']!.toString() : null; final type = property['type'] as String?; final skipEquality = property['ignore_equality'] == true; final defaultValue = property['default_value']?.toString(); - final disallowNull = property.containsKey('disallow_null') - ? (property['disallow_null'] == true) - : disallowNullForDefaults; + final disallowNull = property.containsKey('disallow_null') ? (property['disallow_null'] == true) : disallowNullForDefaults; ItemType itemType; if (type == null) { @@ -272,9 +241,7 @@ class YmlGeneratorConfig { return 'DateTime'; } else if (lowerType == 'int' || lowerType == 'integer') { return 'int'; - } else if (lowerType == 'object' || - lowerType == 'dynamic' || - lowerType == 'any') { + } else if (lowerType == 'object' || lowerType == 'dynamic' || lowerType == 'any') { return 'dynamic'; } else { return typeName; @@ -289,8 +256,7 @@ class YmlGeneratorConfig { //Maybe a generic final dartType = DartType(name); if (dartType.generics.isEmpty) { - throw Exception( - 'getPathForName is null: because `$name` was not added to the config file'); + throw Exception('getPathForName is null: because `$name` was not added to the config file'); } final paths = {}; for (final element in dartType.generics) { @@ -298,8 +264,7 @@ class YmlGeneratorConfig { } return paths; } else { - final baseDirectory = - foundModel.baseDirectory ?? pubspecConfig.baseDirectory; + final baseDirectory = foundModel.baseDirectory ?? pubspecConfig.baseDirectory; final path = foundModel.path; if (path == null) { return [baseDirectory]; @@ -353,26 +318,22 @@ class YmlGeneratorConfig { Model? getModelByName(ItemType itemType) { if (itemType is! ObjectType) return null; - final model = - models.firstWhereOrNull((model) => model.name == itemType.name); + final model = models.firstWhereOrNull((model) => model.name == itemType.name); if (model == null) { - throw Exception( - 'getModelByName is null: because `${itemType.name}` was not added to the config file'); + throw Exception('getModelByName is null: because `${itemType.name}` was not added to the config file'); } return model; } void checkTypesKnown(final Set names, String type) { if (!TypeChecker.isKnownDartType(type) && !names.contains(type)) { - throw Exception( - 'Could not generate all models. `$type` is not added to the config file, but is extended. These types are known: ${names.join(',')}'); + throw Exception('Could not generate all models. `$type` is not added to the config file, but is extended. These types are known: ${names.join(',')}'); } } ItemType _parseSimpleType(String type) { final listRegex = RegExp(r'^\s*[Ll]ist<\s*([a-zA-Z_0-9<>]*)\s*>\s*$'); - final mapRegex = - RegExp(r'^\s*[Mm]ap<([a-zA-Z_0-9<>]*)\s*,\s*([a-zA-Z_0-9<>]*)\s*>\s*$'); + final mapRegex = RegExp(r'^\s*[Mm]ap<([a-zA-Z_0-9<>]*)\s*,\s*([a-zA-Z_0-9<>]*)\s*>\s*$'); final lowerType = type.toLowerCase(); @@ -393,21 +354,17 @@ class YmlGeneratorConfig { return ArrayType(_makeGenericName(arrayType)); } else if (mapRegex.hasMatch(type)) { final match = mapRegex.firstMatch(type)!; - return MapType( - key: _makeGenericName(match.group(1)!), - valueName: _makeGenericName(match.group(2)!)); + return MapType(key: _makeGenericName(match.group(1)!), valueName: _makeGenericName(match.group(2)!)); } return ObjectType(type); } - YmlGeneratorConfig.merge(Iterable configs, String dirName) - : fileName = dirName { + YmlGeneratorConfig.merge(Iterable configs, String dirName) : fileName = dirName { final names = {}; for (final config in configs) { for (final model in config.models) { if (names.containsKey(model.name)) { - throw Exception( - 'Model with same name ${model.name} found in multiple files: ${names[model.name]!.fileName} and ${config.fileName}'); + throw Exception('Model with same name ${model.name} found in multiple files: ${names[model.name]!.fileName} and ${config.fileName}'); } names[model.name] = config; } diff --git a/lib/model/model/enum_model.dart b/lib/model/model/enum_model.dart index ebea3c1..1f9a099 100644 --- a/lib/model/model/enum_model.dart +++ b/lib/model/model/enum_model.dart @@ -1,23 +1,19 @@ +import 'package:model_generator/model/item_type/integer_type.dart'; import 'package:model_generator/model/item_type/item_type.dart'; -import 'package:model_generator/model/item_type/string_type.dart'; import 'package:model_generator/model/model/model.dart'; class EnumModel extends Model { final List? fields; - final ItemType itemType; - final bool generateMap; - final bool generateExtensions; + final String keyProperty; EnumModel({ required String name, + required this.keyProperty, String? path, String? baseDirectory, this.fields, - this.itemType = const StringType(), List? extraImports, List? extraAnnotations, - this.generateMap = false, - this.generateExtensions = false, String? description, }) : super( name: name, @@ -31,27 +27,34 @@ class EnumModel extends Model { class EnumField { final String name; + final List enumProperties; final String serializedName; - final String? value; - final String? description; EnumField._({ required this.name, required this.serializedName, - required this.value, - required this.description, + required this.enumProperties, }); factory EnumField({ required String name, + required List enumProperties, required String rawName, - String? value, - String? description, }) => EnumField._( name: name, + enumProperties: enumProperties, serializedName: rawName, - value: value, - description: description, ); } + +class EnumProperty { + final String value; + final String name; + final ItemType type; + + EnumProperty({ + required this.value, + required this.name, + }) : type = IntegerType(); +} diff --git a/lib/writer/enum_model_writer.dart b/lib/writer/enum_model_writer.dart index f90f2d2..62d42e4 100644 --- a/lib/writer/enum_model_writer.dart +++ b/lib/writer/enum_model_writer.dart @@ -2,6 +2,7 @@ import 'package:model_generator/model/item_type/double_type.dart'; import 'package:model_generator/model/item_type/string_type.dart'; import 'package:model_generator/model/model/enum_model.dart'; import 'package:model_generator/util/case_util.dart'; +import 'package:model_generator/util/list_extensions.dart'; import 'package:model_generator/writer/object_model_writer.dart'; class EnumModelWriter { @@ -22,20 +23,15 @@ class EnumModelWriter { } final jsonModelName = CaseUtil(jsonModel.name); - final itemTypeName = CaseUtil(jsonModel.itemType.name); sb.writeln('enum ${jsonModelName.pascalCase} {'); jsonModel.fields?.forEach((key) { - final jsonValue = key.value == null || key.value?.isEmpty == null - ? key.serializedName - : key.value; - final description = key.description; - if (description != null) { - sb.writeln(' ///$description'); - } - if (jsonModel.itemType is StringType) { + final keyProperty = key.enumProperties.firstWhereOrNull((element) => element.name.toLowerCase() == jsonModel.keyProperty); + final jsonValue = keyProperty?.value ?? key.serializedName; + + if (keyProperty?.type is StringType) { sb.writeln(' @JsonValue(\'$jsonValue\')'); - } else if (jsonModel.itemType is DoubleType && jsonValue != null) { + } else if (keyProperty?.type is DoubleType) { final doubleValue = double.tryParse(jsonValue); sb.writeln(' @JsonValue($doubleValue)'); } else { @@ -45,70 +41,6 @@ class EnumModelWriter { }); sb.writeln('}'); - if (jsonModel.generateMap) { - sb - ..writeln() - ..writeln('const ${jsonModelName.camelCase}Mapping = {'); - - jsonModel.fields?.forEach((key) { - final jsonValue = key.value == null || key.value?.isEmpty == null - ? key.serializedName - : key.value; - sb.write(' ${jsonModelName.pascalCase}.${key.name}: '); - if (jsonModel.itemType is StringType) { - sb.writeln('\'$jsonValue\','); - } else if (jsonModel.itemType is DoubleType && jsonValue != null) { - final doubleValue = double.tryParse(jsonValue); - sb.writeln('$doubleValue,'); - } else { - sb.writeln('$jsonValue,'); - } - }); - - sb - ..writeln('};') - ..writeln(); - - if (jsonModel.itemType is DoubleType) { - sb.writeln('final reverse${jsonModelName.pascalCase}Mapping = {'); - } else { - sb.writeln('const reverse${jsonModelName.pascalCase}Mapping = {'); - } - - jsonModel.fields?.forEach((key) { - final jsonValue = key.value == null || key.value?.isEmpty == null - ? key.serializedName - : key.value; - if (jsonModel.itemType is StringType) { - sb.write(' \'$jsonValue\': '); - } else if (jsonModel.itemType is DoubleType && jsonValue != null) { - final doubleValue = double.tryParse(jsonValue); - sb.write(' $doubleValue: '); - } else { - sb.write(' $jsonValue: '); - } - sb.writeln('${jsonModelName.pascalCase}.${key.name},'); - }); - - sb.writeln('};'); - - if (jsonModel.generateExtensions) { - sb - ..writeln() - ..writeln( - 'extension ${jsonModelName.pascalCase}Extension on ${jsonModelName.pascalCase} {') - ..writeln( - ' ${itemTypeName.originalText} get ${itemTypeName.camelCase}Value => ${jsonModelName.camelCase}Mapping[this]!;') - ..writeln('}') - ..writeln() - ..writeln( - 'extension ${jsonModelName.pascalCase}${itemTypeName.pascalCase}Extension on ${itemTypeName.originalText} {') - ..writeln( - ' ${jsonModelName.pascalCase}? get as${jsonModelName.pascalCase} => reverse${jsonModelName.pascalCase}Mapping[this];') - ..writeln('}'); - } - } - return sb.toString(); } } diff --git a/test/config/yml_generator_config/enum-normal.txt b/test/config/yml_generator_config/enum-normal.txt index d453524..f92c07b 100644 --- a/test/config/yml_generator_config/enum-normal.txt +++ b/test/config/yml_generator_config/enum-normal.txt @@ -6,19 +6,27 @@ User: Gender: type: enum + key_property: value properties: MALE: + value: male FEMALE: value: femAle other: + value: other X: + value: x Vehicles: type: enum + key_property: value uppercase_enums: false properties: male: + value: male female: value: femAle other: + value: other X: + value: x diff --git a/test/config/yml_generator_config_test.dart b/test/config/yml_generator_config_test.dart index fca5c3b..d9a204b 100644 --- a/test/config/yml_generator_config_test.dart +++ b/test/config/yml_generator_config_test.dart @@ -178,33 +178,44 @@ void main() { final enumModel2 = ymlConfig.models[2] as EnumModel; // ignore: avoid_as expect(enumModel.fields, isNotNull); expect(enumModel.fields!.length, 4); + expect(enumModel.keyProperty, 'value'); expect(enumModel.fields![0].name, 'MALE'); expect(enumModel.fields![0].serializedName, 'MALE'); - expect(enumModel.fields![0].value, null); + expect(enumModel.fields![0].enumProperties[0].value, 'male'); + expect(enumModel.fields![0].enumProperties[0].name, 'value'); expect(enumModel.fields![1].name, 'FEMALE'); expect(enumModel.fields![1].serializedName, 'FEMALE'); - expect(enumModel.fields![1].value, 'femAle'); + expect(enumModel.fields![1].enumProperties[0].value, 'femAle'); + expect(enumModel.fields![1].enumProperties[0].name, 'value'); expect(enumModel.fields![2].name, 'OTHER'); expect(enumModel.fields![2].serializedName, 'other'); - expect(enumModel.fields![2].value, null); + expect(enumModel.fields![2].enumProperties[0].value, 'other'); + expect(enumModel.fields![2].enumProperties[0].name, 'value'); expect(enumModel.fields![3].name, 'X'); expect(enumModel.fields![3].serializedName, 'X'); - expect(enumModel.fields![3].value, null); + expect(enumModel.fields![3].enumProperties[0].value, 'x'); + expect(enumModel.fields![3].enumProperties[0].name, 'value'); + expect(enumModel2.fields, isNotNull); expect(enumModel2.fields!.length, 4); + expect(enumModel.keyProperty, 'value'); expect(enumModel2.fields![0].name, 'male'); expect(enumModel2.fields![0].serializedName, 'male'); - expect(enumModel2.fields![0].value, null); + expect(enumModel.fields![0].enumProperties[0].value, 'male'); + expect(enumModel.fields![0].enumProperties[0].name, 'value'); expect(enumModel2.fields![1].name, 'female'); expect(enumModel2.fields![1].serializedName, 'female'); - expect(enumModel2.fields![1].value, 'femAle'); + expect(enumModel.fields![1].enumProperties[0].value, 'femAle'); + expect(enumModel.fields![1].enumProperties[0].name, 'value'); expect(enumModel2.fields![2].name, 'other'); expect(enumModel2.fields![2].serializedName, 'other'); - expect(enumModel2.fields![2].value, null); + expect(enumModel.fields![2].enumProperties[0].value, 'other'); + expect(enumModel.fields![2].enumProperties[0].name, 'value'); expect(enumModel2.fields![3].name, 'X'); expect(enumModel2.fields![3].serializedName, 'X'); - expect(enumModel2.fields![3].value, null); + expect(enumModel.fields![3].enumProperties[0].value, 'x'); + expect(enumModel.fields![3].enumProperties[0].name, 'value'); }); test('Error Enum no properties map', () { diff --git a/test/model/model/enum_model_test.dart b/test/model/model/enum_model_test.dart index 0ec0709..4ae4e98 100644 --- a/test/model/model/enum_model_test.dart +++ b/test/model/model/enum_model_test.dart @@ -6,6 +6,7 @@ void main() { group('Default', () { test('Normal EnumModel', () { final model = EnumModel( + keyProperty: 'keyProperty', name: 'MyEnumModel', path: 'path_to_my_model', baseDirectory: 'base_dir', @@ -18,6 +19,7 @@ void main() { group('Custom Path', () { test('Normal Custom Path', () { final model = EnumModel( + keyProperty: 'keyProperty', name: 'MyEnumModel', path: 'path_to_my_model/', baseDirectory: 'base_dir', @@ -29,6 +31,7 @@ void main() { test('Normal Custom Base Dir', () { final model = EnumModel( + keyProperty: 'keyProperty', name: 'MyEnumModel', path: 'path_to_my_model', baseDirectory: 'base_dir/', @@ -44,32 +47,53 @@ void main() { group('Default', () { test('Normal EnumField', () { final field = EnumField( - name: 'MY_ENUM_VALUE', - rawName: 'MY_ENUM_VALUE', - value: 'MY_ENUM_VALUE'); + name: 'MY_ENUM_VALUE', + rawName: 'MY_ENUM_VALUE', + enumProperties: [ + EnumProperty( + value: 'MY_ENUM_VALUE', + name: 'MY_ENUM_NAME', + ), + ], + ); expect(field.name, 'MY_ENUM_VALUE'); expect(field.serializedName, 'MY_ENUM_VALUE'); - expect(field.value, 'MY_ENUM_VALUE'); + expect(field.enumProperties.first.value, 'MY_ENUM_VALUE'); + expect(field.enumProperties.first.name, 'MY_ENUM_NAME'); }); test('Normal EnumField, lowercased', () { final field = EnumField( - name: 'my_enum_value', - rawName: 'MY_ENUM_VALUE', - value: 'MY_ENUM_VALUE'); + name: 'my_enum_value', + rawName: 'MY_ENUM_VALUE', + enumProperties: [ + EnumProperty( + value: 'MY_ENUM_VALUE', + name: 'MY_ENUM_NAME', + ), + ], + ); expect(field.name, 'my_enum_value'); expect(field.serializedName, 'MY_ENUM_VALUE'); - expect(field.value, 'MY_ENUM_VALUE'); + expect(field.enumProperties.first.value, 'MY_ENUM_VALUE'); + expect(field.enumProperties.first.name, 'MY_ENUM_NAME'); }); }); group('Custom serializedName', () { test('Normal Custom Base Dir', () { final field = EnumField( - name: 'MY_ENUM_VALUE', - rawName: 'my_enum_value', - value: 'my_enum_value'); + name: 'MY_ENUM_VALUE', + rawName: 'my_enum_value', + enumProperties: [ + EnumProperty( + value: 'MY_ENUM_VALUE', + name: 'MY_ENUM_NAME', + ), + ], + ); expect(field.name, 'MY_ENUM_VALUE'); expect(field.serializedName, 'my_enum_value'); - expect(field.value, 'my_enum_value'); + expect(field.enumProperties.first.value, 'MY_ENUM_VALUE'); + expect(field.enumProperties.first.name, 'MY_ENUM_NAME'); }); }); }); diff --git a/test/writer/enum_model_writer/custom-value-map-extension.txt b/test/writer/enum_model_writer/custom-value-map-extension/output.txt similarity index 100% rename from test/writer/enum_model_writer/custom-value-map-extension.txt rename to test/writer/enum_model_writer/custom-value-map-extension/output.txt diff --git a/test/writer/enum_model_writer/custom-value-map.txt b/test/writer/enum_model_writer/custom-value-map/output.txt similarity index 100% rename from test/writer/enum_model_writer/custom-value-map.txt rename to test/writer/enum_model_writer/custom-value-map/output.txt diff --git a/test/writer/enum_model_writer/custom-value.txt b/test/writer/enum_model_writer/custom-value/output.txt similarity index 100% rename from test/writer/enum_model_writer/custom-value.txt rename to test/writer/enum_model_writer/custom-value/output.txt diff --git a/test/writer/enum_model_writer/no-fields.txt b/test/writer/enum_model_writer/no-fields/output.txt similarity index 100% rename from test/writer/enum_model_writer/no-fields.txt rename to test/writer/enum_model_writer/no-fields/output.txt diff --git a/test/writer/enum_model_writer/normal-description.txt b/test/writer/enum_model_writer/normal-description/output.txt similarity index 100% rename from test/writer/enum_model_writer/normal-description.txt rename to test/writer/enum_model_writer/normal-description/output.txt diff --git a/test/writer/enum_model_writer/normal.txt b/test/writer/enum_model_writer/normal/output.txt similarity index 100% rename from test/writer/enum_model_writer/normal.txt rename to test/writer/enum_model_writer/normal/output.txt diff --git a/test/writer/enum_model_writer/normal_with_double_type.txt b/test/writer/enum_model_writer/normal_with_double_type/output.txt similarity index 100% rename from test/writer/enum_model_writer/normal_with_double_type.txt rename to test/writer/enum_model_writer/normal_with_double_type/output.txt diff --git a/test/writer/enum_model_writer/normal_with_double_type_map.txt b/test/writer/enum_model_writer/normal_with_double_type_map/output.txt similarity index 100% rename from test/writer/enum_model_writer/normal_with_double_type_map.txt rename to test/writer/enum_model_writer/normal_with_double_type_map/output.txt diff --git a/test/writer/enum_model_writer/normal_with_double_type_map_extension.txt b/test/writer/enum_model_writer/normal_with_double_type_map_extension/output.txt similarity index 100% rename from test/writer/enum_model_writer/normal_with_double_type_map_extension.txt rename to test/writer/enum_model_writer/normal_with_double_type_map_extension/output.txt diff --git a/test/writer/enum_model_writer/normal_with_int_type.txt b/test/writer/enum_model_writer/normal_with_int_type/output.txt similarity index 100% rename from test/writer/enum_model_writer/normal_with_int_type.txt rename to test/writer/enum_model_writer/normal_with_int_type/output.txt diff --git a/test/writer/enum_model_writer/normal_with_int_type_map.txt b/test/writer/enum_model_writer/normal_with_int_type_map/output.txt similarity index 100% rename from test/writer/enum_model_writer/normal_with_int_type_map.txt rename to test/writer/enum_model_writer/normal_with_int_type_map/output.txt diff --git a/test/writer/enum_model_writer/normal_with_int_type_map_extension.txt b/test/writer/enum_model_writer/normal_with_int_type_map_extension/output.txt similarity index 100% rename from test/writer/enum_model_writer/normal_with_int_type_map_extension.txt rename to test/writer/enum_model_writer/normal_with_int_type_map_extension/output.txt diff --git a/test/writer/enum_model_writer/null-value.txt b/test/writer/enum_model_writer/null-value/output.txt similarity index 100% rename from test/writer/enum_model_writer/null-value.txt rename to test/writer/enum_model_writer/null-value/output.txt diff --git a/test/writer/enum_model_writer_test.dart b/test/writer/enum_model_writer_test.dart index 98044bc..48e5569 100644 --- a/test/writer/enum_model_writer_test.dart +++ b/test/writer/enum_model_writer_test.dart @@ -1,296 +1,5 @@ -import 'package:model_generator/model/item_type/double_type.dart'; -import 'package:model_generator/model/item_type/integer_type.dart'; import 'package:test/test.dart'; -import 'package:model_generator/model/model/enum_model.dart'; - -import 'writer_test_helper.dart'; void main() { - group('EnumModel', () { - test('Normal EnumModel', () { - final model = EnumModel( - name: 'MyEnumModel', - path: 'path_to_my_model', - baseDirectory: 'base_dir', - fields: [ - EnumField( - name: 'MY_VALUE_1', - rawName: 'MY_VALUE_1', - value: 'MY_VALUE_1', - description: 'A good description of this field', - ), - EnumField( - name: 'MY_VALUE_2', - rawName: 'MY_VALUE_2', - value: 'MY_VALUE_2', - ), - ], - ); - WriterTestHelper.testEnumModelWriter(model, 'normal'); - }); - - test('Normal EnumModel with int type', () { - final model = EnumModel( - name: 'MyEnumModel', - path: 'path_to_my_model', - baseDirectory: 'base_dir', - itemType: IntegerType(), - fields: [ - EnumField( - name: 'MY_VALUE_1', - rawName: 'MY_VALUE_1', - value: '1', - description: 'A good description of this field', - ), - EnumField( - name: 'MY_VALUE_2', - rawName: 'MY_VALUE_2', - value: '2', - ), - ], - ); - WriterTestHelper.testEnumModelWriter(model, 'normal_with_int_type'); - }); - - test('Normal EnumModel with int type generate map', () { - final model = EnumModel( - name: 'MyEnumModel', - path: 'path_to_my_model', - baseDirectory: 'base_dir', - itemType: IntegerType(), - generateMap: true, - fields: [ - EnumField( - name: 'MY_VALUE_1', - rawName: 'MY_VALUE_1', - value: '1', - description: 'A good description of this field', - ), - EnumField( - name: 'MY_VALUE_2', - rawName: 'MY_VALUE_2', - value: '2', - ), - ], - ); - WriterTestHelper.testEnumModelWriter(model, 'normal_with_int_type_map'); - }); - - test('Normal EnumModel with int type generate map extension', () { - final model = EnumModel( - name: 'MyEnumModel', - path: 'path_to_my_model', - baseDirectory: 'base_dir', - itemType: IntegerType(), - generateMap: true, - generateExtensions: true, - fields: [ - EnumField( - name: 'MY_VALUE_1', - rawName: 'MY_VALUE_1', - value: '1', - description: 'A good description of this field', - ), - EnumField( - name: 'MY_VALUE_2', - rawName: 'MY_VALUE_2', - value: '2', - ), - ], - ); - WriterTestHelper.testEnumModelWriter( - model, 'normal_with_int_type_map_extension'); - }); - - test('Normal EnumModel with double type', () { - final model = EnumModel( - name: 'MyEnumModel', - path: 'path_to_my_model', - baseDirectory: 'base_dir', - itemType: DoubleType(), - fields: [ - EnumField( - name: 'MY_VALUE_1', - rawName: 'MY_VALUE_1', - value: '1.0', - description: 'A good description of this field', - ), - EnumField( - name: 'MY_VALUE_2', - rawName: 'MY_VALUE_2', - value: '2.2', - ), - ], - ); - WriterTestHelper.testEnumModelWriter(model, 'normal_with_double_type'); - }); - - test('Normal EnumModel with double type generate map', () { - final model = EnumModel( - name: 'MyEnumModel', - path: 'path_to_my_model', - baseDirectory: 'base_dir', - itemType: DoubleType(), - generateMap: true, - fields: [ - EnumField( - name: 'MY_VALUE_1', - rawName: 'MY_VALUE_1', - value: '1.0', - description: 'A good description of this field', - ), - EnumField( - name: 'MY_VALUE_2', - rawName: 'MY_VALUE_2', - value: '2.2', - ), - ], - ); - WriterTestHelper.testEnumModelWriter( - model, 'normal_with_double_type_map'); - }); - - test('Normal EnumModel with double type generate map extension', () { - final model = EnumModel( - name: 'MyEnumModel', - path: 'path_to_my_model', - baseDirectory: 'base_dir', - itemType: DoubleType(), - generateMap: true, - generateExtensions: true, - fields: [ - EnumField( - name: 'MY_VALUE_1', - rawName: 'MY_VALUE_1', - value: '1.0', - description: 'A good description of this field', - ), - EnumField( - name: 'MY_VALUE_2', - rawName: 'MY_VALUE_2', - value: '2.2', - ), - ], - ); - WriterTestHelper.testEnumModelWriter( - model, 'normal_with_double_type_map_extension'); - }); - - test('Normal EnumModel custom value', () { - final model = EnumModel( - name: 'MyEnumModel', - path: 'path_to_my_model', - baseDirectory: 'base_dir', - fields: [ - EnumField( - name: 'MY_VALUE_1', - rawName: 'MY_VALUE_1', - value: 'MY_VALUE_1', - ), - EnumField( - name: 'MY_VALUE_2', - rawName: 'MY_VALUE_2', - value: 'custom_value_2', - ), - ], - ); - WriterTestHelper.testEnumModelWriter(model, 'custom-value'); - }); - - test('Enum model with null enumfield.value ', () { - final model = EnumModel( - name: 'MyEnumModel', - path: 'path_to_my_model', - baseDirectory: 'base_dir', - fields: [ - EnumField( - name: 'MY_VALUE_1', - rawName: 'MY_VALUE_1', - value: 'MY_VALUE_1', - ), - EnumField( - name: 'MY_VALUE_2', - rawName: 'MY_VALUE_2', - ), - ], - ); - WriterTestHelper.testEnumModelWriter(model, 'null-value'); - }); - - test('EnumModel with no fields ', () { - final model = EnumModel( - name: 'MyEnumModel', - path: 'path_to_my_model', - baseDirectory: 'base_dir', - fields: [], - ); - WriterTestHelper.testEnumModelWriter(model, 'no-fields'); - }); - - test('Custom EnumModel generate map', () { - final model = EnumModel( - name: 'MyEnumModel', - path: 'path_to_my_model', - baseDirectory: 'base_dir', - generateMap: true, - fields: [ - EnumField( - name: 'MY_VALUE_1', - rawName: 'MY_VALUE_1', - value: 'customValue', - ), - EnumField( - name: 'MY_VALUE_2', - rawName: 'MY_VALUE_2', - ), - ], - ); - WriterTestHelper.testEnumModelWriter(model, 'custom-value-map'); - }); - - test('Custom EnumModel generate map extension', () { - final model = EnumModel( - name: 'MyEnumModel', - path: 'path_to_my_model', - baseDirectory: 'base_dir', - generateMap: true, - generateExtensions: true, - fields: [ - EnumField( - name: 'MY_VALUE_1', - rawName: 'MY_VALUE_1', - value: 'customValue', - ), - EnumField( - name: 'MY_VALUE_2', - rawName: 'MY_VALUE_2', - ), - ], - ); - WriterTestHelper.testEnumModelWriter(model, 'custom-value-map-extension'); - }); - - test('Normal EnumModel with description', () { - final model = EnumModel( - name: 'MyEnumModel', - path: 'path_to_my_model', - baseDirectory: 'base_dir', - fields: [ - EnumField( - name: 'MY_VALUE_1', - rawName: 'MY_VALUE_1', - value: 'MY_VALUE_1', - description: 'A good description of this field', - ), - EnumField( - name: 'MY_VALUE_2', - rawName: 'MY_VALUE_2', - value: 'MY_VALUE_2', - ), - ], - description: 'A good description of this enum', - ); - WriterTestHelper.testEnumModelWriter(model, 'normal-description'); - }); - }); + group('EnumModel', () {}); } diff --git a/test/writer/writer_test_helper.dart b/test/writer/writer_test_helper.dart deleted file mode 100644 index 55fb148..0000000 --- a/test/writer/writer_test_helper.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'dart:io'; - -import 'package:test/test.dart'; -import 'package:model_generator/model/model/enum_model.dart'; -import 'package:model_generator/writer/enum_model_writer.dart'; - -class WriterTestHelper { - static testEnumModelWriter(EnumModel model, String resultFileName) { - print(Directory.current); - final file = File('test/writer/enum_model_writer/$resultFileName.txt'); - final output = file.readAsStringSync(); - final actual = EnumModelWriter(model).write(); - // print(actual); - expect(actual, output); - } -} From 3b228ecfd9fa668ddb81bae8925b5add691dfeea Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Mon, 4 Sep 2023 17:15:59 +0200 Subject: [PATCH 02/42] #130: added enum model tests --- test/writer/enum_model_writer/pubspec.txt | 4 +++ test/writer/enum_model_writer_test.dart | 41 ++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 test/writer/enum_model_writer/pubspec.txt diff --git a/test/writer/enum_model_writer/pubspec.txt b/test/writer/enum_model_writer/pubspec.txt new file mode 100644 index 0000000..95f3114 --- /dev/null +++ b/test/writer/enum_model_writer/pubspec.txt @@ -0,0 +1,4 @@ +name: model_generator_example + +model_generator: + config_path: model_generator/config.yaml diff --git a/test/writer/enum_model_writer_test.dart b/test/writer/enum_model_writer_test.dart index 48e5569..1ff37a0 100644 --- a/test/writer/enum_model_writer_test.dart +++ b/test/writer/enum_model_writer_test.dart @@ -1,5 +1,44 @@ +import 'dart:io'; + +import 'package:model_generator/config/pubspec_config.dart'; +import 'package:model_generator/config/yml_generator_config.dart'; +import 'package:model_generator/model/model/enum_model.dart'; +import 'package:model_generator/writer/enum_model_writer.dart'; import 'package:test/test.dart'; void main() { - group('EnumModel', () {}); + void testEnumModelWriter(String path) { + final file = File('$path/output.txt'); + final pubspecFile = File('test/writer/enum_model_writer/pubspec.txt'); + final configFile = File('$path/config.txt'); + final expected = file.readAsStringSync(); + final pubspecContent = pubspecFile.readAsStringSync(); + final configContent = configFile.readAsStringSync(); + final pubspecConfig = PubspecConfig(pubspecContent); + final ymlConfig = YmlGeneratorConfig(pubspecConfig, configContent, ''); + final jsonModel = ymlConfig.models.first; + if (jsonModel is! EnumModel) { + throw Exception('The first model in the config file must be an object model and will be validated. The model is ${ymlConfig.models.first.runtimeType}'); + } + + final generateActual = EnumModelWriter(jsonModel).write; + if (expected.startsWith('Exception')) { + expect(generateActual, throwsA(isA())); + } else { + expect(generateActual(), expected); + } + } + + group('EnumModelWriter test', () { + final directory = Directory('test/writer/enum_model_writer'); + final folders = directory.listSync(); + for (final folder in folders) { + if (folder is Directory) { + test('Folder ${folder.path}', () { + print('Testing folder ${folder.path}'); + testEnumModelWriter(folder.path); + }); + } + } + }); } From 07ae5025391d64aeb2774901c558ebe107eb64be Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Mon, 4 Sep 2023 17:32:23 +0200 Subject: [PATCH 03/42] #130: moved shared code to helper --- lib/config/yml_generator_config.dart | 4 +-- lib/model/model/enum_model.dart | 2 +- test/writer/enum_model_writer_test.dart | 24 +++++++---------- test/writer/object_model_writer_test.dart | 25 ++++++------------ test/writer/writer_helper.dart | 32 +++++++++++++++++++++++ 5 files changed, 53 insertions(+), 34 deletions(-) create mode 100644 test/writer/writer_helper.dart diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index 07988ab..cf8d103 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -98,9 +98,9 @@ class YmlGeneratorConfig { if (propertyValue != null && propertyValue is! YamlMap) { throw Exception('$propertyKey should be an object'); } - final propertiesYaml = propertyValue as YamlMap; + final propertiesYaml = propertyValue as YamlMap?; final properties = []; - propertiesYaml.forEach((propertyKey, propertyValue) { + propertiesYaml?.forEach((propertyKey, propertyValue) { properties.add(EnumProperty( value: propertyValue, name: propertyKey, diff --git a/lib/model/model/enum_model.dart b/lib/model/model/enum_model.dart index 1f9a099..0335534 100644 --- a/lib/model/model/enum_model.dart +++ b/lib/model/model/enum_model.dart @@ -4,7 +4,7 @@ import 'package:model_generator/model/model/model.dart'; class EnumModel extends Model { final List? fields; - final String keyProperty; + final String? keyProperty; EnumModel({ required String name, diff --git a/test/writer/enum_model_writer_test.dart b/test/writer/enum_model_writer_test.dart index 1ff37a0..a619c9a 100644 --- a/test/writer/enum_model_writer_test.dart +++ b/test/writer/enum_model_writer_test.dart @@ -1,31 +1,27 @@ import 'dart:io'; -import 'package:model_generator/config/pubspec_config.dart'; -import 'package:model_generator/config/yml_generator_config.dart'; import 'package:model_generator/model/model/enum_model.dart'; import 'package:model_generator/writer/enum_model_writer.dart'; import 'package:test/test.dart'; +import 'writer_helper.dart'; + void main() { void testEnumModelWriter(String path) { - final file = File('$path/output.txt'); - final pubspecFile = File('test/writer/enum_model_writer/pubspec.txt'); - final configFile = File('$path/config.txt'); - final expected = file.readAsStringSync(); - final pubspecContent = pubspecFile.readAsStringSync(); - final configContent = configFile.readAsStringSync(); - final pubspecConfig = PubspecConfig(pubspecContent); - final ymlConfig = YmlGeneratorConfig(pubspecConfig, configContent, ''); - final jsonModel = ymlConfig.models.first; + final result = WriterHelper.prepareYmlConfig( + path: path, + pubspecPath: 'test/writer/enum_model_writer', + ); + final jsonModel = result.config.models.first; if (jsonModel is! EnumModel) { - throw Exception('The first model in the config file must be an object model and will be validated. The model is ${ymlConfig.models.first.runtimeType}'); + throw Exception('The first model in the config file must be an object model and will be validated. The model is ${jsonModel.runtimeType}'); } final generateActual = EnumModelWriter(jsonModel).write; - if (expected.startsWith('Exception')) { + if (result.expected.startsWith('Exception')) { expect(generateActual, throwsA(isA())); } else { - expect(generateActual(), expected); + expect(generateActual(), result.expected); } } diff --git a/test/writer/object_model_writer_test.dart b/test/writer/object_model_writer_test.dart index 33f4a16..6d5bce8 100644 --- a/test/writer/object_model_writer_test.dart +++ b/test/writer/object_model_writer_test.dart @@ -1,33 +1,24 @@ import 'dart:io'; -import 'package:model_generator/config/pubspec_config.dart'; -import 'package:model_generator/config/yml_generator_config.dart'; import 'package:model_generator/model/model/object_model.dart'; import 'package:model_generator/writer/object_model_writer.dart'; import 'package:test/test.dart'; +import 'writer_helper.dart'; + void main() { void testObjectModelWriter(String path) { - final file = File('$path/output.txt'); - final pubspecFile = File('$path/pubspec.txt'); - final configFile = File('$path/config.txt'); - final expected = file.readAsStringSync(); - final pubspecContent = pubspecFile.readAsStringSync(); - final configContent = configFile.readAsStringSync(); - final pubspecConfig = PubspecConfig(pubspecContent); - final ymlConfig = YmlGeneratorConfig(pubspecConfig, configContent, ''); - final jsonModel = ymlConfig.models.first; + final result = WriterHelper.prepareYmlConfig(path: path); + final jsonModel = result.config.models.first; if (jsonModel is! ObjectModel) { - throw Exception( - 'The first model in the config file must be an object model and will be validated. The model is ${ymlConfig.models.first.runtimeType}'); + throw Exception('The first model in the config file must be an object model and will be validated. The model is ${jsonModel.runtimeType}'); } - final generateActual = - ObjectModelWriter(pubspecConfig, jsonModel, ymlConfig).write; - if (expected.startsWith('Exception')) { + final generateActual = ObjectModelWriter(result.pubspecConfig, jsonModel, result.config).write; + if (result.expected.startsWith('Exception')) { expect(generateActual, throwsA(isA())); } else { - expect(generateActual(), expected); + expect(generateActual(), result.expected); } } diff --git a/test/writer/writer_helper.dart b/test/writer/writer_helper.dart new file mode 100644 index 0000000..0541f3c --- /dev/null +++ b/test/writer/writer_helper.dart @@ -0,0 +1,32 @@ +import 'dart:io'; + +import 'package:model_generator/config/pubspec_config.dart'; +import 'package:model_generator/config/yml_generator_config.dart'; + +class WriterHelper { + WriterHelper._(); + + static ({ + String expected, + YmlGeneratorConfig config, + PubspecConfig pubspecConfig, + }) prepareYmlConfig({ + required String path, + String? pubspecPath, + }) { + final file = File('$path/output.txt'); + final pubspecFile = File('${pubspecPath ?? path}/pubspec.txt'); + final configFile = File('$path/config.txt'); + final expected = file.readAsStringSync(); + final pubspecContent = pubspecFile.readAsStringSync(); + final configContent = configFile.readAsStringSync(); + final pubspecConfig = PubspecConfig(pubspecContent); + final ymlConfig = YmlGeneratorConfig(pubspecConfig, configContent, ''); + + return ( + expected: expected, + config: ymlConfig, + pubspecConfig: pubspecConfig, + ); + } +} From f17dbddcb305d24a4e1703e7d46a2a10be0a1a65 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Mon, 4 Sep 2023 18:40:20 +0200 Subject: [PATCH 04/42] #130: fixed normal enum test --- lib/model/model/enum_model.dart | 3 ++- lib/writer/enum_model_writer.dart | 5 +++-- test/writer/enum_model_writer/normal/config.txt | 8 ++++++++ test/writer/enum_model_writer/normal/output.txt | 1 - test/writer/enum_model_writer_test.dart | 2 +- test/writer/object_model_writer_test.dart | 2 +- test/writer/writer_helper.dart | 2 +- 7 files changed, 16 insertions(+), 7 deletions(-) create mode 100644 test/writer/enum_model_writer/normal/config.txt diff --git a/lib/model/model/enum_model.dart b/lib/model/model/enum_model.dart index 0335534..cb0cff6 100644 --- a/lib/model/model/enum_model.dart +++ b/lib/model/model/enum_model.dart @@ -1,5 +1,6 @@ import 'package:model_generator/model/item_type/integer_type.dart'; import 'package:model_generator/model/item_type/item_type.dart'; +import 'package:model_generator/model/item_type/string_type.dart'; import 'package:model_generator/model/model/model.dart'; class EnumModel extends Model { @@ -56,5 +57,5 @@ class EnumProperty { EnumProperty({ required this.value, required this.name, - }) : type = IntegerType(); + }) : type = StringType(); } diff --git a/lib/writer/enum_model_writer.dart b/lib/writer/enum_model_writer.dart index 62d42e4..1341fcf 100644 --- a/lib/writer/enum_model_writer.dart +++ b/lib/writer/enum_model_writer.dart @@ -28,10 +28,11 @@ class EnumModelWriter { jsonModel.fields?.forEach((key) { final keyProperty = key.enumProperties.firstWhereOrNull((element) => element.name.toLowerCase() == jsonModel.keyProperty); final jsonValue = keyProperty?.value ?? key.serializedName; + final propertyType = keyProperty?.type; - if (keyProperty?.type is StringType) { + if (propertyType is StringType || propertyType == null) { sb.writeln(' @JsonValue(\'$jsonValue\')'); - } else if (keyProperty?.type is DoubleType) { + } else if (propertyType is DoubleType) { final doubleValue = double.tryParse(jsonValue); sb.writeln(' @JsonValue($doubleValue)'); } else { diff --git a/test/writer/enum_model_writer/normal/config.txt b/test/writer/enum_model_writer/normal/config.txt new file mode 100644 index 0000000..096d3af --- /dev/null +++ b/test/writer/enum_model_writer/normal/config.txt @@ -0,0 +1,8 @@ +MyEnumModel: + path: test/enum/ + type: enum + properties: + MY_VALUE_1: + value: '1' + MY_VALUE_2: + value: '2' diff --git a/test/writer/enum_model_writer/normal/output.txt b/test/writer/enum_model_writer/normal/output.txt index 526caef..0b50f98 100644 --- a/test/writer/enum_model_writer/normal/output.txt +++ b/test/writer/enum_model_writer/normal/output.txt @@ -3,7 +3,6 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { - ///A good description of this field @JsonValue('MY_VALUE_1') MY_VALUE_1, @JsonValue('MY_VALUE_2') diff --git a/test/writer/enum_model_writer_test.dart b/test/writer/enum_model_writer_test.dart index a619c9a..c6d0ca1 100644 --- a/test/writer/enum_model_writer_test.dart +++ b/test/writer/enum_model_writer_test.dart @@ -8,7 +8,7 @@ import 'writer_helper.dart'; void main() { void testEnumModelWriter(String path) { - final result = WriterHelper.prepareYmlConfig( + final result = WriterHelper.prepareWriterTest( path: path, pubspecPath: 'test/writer/enum_model_writer', ); diff --git a/test/writer/object_model_writer_test.dart b/test/writer/object_model_writer_test.dart index 6d5bce8..c8bae49 100644 --- a/test/writer/object_model_writer_test.dart +++ b/test/writer/object_model_writer_test.dart @@ -8,7 +8,7 @@ import 'writer_helper.dart'; void main() { void testObjectModelWriter(String path) { - final result = WriterHelper.prepareYmlConfig(path: path); + final result = WriterHelper.prepareWriterTest(path: path); final jsonModel = result.config.models.first; if (jsonModel is! ObjectModel) { throw Exception('The first model in the config file must be an object model and will be validated. The model is ${jsonModel.runtimeType}'); diff --git a/test/writer/writer_helper.dart b/test/writer/writer_helper.dart index 0541f3c..a50abb0 100644 --- a/test/writer/writer_helper.dart +++ b/test/writer/writer_helper.dart @@ -10,7 +10,7 @@ class WriterHelper { String expected, YmlGeneratorConfig config, PubspecConfig pubspecConfig, - }) prepareYmlConfig({ + }) prepareWriterTest({ required String path, String? pubspecPath, }) { From e2fdf191f8e0dd9c4cd5ab41addac70ab9ab82ad Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Tue, 5 Sep 2023 10:06:24 +0200 Subject: [PATCH 05/42] #130: added properties to enum writer --- lib/model/model/enum_model.dart | 5 +- lib/writer/enum_model_writer.dart | 29 +- test/config/yml_generator_config_test.dart | 302 ++++++------------ test/model/model/enum_model_test.dart | 3 + .../custom-value-map-extension/output.txt | 28 -- .../custom-value-map/output.txt | 20 -- .../enum_model_writer/custom-value/config.txt | 9 + .../enum_model_writer/custom-value/output.txt | 4 +- .../enum_model_writer/no-fields/output.txt | 6 - .../normal-description/config.txt | 7 + .../normal-description/output.txt | 1 - .../enum_model_writer/normal/config.txt | 4 +- .../normal_with_double_type_map/output.txt | 21 -- .../output.txt | 29 -- .../normal_with_int_type_map/output.txt | 21 -- .../output.txt | 29 -- .../enum_model_writer/null-value/output.txt | 10 - 17 files changed, 148 insertions(+), 380 deletions(-) delete mode 100644 test/writer/enum_model_writer/custom-value-map-extension/output.txt delete mode 100644 test/writer/enum_model_writer/custom-value-map/output.txt create mode 100644 test/writer/enum_model_writer/custom-value/config.txt delete mode 100644 test/writer/enum_model_writer/no-fields/output.txt create mode 100644 test/writer/enum_model_writer/normal-description/config.txt delete mode 100644 test/writer/enum_model_writer/normal_with_double_type_map/output.txt delete mode 100644 test/writer/enum_model_writer/normal_with_double_type_map_extension/output.txt delete mode 100644 test/writer/enum_model_writer/normal_with_int_type_map/output.txt delete mode 100644 test/writer/enum_model_writer/normal_with_int_type_map_extension/output.txt delete mode 100644 test/writer/enum_model_writer/null-value/output.txt diff --git a/lib/model/model/enum_model.dart b/lib/model/model/enum_model.dart index cb0cff6..ffb48c9 100644 --- a/lib/model/model/enum_model.dart +++ b/lib/model/model/enum_model.dart @@ -1,18 +1,17 @@ -import 'package:model_generator/model/item_type/integer_type.dart'; import 'package:model_generator/model/item_type/item_type.dart'; import 'package:model_generator/model/item_type/string_type.dart'; import 'package:model_generator/model/model/model.dart'; class EnumModel extends Model { - final List? fields; + final List fields; final String? keyProperty; EnumModel({ required String name, required this.keyProperty, + required this.fields, String? path, String? baseDirectory, - this.fields, List? extraImports, List? extraAnnotations, String? description, diff --git a/lib/writer/enum_model_writer.dart b/lib/writer/enum_model_writer.dart index 1341fcf..8cbb308 100644 --- a/lib/writer/enum_model_writer.dart +++ b/lib/writer/enum_model_writer.dart @@ -23,12 +23,14 @@ class EnumModelWriter { } final jsonModelName = CaseUtil(jsonModel.name); + final properties = jsonModel.fields.first.enumProperties; sb.writeln('enum ${jsonModelName.pascalCase} {'); - jsonModel.fields?.forEach((key) { + for (var key in jsonModel.fields) { final keyProperty = key.enumProperties.firstWhereOrNull((element) => element.name.toLowerCase() == jsonModel.keyProperty); final jsonValue = keyProperty?.value ?? key.serializedName; final propertyType = keyProperty?.type; + final isLast = jsonModel.fields.indexOf(key) == (jsonModel.fields.length - 1); if (propertyType is StringType || propertyType == null) { sb.writeln(' @JsonValue(\'$jsonValue\')'); @@ -38,8 +40,29 @@ class EnumModelWriter { } else { sb.writeln(' @JsonValue($jsonValue)'); } - sb.writeln(' ${key.name},'); - }); + sb.write(' ${key.name}'); + if (key.enumProperties.isNotEmpty && isLast) { + sb.writeln(';'); + } else { + sb.writeln(','); + } + } + + if (properties.isNotEmpty) { + sb.writeln(); + } + + for (var property in properties) { + sb.writeln('final ${property.type} ${property.name};'); + } + if (properties.isNotEmpty) { + sb.write('Const ${jsonModel.name} ({'); + for (var property in properties) { + sb.write('required this.${property.name}, '); + } + sb.writeln('})'); + } + sb.writeln('}'); return sb.toString(); diff --git a/test/config/yml_generator_config_test.dart b/test/config/yml_generator_config_test.dart index d9a204b..d5d6a0d 100644 --- a/test/config/yml_generator_config_test.dart +++ b/test/config/yml_generator_config_test.dart @@ -12,23 +12,19 @@ void main() { group('YmlGeneratorConfig', () { group('Empty', () { test('Behaviour with empty file', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); final ymlConfig = YmlGeneratorConfig(pubspecConfig, '', ''); expect(ymlConfig.models.isEmpty, true); }); }); group('Object', () { test('Normal object', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig = YmlGeneratorConfig(pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig('object-normal'), ''); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-normal'), ''); ymlConfig.checkIfTypesAvailable(); expect(ymlConfig.models.length, 1); expect(ymlConfig.models.first is ObjectModel, true); - final objectModel = - ymlConfig.models.first as ObjectModel; // ignore: avoid_as + final objectModel = ymlConfig.models.first as ObjectModel; // ignore: avoid_as expect(objectModel.path, null); expect(objectModel.baseDirectory, 'model'); expect(objectModel.fileName, 'person'); @@ -37,17 +33,12 @@ void main() { }); test('Normal object with multiple fields', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig = YmlGeneratorConfig( - pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig('object-multiple-fields'), - ''); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-multiple-fields'), ''); ymlConfig.checkIfTypesAvailable(); expect(ymlConfig.models.length, 1); expect(ymlConfig.models.first is ObjectModel, true); - final objectModel = - ymlConfig.models.first as ObjectModel; // ignore: avoid_as + final objectModel = ymlConfig.models.first as ObjectModel; // ignore: avoid_as expect(objectModel.path, null); expect(objectModel.baseDirectory, 'model'); expect(objectModel.fileName, 'person'); @@ -56,15 +47,12 @@ void main() { }); test('Normal object with baseDirectory', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig = YmlGeneratorConfig(pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig('object-base-dir'), ''); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-base-dir'), ''); ymlConfig.checkIfTypesAvailable(); expect(ymlConfig.models.length, 1); expect(ymlConfig.models.first is ObjectModel, true); - final objectModel = - ymlConfig.models.first as ObjectModel; // ignore: avoid_as + final objectModel = ymlConfig.models.first as ObjectModel; // ignore: avoid_as expect(objectModel.path, null); expect(objectModel.baseDirectory, 'custom_base_dir'); expect(objectModel.fileName, 'person'); @@ -73,15 +61,12 @@ void main() { }); test('Normal object with all types', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig = YmlGeneratorConfig(pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig('object-all-types'), ''); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-all-types'), ''); ymlConfig.checkIfTypesAvailable(); expect(ymlConfig.models.length, 2); expect(ymlConfig.models.first is ObjectModel, true); - final objectModel = - ymlConfig.models.first as ObjectModel; // ignore: avoid_as + final objectModel = ymlConfig.models.first as ObjectModel; // ignore: avoid_as expect(objectModel.path, null); expect(objectModel.baseDirectory, 'model'); expect(objectModel.fileName, 'person'); @@ -90,17 +75,11 @@ void main() { }); test('Error property is no object', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); var hasError = false; var errorMessage = ''; try { - YmlGeneratorConfig( - pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig( - 'object-error-no-object'), - '') - .checkIfTypesAvailable(); + YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-error-no-object'), '').checkIfTypesAvailable(); } catch (e) { hasError = true; errorMessage = e.toString(); @@ -110,17 +89,11 @@ void main() { }); test('Error missing type', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); var hasError = false; var errorMessage = ''; try { - YmlGeneratorConfig( - pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig( - 'object-error-missing-type'), - '') - .checkIfTypesAvailable(); + YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-error-missing-type'), '').checkIfTypesAvailable(); } catch (e) { hasError = true; errorMessage = e.toString(); @@ -130,32 +103,23 @@ void main() { }); test('Error no properties', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); var hasError = false; var errorMessage = ''; try { - YmlGeneratorConfig( - pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig( - 'object-error-no-properties'), - '') - .checkIfTypesAvailable(); + YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-error-no-properties'), '').checkIfTypesAvailable(); } catch (e) { hasError = true; errorMessage = e.toString(); } expect(hasError, true); - expect(errorMessage, - 'Exception: Properties can not be null. model: Person'); + expect(errorMessage, 'Exception: Properties can not be null. model: Person'); }); }); group('Custom', () { test('Custom object', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig = YmlGeneratorConfig(pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig('custom-normal'), ''); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('custom-normal'), ''); ymlConfig.checkIfTypesAvailable(); expect(ymlConfig.models.length, 2); expect(ymlConfig.models.first is ObjectModel, true); @@ -164,10 +128,8 @@ void main() { }); group('Enum', () { test('Normal Enum', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig = YmlGeneratorConfig(pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig('enum-normal'), ''); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('enum-normal'), ''); ymlConfig.checkIfTypesAvailable(); expect(ymlConfig.models.length, 3); expect(ymlConfig.models.first is ObjectModel, true); @@ -177,59 +139,52 @@ void main() { final enumModel = ymlConfig.models[1] as EnumModel; // ignore: avoid_as final enumModel2 = ymlConfig.models[2] as EnumModel; // ignore: avoid_as expect(enumModel.fields, isNotNull); - expect(enumModel.fields!.length, 4); + expect(enumModel.fields.length, 4); expect(enumModel.keyProperty, 'value'); - expect(enumModel.fields![0].name, 'MALE'); - expect(enumModel.fields![0].serializedName, 'MALE'); - expect(enumModel.fields![0].enumProperties[0].value, 'male'); - expect(enumModel.fields![0].enumProperties[0].name, 'value'); - expect(enumModel.fields![1].name, 'FEMALE'); - expect(enumModel.fields![1].serializedName, 'FEMALE'); - expect(enumModel.fields![1].enumProperties[0].value, 'femAle'); - expect(enumModel.fields![1].enumProperties[0].name, 'value'); - expect(enumModel.fields![2].name, 'OTHER'); - expect(enumModel.fields![2].serializedName, 'other'); - expect(enumModel.fields![2].enumProperties[0].value, 'other'); - expect(enumModel.fields![2].enumProperties[0].name, 'value'); - expect(enumModel.fields![3].name, 'X'); - expect(enumModel.fields![3].serializedName, 'X'); - expect(enumModel.fields![3].enumProperties[0].value, 'x'); - expect(enumModel.fields![3].enumProperties[0].name, 'value'); - + expect(enumModel.fields[0].name, 'MALE'); + expect(enumModel.fields[0].serializedName, 'MALE'); + expect(enumModel.fields[0].enumProperties[0].value, 'male'); + expect(enumModel.fields[0].enumProperties[0].name, 'value'); + expect(enumModel.fields[1].name, 'FEMALE'); + expect(enumModel.fields[1].serializedName, 'FEMALE'); + expect(enumModel.fields[1].enumProperties[0].value, 'femAle'); + expect(enumModel.fields[1].enumProperties[0].name, 'value'); + expect(enumModel.fields[2].name, 'OTHER'); + expect(enumModel.fields[2].serializedName, 'other'); + expect(enumModel.fields[2].enumProperties[0].value, 'other'); + expect(enumModel.fields[2].enumProperties[0].name, 'value'); + expect(enumModel.fields[3].name, 'X'); + expect(enumModel.fields[3].serializedName, 'X'); + expect(enumModel.fields[3].enumProperties[0].value, 'x'); + expect(enumModel.fields[3].enumProperties[0].name, 'value'); expect(enumModel2.fields, isNotNull); - expect(enumModel2.fields!.length, 4); + expect(enumModel2.fields.length, 4); expect(enumModel.keyProperty, 'value'); - expect(enumModel2.fields![0].name, 'male'); - expect(enumModel2.fields![0].serializedName, 'male'); - expect(enumModel.fields![0].enumProperties[0].value, 'male'); - expect(enumModel.fields![0].enumProperties[0].name, 'value'); - expect(enumModel2.fields![1].name, 'female'); - expect(enumModel2.fields![1].serializedName, 'female'); - expect(enumModel.fields![1].enumProperties[0].value, 'femAle'); - expect(enumModel.fields![1].enumProperties[0].name, 'value'); - expect(enumModel2.fields![2].name, 'other'); - expect(enumModel2.fields![2].serializedName, 'other'); - expect(enumModel.fields![2].enumProperties[0].value, 'other'); - expect(enumModel.fields![2].enumProperties[0].name, 'value'); - expect(enumModel2.fields![3].name, 'X'); - expect(enumModel2.fields![3].serializedName, 'X'); - expect(enumModel.fields![3].enumProperties[0].value, 'x'); - expect(enumModel.fields![3].enumProperties[0].name, 'value'); + expect(enumModel2.fields[0].name, 'male'); + expect(enumModel2.fields[0].serializedName, 'male'); + expect(enumModel.fields[0].enumProperties[0].value, 'male'); + expect(enumModel.fields[0].enumProperties[0].name, 'value'); + expect(enumModel2.fields[1].name, 'female'); + expect(enumModel2.fields[1].serializedName, 'female'); + expect(enumModel.fields[1].enumProperties[0].value, 'femAle'); + expect(enumModel.fields[1].enumProperties[0].name, 'value'); + expect(enumModel2.fields[2].name, 'other'); + expect(enumModel2.fields[2].serializedName, 'other'); + expect(enumModel.fields[2].enumProperties[0].value, 'other'); + expect(enumModel.fields[2].enumProperties[0].name, 'value'); + expect(enumModel2.fields[3].name, 'X'); + expect(enumModel2.fields[3].serializedName, 'X'); + expect(enumModel.fields[3].enumProperties[0].value, 'x'); + expect(enumModel.fields[3].enumProperties[0].name, 'value'); }); test('Error Enum no properties map', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); var hasError = false; var errorMessage = ''; try { - YmlGeneratorConfig( - pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig( - 'enum-error-no-object'), - '') - .checkIfTypesAvailable(); + YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('enum-error-no-object'), '').checkIfTypesAvailable(); } catch (e) { hasError = true; errorMessage = e.toString(); @@ -239,77 +194,54 @@ void main() { }); test('Error Enum', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); var hasError = false; var errorMessage = ''; try { - YmlGeneratorConfig( - pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig( - 'enum-error-no-properties-map'), - '') - .checkIfTypesAvailable(); + YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('enum-error-no-properties-map'), '').checkIfTypesAvailable(); } catch (e) { hasError = true; errorMessage = e.toString(); } expect(hasError, true); - expect(errorMessage, - 'Exception: Properties should be a map, right now you are using a String. model: Gender'); + expect(errorMessage, 'Exception: Properties should be a map, right now you are using a String. model: Gender'); }); }); test('Error with not registered object', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); var hasError = false; var errorMessage = ''; try { - YmlGeneratorConfig( - pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig('error-not-registered'), - '') - .checkIfTypesAvailable(); + YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('error-not-registered'), '').checkIfTypesAvailable(); } catch (e) { hasError = true; errorMessage = e.toString(); } expect(hasError, true); - expect(errorMessage, - 'Exception: Could not generate all models. `Address` is not added to the config file'); + expect(errorMessage, 'Exception: Could not generate all models. `Address` is not added to the config file'); }); test('Error with not registered extend', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); var hasError = false; var errorMessage = ''; try { - YmlGeneratorConfig( - pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig( - 'error-not-registered-extend'), - '') - .checkIfTypesAvailable(); + YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('error-not-registered-extend'), '').checkIfTypesAvailable(); } catch (e) { hasError = true; errorMessage = e.toString(); } expect(hasError, true); - expect(errorMessage, - 'Exception: Could not generate all models. `Address` is not added to the config file, but is extended. These types are known: Person'); + expect(errorMessage, 'Exception: Could not generate all models. `Address` is not added to the config file, but is extended. These types are known: Person'); }); group('Getters', () { test('Get path with invalid model', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); var hasError = false; var errorMessage = ''; - final config = YmlGeneratorConfig(pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig('object-normal'), '') - ..checkIfTypesAvailable(); + final config = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-normal'), '')..checkIfTypesAvailable(); try { config.getPathsForName(pubspecConfig, 'TESTING'); } catch (e) { @@ -317,33 +249,25 @@ void main() { errorMessage = e.toString(); } expect(hasError, true); - expect(errorMessage, - 'Exception: getPathForName is null: because `TESTING` was not added to the config file'); + expect(errorMessage, 'Exception: getPathForName is null: because `TESTING` was not added to the config file'); }); test('Get paths with generic model', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final config = YmlGeneratorConfig(pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig('generics-normal'), ''); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final config = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('generics-normal'), ''); config.checkIfTypesAvailable(); - expect(config.getPathsForName(pubspecConfig, 'List').toList(), - ['model']); + expect(config.getPathsForName(pubspecConfig, 'List').toList(), ['model']); }); test('Get paths with dart:core model', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final config = YmlGeneratorConfig(pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig('custom-dart-core'), ''); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final config = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('custom-dart-core'), ''); config.checkIfTypesAvailable(); expect(config.getPathsForName(pubspecConfig, 'Address').toList(), []); }); test('Get path with invalid model', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); var hasError = false; var errorMessage = ''; - final config = YmlGeneratorConfig(pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig('object-normal'), ''); + final config = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-normal'), ''); config.checkIfTypesAvailable(); try { config.getModelByName(ObjectType('TESTING')); @@ -352,76 +276,46 @@ void main() { errorMessage = e.toString(); } expect(hasError, true); - expect(errorMessage, - 'Exception: getModelByName is null: because `TESTING` was not added to the config file'); + expect(errorMessage, 'Exception: getModelByName is null: because `TESTING` was not added to the config file'); }); }); group('Config merging tests', () { test('Test merge happy path', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig1 = YmlGeneratorConfig(pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig('object-normal'), ''); - final ymlConfig2 = YmlGeneratorConfig(pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig('enum-normal'), ''); - final merged = - YmlGeneratorConfig.merge([ymlConfig1, ymlConfig2], 'dirName'); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig1 = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-normal'), ''); + final ymlConfig2 = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('enum-normal'), ''); + final merged = YmlGeneratorConfig.merge([ymlConfig1, ymlConfig2], 'dirName'); expect(merged.models.length, 4); expect(merged.models.any((element) => element.name == 'Person'), true); expect(merged.models.any((element) => element.name == 'User'), true); expect(merged.models.any((element) => element.name == 'Gender'), true); - expect( - merged.models.any((element) => element.name == 'Vehicles'), true); + expect(merged.models.any((element) => element.name == 'Vehicles'), true); merged.checkIfTypesAvailable(); }); test('Test merge reference other file', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig1 = YmlGeneratorConfig( - pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig('object-reference-other'), - ''); - final ymlConfig2 = YmlGeneratorConfig(pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig('enum-normal'), ''); - final merged = - YmlGeneratorConfig.merge([ymlConfig1, ymlConfig2], 'dirName'); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig1 = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-reference-other'), ''); + final ymlConfig2 = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('enum-normal'), ''); + final merged = YmlGeneratorConfig.merge([ymlConfig1, ymlConfig2], 'dirName'); expect(merged.models.length, 4); expect(merged.models.any((element) => element.name == 'Person'), true); expect(merged.models.any((element) => element.name == 'User'), true); expect(merged.models.any((element) => element.name == 'Gender'), true); - expect( - merged.models.any((element) => element.name == 'Vehicles'), true); + expect(merged.models.any((element) => element.name == 'Vehicles'), true); merged.checkIfTypesAvailable(); }); test('Test merge reference not found', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig1 = YmlGeneratorConfig( - pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig( - 'object-reference-other-unknown'), - ''); - final ymlConfig2 = YmlGeneratorConfig(pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig('enum-normal'), ''); - final merged = - YmlGeneratorConfig.merge([ymlConfig1, ymlConfig2], 'dirName'); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig1 = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-reference-other-unknown'), ''); + final ymlConfig2 = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('enum-normal'), ''); + final merged = YmlGeneratorConfig.merge([ymlConfig1, ymlConfig2], 'dirName'); expect(() => merged.checkIfTypesAvailable(), throwsA(isA())); }); test('Test duplicate models', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig1 = YmlGeneratorConfig( - pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig( - 'object-reference-other-unknown'), - ''); - final ymlConfig2 = YmlGeneratorConfig( - pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig('object-reference-other'), - ''); - expect( - () => YmlGeneratorConfig.merge([ymlConfig1, ymlConfig2], 'dirName'), - throwsA(isA())); + final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig1 = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-reference-other-unknown'), ''); + final ymlConfig2 = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-reference-other'), ''); + expect(() => YmlGeneratorConfig.merge([ymlConfig1, ymlConfig2], 'dirName'), throwsA(isA())); }); }); }); diff --git a/test/model/model/enum_model_test.dart b/test/model/model/enum_model_test.dart index 4ae4e98..d9ba24c 100644 --- a/test/model/model/enum_model_test.dart +++ b/test/model/model/enum_model_test.dart @@ -10,6 +10,7 @@ void main() { name: 'MyEnumModel', path: 'path_to_my_model', baseDirectory: 'base_dir', + fields: [], ); expect(model.name, 'MyEnumModel'); expect(model.path, 'path_to_my_model'); @@ -23,6 +24,7 @@ void main() { name: 'MyEnumModel', path: 'path_to_my_model/', baseDirectory: 'base_dir', + fields: [], ); expect(model.name, 'MyEnumModel'); expect(model.path, 'path_to_my_model'); @@ -35,6 +37,7 @@ void main() { name: 'MyEnumModel', path: 'path_to_my_model', baseDirectory: 'base_dir/', + fields: [], ); expect(model.name, 'MyEnumModel'); expect(model.path, 'path_to_my_model'); diff --git a/test/writer/enum_model_writer/custom-value-map-extension/output.txt b/test/writer/enum_model_writer/custom-value-map-extension/output.txt deleted file mode 100644 index adfc467..0000000 --- a/test/writer/enum_model_writer/custom-value-map-extension/output.txt +++ /dev/null @@ -1,28 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -import 'package:json_annotation/json_annotation.dart'; - -enum MyEnumModel { - @JsonValue('customValue') - MY_VALUE_1, - @JsonValue('MY_VALUE_2') - MY_VALUE_2, -} - -const myEnumModelMapping = { - MyEnumModel.MY_VALUE_1: 'customValue', - MyEnumModel.MY_VALUE_2: 'MY_VALUE_2', -}; - -const reverseMyEnumModelMapping = { - 'customValue': MyEnumModel.MY_VALUE_1, - 'MY_VALUE_2': MyEnumModel.MY_VALUE_2, -}; - -extension MyEnumModelExtension on MyEnumModel { - String get stringValue => myEnumModelMapping[this]!; -} - -extension MyEnumModelStringExtension on String { - MyEnumModel? get asMyEnumModel => reverseMyEnumModelMapping[this]; -} diff --git a/test/writer/enum_model_writer/custom-value-map/output.txt b/test/writer/enum_model_writer/custom-value-map/output.txt deleted file mode 100644 index dfffeb1..0000000 --- a/test/writer/enum_model_writer/custom-value-map/output.txt +++ /dev/null @@ -1,20 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -import 'package:json_annotation/json_annotation.dart'; - -enum MyEnumModel { - @JsonValue('customValue') - MY_VALUE_1, - @JsonValue('MY_VALUE_2') - MY_VALUE_2, -} - -const myEnumModelMapping = { - MyEnumModel.MY_VALUE_1: 'customValue', - MyEnumModel.MY_VALUE_2: 'MY_VALUE_2', -}; - -const reverseMyEnumModelMapping = { - 'customValue': MyEnumModel.MY_VALUE_1, - 'MY_VALUE_2': MyEnumModel.MY_VALUE_2, -}; diff --git a/test/writer/enum_model_writer/custom-value/config.txt b/test/writer/enum_model_writer/custom-value/config.txt new file mode 100644 index 0000000..ab4a8d8 --- /dev/null +++ b/test/writer/enum_model_writer/custom-value/config.txt @@ -0,0 +1,9 @@ +MyEnumModel: + path: test/enum/ + type: enum + key_property: value + properties: + MY_VALUE_1: + value: '1' + MY_VALUE_2: + value: '2' diff --git a/test/writer/enum_model_writer/custom-value/output.txt b/test/writer/enum_model_writer/custom-value/output.txt index 102c3f4..d2be8fd 100644 --- a/test/writer/enum_model_writer/custom-value/output.txt +++ b/test/writer/enum_model_writer/custom-value/output.txt @@ -3,8 +3,8 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { - @JsonValue('MY_VALUE_1') + @JsonValue(1) MY_VALUE_1, - @JsonValue('custom_value_2') + @JsonValue(2) MY_VALUE_2, } diff --git a/test/writer/enum_model_writer/no-fields/output.txt b/test/writer/enum_model_writer/no-fields/output.txt deleted file mode 100644 index 005c481..0000000 --- a/test/writer/enum_model_writer/no-fields/output.txt +++ /dev/null @@ -1,6 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -import 'package:json_annotation/json_annotation.dart'; - -enum MyEnumModel { -} diff --git a/test/writer/enum_model_writer/normal-description/config.txt b/test/writer/enum_model_writer/normal-description/config.txt new file mode 100644 index 0000000..51da035 --- /dev/null +++ b/test/writer/enum_model_writer/normal-description/config.txt @@ -0,0 +1,7 @@ +MyEnumModel: + path: test/enum/ + type: enum + description: A good description of this enum + properties: + MY_VALUE_1: + MY_VALUE_2: diff --git a/test/writer/enum_model_writer/normal-description/output.txt b/test/writer/enum_model_writer/normal-description/output.txt index f6f33bb..d4f089a 100644 --- a/test/writer/enum_model_writer/normal-description/output.txt +++ b/test/writer/enum_model_writer/normal-description/output.txt @@ -4,7 +4,6 @@ import 'package:json_annotation/json_annotation.dart'; ///A good description of this enum enum MyEnumModel { - ///A good description of this field @JsonValue('MY_VALUE_1') MY_VALUE_1, @JsonValue('MY_VALUE_2') diff --git a/test/writer/enum_model_writer/normal/config.txt b/test/writer/enum_model_writer/normal/config.txt index 096d3af..69fde93 100644 --- a/test/writer/enum_model_writer/normal/config.txt +++ b/test/writer/enum_model_writer/normal/config.txt @@ -3,6 +3,4 @@ MyEnumModel: type: enum properties: MY_VALUE_1: - value: '1' - MY_VALUE_2: - value: '2' + MY_VALUE_2: \ No newline at end of file diff --git a/test/writer/enum_model_writer/normal_with_double_type_map/output.txt b/test/writer/enum_model_writer/normal_with_double_type_map/output.txt deleted file mode 100644 index 24687ad..0000000 --- a/test/writer/enum_model_writer/normal_with_double_type_map/output.txt +++ /dev/null @@ -1,21 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -import 'package:json_annotation/json_annotation.dart'; - -enum MyEnumModel { - ///A good description of this field - @JsonValue(1.0) - MY_VALUE_1, - @JsonValue(2.2) - MY_VALUE_2, -} - -const myEnumModelMapping = { - MyEnumModel.MY_VALUE_1: 1.0, - MyEnumModel.MY_VALUE_2: 2.2, -}; - -final reverseMyEnumModelMapping = { - 1.0: MyEnumModel.MY_VALUE_1, - 2.2: MyEnumModel.MY_VALUE_2, -}; diff --git a/test/writer/enum_model_writer/normal_with_double_type_map_extension/output.txt b/test/writer/enum_model_writer/normal_with_double_type_map_extension/output.txt deleted file mode 100644 index 209e34f..0000000 --- a/test/writer/enum_model_writer/normal_with_double_type_map_extension/output.txt +++ /dev/null @@ -1,29 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -import 'package:json_annotation/json_annotation.dart'; - -enum MyEnumModel { - ///A good description of this field - @JsonValue(1.0) - MY_VALUE_1, - @JsonValue(2.2) - MY_VALUE_2, -} - -const myEnumModelMapping = { - MyEnumModel.MY_VALUE_1: 1.0, - MyEnumModel.MY_VALUE_2: 2.2, -}; - -final reverseMyEnumModelMapping = { - 1.0: MyEnumModel.MY_VALUE_1, - 2.2: MyEnumModel.MY_VALUE_2, -}; - -extension MyEnumModelExtension on MyEnumModel { - double get doubleValue => myEnumModelMapping[this]!; -} - -extension MyEnumModelDoubleExtension on double { - MyEnumModel? get asMyEnumModel => reverseMyEnumModelMapping[this]; -} diff --git a/test/writer/enum_model_writer/normal_with_int_type_map/output.txt b/test/writer/enum_model_writer/normal_with_int_type_map/output.txt deleted file mode 100644 index 4f96235..0000000 --- a/test/writer/enum_model_writer/normal_with_int_type_map/output.txt +++ /dev/null @@ -1,21 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -import 'package:json_annotation/json_annotation.dart'; - -enum MyEnumModel { - ///A good description of this field - @JsonValue(1) - MY_VALUE_1, - @JsonValue(2) - MY_VALUE_2, -} - -const myEnumModelMapping = { - MyEnumModel.MY_VALUE_1: 1, - MyEnumModel.MY_VALUE_2: 2, -}; - -const reverseMyEnumModelMapping = { - 1: MyEnumModel.MY_VALUE_1, - 2: MyEnumModel.MY_VALUE_2, -}; diff --git a/test/writer/enum_model_writer/normal_with_int_type_map_extension/output.txt b/test/writer/enum_model_writer/normal_with_int_type_map_extension/output.txt deleted file mode 100644 index 1afd4d5..0000000 --- a/test/writer/enum_model_writer/normal_with_int_type_map_extension/output.txt +++ /dev/null @@ -1,29 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -import 'package:json_annotation/json_annotation.dart'; - -enum MyEnumModel { - ///A good description of this field - @JsonValue(1) - MY_VALUE_1, - @JsonValue(2) - MY_VALUE_2, -} - -const myEnumModelMapping = { - MyEnumModel.MY_VALUE_1: 1, - MyEnumModel.MY_VALUE_2: 2, -}; - -const reverseMyEnumModelMapping = { - 1: MyEnumModel.MY_VALUE_1, - 2: MyEnumModel.MY_VALUE_2, -}; - -extension MyEnumModelExtension on MyEnumModel { - int get intValue => myEnumModelMapping[this]!; -} - -extension MyEnumModelIntExtension on int { - MyEnumModel? get asMyEnumModel => reverseMyEnumModelMapping[this]; -} diff --git a/test/writer/enum_model_writer/null-value/output.txt b/test/writer/enum_model_writer/null-value/output.txt deleted file mode 100644 index 0b50f98..0000000 --- a/test/writer/enum_model_writer/null-value/output.txt +++ /dev/null @@ -1,10 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -import 'package:json_annotation/json_annotation.dart'; - -enum MyEnumModel { - @JsonValue('MY_VALUE_1') - MY_VALUE_1, - @JsonValue('MY_VALUE_2') - MY_VALUE_2, -} From 1af26481132a40702f041b85c6d602d9ca449883 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Tue, 5 Sep 2023 13:21:22 +0200 Subject: [PATCH 06/42] #130: fixed tests --- lib/config/yml_generator_config.dart | 57 ++++++++++++++----- lib/model/model/enum_model.dart | 32 +++++++---- lib/writer/enum_model_writer.dart | 10 ++-- .../yml_generator_config/enum-normal.txt | 36 ++++++++---- test/config/yml_generator_config_test.dart | 38 ++++++------- test/model/model/enum_model_test.dart | 36 ++++++------ .../enum_model_writer/custom-value/config.txt | 15 +++-- 7 files changed, 142 insertions(+), 82 deletions(-) diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index cf8d103..668a3b0 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -94,30 +94,61 @@ class YmlGeneratorConfig { final uppercaseEnums = (value['uppercase_enums'] ?? pubspecConfig.uppercaseEnums) == true; final fields = []; + final enumProperties = []; properties.forEach((propertyKey, propertyValue) { - if (propertyValue != null && propertyValue is! YamlMap) { - throw Exception('$propertyKey should be an object'); + final ItemType type; + final bool isJsonKey; + final String name = propertyKey; + + if (propertyValue is YamlMap) { + type = propertyValue['type'] != null ? _parseSimpleType(propertyValue['type']) : StringType(); + isJsonKey = propertyValue['is_json_key'] == true; + } else { + type = _parseSimpleType(propertyValue); + isJsonKey = false; } - final propertiesYaml = propertyValue as YamlMap?; - final properties = []; - propertiesYaml?.forEach((propertyKey, propertyValue) { - properties.add(EnumProperty( - value: propertyValue, - name: propertyKey, - )); + + if (type is! StringType && type is! DoubleType && type is! IntegerType) { + throw Exception('$propertyKey should have a type of integer, double or string'); + } + + enumProperties.add(EnumProperty( + name: name, + type: type, + isJsonKey: isJsonKey, + )); + }); + + final values = value['values']; + if (values == null && properties.isNotEmpty == true) { + throw Exception('The enum $key has defined properties, but a default value is not defined'); + } + + values?.forEach((key, value) { + final properties = value['properties']; + final enumValues = []; + + properties.forEach((key, value) { + enumValues.add( + EnumValue( + value: value, + propertyName: key, + ), + ); }); fields.add(EnumField( - name: uppercaseEnums ? propertyKey.toUpperCase() : propertyKey, - rawName: propertyKey, - enumProperties: properties, + name: uppercaseEnums ? key.toUpperCase() : key, + rawName: key, + values: enumValues, )); }); + models.add(EnumModel( name: key, path: path, - keyProperty: value['key_property'], baseDirectory: baseDirectory, fields: fields, + properties: enumProperties, extraImports: extraImports, extraAnnotations: extraAnnotations, description: description, diff --git a/lib/model/model/enum_model.dart b/lib/model/model/enum_model.dart index ffb48c9..cdc6456 100644 --- a/lib/model/model/enum_model.dart +++ b/lib/model/model/enum_model.dart @@ -1,15 +1,14 @@ import 'package:model_generator/model/item_type/item_type.dart'; -import 'package:model_generator/model/item_type/string_type.dart'; import 'package:model_generator/model/model/model.dart'; class EnumModel extends Model { final List fields; - final String? keyProperty; + final List properties; EnumModel({ required String name, - required this.keyProperty, required this.fields, + required this.properties, String? path, String? baseDirectory, List? extraImports, @@ -27,34 +26,45 @@ class EnumModel extends Model { class EnumField { final String name; - final List enumProperties; final String serializedName; + final List values; EnumField._({ required this.name, required this.serializedName, - required this.enumProperties, + required this.values, }); factory EnumField({ required String name, - required List enumProperties, required String rawName, + required List values, }) => EnumField._( name: name, - enumProperties: enumProperties, serializedName: rawName, + values: values, ); } class EnumProperty { - final String value; + final bool isJsonKey; final String name; - final ItemType type; + ItemType type; EnumProperty({ - required this.value, required this.name, - }) : type = StringType(); + required this.type, + this.isJsonKey = false, + }); +} + +class EnumValue { + final String value; + final String propertyName; + + EnumValue({ + required this.value, + required this.propertyName, + }); } diff --git a/lib/writer/enum_model_writer.dart b/lib/writer/enum_model_writer.dart index 8cbb308..01312a5 100644 --- a/lib/writer/enum_model_writer.dart +++ b/lib/writer/enum_model_writer.dart @@ -23,12 +23,12 @@ class EnumModelWriter { } final jsonModelName = CaseUtil(jsonModel.name); - final properties = jsonModel.fields.first.enumProperties; + final properties = jsonModel.properties; sb.writeln('enum ${jsonModelName.pascalCase} {'); for (var key in jsonModel.fields) { - final keyProperty = key.enumProperties.firstWhereOrNull((element) => element.name.toLowerCase() == jsonModel.keyProperty); - final jsonValue = keyProperty?.value ?? key.serializedName; + final keyProperty = properties.firstWhereOrNull((property) => property.isJsonKey); + final jsonValue = key.values.firstWhereOrNull((value) => value.propertyName == keyProperty?.name)?.value ?? key.serializedName; final propertyType = keyProperty?.type; final isLast = jsonModel.fields.indexOf(key) == (jsonModel.fields.length - 1); @@ -41,7 +41,7 @@ class EnumModelWriter { sb.writeln(' @JsonValue($jsonValue)'); } sb.write(' ${key.name}'); - if (key.enumProperties.isNotEmpty && isLast) { + if (properties.isNotEmpty && isLast) { sb.writeln(';'); } else { sb.writeln(','); @@ -53,7 +53,7 @@ class EnumModelWriter { } for (var property in properties) { - sb.writeln('final ${property.type} ${property.name};'); + sb.writeln('final ${property.type.name} ${property.name};'); } if (properties.isNotEmpty) { sb.write('Const ${jsonModel.name} ({'); diff --git a/test/config/yml_generator_config/enum-normal.txt b/test/config/yml_generator_config/enum-normal.txt index f92c07b..17f0735 100644 --- a/test/config/yml_generator_config/enum-normal.txt +++ b/test/config/yml_generator_config/enum-normal.txt @@ -6,27 +6,41 @@ User: Gender: type: enum - key_property: value properties: + value: + type: String + is_json_key: true + values: MALE: - value: male + properties: + value: male FEMALE: - value: femAle + properties: + value: femAle other: - value: other + properties: + value: other X: - value: x + properties: + value: x Vehicles: type: enum - key_property: value uppercase_enums: false properties: + value: + type: String + is_json_key: true + values: male: - value: male + properties: + value: male female: - value: femAle + properties: + value: femAle other: - value: other - X: - value: x + properties: + value: other + x: + properties: + value: x diff --git a/test/config/yml_generator_config_test.dart b/test/config/yml_generator_config_test.dart index d5d6a0d..8f237fc 100644 --- a/test/config/yml_generator_config_test.dart +++ b/test/config/yml_generator_config_test.dart @@ -140,43 +140,41 @@ void main() { final enumModel2 = ymlConfig.models[2] as EnumModel; // ignore: avoid_as expect(enumModel.fields, isNotNull); expect(enumModel.fields.length, 4); - expect(enumModel.keyProperty, 'value'); expect(enumModel.fields[0].name, 'MALE'); expect(enumModel.fields[0].serializedName, 'MALE'); - expect(enumModel.fields[0].enumProperties[0].value, 'male'); - expect(enumModel.fields[0].enumProperties[0].name, 'value'); + expect(enumModel.fields[0].values[0].value, 'male'); + expect(enumModel.fields[0].values[0].propertyName, 'value'); expect(enumModel.fields[1].name, 'FEMALE'); expect(enumModel.fields[1].serializedName, 'FEMALE'); - expect(enumModel.fields[1].enumProperties[0].value, 'femAle'); - expect(enumModel.fields[1].enumProperties[0].name, 'value'); + expect(enumModel.fields[1].values[0].value, 'femAle'); + expect(enumModel.fields[1].values[0].propertyName, 'value'); expect(enumModel.fields[2].name, 'OTHER'); expect(enumModel.fields[2].serializedName, 'other'); - expect(enumModel.fields[2].enumProperties[0].value, 'other'); - expect(enumModel.fields[2].enumProperties[0].name, 'value'); + expect(enumModel.fields[2].values[0].value, 'other'); + expect(enumModel.fields[2].values[0].propertyName, 'value'); expect(enumModel.fields[3].name, 'X'); expect(enumModel.fields[3].serializedName, 'X'); - expect(enumModel.fields[3].enumProperties[0].value, 'x'); - expect(enumModel.fields[3].enumProperties[0].name, 'value'); + expect(enumModel.fields[3].values[0].value, 'x'); + expect(enumModel.fields[3].values[0].propertyName, 'value'); expect(enumModel2.fields, isNotNull); expect(enumModel2.fields.length, 4); - expect(enumModel.keyProperty, 'value'); expect(enumModel2.fields[0].name, 'male'); expect(enumModel2.fields[0].serializedName, 'male'); - expect(enumModel.fields[0].enumProperties[0].value, 'male'); - expect(enumModel.fields[0].enumProperties[0].name, 'value'); + expect(enumModel.fields[0].values[0].value, 'male'); + expect(enumModel.fields[0].values[0].propertyName, 'value'); expect(enumModel2.fields[1].name, 'female'); expect(enumModel2.fields[1].serializedName, 'female'); - expect(enumModel.fields[1].enumProperties[0].value, 'femAle'); - expect(enumModel.fields[1].enumProperties[0].name, 'value'); + expect(enumModel.fields[1].values[0].value, 'femAle'); + expect(enumModel.fields[1].values[0].propertyName, 'value'); expect(enumModel2.fields[2].name, 'other'); expect(enumModel2.fields[2].serializedName, 'other'); - expect(enumModel.fields[2].enumProperties[0].value, 'other'); - expect(enumModel.fields[2].enumProperties[0].name, 'value'); - expect(enumModel2.fields[3].name, 'X'); - expect(enumModel2.fields[3].serializedName, 'X'); - expect(enumModel.fields[3].enumProperties[0].value, 'x'); - expect(enumModel.fields[3].enumProperties[0].name, 'value'); + expect(enumModel.fields[2].values[0].value, 'other'); + expect(enumModel.fields[2].values[0].propertyName, 'value'); + expect(enumModel2.fields[3].name, 'x'); + expect(enumModel2.fields[3].serializedName, 'x'); + expect(enumModel.fields[3].values[0].value, 'x'); + expect(enumModel.fields[3].values[0].propertyName, 'value'); }); test('Error Enum no properties map', () { diff --git a/test/model/model/enum_model_test.dart b/test/model/model/enum_model_test.dart index d9ba24c..ebf2bc2 100644 --- a/test/model/model/enum_model_test.dart +++ b/test/model/model/enum_model_test.dart @@ -6,11 +6,11 @@ void main() { group('Default', () { test('Normal EnumModel', () { final model = EnumModel( - keyProperty: 'keyProperty', name: 'MyEnumModel', path: 'path_to_my_model', baseDirectory: 'base_dir', fields: [], + properties: [], ); expect(model.name, 'MyEnumModel'); expect(model.path, 'path_to_my_model'); @@ -20,11 +20,11 @@ void main() { group('Custom Path', () { test('Normal Custom Path', () { final model = EnumModel( - keyProperty: 'keyProperty', name: 'MyEnumModel', path: 'path_to_my_model/', baseDirectory: 'base_dir', fields: [], + properties: [], ); expect(model.name, 'MyEnumModel'); expect(model.path, 'path_to_my_model'); @@ -33,11 +33,11 @@ void main() { test('Normal Custom Base Dir', () { final model = EnumModel( - keyProperty: 'keyProperty', name: 'MyEnumModel', path: 'path_to_my_model', baseDirectory: 'base_dir/', fields: [], + properties: [], ); expect(model.name, 'MyEnumModel'); expect(model.path, 'path_to_my_model'); @@ -52,33 +52,33 @@ void main() { final field = EnumField( name: 'MY_ENUM_VALUE', rawName: 'MY_ENUM_VALUE', - enumProperties: [ - EnumProperty( + values: [ + EnumValue( value: 'MY_ENUM_VALUE', - name: 'MY_ENUM_NAME', + propertyName: 'MY_PROPERTY_NAME', ), ], ); expect(field.name, 'MY_ENUM_VALUE'); expect(field.serializedName, 'MY_ENUM_VALUE'); - expect(field.enumProperties.first.value, 'MY_ENUM_VALUE'); - expect(field.enumProperties.first.name, 'MY_ENUM_NAME'); + expect(field.values.first.value, 'MY_ENUM_VALUE'); + expect(field.values.first.propertyName, 'MY_PROPERTY_NAME'); }); test('Normal EnumField, lowercased', () { final field = EnumField( name: 'my_enum_value', rawName: 'MY_ENUM_VALUE', - enumProperties: [ - EnumProperty( + values: [ + EnumValue( value: 'MY_ENUM_VALUE', - name: 'MY_ENUM_NAME', + propertyName: 'MY_PROPERTY_NAME', ), ], ); expect(field.name, 'my_enum_value'); expect(field.serializedName, 'MY_ENUM_VALUE'); - expect(field.enumProperties.first.value, 'MY_ENUM_VALUE'); - expect(field.enumProperties.first.name, 'MY_ENUM_NAME'); + expect(field.values.first.value, 'MY_ENUM_VALUE'); + expect(field.values.first.propertyName, 'MY_PROPERTY_NAME'); }); }); group('Custom serializedName', () { @@ -86,17 +86,17 @@ void main() { final field = EnumField( name: 'MY_ENUM_VALUE', rawName: 'my_enum_value', - enumProperties: [ - EnumProperty( + values: [ + EnumValue( value: 'MY_ENUM_VALUE', - name: 'MY_ENUM_NAME', + propertyName: 'MY_PROPERTY_NAME', ), ], ); expect(field.name, 'MY_ENUM_VALUE'); expect(field.serializedName, 'my_enum_value'); - expect(field.enumProperties.first.value, 'MY_ENUM_VALUE'); - expect(field.enumProperties.first.name, 'MY_ENUM_NAME'); + expect(field.values.first.value, 'MY_ENUM_VALUE'); + expect(field.values.first.propertyName, 'MY_PROPERTY_NAME'); }); }); }); diff --git a/test/writer/enum_model_writer/custom-value/config.txt b/test/writer/enum_model_writer/custom-value/config.txt index ab4a8d8..bc03231 100644 --- a/test/writer/enum_model_writer/custom-value/config.txt +++ b/test/writer/enum_model_writer/custom-value/config.txt @@ -1,9 +1,16 @@ MyEnumModel: path: test/enum/ type: enum - key_property: value properties: + technical_key2: + is_json_key: true + type: int + values: MY_VALUE_1: - value: '1' - MY_VALUE_2: - value: '2' + properties: + technical_key: 'some_key' + technical_key2: '1' + MY_VALUE_1: + properties: + technical_key: 'some_key' + technical_key2: '2' \ No newline at end of file From fcf0054f8f0ff587c373bbc0caef31c8e7be8f33 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Tue, 5 Sep 2023 13:39:19 +0200 Subject: [PATCH 07/42] #130: fixed more tests --- lib/config/yml_generator_config.dart | 14 +++++++------- .../enum_model_writer/custom-value/config.txt | 10 ++++------ .../normal-description/config.txt | 2 +- test/writer/enum_model_writer/normal/config.txt | 2 +- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index 668a3b0..7df5f66 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -84,10 +84,10 @@ class YmlGeneratorConfig { )); return; } - if (properties == null) { + if (properties == null && type != 'enum') { throw Exception('Properties can not be null. model: $key'); } - if (properties is! YamlMap) { + if (properties is! YamlMap && type != 'enum') { throw Exception('Properties should be a map, right now you are using a ${properties.runtimeType}. model: $key'); } if (type == 'enum') { @@ -95,7 +95,7 @@ class YmlGeneratorConfig { final fields = []; final enumProperties = []; - properties.forEach((propertyKey, propertyValue) { + properties?.forEach((propertyKey, propertyValue) { final ItemType type; final bool isJsonKey; final String name = propertyKey; @@ -119,19 +119,19 @@ class YmlGeneratorConfig { )); }); - final values = value['values']; + final values = value['values'] as YamlMap?; if (values == null && properties.isNotEmpty == true) { throw Exception('The enum $key has defined properties, but a default value is not defined'); } values?.forEach((key, value) { - final properties = value['properties']; + final properties = value?['properties'] as YamlMap?; final enumValues = []; - properties.forEach((key, value) { + properties?.forEach((key, value) { enumValues.add( EnumValue( - value: value, + value: value.toString(), propertyName: key, ), ); diff --git a/test/writer/enum_model_writer/custom-value/config.txt b/test/writer/enum_model_writer/custom-value/config.txt index bc03231..fa2a3ca 100644 --- a/test/writer/enum_model_writer/custom-value/config.txt +++ b/test/writer/enum_model_writer/custom-value/config.txt @@ -2,15 +2,13 @@ MyEnumModel: path: test/enum/ type: enum properties: - technical_key2: + jsonKey: is_json_key: true type: int values: MY_VALUE_1: properties: - technical_key: 'some_key' - technical_key2: '1' - MY_VALUE_1: + jsonKey: 1 + MY_VALUE_2: properties: - technical_key: 'some_key' - technical_key2: '2' \ No newline at end of file + jsonKey: 2 \ No newline at end of file diff --git a/test/writer/enum_model_writer/normal-description/config.txt b/test/writer/enum_model_writer/normal-description/config.txt index 51da035..a3eab7c 100644 --- a/test/writer/enum_model_writer/normal-description/config.txt +++ b/test/writer/enum_model_writer/normal-description/config.txt @@ -2,6 +2,6 @@ MyEnumModel: path: test/enum/ type: enum description: A good description of this enum - properties: + values: MY_VALUE_1: MY_VALUE_2: diff --git a/test/writer/enum_model_writer/normal/config.txt b/test/writer/enum_model_writer/normal/config.txt index 69fde93..428ebce 100644 --- a/test/writer/enum_model_writer/normal/config.txt +++ b/test/writer/enum_model_writer/normal/config.txt @@ -1,6 +1,6 @@ MyEnumModel: path: test/enum/ type: enum - properties: + values: MY_VALUE_1: MY_VALUE_2: \ No newline at end of file From db942714c67677a541f8d9575a55dc6c6e371a78 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Tue, 5 Sep 2023 15:27:01 +0200 Subject: [PATCH 08/42] #130: finished property functionality --- lib/config/yml_generator_config.dart | 1 + lib/model/model/enum_model.dart | 2 + lib/writer/enum_model_writer.dart | 49 +++++++++++++++---- .../enum_model_writer/custom-value/config.txt | 10 +++- .../enum_model_writer/custom-value/output.txt | 24 +++++++-- .../normal-description/output.txt | 14 +++++- .../enum_model_writer/normal/output.txt | 14 +++++- .../normal_no_default_json_key/config.txt | 7 +++ .../normal_no_default_json_key/output.txt | 10 ++++ .../normal_with_double_type/config.txt | 14 ++++++ .../normal_with_double_type/output.txt | 17 +++++-- .../normal_with_int_type/config.txt | 14 ++++++ .../normal_with_int_type/output.txt | 15 ++++-- 13 files changed, 166 insertions(+), 25 deletions(-) create mode 100644 test/writer/enum_model_writer/normal_no_default_json_key/config.txt create mode 100644 test/writer/enum_model_writer/normal_no_default_json_key/output.txt create mode 100644 test/writer/enum_model_writer/normal_with_double_type/config.txt create mode 100644 test/writer/enum_model_writer/normal_with_int_type/config.txt diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index 7df5f66..5bf9e84 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -144,6 +144,7 @@ class YmlGeneratorConfig { }); models.add(EnumModel( + addJsonKeyToProperties: value['use_default_json_key'] ?? true, name: key, path: path, baseDirectory: baseDirectory, diff --git a/lib/model/model/enum_model.dart b/lib/model/model/enum_model.dart index cdc6456..d27d174 100644 --- a/lib/model/model/enum_model.dart +++ b/lib/model/model/enum_model.dart @@ -4,11 +4,13 @@ import 'package:model_generator/model/model/model.dart'; class EnumModel extends Model { final List fields; final List properties; + final bool addJsonKeyToProperties; EnumModel({ required String name, required this.fields, required this.properties, + this.addJsonKeyToProperties = true, String? path, String? baseDirectory, List? extraImports, diff --git a/lib/writer/enum_model_writer.dart b/lib/writer/enum_model_writer.dart index 01312a5..a999212 100644 --- a/lib/writer/enum_model_writer.dart +++ b/lib/writer/enum_model_writer.dart @@ -1,4 +1,5 @@ import 'package:model_generator/model/item_type/double_type.dart'; +import 'package:model_generator/model/item_type/item_type.dart'; import 'package:model_generator/model/item_type/string_type.dart'; import 'package:model_generator/model/model/enum_model.dart'; import 'package:model_generator/util/case_util.dart'; @@ -24,10 +25,12 @@ class EnumModelWriter { final jsonModelName = CaseUtil(jsonModel.name); final properties = jsonModel.properties; + final keyProperty = properties.firstWhereOrNull((property) => property.isJsonKey); + final addDefaultJsonKey = keyProperty == null && jsonModel.addJsonKeyToProperties; + final addProperties = properties.isNotEmpty || addDefaultJsonKey; sb.writeln('enum ${jsonModelName.pascalCase} {'); for (var key in jsonModel.fields) { - final keyProperty = properties.firstWhereOrNull((property) => property.isJsonKey); final jsonValue = key.values.firstWhereOrNull((value) => value.propertyName == keyProperty?.name)?.value ?? key.serializedName; final propertyType = keyProperty?.type; final isLast = jsonModel.fields.indexOf(key) == (jsonModel.fields.length - 1); @@ -41,30 +44,58 @@ class EnumModelWriter { sb.writeln(' @JsonValue($jsonValue)'); } sb.write(' ${key.name}'); - if (properties.isNotEmpty && isLast) { - sb.writeln(';'); + + if (addProperties) { + sb.writeln('('); + if (addDefaultJsonKey) { + sb.writeln(' jsonValue: \'$jsonValue\','); + } + for (var value in key.values) { + final type = itemTypeForProperty(value.propertyName, properties); + sb.write(' ${value.propertyName}: '); + if (type is StringType) { + sb.writeln('\'${value.value}\','); + } else { + sb.writeln('${value.value},'); + } + } + if (isLast) { + sb.writeln(' );'); + } else { + sb.writeln(' ),'); + } } else { sb.writeln(','); } } - if (properties.isNotEmpty) { + if (addProperties) { sb.writeln(); } + if (addDefaultJsonKey) { + sb.writeln(' final String jsonValue;'); + } for (var property in properties) { - sb.writeln('final ${property.type.name} ${property.name};'); + sb.writeln(' final ${property.type.name} ${property.name};'); } - if (properties.isNotEmpty) { - sb.write('Const ${jsonModel.name} ({'); + if (addProperties) { + sb.writeln(); + sb.writeln(' const ${jsonModelName.pascalCase}({'); for (var property in properties) { - sb.write('required this.${property.name}, '); + sb.writeln(' required this.${property.name},'); } - sb.writeln('})'); + if (addDefaultJsonKey) { + sb.writeln(' required this.jsonValue,'); + } + sb.writeln(' });'); } sb.writeln('}'); return sb.toString(); } + + ItemType itemTypeForProperty(String propertyName, List properties) => + properties.firstWhereOrNull((property) => property.name == propertyName)?.type ?? StringType(); } diff --git a/test/writer/enum_model_writer/custom-value/config.txt b/test/writer/enum_model_writer/custom-value/config.txt index fa2a3ca..c5e81bc 100644 --- a/test/writer/enum_model_writer/custom-value/config.txt +++ b/test/writer/enum_model_writer/custom-value/config.txt @@ -1,14 +1,20 @@ -MyEnumModel: +Person: path: test/enum/ type: enum properties: jsonKey: is_json_key: true type: int + firstName: String + lastName: String values: MY_VALUE_1: properties: jsonKey: 1 + firstName: firstName1 + lastName: lastName1 MY_VALUE_2: properties: - jsonKey: 2 \ No newline at end of file + jsonKey: 2 + firstName: firstName2 + lastName: lastName2 diff --git a/test/writer/enum_model_writer/custom-value/output.txt b/test/writer/enum_model_writer/custom-value/output.txt index d2be8fd..e598946 100644 --- a/test/writer/enum_model_writer/custom-value/output.txt +++ b/test/writer/enum_model_writer/custom-value/output.txt @@ -2,9 +2,27 @@ import 'package:json_annotation/json_annotation.dart'; -enum MyEnumModel { +enum Person { @JsonValue(1) - MY_VALUE_1, + MY_VALUE_1( + jsonKey: 1, + firstName: 'firstName1', + lastName: 'lastName1', + ), @JsonValue(2) - MY_VALUE_2, + MY_VALUE_2( + jsonKey: 2, + firstName: 'firstName2', + lastName: 'lastName2', + ); + + final int jsonKey; + final String firstName; + final String lastName; + + const Person({ + required this.jsonKey, + required this.firstName, + required this.lastName, + }); } diff --git a/test/writer/enum_model_writer/normal-description/output.txt b/test/writer/enum_model_writer/normal-description/output.txt index d4f089a..5ad103e 100644 --- a/test/writer/enum_model_writer/normal-description/output.txt +++ b/test/writer/enum_model_writer/normal-description/output.txt @@ -5,7 +5,17 @@ import 'package:json_annotation/json_annotation.dart'; ///A good description of this enum enum MyEnumModel { @JsonValue('MY_VALUE_1') - MY_VALUE_1, + MY_VALUE_1( + jsonValue: 'MY_VALUE_1', + ), @JsonValue('MY_VALUE_2') - MY_VALUE_2, + MY_VALUE_2( + jsonValue: 'MY_VALUE_2', + ); + + final String jsonValue; + + const MyEnumModel({ + required this.jsonValue, + }); } diff --git a/test/writer/enum_model_writer/normal/output.txt b/test/writer/enum_model_writer/normal/output.txt index 0b50f98..b069d4d 100644 --- a/test/writer/enum_model_writer/normal/output.txt +++ b/test/writer/enum_model_writer/normal/output.txt @@ -4,7 +4,17 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { @JsonValue('MY_VALUE_1') - MY_VALUE_1, + MY_VALUE_1( + jsonValue: 'MY_VALUE_1', + ), @JsonValue('MY_VALUE_2') - MY_VALUE_2, + MY_VALUE_2( + jsonValue: 'MY_VALUE_2', + ); + + final String jsonValue; + + const MyEnumModel({ + required this.jsonValue, + }); } diff --git a/test/writer/enum_model_writer/normal_no_default_json_key/config.txt b/test/writer/enum_model_writer/normal_no_default_json_key/config.txt new file mode 100644 index 0000000..f6368f0 --- /dev/null +++ b/test/writer/enum_model_writer/normal_no_default_json_key/config.txt @@ -0,0 +1,7 @@ +MyEnumModel: + path: test/enum/ + use_default_json_key: false + type: enum + values: + MY_VALUE_1: + MY_VALUE_2: \ No newline at end of file diff --git a/test/writer/enum_model_writer/normal_no_default_json_key/output.txt b/test/writer/enum_model_writer/normal_no_default_json_key/output.txt new file mode 100644 index 0000000..0b50f98 --- /dev/null +++ b/test/writer/enum_model_writer/normal_no_default_json_key/output.txt @@ -0,0 +1,10 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +import 'package:json_annotation/json_annotation.dart'; + +enum MyEnumModel { + @JsonValue('MY_VALUE_1') + MY_VALUE_1, + @JsonValue('MY_VALUE_2') + MY_VALUE_2, +} diff --git a/test/writer/enum_model_writer/normal_with_double_type/config.txt b/test/writer/enum_model_writer/normal_with_double_type/config.txt new file mode 100644 index 0000000..9b99fdd --- /dev/null +++ b/test/writer/enum_model_writer/normal_with_double_type/config.txt @@ -0,0 +1,14 @@ +MyEnumModel: + path: test/enum/ + type: enum + properties: + value: + type: double + is_json_key: true + values: + MY_VALUE_1: + properties: + value: 1.2 + MY_VALUE_2: + properties: + value: 2.2 \ No newline at end of file diff --git a/test/writer/enum_model_writer/normal_with_double_type/output.txt b/test/writer/enum_model_writer/normal_with_double_type/output.txt index b4eb47d..65b28dc 100644 --- a/test/writer/enum_model_writer/normal_with_double_type/output.txt +++ b/test/writer/enum_model_writer/normal_with_double_type/output.txt @@ -3,9 +3,18 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { - ///A good description of this field - @JsonValue(1.0) - MY_VALUE_1, + @JsonValue(1.2) + MY_VALUE_1( + value: 1.2, + ), @JsonValue(2.2) - MY_VALUE_2, + MY_VALUE_2( + value: 2.2, + ); + + final double value; + + const MyEnumModel({ + required this.value, + }); } diff --git a/test/writer/enum_model_writer/normal_with_int_type/config.txt b/test/writer/enum_model_writer/normal_with_int_type/config.txt new file mode 100644 index 0000000..2d2571a --- /dev/null +++ b/test/writer/enum_model_writer/normal_with_int_type/config.txt @@ -0,0 +1,14 @@ +MyEnumModel: + path: test/enum/ + type: enum + properties: + value: + type: int + is_json_key: true + values: + MY_VALUE_1: + properties: + value: 1 + MY_VALUE_2: + properties: + value: 2 \ No newline at end of file diff --git a/test/writer/enum_model_writer/normal_with_int_type/output.txt b/test/writer/enum_model_writer/normal_with_int_type/output.txt index e69141c..58d7bd9 100644 --- a/test/writer/enum_model_writer/normal_with_int_type/output.txt +++ b/test/writer/enum_model_writer/normal_with_int_type/output.txt @@ -3,9 +3,18 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { - ///A good description of this field @JsonValue(1) - MY_VALUE_1, + MY_VALUE_1( + value: 1, + ), @JsonValue(2) - MY_VALUE_2, + MY_VALUE_2( + value: 2, + ); + + final int value; + + const MyEnumModel({ + required this.value, + }); } From 3563642f9b39f45945d7b11b85070ec0cadb3608 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Tue, 5 Sep 2023 15:48:38 +0200 Subject: [PATCH 09/42] #130: added description fields --- lib/config/yml_generator_config.dart | 2 ++ lib/model/model/enum_model.dart | 4 +++ lib/writer/enum_model_writer.dart | 3 ++ .../enum_model_writer/custom-value/config.txt | 4 +-- .../enum_model_writer/custom-value/output.txt | 4 +-- .../enum_model_writer/full_enum/config.txt | 29 +++++++++++++++++++ .../enum_model_writer/full_enum/output.txt | 28 ++++++++++++++++++ .../normal_field_description/config.txt | 8 +++++ .../normal_field_description/output.txt | 22 ++++++++++++++ .../normal_with_string_type/config.txt | 14 +++++++++ .../normal_with_string_type/output.txt | 20 +++++++++++++ 11 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 test/writer/enum_model_writer/full_enum/config.txt create mode 100644 test/writer/enum_model_writer/full_enum/output.txt create mode 100644 test/writer/enum_model_writer/normal_field_description/config.txt create mode 100644 test/writer/enum_model_writer/normal_field_description/output.txt create mode 100644 test/writer/enum_model_writer/normal_with_string_type/config.txt create mode 100644 test/writer/enum_model_writer/normal_with_string_type/output.txt diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index 5bf9e84..e2f780d 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -126,6 +126,7 @@ class YmlGeneratorConfig { values?.forEach((key, value) { final properties = value?['properties'] as YamlMap?; + final description = value?['description']; final enumValues = []; properties?.forEach((key, value) { @@ -140,6 +141,7 @@ class YmlGeneratorConfig { name: uppercaseEnums ? key.toUpperCase() : key, rawName: key, values: enumValues, + description: description, )); }); diff --git a/lib/model/model/enum_model.dart b/lib/model/model/enum_model.dart index d27d174..2e68f20 100644 --- a/lib/model/model/enum_model.dart +++ b/lib/model/model/enum_model.dart @@ -29,23 +29,27 @@ class EnumModel extends Model { class EnumField { final String name; final String serializedName; + final String? description; final List values; EnumField._({ required this.name, required this.serializedName, required this.values, + this.description, }); factory EnumField({ required String name, required String rawName, required List values, + String? description, }) => EnumField._( name: name, serializedName: rawName, values: values, + description: description, ); } diff --git a/lib/writer/enum_model_writer.dart b/lib/writer/enum_model_writer.dart index a999212..1be37c2 100644 --- a/lib/writer/enum_model_writer.dart +++ b/lib/writer/enum_model_writer.dart @@ -35,6 +35,9 @@ class EnumModelWriter { final propertyType = keyProperty?.type; final isLast = jsonModel.fields.indexOf(key) == (jsonModel.fields.length - 1); + if (key.description != null) { + sb.writeln(' ///${key.description}'); + } if (propertyType is StringType || propertyType == null) { sb.writeln(' @JsonValue(\'$jsonValue\')'); } else if (propertyType is DoubleType) { diff --git a/test/writer/enum_model_writer/custom-value/config.txt b/test/writer/enum_model_writer/custom-value/config.txt index c5e81bc..5bb2480 100644 --- a/test/writer/enum_model_writer/custom-value/config.txt +++ b/test/writer/enum_model_writer/custom-value/config.txt @@ -8,12 +8,12 @@ Person: firstName: String lastName: String values: - MY_VALUE_1: + MAN: properties: jsonKey: 1 firstName: firstName1 lastName: lastName1 - MY_VALUE_2: + WOMAN: properties: jsonKey: 2 firstName: firstName2 diff --git a/test/writer/enum_model_writer/custom-value/output.txt b/test/writer/enum_model_writer/custom-value/output.txt index e598946..773563d 100644 --- a/test/writer/enum_model_writer/custom-value/output.txt +++ b/test/writer/enum_model_writer/custom-value/output.txt @@ -4,13 +4,13 @@ import 'package:json_annotation/json_annotation.dart'; enum Person { @JsonValue(1) - MY_VALUE_1( + MAN( jsonKey: 1, firstName: 'firstName1', lastName: 'lastName1', ), @JsonValue(2) - MY_VALUE_2( + WOMAN( jsonKey: 2, firstName: 'firstName2', lastName: 'lastName2', diff --git a/test/writer/enum_model_writer/full_enum/config.txt b/test/writer/enum_model_writer/full_enum/config.txt new file mode 100644 index 0000000..9a0a88d --- /dev/null +++ b/test/writer/enum_model_writer/full_enum/config.txt @@ -0,0 +1,29 @@ +Person: + path: test/enum/ + type: enum + description: This is a enum of a person + properties: + jsonKey: + is_json_key: true + type: int + firstName: String + lastName: String + age: int + height: double + values: + MAN: + description: enum of a man + properties: + jsonKey: 1 + firstName: firstName1 + lastName: lastName1 + age: 12 + height: 12.4 + WOMAN: + description: enum of a woman + properties: + jsonKey: 2 + firstName: firstName2 + lastName: lastName2 + age: 16 + height: 22 diff --git a/test/writer/enum_model_writer/full_enum/output.txt b/test/writer/enum_model_writer/full_enum/output.txt new file mode 100644 index 0000000..e598946 --- /dev/null +++ b/test/writer/enum_model_writer/full_enum/output.txt @@ -0,0 +1,28 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +import 'package:json_annotation/json_annotation.dart'; + +enum Person { + @JsonValue(1) + MY_VALUE_1( + jsonKey: 1, + firstName: 'firstName1', + lastName: 'lastName1', + ), + @JsonValue(2) + MY_VALUE_2( + jsonKey: 2, + firstName: 'firstName2', + lastName: 'lastName2', + ); + + final int jsonKey; + final String firstName; + final String lastName; + + const Person({ + required this.jsonKey, + required this.firstName, + required this.lastName, + }); +} diff --git a/test/writer/enum_model_writer/normal_field_description/config.txt b/test/writer/enum_model_writer/normal_field_description/config.txt new file mode 100644 index 0000000..df272d2 --- /dev/null +++ b/test/writer/enum_model_writer/normal_field_description/config.txt @@ -0,0 +1,8 @@ +MyEnumModel: + path: test/enum/ + type: enum + values: + MY_VALUE_1: + description: This is value 1 + MY_VALUE_2: + description: This is value 2 \ No newline at end of file diff --git a/test/writer/enum_model_writer/normal_field_description/output.txt b/test/writer/enum_model_writer/normal_field_description/output.txt new file mode 100644 index 0000000..6d3944a --- /dev/null +++ b/test/writer/enum_model_writer/normal_field_description/output.txt @@ -0,0 +1,22 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +import 'package:json_annotation/json_annotation.dart'; + +enum MyEnumModel { + ///This is value 1 + @JsonValue('MY_VALUE_1') + MY_VALUE_1( + jsonValue: 'MY_VALUE_1', + ), + ///This is value 2 + @JsonValue('MY_VALUE_2') + MY_VALUE_2( + jsonValue: 'MY_VALUE_2', + ); + + final String jsonValue; + + const MyEnumModel({ + required this.jsonValue, + }); +} diff --git a/test/writer/enum_model_writer/normal_with_string_type/config.txt b/test/writer/enum_model_writer/normal_with_string_type/config.txt new file mode 100644 index 0000000..412f248 --- /dev/null +++ b/test/writer/enum_model_writer/normal_with_string_type/config.txt @@ -0,0 +1,14 @@ +MyEnumModel: + path: test/enum/ + type: enum + properties: + value: + type: String + is_json_key: true + values: + MY_VALUE_1: + properties: + value: my_value1 + MY_VALUE_2: + properties: + value: my_value2 \ No newline at end of file diff --git a/test/writer/enum_model_writer/normal_with_string_type/output.txt b/test/writer/enum_model_writer/normal_with_string_type/output.txt new file mode 100644 index 0000000..f958f6f --- /dev/null +++ b/test/writer/enum_model_writer/normal_with_string_type/output.txt @@ -0,0 +1,20 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +import 'package:json_annotation/json_annotation.dart'; + +enum MyEnumModel { + @JsonValue('my_value1') + MY_VALUE_1( + value: 'my_value1', + ), + @JsonValue('my_value2') + MY_VALUE_2( + value: 'my_value2', + ); + + final String value; + + const MyEnumModel({ + required this.value, + }); +} From e450b8d7d19f0e35dd765f82c705fbdcd2ad14b6 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Tue, 5 Sep 2023 16:08:46 +0200 Subject: [PATCH 10/42] #130: added support for optional values --- lib/config/yml_generator_config.dart | 19 ++++++++++++------ lib/model/model/enum_model.dart | 2 ++ lib/writer/enum_model_writer.dart | 16 +++++++++++---- .../optional_values/config.txt | 15 ++++++++++++++ .../optional_values/output.txt | 20 +++++++++++++++++++ 5 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 test/writer/enum_model_writer/optional_values/config.txt create mode 100644 test/writer/enum_model_writer/optional_values/output.txt diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index e2f780d..e54d0dc 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -96,26 +96,33 @@ class YmlGeneratorConfig { final fields = []; final enumProperties = []; properties?.forEach((propertyKey, propertyValue) { - final ItemType type; + final ItemType itemType; + final String type; final bool isJsonKey; final String name = propertyKey; if (propertyValue is YamlMap) { - type = propertyValue['type'] != null ? _parseSimpleType(propertyValue['type']) : StringType(); + type = propertyValue['type']; isJsonKey = propertyValue['is_json_key'] == true; } else { - type = _parseSimpleType(propertyValue); - isJsonKey = false; + type = propertyValue; + isJsonKey = false; } - if (type is! StringType && type is! DoubleType && type is! IntegerType) { + final optional = type.endsWith('?'); + final typeString = optional ? type.substring(0, type.length - 1) : type; + + itemType = _parseSimpleType(typeString); + + if (itemType is! StringType && itemType is! DoubleType && itemType is! IntegerType) { throw Exception('$propertyKey should have a type of integer, double or string'); } enumProperties.add(EnumProperty( name: name, - type: type, + type: itemType, isJsonKey: isJsonKey, + isOptional: optional, )); }); diff --git a/lib/model/model/enum_model.dart b/lib/model/model/enum_model.dart index 2e68f20..3c0065e 100644 --- a/lib/model/model/enum_model.dart +++ b/lib/model/model/enum_model.dart @@ -55,12 +55,14 @@ class EnumField { class EnumProperty { final bool isJsonKey; + final bool isOptional; final String name; ItemType type; EnumProperty({ required this.name, required this.type, + required this.isOptional, this.isJsonKey = false, }); } diff --git a/lib/writer/enum_model_writer.dart b/lib/writer/enum_model_writer.dart index 1be37c2..397cee8 100644 --- a/lib/writer/enum_model_writer.dart +++ b/lib/writer/enum_model_writer.dart @@ -80,17 +80,25 @@ class EnumModelWriter { sb.writeln(' final String jsonValue;'); } for (var property in properties) { - sb.writeln(' final ${property.type.name} ${property.name};'); + sb.write(' final ${property.type.name}'); + if (property.isOptional) { + sb.write('?'); + } + sb.writeln(' ${property.name};'); } if (addProperties) { sb.writeln(); sb.writeln(' const ${jsonModelName.pascalCase}({'); - for (var property in properties) { - sb.writeln(' required this.${property.name},'); - } if (addDefaultJsonKey) { sb.writeln(' required this.jsonValue,'); } + for (var property in properties) { + sb.write(' '); + if(!property.isOptional){ + sb.write('required '); + } + sb.writeln('this.${property.name},'); + } sb.writeln(' });'); } diff --git a/test/writer/enum_model_writer/optional_values/config.txt b/test/writer/enum_model_writer/optional_values/config.txt new file mode 100644 index 0000000..ef2f75e --- /dev/null +++ b/test/writer/enum_model_writer/optional_values/config.txt @@ -0,0 +1,15 @@ +MyEnumModel: + path: test/enum/ + type: enum + properties: + firstName: String + lastName: String? + values: + MY_VALUE_1: + properties: + firstName: firstName + lastName: lastName + MY_VALUE_2: + properties: + firstName: firstName + lastName: lastName \ No newline at end of file diff --git a/test/writer/enum_model_writer/optional_values/output.txt b/test/writer/enum_model_writer/optional_values/output.txt new file mode 100644 index 0000000..b069d4d --- /dev/null +++ b/test/writer/enum_model_writer/optional_values/output.txt @@ -0,0 +1,20 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +import 'package:json_annotation/json_annotation.dart'; + +enum MyEnumModel { + @JsonValue('MY_VALUE_1') + MY_VALUE_1( + jsonValue: 'MY_VALUE_1', + ), + @JsonValue('MY_VALUE_2') + MY_VALUE_2( + jsonValue: 'MY_VALUE_2', + ); + + final String jsonValue; + + const MyEnumModel({ + required this.jsonValue, + }); +} From 06c6b8b8e6dc3668270f86fbddd439eddfc1b2fe Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Wed, 6 Sep 2023 09:45:30 +0200 Subject: [PATCH 11/42] #130: added default values --- lib/config/yml_generator_config.dart | 11 ++++-- lib/model/model/enum_model.dart | 2 ++ lib/writer/enum_model_writer.dart | 23 +++++++------ .../default_values/config.txt | 19 +++++++++++ .../default_values/output.txt | 34 +++++++++++++++++++ .../config.txt | 0 .../output.txt | 0 .../config.txt | 0 .../output.txt | 0 .../config.txt | 0 .../output.txt | 0 .../enum_model_writer/full_enum/config.txt | 16 ++++++--- .../enum_model_writer/full_enum/output.txt | 28 ++++++++++++--- .../config.txt | 0 .../output.txt | 0 .../optional_values_default/config.txt | 13 +++++++ .../optional_values_default/output.txt | 28 +++++++++++++++ .../config.txt | 0 .../output.txt | 0 19 files changed, 152 insertions(+), 22 deletions(-) create mode 100644 test/writer/enum_model_writer/default_values/config.txt create mode 100644 test/writer/enum_model_writer/default_values/output.txt rename test/writer/enum_model_writer/{normal-description => description}/config.txt (100%) rename test/writer/enum_model_writer/{normal-description => description}/output.txt (100%) rename test/writer/enum_model_writer/{normal_with_double_type => double_type}/config.txt (100%) rename test/writer/enum_model_writer/{normal_with_double_type => double_type}/output.txt (100%) rename test/writer/enum_model_writer/{normal_field_description => field_description}/config.txt (100%) rename test/writer/enum_model_writer/{normal_field_description => field_description}/output.txt (100%) rename test/writer/enum_model_writer/{normal_with_int_type => int_type}/config.txt (100%) rename test/writer/enum_model_writer/{normal_with_int_type => int_type}/output.txt (100%) create mode 100644 test/writer/enum_model_writer/optional_values_default/config.txt create mode 100644 test/writer/enum_model_writer/optional_values_default/output.txt rename test/writer/enum_model_writer/{normal_with_string_type => string_type}/config.txt (100%) rename test/writer/enum_model_writer/{normal_with_string_type => string_type}/output.txt (100%) diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index e54d0dc..4a1867c 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -96,17 +96,21 @@ class YmlGeneratorConfig { final fields = []; final enumProperties = []; properties?.forEach((propertyKey, propertyValue) { - final ItemType itemType; - final String type; final bool isJsonKey; + final String type; + final String? defaultValue; + final ItemType itemType; + final String name = propertyKey; if (propertyValue is YamlMap) { type = propertyValue['type']; isJsonKey = propertyValue['is_json_key'] == true; + defaultValue = propertyValue['default_value']; } else { type = propertyValue; - isJsonKey = false; + isJsonKey = false; + defaultValue = null; } final optional = type.endsWith('?'); @@ -123,6 +127,7 @@ class YmlGeneratorConfig { type: itemType, isJsonKey: isJsonKey, isOptional: optional, + defaultValue: defaultValue, )); }); diff --git a/lib/model/model/enum_model.dart b/lib/model/model/enum_model.dart index 3c0065e..7e8be09 100644 --- a/lib/model/model/enum_model.dart +++ b/lib/model/model/enum_model.dart @@ -57,12 +57,14 @@ class EnumProperty { final bool isJsonKey; final bool isOptional; final String name; + String? defaultValue; ItemType type; EnumProperty({ required this.name, required this.type, required this.isOptional, + this.defaultValue, this.isJsonKey = false, }); } diff --git a/lib/writer/enum_model_writer.dart b/lib/writer/enum_model_writer.dart index 397cee8..6582590 100644 --- a/lib/writer/enum_model_writer.dart +++ b/lib/writer/enum_model_writer.dart @@ -1,5 +1,4 @@ import 'package:model_generator/model/item_type/double_type.dart'; -import 'package:model_generator/model/item_type/item_type.dart'; import 'package:model_generator/model/item_type/string_type.dart'; import 'package:model_generator/model/model/enum_model.dart'; import 'package:model_generator/util/case_util.dart'; @@ -53,13 +52,14 @@ class EnumModelWriter { if (addDefaultJsonKey) { sb.writeln(' jsonValue: \'$jsonValue\','); } - for (var value in key.values) { - final type = itemTypeForProperty(value.propertyName, properties); - sb.write(' ${value.propertyName}: '); - if (type is StringType) { - sb.writeln('\'${value.value}\','); + for (var property in properties) { + final enumValue = valueForProperty(property.name, key.values); + final value = enumValue?.value ?? property.defaultValue; + sb.write(' ${property.name}: '); + if (property.type is StringType && value != null) { + sb.writeln('\'$value\','); } else { - sb.writeln('${value.value},'); + sb.writeln('$value,'); } } if (isLast) { @@ -94,7 +94,7 @@ class EnumModelWriter { } for (var property in properties) { sb.write(' '); - if(!property.isOptional){ + if (!property.isOptional) { sb.write('required '); } sb.writeln('this.${property.name},'); @@ -107,6 +107,9 @@ class EnumModelWriter { return sb.toString(); } - ItemType itemTypeForProperty(String propertyName, List properties) => - properties.firstWhereOrNull((property) => property.name == propertyName)?.type ?? StringType(); + EnumValue? valueForProperty( + String propertyName, + List values, + ) => + values.firstWhereOrNull((value) => value.propertyName == propertyName); } diff --git a/test/writer/enum_model_writer/default_values/config.txt b/test/writer/enum_model_writer/default_values/config.txt new file mode 100644 index 0000000..d9b8af8 --- /dev/null +++ b/test/writer/enum_model_writer/default_values/config.txt @@ -0,0 +1,19 @@ +MyEnumModel: + path: test/enum/ + type: enum + properties: + firstName: String + lastName: + type: String + default_value: lastName + values: + MY_VALUE_1: + properties: + firstName: firstName + MY_VALUE_2: + properties: + firstName: firstName + MY_VALUE_3: + properties: + firstName: firstName + lastName: specifiedLastName \ No newline at end of file diff --git a/test/writer/enum_model_writer/default_values/output.txt b/test/writer/enum_model_writer/default_values/output.txt new file mode 100644 index 0000000..8fad0e6 --- /dev/null +++ b/test/writer/enum_model_writer/default_values/output.txt @@ -0,0 +1,34 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +import 'package:json_annotation/json_annotation.dart'; + +enum MyEnumModel { + @JsonValue('MY_VALUE_1') + MY_VALUE_1( + jsonValue: 'MY_VALUE_1', + firstName: 'firstName', + lastName: 'lastName', + ), + @JsonValue('MY_VALUE_2') + MY_VALUE_2( + jsonValue: 'MY_VALUE_2', + firstName: 'firstName', + lastName: 'lastName', + ), + @JsonValue('MY_VALUE_3') + MY_VALUE_3( + jsonValue: 'MY_VALUE_3', + firstName: 'firstName', + lastName: 'specifiedLastName', + ); + + final String jsonValue; + final String firstName; + final String lastName; + + const MyEnumModel({ + required this.jsonValue, + required this.firstName, + required this.lastName, + }); +} diff --git a/test/writer/enum_model_writer/normal-description/config.txt b/test/writer/enum_model_writer/description/config.txt similarity index 100% rename from test/writer/enum_model_writer/normal-description/config.txt rename to test/writer/enum_model_writer/description/config.txt diff --git a/test/writer/enum_model_writer/normal-description/output.txt b/test/writer/enum_model_writer/description/output.txt similarity index 100% rename from test/writer/enum_model_writer/normal-description/output.txt rename to test/writer/enum_model_writer/description/output.txt diff --git a/test/writer/enum_model_writer/normal_with_double_type/config.txt b/test/writer/enum_model_writer/double_type/config.txt similarity index 100% rename from test/writer/enum_model_writer/normal_with_double_type/config.txt rename to test/writer/enum_model_writer/double_type/config.txt diff --git a/test/writer/enum_model_writer/normal_with_double_type/output.txt b/test/writer/enum_model_writer/double_type/output.txt similarity index 100% rename from test/writer/enum_model_writer/normal_with_double_type/output.txt rename to test/writer/enum_model_writer/double_type/output.txt diff --git a/test/writer/enum_model_writer/normal_field_description/config.txt b/test/writer/enum_model_writer/field_description/config.txt similarity index 100% rename from test/writer/enum_model_writer/normal_field_description/config.txt rename to test/writer/enum_model_writer/field_description/config.txt diff --git a/test/writer/enum_model_writer/normal_field_description/output.txt b/test/writer/enum_model_writer/field_description/output.txt similarity index 100% rename from test/writer/enum_model_writer/normal_field_description/output.txt rename to test/writer/enum_model_writer/field_description/output.txt diff --git a/test/writer/enum_model_writer/full_enum/config.txt b/test/writer/enum_model_writer/full_enum/config.txt index 9a0a88d..16bc21c 100644 --- a/test/writer/enum_model_writer/full_enum/config.txt +++ b/test/writer/enum_model_writer/full_enum/config.txt @@ -7,16 +7,17 @@ Person: is_json_key: true type: int firstName: String - lastName: String - age: int - height: double + lastName: + type: String + default_value: lastName + age: int? + height: double? values: MAN: description: enum of a man properties: jsonKey: 1 firstName: firstName1 - lastName: lastName1 age: 12 height: 12.4 WOMAN: @@ -24,6 +25,11 @@ Person: properties: jsonKey: 2 firstName: firstName2 - lastName: lastName2 age: 16 height: 22 + OTHER: + description: enum of a other + properties: + jsonKey: 3 + firstName: firstName3 + lastName: SpecifiedLastName \ No newline at end of file diff --git a/test/writer/enum_model_writer/full_enum/output.txt b/test/writer/enum_model_writer/full_enum/output.txt index e598946..2410327 100644 --- a/test/writer/enum_model_writer/full_enum/output.txt +++ b/test/writer/enum_model_writer/full_enum/output.txt @@ -2,27 +2,47 @@ import 'package:json_annotation/json_annotation.dart'; +///This is a enum of a person enum Person { + ///enum of a man @JsonValue(1) - MY_VALUE_1( + MAN( jsonKey: 1, firstName: 'firstName1', - lastName: 'lastName1', + lastName: 'lastName', + age: 12, + height: 12.4, ), + ///enum of a woman @JsonValue(2) - MY_VALUE_2( + WOMAN( jsonKey: 2, firstName: 'firstName2', - lastName: 'lastName2', + lastName: 'lastName', + age: 16, + height: 22, + ), + ///enum of a other + @JsonValue(3) + OTHER( + jsonKey: 3, + firstName: 'firstName3', + lastName: 'SpecifiedLastName', + age: null, + height: null, ); final int jsonKey; final String firstName; final String lastName; + final int? age; + final double? height; const Person({ required this.jsonKey, required this.firstName, required this.lastName, + this.age, + this.height, }); } diff --git a/test/writer/enum_model_writer/normal_with_int_type/config.txt b/test/writer/enum_model_writer/int_type/config.txt similarity index 100% rename from test/writer/enum_model_writer/normal_with_int_type/config.txt rename to test/writer/enum_model_writer/int_type/config.txt diff --git a/test/writer/enum_model_writer/normal_with_int_type/output.txt b/test/writer/enum_model_writer/int_type/output.txt similarity index 100% rename from test/writer/enum_model_writer/normal_with_int_type/output.txt rename to test/writer/enum_model_writer/int_type/output.txt diff --git a/test/writer/enum_model_writer/optional_values_default/config.txt b/test/writer/enum_model_writer/optional_values_default/config.txt new file mode 100644 index 0000000..94606db --- /dev/null +++ b/test/writer/enum_model_writer/optional_values_default/config.txt @@ -0,0 +1,13 @@ +MyEnumModel: + path: test/enum/ + type: enum + properties: + firstName: String + lastName: String? + values: + MY_VALUE_1: + properties: + firstName: firstName + MY_VALUE_2: + properties: + firstName: firstName \ No newline at end of file diff --git a/test/writer/enum_model_writer/optional_values_default/output.txt b/test/writer/enum_model_writer/optional_values_default/output.txt new file mode 100644 index 0000000..978c0a7 --- /dev/null +++ b/test/writer/enum_model_writer/optional_values_default/output.txt @@ -0,0 +1,28 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +import 'package:json_annotation/json_annotation.dart'; + +enum MyEnumModel { + @JsonValue('MY_VALUE_1') + MY_VALUE_1( + jsonValue: 'MY_VALUE_1', + firstName: 'firstName', + lastName: null, + ), + @JsonValue('MY_VALUE_2') + MY_VALUE_2( + jsonValue: 'MY_VALUE_2', + firstName: 'firstName', + lastName: null, + ); + + final String jsonValue; + final String firstName; + final String? lastName; + + const MyEnumModel({ + required this.jsonValue, + required this.firstName, + this.lastName, + }); +} diff --git a/test/writer/enum_model_writer/normal_with_string_type/config.txt b/test/writer/enum_model_writer/string_type/config.txt similarity index 100% rename from test/writer/enum_model_writer/normal_with_string_type/config.txt rename to test/writer/enum_model_writer/string_type/config.txt diff --git a/test/writer/enum_model_writer/normal_with_string_type/output.txt b/test/writer/enum_model_writer/string_type/output.txt similarity index 100% rename from test/writer/enum_model_writer/normal_with_string_type/output.txt rename to test/writer/enum_model_writer/string_type/output.txt From 8b5002539d3a20cfc4371f5925295a2f656b1577 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Wed, 6 Sep 2023 09:47:38 +0200 Subject: [PATCH 12/42] #130: fixed test --- test/writer/enum_model_writer/optional_values/output.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/writer/enum_model_writer/optional_values/output.txt b/test/writer/enum_model_writer/optional_values/output.txt index b069d4d..236d2bd 100644 --- a/test/writer/enum_model_writer/optional_values/output.txt +++ b/test/writer/enum_model_writer/optional_values/output.txt @@ -6,15 +6,23 @@ enum MyEnumModel { @JsonValue('MY_VALUE_1') MY_VALUE_1( jsonValue: 'MY_VALUE_1', + firstName: 'firstName', + lastName: 'lastName', ), @JsonValue('MY_VALUE_2') MY_VALUE_2( jsonValue: 'MY_VALUE_2', + firstName: 'firstName', + lastName: 'lastName', ); final String jsonValue; + final String firstName; + final String? lastName; const MyEnumModel({ required this.jsonValue, + required this.firstName, + this.lastName, }); } From 249f59517249ecebbdf5349b2667541f1d97fff5 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Wed, 6 Sep 2023 10:05:25 +0200 Subject: [PATCH 13/42] #130: added more accurate error loging --- lib/config/yml_generator_config.dart | 12 ++++++++++-- lib/model/model/enum_model.dart | 12 ++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index 4a1867c..12c7eb7 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -157,7 +157,7 @@ class YmlGeneratorConfig { )); }); - models.add(EnumModel( + final enumModel = EnumModel( addJsonKeyToProperties: value['use_default_json_key'] ?? true, name: key, path: path, @@ -167,7 +167,15 @@ class YmlGeneratorConfig { extraImports: extraImports, extraAnnotations: extraAnnotations, description: description, - )); + ); + + final error = enumModel.validate(); + + if (error != null) { + throw Exception(error); + } + + models.add(enumModel); } else { final staticCreate = (value['static_create'] ?? false) == true; final disallowNullForDefaults = value.containsKey('disallow_null_for_defaults') ? (value['disallow_null_for_defaults'] == true) : pubspecConfig.disallowNullForDefaults; diff --git a/lib/model/model/enum_model.dart b/lib/model/model/enum_model.dart index 7e8be09..60f3f6e 100644 --- a/lib/model/model/enum_model.dart +++ b/lib/model/model/enum_model.dart @@ -24,6 +24,18 @@ class EnumModel extends Model { extraAnnotations: extraAnnotations, description: description, ); + + String? validate() { + for (final property in properties) { + for (final field in fields) { + final containsProperty = field.values.map((value) => value.propertyName).contains(property.name); + if (!containsProperty && !property.isOptional && property.defaultValue == null) { + return 'There is no value defined for property ${property.name} for the enum value ${field.name} in model $name. Either make this property optional or give it a value'; + } + } + } + return null; + } } class EnumField { From 623999110ca91b6d3d0cb71b97ef2339550746f6 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Wed, 6 Sep 2023 12:04:14 +0200 Subject: [PATCH 14/42] #130: cleaned up code --- lib/config/yml_generator_config.dart | 14 +- lib/model/model/enum_model.dart | 48 ++++- lib/writer/enum_model_writer.dart | 3 +- test/writer/enum_model_reader_test.dart | 255 ++++++++++++++++++++++++ test/writer/model_reader_test.dart | 29 --- 5 files changed, 310 insertions(+), 39 deletions(-) create mode 100644 test/writer/enum_model_reader_test.dart diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index 12c7eb7..937096a 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -106,7 +106,7 @@ class YmlGeneratorConfig { if (propertyValue is YamlMap) { type = propertyValue['type']; isJsonKey = propertyValue['is_json_key'] == true; - defaultValue = propertyValue['default_value']; + defaultValue = propertyValue['default_value']?.toString(); } else { type = propertyValue; isJsonKey = false; @@ -118,8 +118,8 @@ class YmlGeneratorConfig { itemType = _parseSimpleType(typeString); - if (itemType is! StringType && itemType is! DoubleType && itemType is! IntegerType) { - throw Exception('$propertyKey should have a type of integer, double or string'); + if (itemType is! StringType && itemType is! DoubleType && itemType is! IntegerType && itemType is! BooleanType) { + throw Exception('$propertyKey should have a type of integer, boolean, double or string'); } enumProperties.add(EnumProperty( @@ -132,11 +132,11 @@ class YmlGeneratorConfig { }); final values = value['values'] as YamlMap?; - if (values == null && properties.isNotEmpty == true) { - throw Exception('The enum $key has defined properties, but a default value is not defined'); + if (values == null) { + throw Exception('Values can not be null. model: $key'); } - values?.forEach((key, value) { + values.forEach((key, value) { final properties = value?['properties'] as YamlMap?; final description = value?['description']; final enumValues = []; @@ -168,7 +168,7 @@ class YmlGeneratorConfig { extraAnnotations: extraAnnotations, description: description, ); - + final error = enumModel.validate(); if (error != null) { diff --git a/lib/model/model/enum_model.dart b/lib/model/model/enum_model.dart index 60f3f6e..0bfc9fc 100644 --- a/lib/model/model/enum_model.dart +++ b/lib/model/model/enum_model.dart @@ -1,5 +1,9 @@ +import 'package:model_generator/model/item_type/boolean_type.dart'; +import 'package:model_generator/model/item_type/double_type.dart'; +import 'package:model_generator/model/item_type/integer_type.dart'; import 'package:model_generator/model/item_type/item_type.dart'; import 'package:model_generator/model/model/model.dart'; +import 'package:model_generator/util/list_extensions.dart'; class EnumModel extends Model { final List fields; @@ -28,14 +32,54 @@ class EnumModel extends Model { String? validate() { for (final property in properties) { for (final field in fields) { - final containsProperty = field.values.map((value) => value.propertyName).contains(property.name); - if (!containsProperty && !property.isOptional && property.defaultValue == null) { + final value = field.values.firstWhereOrNull((value) => value.propertyName == property.name)?.value; + if (value == null && !property.isOptional && property.defaultValue == null) { return 'There is no value defined for property ${property.name} for the enum value ${field.name} in model $name. Either make this property optional or give it a value'; } + final toParseValue = value ?? property.defaultValue; + if (property.type is DoubleType) { + return testValueType( + parser: double.tryParse, + typeName: DoubleType().name, + toParseValue: toParseValue!, + propertyName: property.name, + fieldName: field.name, + ); + } else if (property.type is IntegerType) { + return testValueType( + parser: int.tryParse, + typeName: IntegerType().name, + toParseValue: toParseValue!, + propertyName: property.name, + fieldName: field.name, + ); + } else if (property.type is BooleanType) { + return testValueType( + parser: bool.tryParse, + typeName: BooleanType().name, + toParseValue: toParseValue!, + propertyName: property.name, + fieldName: field.name, + ); + } } } return null; } + + String? testValueType({ + required T? Function(String toParseValue) parser, + required String typeName, + required String toParseValue, + required String propertyName, + required String fieldName, + }) { + final result = parser(toParseValue); + if (result == null) { + return 'Model: $name, Property $propertyName is of type $typeName but the corresponding value on enum value $fieldName is not, make sure they have the same type'; + } + return null; + } } class EnumField { diff --git a/lib/writer/enum_model_writer.dart b/lib/writer/enum_model_writer.dart index 6582590..f0985d5 100644 --- a/lib/writer/enum_model_writer.dart +++ b/lib/writer/enum_model_writer.dart @@ -54,7 +54,8 @@ class EnumModelWriter { } for (var property in properties) { final enumValue = valueForProperty(property.name, key.values); - final value = enumValue?.value ?? property.defaultValue; + var value = enumValue?.value ?? property.defaultValue; + sb.write(' ${property.name}: '); if (property.type is StringType && value != null) { sb.writeln('\'$value\','); diff --git a/test/writer/enum_model_reader_test.dart b/test/writer/enum_model_reader_test.dart new file mode 100644 index 0000000..891115a --- /dev/null +++ b/test/writer/enum_model_reader_test.dart @@ -0,0 +1,255 @@ +import 'package:model_generator/config/pubspec_config.dart'; +import 'package:model_generator/config/yml_generator_config.dart'; +import 'package:model_generator/model/item_type/boolean_type.dart'; +import 'package:model_generator/model/item_type/integer_type.dart'; +import 'package:model_generator/model/item_type/string_type.dart'; +import 'package:model_generator/model/model/enum_model.dart'; +import 'package:test/test.dart'; + +void main() { + group('EnumModel reader test', () { + test('Test simple enum', () { + final models = YmlGeneratorConfig( + PubspecConfig("name: test"), + """ +Gender: + path: user/person/ + type: enum + description: this is an enum + values: + MALE: + description: this is a enum of male + FEMALE: + description: this is a enum of female +""", + '') + .models; + + expect(models.length, 1); + final model = models.first; + expect(model is EnumModel, true); + model as EnumModel; + + expect(model.properties, isEmpty); + expect(model.fields.length, 2); + expect(model.addJsonKeyToProperties, true); + expect(model.description, 'this is an enum'); + + expect(model.fields[0].description, 'this is a enum of male'); + + expect(model.fields[1].description, 'this is a enum of female'); + }); + + test('Test complex enum', () { + final models = YmlGeneratorConfig( + PubspecConfig("name: test"), + """ +Gender: + path: user/person/ + type: enum + description: this is an enum + use_default_json_key: false + properties: + abbreviation: String + isMale: + type: bool + default_value: true + name: + type: String? + jsonKey: + type: int + is_json_key: true + values: + MALE: + description: this is a enum of male + properties: + abbreviation: m + jsonKey: 1 + FEMALE: + description: this is a enum of female + properties: + abbreviation: f + isMale: false + jsonKey: 2 +""", + '') + .models; + + expect(models.length, 1); + final model = models.first; + expect(model is EnumModel, true); + model as EnumModel; + + expect(model.properties.length, 4); + expect(model.fields.length, 2); + expect(model.addJsonKeyToProperties, false); + expect(model.description, 'this is an enum'); + + expect(model.properties[0].type, isA()); + expect(model.properties[3].isOptional, false); + + expect(model.properties[1].defaultValue, 'true'); + expect(model.properties[1].type, isA()); + expect(model.properties[3].isOptional, false); + + expect(model.properties[2].type, isA()); + expect(model.properties[2].isOptional, true); + + expect(model.properties[3].isOptional, false); + expect(model.properties[3].isJsonKey, true); + expect(model.properties[3].type, isA()); + + expect(model.fields[0].description, 'this is a enum of male'); + expect(model.fields[0].values[0].value, 'm'); + expect(model.fields[0].values[1].value, '1'); + + expect(model.fields[1].description, 'this is a enum of female'); + expect(model.fields[1].values[0].value, 'f'); + expect(model.fields[1].values[1].value, 'false'); + expect(model.fields[1].values[2].value, '2'); + }); + + void testEnumError({ + required String enumYml, + required String expectedError, + }) { + dynamic error; + try { + YmlGeneratorConfig(PubspecConfig("name: test"), enumYml, '').models; + } catch (e) { + error = e; + } + expect(error, isNotNull); + expect(error, isException); + if (error is Exception) { + expect(error.toString(), expectedError); + } + } + + test( + 'Test enum without values', + () => testEnumError( + expectedError: 'Exception: Values can not be null. model: Gender', + enumYml: """ +Gender: + path: user/person/ + type: enum + description: this is an enum +""", + )); + + test( + 'Test enum with unsupported type', + () => testEnumError( + expectedError: 'Exception: list should have a type of integer, boolean, double or string', + enumYml: """ +Gender: + path: user/person/ + type: enum + description: this is an enum + properties: + list: List + values: + MALE: + description: this is a enum of male + properties: + list: [] + FEMALE: + description: this is a enum of female + properties: + list: [] +""", + )); + + test( + 'Test enum with missing values', + () => testEnumError( + expectedError: + 'Exception: There is no value defined for property name for the enum value MALE in model Gender. Either make this property optional or give it a value', + enumYml: """ +Gender: + path: user/person/ + type: enum + description: this is an enum + properties: + name: String + values: + MALE: + description: this is a enum of male + properties: + FEMALE: + description: this is a enum of female + properties: +""", + )); + + test( + 'Test enum with incorrect type bool', + () => testEnumError( + expectedError: 'Exception: Model: Gender, Property isMale is of type bool but the corresponding value on enum value MALE is not, make sure they have the same type', + enumYml: """ +Gender: + path: user/person/ + type: enum + description: this is an enum + properties: + isMale: bool + values: + MALE: + description: this is a enum of male + properties: + isMale: 1 + FEMALE: + description: this is a enum of female + properties: + isMale: 1 +""", + )); + + test( + 'Test enum with incorrect type integer', + () => testEnumError( + expectedError: 'Exception: Model: Gender, Property isMale is of type int but the corresponding value on enum value MALE is not, make sure they have the same type', + enumYml: """ +Gender: + path: user/person/ + type: enum + description: this is an enum + properties: + isMale: int + values: + MALE: + description: this is a enum of male + properties: + isMale: hello + FEMALE: + description: this is a enum of female + properties: + isMale: hello +""", + )); + + test( + 'Test enum with incorrect type double', + () => testEnumError( + expectedError: 'Exception: Model: Gender, Property isMale is of type double but the corresponding value on enum value MALE is not, make sure they have the same type', + enumYml: """ +Gender: + path: user/person/ + type: enum + description: this is an enum + properties: + isMale: double + values: + MALE: + description: this is a enum of male + properties: + isMale: hello + FEMALE: + description: this is a enum of female + properties: + isMale: hello +""", + )); + }); +} diff --git a/test/writer/model_reader_test.dart b/test/writer/model_reader_test.dart index 7ab06de..90d43c3 100644 --- a/test/writer/model_reader_test.dart +++ b/test/writer/model_reader_test.dart @@ -227,35 +227,6 @@ TestModel2: expect(nullableRef.type, isA()); expect(nullableRef.isRequired, false); }); - - test('Test enum item_type should be string or integer', () { - dynamic error; - try { - YmlGeneratorConfig( - PubspecConfig("name: test"), - """ -Gender: - path: user/person/ - type: enum - item_type: List - properties: - MALE: - value: male - FEMALE: - value: female -""", - '') - .models; - } catch (e) { - error = e; - } - expect(error, isNotNull); - expect(error, isException); - if (error is Exception) { - expect(error.toString(), - 'Exception: item_type should be a string or integer. model: Gender'); - } - }); }); } From 546dc2786f6f8842125da59d328537bafd468377 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Wed, 6 Sep 2023 12:25:48 +0200 Subject: [PATCH 15/42] #130: regenerated enum values --- .../article/custom_base_directory_obj.dart | 24 +++---- .../article/no_custom_base_directory_obj.dart | 24 +++---- example/lib/model/ogm.dart | 12 ++-- example/lib/model/status/double_status.dart | 48 ++++++------- example/lib/model/status/status.dart | 40 +++++------ example/lib/model/user/person/gender.dart | 50 +++++++++----- example/lib/model/user/person/person.dart | 22 +++--- example/lib/model/user/person/person.g.dart | 8 +-- .../user/profile/admin_profile_data.dart | 24 +++---- .../model/user/profile/user_profile_data.dart | 20 +++--- .../profile/user_profile_data_extended.dart | 25 ++++--- example/lib/model/user/project/project.dart | 29 ++++---- example/lib/model/user/testing.dart | 24 +++---- example/model_generator/enums.yaml | 67 +++++++++++++------ lib/config/yml_generator_config.dart | 17 ++++- test/writer/enum_model_reader_test.dart | 43 ++++++++++++ 16 files changed, 275 insertions(+), 202 deletions(-) diff --git a/example/lib/custom_model_directory/article/custom_base_directory_obj.dart b/example/lib/custom_model_directory/article/custom_base_directory_obj.dart index 2dab8ff..c2df5c0 100644 --- a/example/lib/custom_model_directory/article/custom_base_directory_obj.dart +++ b/example/lib/custom_model_directory/article/custom_base_directory_obj.dart @@ -15,8 +15,7 @@ class CustomBaseDirectoryObj { this.name, }); - factory CustomBaseDirectoryObj.fromJson(Map json) => - _$CustomBaseDirectoryObjFromJson(json); + factory CustomBaseDirectoryObj.fromJson(Map json) => _$CustomBaseDirectoryObjFromJson(json); Map toJson() => _$CustomBaseDirectoryObjToJson(this); @@ -28,24 +27,23 @@ class CustomBaseDirectoryObj { name == other.name; @override - int get hashCode => name.hashCode; + int get hashCode => + name.hashCode; @override - String toString() => 'CustomBaseDirectoryObj{' + String toString() => + 'CustomBaseDirectoryObj{' 'name: $name' '}'; + } const deserializeCustomBaseDirectoryObj = CustomBaseDirectoryObj.fromJson; -Map serializeCustomBaseDirectoryObj( - CustomBaseDirectoryObj object) => - object.toJson(); +Map serializeCustomBaseDirectoryObj(CustomBaseDirectoryObj object) => object.toJson(); -List deserializeCustomBaseDirectoryObjList( - List> jsonList) => - jsonList.map(CustomBaseDirectoryObj.fromJson).toList(); +List deserializeCustomBaseDirectoryObjList(List> jsonList) + => jsonList.map(CustomBaseDirectoryObj.fromJson).toList(); -List> serializeCustomBaseDirectoryObjList( - List objects) => - objects.map((object) => object.toJson()).toList(); +List> serializeCustomBaseDirectoryObjList(List objects) + => objects.map((object) => object.toJson()).toList(); diff --git a/example/lib/model/article/no_custom_base_directory_obj.dart b/example/lib/model/article/no_custom_base_directory_obj.dart index 306bd77..0a2df06 100644 --- a/example/lib/model/article/no_custom_base_directory_obj.dart +++ b/example/lib/model/article/no_custom_base_directory_obj.dart @@ -16,8 +16,7 @@ class NoCustomBaseDirectoryObj { this.customBaseDirectoryObj, }); - factory NoCustomBaseDirectoryObj.fromJson(Map json) => - _$NoCustomBaseDirectoryObjFromJson(json); + factory NoCustomBaseDirectoryObj.fromJson(Map json) => _$NoCustomBaseDirectoryObjFromJson(json); Map toJson() => _$NoCustomBaseDirectoryObjToJson(this); @@ -29,24 +28,23 @@ class NoCustomBaseDirectoryObj { customBaseDirectoryObj == other.customBaseDirectoryObj; @override - int get hashCode => customBaseDirectoryObj.hashCode; + int get hashCode => + customBaseDirectoryObj.hashCode; @override - String toString() => 'NoCustomBaseDirectoryObj{' + String toString() => + 'NoCustomBaseDirectoryObj{' 'customBaseDirectoryObj: $customBaseDirectoryObj' '}'; + } const deserializeNoCustomBaseDirectoryObj = NoCustomBaseDirectoryObj.fromJson; -Map serializeNoCustomBaseDirectoryObj( - NoCustomBaseDirectoryObj object) => - object.toJson(); +Map serializeNoCustomBaseDirectoryObj(NoCustomBaseDirectoryObj object) => object.toJson(); -List deserializeNoCustomBaseDirectoryObjList( - List> jsonList) => - jsonList.map(NoCustomBaseDirectoryObj.fromJson).toList(); +List deserializeNoCustomBaseDirectoryObjList(List> jsonList) + => jsonList.map(NoCustomBaseDirectoryObj.fromJson).toList(); -List> serializeNoCustomBaseDirectoryObjList( - List objects) => - objects.map((object) => object.toJson()).toList(); +List> serializeNoCustomBaseDirectoryObjList(List objects) + => objects.map((object) => object.toJson()).toList(); diff --git a/example/lib/model/ogm.dart b/example/lib/model/ogm.dart index 149f048..478d298 100644 --- a/example/lib/model/ogm.dart +++ b/example/lib/model/ogm.dart @@ -92,7 +92,8 @@ class OGM { simpleMap.hashCode; @override - String toString() => 'OGM{' + String toString() => + 'OGM{' 'beneficiary: $beneficiary, ' 'beneficiaryIBAN: $beneficiaryIBAN, ' 'testTest: $testTest, ' @@ -107,14 +108,15 @@ class OGM { 'fields: $fields, ' 'simpleMap: $simpleMap' '}'; + } const deserializeOGM = OGM.fromJson; Map serializeOGM(OGM object) => object.toJson(); -List deserializeOGMList(List> jsonList) => - jsonList.map(OGM.fromJson).toList(); +List deserializeOGMList(List> jsonList) + => jsonList.map(OGM.fromJson).toList(); -List> serializeOGMList(List objects) => - objects.map((object) => object.toJson()).toList(); +List> serializeOGMList(List objects) + => objects.map((object) => object.toJson()).toList(); diff --git a/example/lib/model/status/double_status.dart b/example/lib/model/status/double_status.dart index f888ab3..7e31ce2 100644 --- a/example/lib/model/status/double_status.dart +++ b/example/lib/model/status/double_status.dart @@ -3,34 +3,26 @@ import 'package:json_annotation/json_annotation.dart'; enum DoubleStatus { - @JsonValue(0.0) - STATUS_0, - @JsonValue(1.0) - STATUS_1, - @JsonValue(2.0) - STATUS_2, - @JsonValue(3.0) - STATUS_3, -} - -const doubleStatusMapping = { - DoubleStatus.STATUS_0: 0.0, - DoubleStatus.STATUS_1: 1.0, - DoubleStatus.STATUS_2: 2.0, - DoubleStatus.STATUS_3: 3.0, -}; + @JsonValue(0.1) + STATUS_0( + value: 0.1, + ), + @JsonValue(1.1) + STATUS_1( + value: 1.1, + ), + @JsonValue(2.2) + STATUS_2( + value: 2.2, + ), + @JsonValue(3.3) + STATUS_3( + value: 3.3, + ); -final reverseDoubleStatusMapping = { - 0.0: DoubleStatus.STATUS_0, - 1.0: DoubleStatus.STATUS_1, - 2.0: DoubleStatus.STATUS_2, - 3.0: DoubleStatus.STATUS_3, -}; - -extension DoubleStatusExtension on DoubleStatus { - double get doubleValue => doubleStatusMapping[this]!; -} + final double value; -extension DoubleStatusDoubleExtension on double { - DoubleStatus? get asDoubleStatus => reverseDoubleStatusMapping[this]; + const DoubleStatus({ + required this.value, + }); } diff --git a/example/lib/model/status/status.dart b/example/lib/model/status/status.dart index a0d45ff..0fc4231 100644 --- a/example/lib/model/status/status.dart +++ b/example/lib/model/status/status.dart @@ -4,33 +4,25 @@ import 'package:json_annotation/json_annotation.dart'; enum Status { @JsonValue(0) - STATUS_0, + STATUS_0( + value: 0, + ), @JsonValue(1) - STATUS_1, + STATUS_1( + value: 1, + ), @JsonValue(2) - STATUS_2, + STATUS_2( + value: 2, + ), @JsonValue(3) - STATUS_3, -} - -const statusMapping = { - Status.STATUS_0: 0, - Status.STATUS_1: 1, - Status.STATUS_2: 2, - Status.STATUS_3: 3, -}; + STATUS_3( + value: 3, + ); -const reverseStatusMapping = { - 0: Status.STATUS_0, - 1: Status.STATUS_1, - 2: Status.STATUS_2, - 3: Status.STATUS_3, -}; - -extension StatusExtension on Status { - int get intValue => statusMapping[this]!; -} + final int value; -extension StatusIntExtension on int { - Status? get asStatus => reverseStatusMapping[this]; + const Status({ + required this.value, + }); } diff --git a/example/lib/model/user/person/gender.dart b/example/lib/model/user/person/gender.dart index a82ca2d..8019bc4 100644 --- a/example/lib/model/user/person/gender.dart +++ b/example/lib/model/user/person/gender.dart @@ -4,25 +4,45 @@ import 'package:json_annotation/json_annotation.dart'; enum Gender { @JsonValue('_mAl3') - MALE(name: 'brian'), + MALE( + value: '_mAl3', + ), @JsonValue('femAle') - FEMALE(name: 'brian'), + FEMALE( + value: 'femAle', + ), @JsonValue('X') - X(name: 'brian'), - @JsonValue('GENDER_X') - GENDER_X(name: 'brian'), - @JsonValue('null') - GENDER_Y(name: 'brian'), + X( + value: 'X', + ), + @JsonValue('gender_x') + GENDER_X( + value: 'gender_x', + ), + @JsonValue('gender_y') + GENDER_Y( + value: 'gender_y', + ), @JsonValue('gender_z') - GENDER_Z(name: 'brian'), - @JsonValue('GENDER_abC') - GENDER_ABC(name: 'brian'), - @JsonValue('null') - GENDER_DEF(name: 'brian'), + GENDER_Z( + value: 'gender_z', + ), + @JsonValue('gender_abc') + GENDER_ABC( + value: 'gender_abc', + ), + @JsonValue('gender_def') + GENDER_DEF( + value: 'gender_def', + ), @JsonValue('GENDER_lap') - GENDER_LAP(name: 'brian'); + GENDER_LAP( + value: 'GENDER_lap', + ); - final String name; + final String value; - const Gender({required this.name}); + const Gender({ + required this.value, + }); } diff --git a/example/lib/model/user/person/person.dart b/example/lib/model/user/person/person.dart index 1606912..1a1b74c 100644 --- a/example/lib/model/user/person/person.dart +++ b/example/lib/model/user/person/person.dart @@ -11,11 +11,7 @@ part 'person.g.dart'; class Person { @JsonKey(name: 'firstName', required: true, includeIfNull: false) final String firstName; - @JsonKey( - name: 'gender', - required: true, - includeIfNull: false, - unknownEnumValue: Gender.X) + @JsonKey(name: 'gender', required: true, includeIfNull: false, unknownEnumValue: Gender.X) final Gender gender; const Person({ @@ -36,21 +32,25 @@ class Person { gender == other.gender; @override - int get hashCode => firstName.hashCode ^ gender.hashCode; + int get hashCode => + firstName.hashCode ^ + gender.hashCode; @override - String toString() => 'Person{' + String toString() => + 'Person{' 'firstName: $firstName, ' 'gender: $gender' '}'; + } const deserializePerson = Person.fromJson; Map serializePerson(Person object) => object.toJson(); -List deserializePersonList(List> jsonList) => - jsonList.map(Person.fromJson).toList(); +List deserializePersonList(List> jsonList) + => jsonList.map(Person.fromJson).toList(); -List> serializePersonList(List objects) => - objects.map((object) => object.toJson()).toList(); +List> serializePersonList(List objects) + => objects.map((object) => object.toJson()).toList(); diff --git a/example/lib/model/user/person/person.g.dart b/example/lib/model/user/person/person.g.dart index 970221b..5b0b759 100644 --- a/example/lib/model/user/person/person.g.dart +++ b/example/lib/model/user/person/person.g.dart @@ -27,10 +27,10 @@ const _$GenderEnumMap = { Gender.MALE: '_mAl3', Gender.FEMALE: 'femAle', Gender.X: 'X', - Gender.GENDER_X: 'GENDER_X', - Gender.GENDER_Y: 'null', + Gender.GENDER_X: 'gender_x', + Gender.GENDER_Y: 'gender_y', Gender.GENDER_Z: 'gender_z', - Gender.GENDER_ABC: 'GENDER_abC', - Gender.GENDER_DEF: 'null', + Gender.GENDER_ABC: 'gender_abc', + Gender.GENDER_DEF: 'gender_def', Gender.GENDER_LAP: 'GENDER_lap', }; diff --git a/example/lib/model/user/profile/admin_profile_data.dart b/example/lib/model/user/profile/admin_profile_data.dart index ac5a8af..d1c3047 100644 --- a/example/lib/model/user/profile/admin_profile_data.dart +++ b/example/lib/model/user/profile/admin_profile_data.dart @@ -44,8 +44,7 @@ class AdminProfileData extends UserProfileDataExtended { personsById: personsById, ); - factory AdminProfileData.fromJson(Map json) => - _$AdminProfileDataFromJson(json); + factory AdminProfileData.fromJson(Map json) => _$AdminProfileDataFromJson(json); @override Map toJson() => _$AdminProfileDataToJson(this); @@ -59,10 +58,13 @@ class AdminProfileData extends UserProfileDataExtended { super == other; @override - int get hashCode => privileges.hashCode ^ super.hashCode; + int get hashCode => + privileges.hashCode ^ + super.hashCode; @override - String toString() => 'AdminProfileData{' + String toString() => + 'AdminProfileData{' 'privileges: $privileges, ' 'additionalField: $additionalField, ' 'firstName: $firstName, ' @@ -77,17 +79,15 @@ class AdminProfileData extends UserProfileDataExtended { 'persons: $persons, ' 'personsById: $personsById' '}'; + } const deserializeAdminProfileData = AdminProfileData.fromJson; -Map serializeAdminProfileData(AdminProfileData object) => - object.toJson(); +Map serializeAdminProfileData(AdminProfileData object) => object.toJson(); -List deserializeAdminProfileDataList( - List> jsonList) => - jsonList.map(AdminProfileData.fromJson).toList(); +List deserializeAdminProfileDataList(List> jsonList) + => jsonList.map(AdminProfileData.fromJson).toList(); -List> serializeAdminProfileDataList( - List objects) => - objects.map((object) => object.toJson()).toList(); +List> serializeAdminProfileDataList(List objects) + => objects.map((object) => object.toJson()).toList(); diff --git a/example/lib/model/user/profile/user_profile_data.dart b/example/lib/model/user/profile/user_profile_data.dart index 84b9c2d..7716bb7 100644 --- a/example/lib/model/user/profile/user_profile_data.dart +++ b/example/lib/model/user/profile/user_profile_data.dart @@ -48,8 +48,7 @@ class UserProfileData { this.personsById, }); - factory UserProfileData.fromJson(Map json) => - _$UserProfileDataFromJson(json); + factory UserProfileData.fromJson(Map json) => _$UserProfileDataFromJson(json); Map toJson() => _$UserProfileDataToJson(this); @@ -85,7 +84,8 @@ class UserProfileData { personsById.hashCode; @override - String toString() => 'UserProfileData{' + String toString() => + 'UserProfileData{' 'firstName: $firstName, ' 'lastName: $lastName, ' 'standardLanguage: $standardLanguage, ' @@ -98,17 +98,15 @@ class UserProfileData { 'persons: $persons, ' 'personsById: $personsById' '}'; + } const deserializeUserProfileData = UserProfileData.fromJson; -Map serializeUserProfileData(UserProfileData object) => - object.toJson(); +Map serializeUserProfileData(UserProfileData object) => object.toJson(); -List deserializeUserProfileDataList( - List> jsonList) => - jsonList.map(UserProfileData.fromJson).toList(); +List deserializeUserProfileDataList(List> jsonList) + => jsonList.map(UserProfileData.fromJson).toList(); -List> serializeUserProfileDataList( - List objects) => - objects.map((object) => object.toJson()).toList(); +List> serializeUserProfileDataList(List objects) + => objects.map((object) => object.toJson()).toList(); diff --git a/example/lib/model/user/profile/user_profile_data_extended.dart b/example/lib/model/user/profile/user_profile_data_extended.dart index c0e77fb..532c1a6 100644 --- a/example/lib/model/user/profile/user_profile_data_extended.dart +++ b/example/lib/model/user/profile/user_profile_data_extended.dart @@ -42,8 +42,7 @@ class UserProfileDataExtended extends UserProfileData { personsById: personsById, ); - factory UserProfileDataExtended.fromJson(Map json) => - _$UserProfileDataExtendedFromJson(json); + factory UserProfileDataExtended.fromJson(Map json) => _$UserProfileDataExtendedFromJson(json); @override Map toJson() => _$UserProfileDataExtendedToJson(this); @@ -57,10 +56,13 @@ class UserProfileDataExtended extends UserProfileData { super == other; @override - int get hashCode => additionalField.hashCode ^ super.hashCode; + int get hashCode => + additionalField.hashCode ^ + super.hashCode; @override - String toString() => 'UserProfileDataExtended{' + String toString() => + 'UserProfileDataExtended{' 'additionalField: $additionalField, ' 'firstName: $firstName, ' 'lastName: $lastName, ' @@ -74,18 +76,15 @@ class UserProfileDataExtended extends UserProfileData { 'persons: $persons, ' 'personsById: $personsById' '}'; + } const deserializeUserProfileDataExtended = UserProfileDataExtended.fromJson; -Map serializeUserProfileDataExtended( - UserProfileDataExtended object) => - object.toJson(); +Map serializeUserProfileDataExtended(UserProfileDataExtended object) => object.toJson(); -List deserializeUserProfileDataExtendedList( - List> jsonList) => - jsonList.map(UserProfileDataExtended.fromJson).toList(); +List deserializeUserProfileDataExtendedList(List> jsonList) + => jsonList.map(UserProfileDataExtended.fromJson).toList(); -List> serializeUserProfileDataExtendedList( - List objects) => - objects.map((object) => object.toJson()).toList(); +List> serializeUserProfileDataExtendedList(List objects) + => objects.map((object) => object.toJson()).toList(); diff --git a/example/lib/model/user/project/project.dart b/example/lib/model/user/project/project.dart index b9afa89..5da61e1 100644 --- a/example/lib/model/user/project/project.dart +++ b/example/lib/model/user/project/project.dart @@ -9,16 +9,11 @@ part 'project.g.dart'; @JsonSerializable(explicitToJson: true) @immutable class Project { - @JsonKey( - name: 'name', - required: false, - disallowNullValue: false, - includeIfNull: false) + @JsonKey(name: 'name', required: false, disallowNullValue: false, includeIfNull: false) final String name; @JsonKey(name: 'cost', includeIfNull: false) final double? cost; - @JsonKey( - name: 'status', includeIfNull: false, unknownEnumValue: Status.STATUS_0) + @JsonKey(name: 'status', includeIfNull: false, unknownEnumValue: Status.STATUS_0) final Status? status; const Project({ @@ -27,8 +22,7 @@ class Project { this.status, }); - factory Project.fromJson(Object? json) => - _$ProjectFromJson(json as Map); // ignore: avoid_as + factory Project.fromJson(Object? json) => _$ProjectFromJson(json as Map); // ignore: avoid_as Map toJson() => _$ProjectToJson(this); @@ -45,22 +39,27 @@ class Project { status == other.status; @override - int get hashCode => name.hashCode ^ cost.hashCode ^ status.hashCode; + int get hashCode => + name.hashCode ^ + cost.hashCode ^ + status.hashCode; @override - String toString() => 'Project{' + String toString() => + 'Project{' 'name: $name, ' 'cost: $cost, ' 'status: $status' '}'; + } const deserializeProject = Project.fromJson; Map serializeProject(Project object) => object.toJson(); -List deserializeProjectList(List> jsonList) => - jsonList.map(Project.fromJson).toList(); +List deserializeProjectList(List> jsonList) + => jsonList.map(Project.fromJson).toList(); -List> serializeProjectList(List objects) => - objects.map((object) => object.toJson()).toList(); +List> serializeProjectList(List objects) + => objects.map((object) => object.toJson()).toList(); diff --git a/example/lib/model/user/testing.dart b/example/lib/model/user/testing.dart index d99ceed..cde1781 100644 --- a/example/lib/model/user/testing.dart +++ b/example/lib/model/user/testing.dart @@ -10,11 +10,7 @@ part 'testing.g.dart'; class Testing { @JsonKey(name: 'beneficiary', required: true, includeIfNull: false) final String beneficiary; - @JsonKey( - name: 'isFavourite', - includeIfNull: false, - includeFromJson: false, - includeToJson: false) + @JsonKey(name: 'isFavourite', includeIfNull: false, includeFromJson: false, includeToJson: false) String? isFavourite; @JsonKey(name: 'structuredMessage', includeIfNull: false) final String? structuredMessage; @@ -24,11 +20,7 @@ class Testing { final dynamic dynamicField; @JsonKey(name: 'duration', includeIfNull: false) final Duration? duration; - @JsonKey( - name: 'duration_from_json_test', - includeIfNull: false, - fromJson: handleDurationFromToJsonFromJson, - toJson: handleDurationFromToJsonToJson) + @JsonKey(name: 'duration_from_json_test', includeIfNull: false, fromJson: handleDurationFromToJsonFromJson, toJson: handleDurationFromToJsonToJson) final DurationFromToJson? durationFromJsonTest; Testing({ @@ -41,18 +33,18 @@ class Testing { this.durationFromJsonTest, }); - factory Testing.fromJson(Map json) => - _$TestingFromJson(json); + factory Testing.fromJson(Map json) => _$TestingFromJson(json); Map toJson() => _$TestingToJson(this); + } const deserializeTesting = Testing.fromJson; Map serializeTesting(Testing object) => object.toJson(); -List deserializeTestingList(List> jsonList) => - jsonList.map(Testing.fromJson).toList(); +List deserializeTestingList(List> jsonList) + => jsonList.map(Testing.fromJson).toList(); -List> serializeTestingList(List objects) => - objects.map((object) => object.toJson()).toList(); +List> serializeTestingList(List objects) + => objects.map((object) => object.toJson()).toList(); diff --git a/example/model_generator/enums.yaml b/example/model_generator/enums.yaml index c82c919..a2ca01a 100644 --- a/example/model_generator/enums.yaml +++ b/example/model_generator/enums.yaml @@ -2,51 +2,76 @@ Gender: path: user/person/ type: enum properties: + value: + type: String + is_json_key: true + values: MALE: - value: _mAl3 + properties: + value: _mAl3 FEMALE: - value: femAle + properties: + value: femAle X: - value: X + properties: + value: X GENDER_X: + properties: + value: gender_x GENDER_Y: - value: + properties: + value: gender_y GENDER_z: - value: gender_z + properties: + value: gender_z GENDER_abC: + properties: + value: gender_abc GENDER_def: - value: + properties: + value: gender_def GENDER_lap: - value: GENDER_lap + properties: + value: GENDER_lap Status: path: status type: enum - item_type: int - generate_map: true - generate_extensions: true properties: + value: + type: int + is_json_key: true + values: status_0: - value: 0 + properties: + value: 0 status_1: - value: 1 + properties: + value: 1 status_2: - value: 2 + properties: + value: 2 status_3: - value: 3 + properties: + value: 3 DoubleStatus: path: status type: enum - item_type: double - generate_map: true - generate_extensions: true properties: + value: + type: double + is_json_key: true + values: status_0: - value: 0.0 + properties: + value: 0.1 status_1: - value: 1.0 + properties: + value: 1.1 status_2: - value: 2.0 + properties: + value: 2.2 status_3: - value: 3.0 + properties: + value: 3.3 diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index 937096a..2c477bc 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -91,6 +91,21 @@ class YmlGeneratorConfig { throw Exception('Properties should be a map, right now you are using a ${properties.runtimeType}. model: $key'); } if (type == 'enum') { + final deprecatedItemType = value['item_type']; + if (deprecatedItemType != null) { + throw Exception('item_type is removed, follow the migration to version 7.0.0'); + } + + final deprecatedGenerateExtensions = value['generate_extensions']; + if (deprecatedGenerateExtensions != null) { + throw Exception('generate_extensions is removed, follow the migration to version 7.0.0'); + } + + final deprecatedGenerateMap = value['generate_map']; + if (deprecatedGenerateMap != null) { + throw Exception('generate_map is removed, follow the migration to version 7.0.0'); + } + final uppercaseEnums = (value['uppercase_enums'] ?? pubspecConfig.uppercaseEnums) == true; final fields = []; @@ -102,7 +117,7 @@ class YmlGeneratorConfig { final ItemType itemType; final String name = propertyKey; - + if (propertyValue is YamlMap) { type = propertyValue['type']; isJsonKey = propertyValue['is_json_key'] == true; diff --git a/test/writer/enum_model_reader_test.dart b/test/writer/enum_model_reader_test.dart index 891115a..44cc437 100644 --- a/test/writer/enum_model_reader_test.dart +++ b/test/writer/enum_model_reader_test.dart @@ -249,6 +249,49 @@ Gender: description: this is a enum of female properties: isMale: hello +""", + )); + + test( + 'item_type not supported anymore', + () => testEnumError( + expectedError: 'Exception: item_type is removed, follow the migration to version 7.0.0', + enumYml: """ +Gender: + path: user/person/ + type: enum + item_type: double + values: + MALE: + FEMALE: +""", + )); + test( + 'generate_map not supported anymore', + () => testEnumError( + expectedError: 'Exception: generate_map is removed, follow the migration to version 7.0.0', + enumYml: """ +Gender: + path: user/person/ + type: enum + generate_map: true + values: + MALE: + FEMALE: +""", + )); + test( + 'generate_extensions not supported anymore', + () => testEnumError( + expectedError: 'Exception: generate_extensions is removed, follow the migration to version 7.0.0', + enumYml: """ +Gender: + path: user/person/ + type: enum + generate_extensions: true + values: + MALE: + FEMALE: """, )); }); From ad74fed6cc162caef9f7063c25ec2687f3f6d5bb Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Wed, 6 Sep 2023 12:26:04 +0200 Subject: [PATCH 16/42] #130: formatted files --- .../article/custom_base_directory_obj.dart | 24 +- .../article/no_custom_base_directory_obj.dart | 24 +- example/lib/model/ogm.dart | 12 +- example/lib/model/user/person/person.dart | 22 +- .../user/profile/admin_profile_data.dart | 24 +- .../model/user/profile/user_profile_data.dart | 20 +- .../profile/user_profile_data_extended.dart | 25 +- example/lib/model/user/project/project.dart | 29 +-- example/lib/model/user/testing.dart | 24 +- lib/config/yml_generator_config.dart | 115 ++++++--- lib/model/model/enum_model.dart | 8 +- lib/writer/enum_model_writer.dart | 15 +- test/config/yml_generator_config_test.dart | 233 +++++++++++++----- test/writer/enum_model_reader_test.dart | 21 +- test/writer/enum_model_writer_test.dart | 3 +- test/writer/object_model_writer_test.dart | 6 +- 16 files changed, 394 insertions(+), 211 deletions(-) diff --git a/example/lib/custom_model_directory/article/custom_base_directory_obj.dart b/example/lib/custom_model_directory/article/custom_base_directory_obj.dart index c2df5c0..2dab8ff 100644 --- a/example/lib/custom_model_directory/article/custom_base_directory_obj.dart +++ b/example/lib/custom_model_directory/article/custom_base_directory_obj.dart @@ -15,7 +15,8 @@ class CustomBaseDirectoryObj { this.name, }); - factory CustomBaseDirectoryObj.fromJson(Map json) => _$CustomBaseDirectoryObjFromJson(json); + factory CustomBaseDirectoryObj.fromJson(Map json) => + _$CustomBaseDirectoryObjFromJson(json); Map toJson() => _$CustomBaseDirectoryObjToJson(this); @@ -27,23 +28,24 @@ class CustomBaseDirectoryObj { name == other.name; @override - int get hashCode => - name.hashCode; + int get hashCode => name.hashCode; @override - String toString() => - 'CustomBaseDirectoryObj{' + String toString() => 'CustomBaseDirectoryObj{' 'name: $name' '}'; - } const deserializeCustomBaseDirectoryObj = CustomBaseDirectoryObj.fromJson; -Map serializeCustomBaseDirectoryObj(CustomBaseDirectoryObj object) => object.toJson(); +Map serializeCustomBaseDirectoryObj( + CustomBaseDirectoryObj object) => + object.toJson(); -List deserializeCustomBaseDirectoryObjList(List> jsonList) - => jsonList.map(CustomBaseDirectoryObj.fromJson).toList(); +List deserializeCustomBaseDirectoryObjList( + List> jsonList) => + jsonList.map(CustomBaseDirectoryObj.fromJson).toList(); -List> serializeCustomBaseDirectoryObjList(List objects) - => objects.map((object) => object.toJson()).toList(); +List> serializeCustomBaseDirectoryObjList( + List objects) => + objects.map((object) => object.toJson()).toList(); diff --git a/example/lib/model/article/no_custom_base_directory_obj.dart b/example/lib/model/article/no_custom_base_directory_obj.dart index 0a2df06..306bd77 100644 --- a/example/lib/model/article/no_custom_base_directory_obj.dart +++ b/example/lib/model/article/no_custom_base_directory_obj.dart @@ -16,7 +16,8 @@ class NoCustomBaseDirectoryObj { this.customBaseDirectoryObj, }); - factory NoCustomBaseDirectoryObj.fromJson(Map json) => _$NoCustomBaseDirectoryObjFromJson(json); + factory NoCustomBaseDirectoryObj.fromJson(Map json) => + _$NoCustomBaseDirectoryObjFromJson(json); Map toJson() => _$NoCustomBaseDirectoryObjToJson(this); @@ -28,23 +29,24 @@ class NoCustomBaseDirectoryObj { customBaseDirectoryObj == other.customBaseDirectoryObj; @override - int get hashCode => - customBaseDirectoryObj.hashCode; + int get hashCode => customBaseDirectoryObj.hashCode; @override - String toString() => - 'NoCustomBaseDirectoryObj{' + String toString() => 'NoCustomBaseDirectoryObj{' 'customBaseDirectoryObj: $customBaseDirectoryObj' '}'; - } const deserializeNoCustomBaseDirectoryObj = NoCustomBaseDirectoryObj.fromJson; -Map serializeNoCustomBaseDirectoryObj(NoCustomBaseDirectoryObj object) => object.toJson(); +Map serializeNoCustomBaseDirectoryObj( + NoCustomBaseDirectoryObj object) => + object.toJson(); -List deserializeNoCustomBaseDirectoryObjList(List> jsonList) - => jsonList.map(NoCustomBaseDirectoryObj.fromJson).toList(); +List deserializeNoCustomBaseDirectoryObjList( + List> jsonList) => + jsonList.map(NoCustomBaseDirectoryObj.fromJson).toList(); -List> serializeNoCustomBaseDirectoryObjList(List objects) - => objects.map((object) => object.toJson()).toList(); +List> serializeNoCustomBaseDirectoryObjList( + List objects) => + objects.map((object) => object.toJson()).toList(); diff --git a/example/lib/model/ogm.dart b/example/lib/model/ogm.dart index 478d298..149f048 100644 --- a/example/lib/model/ogm.dart +++ b/example/lib/model/ogm.dart @@ -92,8 +92,7 @@ class OGM { simpleMap.hashCode; @override - String toString() => - 'OGM{' + String toString() => 'OGM{' 'beneficiary: $beneficiary, ' 'beneficiaryIBAN: $beneficiaryIBAN, ' 'testTest: $testTest, ' @@ -108,15 +107,14 @@ class OGM { 'fields: $fields, ' 'simpleMap: $simpleMap' '}'; - } const deserializeOGM = OGM.fromJson; Map serializeOGM(OGM object) => object.toJson(); -List deserializeOGMList(List> jsonList) - => jsonList.map(OGM.fromJson).toList(); +List deserializeOGMList(List> jsonList) => + jsonList.map(OGM.fromJson).toList(); -List> serializeOGMList(List objects) - => objects.map((object) => object.toJson()).toList(); +List> serializeOGMList(List objects) => + objects.map((object) => object.toJson()).toList(); diff --git a/example/lib/model/user/person/person.dart b/example/lib/model/user/person/person.dart index 1a1b74c..1606912 100644 --- a/example/lib/model/user/person/person.dart +++ b/example/lib/model/user/person/person.dart @@ -11,7 +11,11 @@ part 'person.g.dart'; class Person { @JsonKey(name: 'firstName', required: true, includeIfNull: false) final String firstName; - @JsonKey(name: 'gender', required: true, includeIfNull: false, unknownEnumValue: Gender.X) + @JsonKey( + name: 'gender', + required: true, + includeIfNull: false, + unknownEnumValue: Gender.X) final Gender gender; const Person({ @@ -32,25 +36,21 @@ class Person { gender == other.gender; @override - int get hashCode => - firstName.hashCode ^ - gender.hashCode; + int get hashCode => firstName.hashCode ^ gender.hashCode; @override - String toString() => - 'Person{' + String toString() => 'Person{' 'firstName: $firstName, ' 'gender: $gender' '}'; - } const deserializePerson = Person.fromJson; Map serializePerson(Person object) => object.toJson(); -List deserializePersonList(List> jsonList) - => jsonList.map(Person.fromJson).toList(); +List deserializePersonList(List> jsonList) => + jsonList.map(Person.fromJson).toList(); -List> serializePersonList(List objects) - => objects.map((object) => object.toJson()).toList(); +List> serializePersonList(List objects) => + objects.map((object) => object.toJson()).toList(); diff --git a/example/lib/model/user/profile/admin_profile_data.dart b/example/lib/model/user/profile/admin_profile_data.dart index d1c3047..ac5a8af 100644 --- a/example/lib/model/user/profile/admin_profile_data.dart +++ b/example/lib/model/user/profile/admin_profile_data.dart @@ -44,7 +44,8 @@ class AdminProfileData extends UserProfileDataExtended { personsById: personsById, ); - factory AdminProfileData.fromJson(Map json) => _$AdminProfileDataFromJson(json); + factory AdminProfileData.fromJson(Map json) => + _$AdminProfileDataFromJson(json); @override Map toJson() => _$AdminProfileDataToJson(this); @@ -58,13 +59,10 @@ class AdminProfileData extends UserProfileDataExtended { super == other; @override - int get hashCode => - privileges.hashCode ^ - super.hashCode; + int get hashCode => privileges.hashCode ^ super.hashCode; @override - String toString() => - 'AdminProfileData{' + String toString() => 'AdminProfileData{' 'privileges: $privileges, ' 'additionalField: $additionalField, ' 'firstName: $firstName, ' @@ -79,15 +77,17 @@ class AdminProfileData extends UserProfileDataExtended { 'persons: $persons, ' 'personsById: $personsById' '}'; - } const deserializeAdminProfileData = AdminProfileData.fromJson; -Map serializeAdminProfileData(AdminProfileData object) => object.toJson(); +Map serializeAdminProfileData(AdminProfileData object) => + object.toJson(); -List deserializeAdminProfileDataList(List> jsonList) - => jsonList.map(AdminProfileData.fromJson).toList(); +List deserializeAdminProfileDataList( + List> jsonList) => + jsonList.map(AdminProfileData.fromJson).toList(); -List> serializeAdminProfileDataList(List objects) - => objects.map((object) => object.toJson()).toList(); +List> serializeAdminProfileDataList( + List objects) => + objects.map((object) => object.toJson()).toList(); diff --git a/example/lib/model/user/profile/user_profile_data.dart b/example/lib/model/user/profile/user_profile_data.dart index 7716bb7..84b9c2d 100644 --- a/example/lib/model/user/profile/user_profile_data.dart +++ b/example/lib/model/user/profile/user_profile_data.dart @@ -48,7 +48,8 @@ class UserProfileData { this.personsById, }); - factory UserProfileData.fromJson(Map json) => _$UserProfileDataFromJson(json); + factory UserProfileData.fromJson(Map json) => + _$UserProfileDataFromJson(json); Map toJson() => _$UserProfileDataToJson(this); @@ -84,8 +85,7 @@ class UserProfileData { personsById.hashCode; @override - String toString() => - 'UserProfileData{' + String toString() => 'UserProfileData{' 'firstName: $firstName, ' 'lastName: $lastName, ' 'standardLanguage: $standardLanguage, ' @@ -98,15 +98,17 @@ class UserProfileData { 'persons: $persons, ' 'personsById: $personsById' '}'; - } const deserializeUserProfileData = UserProfileData.fromJson; -Map serializeUserProfileData(UserProfileData object) => object.toJson(); +Map serializeUserProfileData(UserProfileData object) => + object.toJson(); -List deserializeUserProfileDataList(List> jsonList) - => jsonList.map(UserProfileData.fromJson).toList(); +List deserializeUserProfileDataList( + List> jsonList) => + jsonList.map(UserProfileData.fromJson).toList(); -List> serializeUserProfileDataList(List objects) - => objects.map((object) => object.toJson()).toList(); +List> serializeUserProfileDataList( + List objects) => + objects.map((object) => object.toJson()).toList(); diff --git a/example/lib/model/user/profile/user_profile_data_extended.dart b/example/lib/model/user/profile/user_profile_data_extended.dart index 532c1a6..c0e77fb 100644 --- a/example/lib/model/user/profile/user_profile_data_extended.dart +++ b/example/lib/model/user/profile/user_profile_data_extended.dart @@ -42,7 +42,8 @@ class UserProfileDataExtended extends UserProfileData { personsById: personsById, ); - factory UserProfileDataExtended.fromJson(Map json) => _$UserProfileDataExtendedFromJson(json); + factory UserProfileDataExtended.fromJson(Map json) => + _$UserProfileDataExtendedFromJson(json); @override Map toJson() => _$UserProfileDataExtendedToJson(this); @@ -56,13 +57,10 @@ class UserProfileDataExtended extends UserProfileData { super == other; @override - int get hashCode => - additionalField.hashCode ^ - super.hashCode; + int get hashCode => additionalField.hashCode ^ super.hashCode; @override - String toString() => - 'UserProfileDataExtended{' + String toString() => 'UserProfileDataExtended{' 'additionalField: $additionalField, ' 'firstName: $firstName, ' 'lastName: $lastName, ' @@ -76,15 +74,18 @@ class UserProfileDataExtended extends UserProfileData { 'persons: $persons, ' 'personsById: $personsById' '}'; - } const deserializeUserProfileDataExtended = UserProfileDataExtended.fromJson; -Map serializeUserProfileDataExtended(UserProfileDataExtended object) => object.toJson(); +Map serializeUserProfileDataExtended( + UserProfileDataExtended object) => + object.toJson(); -List deserializeUserProfileDataExtendedList(List> jsonList) - => jsonList.map(UserProfileDataExtended.fromJson).toList(); +List deserializeUserProfileDataExtendedList( + List> jsonList) => + jsonList.map(UserProfileDataExtended.fromJson).toList(); -List> serializeUserProfileDataExtendedList(List objects) - => objects.map((object) => object.toJson()).toList(); +List> serializeUserProfileDataExtendedList( + List objects) => + objects.map((object) => object.toJson()).toList(); diff --git a/example/lib/model/user/project/project.dart b/example/lib/model/user/project/project.dart index 5da61e1..b9afa89 100644 --- a/example/lib/model/user/project/project.dart +++ b/example/lib/model/user/project/project.dart @@ -9,11 +9,16 @@ part 'project.g.dart'; @JsonSerializable(explicitToJson: true) @immutable class Project { - @JsonKey(name: 'name', required: false, disallowNullValue: false, includeIfNull: false) + @JsonKey( + name: 'name', + required: false, + disallowNullValue: false, + includeIfNull: false) final String name; @JsonKey(name: 'cost', includeIfNull: false) final double? cost; - @JsonKey(name: 'status', includeIfNull: false, unknownEnumValue: Status.STATUS_0) + @JsonKey( + name: 'status', includeIfNull: false, unknownEnumValue: Status.STATUS_0) final Status? status; const Project({ @@ -22,7 +27,8 @@ class Project { this.status, }); - factory Project.fromJson(Object? json) => _$ProjectFromJson(json as Map); // ignore: avoid_as + factory Project.fromJson(Object? json) => + _$ProjectFromJson(json as Map); // ignore: avoid_as Map toJson() => _$ProjectToJson(this); @@ -39,27 +45,22 @@ class Project { status == other.status; @override - int get hashCode => - name.hashCode ^ - cost.hashCode ^ - status.hashCode; + int get hashCode => name.hashCode ^ cost.hashCode ^ status.hashCode; @override - String toString() => - 'Project{' + String toString() => 'Project{' 'name: $name, ' 'cost: $cost, ' 'status: $status' '}'; - } const deserializeProject = Project.fromJson; Map serializeProject(Project object) => object.toJson(); -List deserializeProjectList(List> jsonList) - => jsonList.map(Project.fromJson).toList(); +List deserializeProjectList(List> jsonList) => + jsonList.map(Project.fromJson).toList(); -List> serializeProjectList(List objects) - => objects.map((object) => object.toJson()).toList(); +List> serializeProjectList(List objects) => + objects.map((object) => object.toJson()).toList(); diff --git a/example/lib/model/user/testing.dart b/example/lib/model/user/testing.dart index cde1781..d99ceed 100644 --- a/example/lib/model/user/testing.dart +++ b/example/lib/model/user/testing.dart @@ -10,7 +10,11 @@ part 'testing.g.dart'; class Testing { @JsonKey(name: 'beneficiary', required: true, includeIfNull: false) final String beneficiary; - @JsonKey(name: 'isFavourite', includeIfNull: false, includeFromJson: false, includeToJson: false) + @JsonKey( + name: 'isFavourite', + includeIfNull: false, + includeFromJson: false, + includeToJson: false) String? isFavourite; @JsonKey(name: 'structuredMessage', includeIfNull: false) final String? structuredMessage; @@ -20,7 +24,11 @@ class Testing { final dynamic dynamicField; @JsonKey(name: 'duration', includeIfNull: false) final Duration? duration; - @JsonKey(name: 'duration_from_json_test', includeIfNull: false, fromJson: handleDurationFromToJsonFromJson, toJson: handleDurationFromToJsonToJson) + @JsonKey( + name: 'duration_from_json_test', + includeIfNull: false, + fromJson: handleDurationFromToJsonFromJson, + toJson: handleDurationFromToJsonToJson) final DurationFromToJson? durationFromJsonTest; Testing({ @@ -33,18 +41,18 @@ class Testing { this.durationFromJsonTest, }); - factory Testing.fromJson(Map json) => _$TestingFromJson(json); + factory Testing.fromJson(Map json) => + _$TestingFromJson(json); Map toJson() => _$TestingToJson(this); - } const deserializeTesting = Testing.fromJson; Map serializeTesting(Testing object) => object.toJson(); -List deserializeTestingList(List> jsonList) - => jsonList.map(Testing.fromJson).toList(); +List deserializeTestingList(List> jsonList) => + jsonList.map(Testing.fromJson).toList(); -List> serializeTestingList(List objects) - => objects.map((object) => object.toJson()).toList(); +List> serializeTestingList(List objects) => + objects.map((object) => object.toJson()).toList(); diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index 2c477bc..98f71e3 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -27,16 +27,20 @@ class YmlGeneratorConfig { List get models => _models; - YmlGeneratorConfig(PubspecConfig pubspecConfig, String configContent, this.fileName) { + YmlGeneratorConfig( + PubspecConfig pubspecConfig, String configContent, this.fileName) { final yamlContent = loadYaml(configContent); if (yamlContent == null) return; // Ignore empty file yamlContent.forEach((key, value) { - final String baseDirectory = value['base_directory'] ?? pubspecConfig.baseDirectory; + final String baseDirectory = + value['base_directory'] ?? pubspecConfig.baseDirectory; final String? path = value['path']; final String? extendsModel = value['extends']; - final bool generateForGenerics = value['generate_for_generics'] ?? pubspecConfig.generateForGenerics; + final bool generateForGenerics = + value['generate_for_generics'] ?? pubspecConfig.generateForGenerics; - final extraImports = value.containsKey('extra_imports') ? [] : null; + final extraImports = + value.containsKey('extra_imports') ? [] : null; final extraImportsVal = value['extra_imports']; extraImportsVal?.forEach((e) { if (e != null) { @@ -44,7 +48,8 @@ class YmlGeneratorConfig { } }); - final extraAnnotations = value.containsKey('extra_annotations') ? [] : null; + final extraAnnotations = + value.containsKey('extra_annotations') ? [] : null; final extraAnnotationsVal = value['extra_annotations']; extraAnnotationsVal?.forEach((e) { if (e != null) { @@ -88,25 +93,30 @@ class YmlGeneratorConfig { throw Exception('Properties can not be null. model: $key'); } if (properties is! YamlMap && type != 'enum') { - throw Exception('Properties should be a map, right now you are using a ${properties.runtimeType}. model: $key'); + throw Exception( + 'Properties should be a map, right now you are using a ${properties.runtimeType}. model: $key'); } if (type == 'enum') { final deprecatedItemType = value['item_type']; if (deprecatedItemType != null) { - throw Exception('item_type is removed, follow the migration to version 7.0.0'); + throw Exception( + 'item_type is removed, follow the migration to version 7.0.0'); } final deprecatedGenerateExtensions = value['generate_extensions']; if (deprecatedGenerateExtensions != null) { - throw Exception('generate_extensions is removed, follow the migration to version 7.0.0'); + throw Exception( + 'generate_extensions is removed, follow the migration to version 7.0.0'); } final deprecatedGenerateMap = value['generate_map']; if (deprecatedGenerateMap != null) { - throw Exception('generate_map is removed, follow the migration to version 7.0.0'); + throw Exception( + 'generate_map is removed, follow the migration to version 7.0.0'); } - final uppercaseEnums = (value['uppercase_enums'] ?? pubspecConfig.uppercaseEnums) == true; + final uppercaseEnums = + (value['uppercase_enums'] ?? pubspecConfig.uppercaseEnums) == true; final fields = []; final enumProperties = []; @@ -117,7 +127,7 @@ class YmlGeneratorConfig { final ItemType itemType; final String name = propertyKey; - + if (propertyValue is YamlMap) { type = propertyValue['type']; isJsonKey = propertyValue['is_json_key'] == true; @@ -129,12 +139,17 @@ class YmlGeneratorConfig { } final optional = type.endsWith('?'); - final typeString = optional ? type.substring(0, type.length - 1) : type; + final typeString = + optional ? type.substring(0, type.length - 1) : type; itemType = _parseSimpleType(typeString); - if (itemType is! StringType && itemType is! DoubleType && itemType is! IntegerType && itemType is! BooleanType) { - throw Exception('$propertyKey should have a type of integer, boolean, double or string'); + if (itemType is! StringType && + itemType is! DoubleType && + itemType is! IntegerType && + itemType is! BooleanType) { + throw Exception( + '$propertyKey should have a type of integer, boolean, double or string'); } enumProperties.add(EnumProperty( @@ -193,18 +208,23 @@ class YmlGeneratorConfig { models.add(enumModel); } else { final staticCreate = (value['static_create'] ?? false) == true; - final disallowNullForDefaults = value.containsKey('disallow_null_for_defaults') ? (value['disallow_null_for_defaults'] == true) : pubspecConfig.disallowNullForDefaults; + final disallowNullForDefaults = + value.containsKey('disallow_null_for_defaults') + ? (value['disallow_null_for_defaults'] == true) + : pubspecConfig.disallowNullForDefaults; final fields = []; properties.forEach((propertyKey, propertyValue) { if (propertyValue is YamlMap) { - fields.add(getField(propertyKey, propertyValue, disallowNullForDefaults: disallowNullForDefaults)); + fields.add(getField(propertyKey, propertyValue, + disallowNullForDefaults: disallowNullForDefaults)); } else if (propertyValue is String) { fields.add(getSimpleField(name: propertyKey, value: propertyValue)); } else { throw Exception('$propertyKey should be an object'); } }); - final mappedConverters = converters?.map((element) => element.toString()).toList(); + final mappedConverters = + converters?.map((element) => element.toString()).toList(); models.add(ObjectModel( name: key, path: path, @@ -226,25 +246,36 @@ class YmlGeneratorConfig { }); } - Field getField(String name, YamlMap property, {required bool disallowNullForDefaults}) { + Field getField(String name, YamlMap property, + {required bool disallowNullForDefaults}) { try { if (property.containsKey('required')) { - throw ArgumentError('required is removed, follow the migration to version 7.0.0'); + throw ArgumentError( + 'required is removed, follow the migration to version 7.0.0'); } - final ignored = property.containsKey('ignore') && property['ignore'] == true; - final includeFromJson = !property.containsKey('includeFromJson') || property['includeFromJson'] == true; - final includeToJson = !property.containsKey('includeToJson') || property['includeToJson'] == true; - final nonFinal = ignored || property.containsKey('non_final') && property['non_final'] == true; - final includeIfNull = property.containsKey('include_if_null') && property['include_if_null'] == true; + final ignored = + property.containsKey('ignore') && property['ignore'] == true; + final includeFromJson = !property.containsKey('includeFromJson') || + property['includeFromJson'] == true; + final includeToJson = !property.containsKey('includeToJson') || + property['includeToJson'] == true; + final nonFinal = ignored || + property.containsKey('non_final') && property['non_final'] == true; + final includeIfNull = property.containsKey('include_if_null') && + property['include_if_null'] == true; final unknownEnumValue = property['unknown_enum_value']; final jsonKey = property['jsonKey'] ?? property['jsonkey']; final fromJson = property['fromJson']; final toJson = property['toJson']; - final description = property.containsKey('description') ? property['description']!.toString() : null; + final description = property.containsKey('description') + ? property['description']!.toString() + : null; final type = property['type'] as String?; final skipEquality = property['ignore_equality'] == true; final defaultValue = property['default_value']?.toString(); - final disallowNull = property.containsKey('disallow_null') ? (property['disallow_null'] == true) : disallowNullForDefaults; + final disallowNull = property.containsKey('disallow_null') + ? (property['disallow_null'] == true) + : disallowNullForDefaults; ItemType itemType; if (type == null) { @@ -310,7 +341,9 @@ class YmlGeneratorConfig { return 'DateTime'; } else if (lowerType == 'int' || lowerType == 'integer') { return 'int'; - } else if (lowerType == 'object' || lowerType == 'dynamic' || lowerType == 'any') { + } else if (lowerType == 'object' || + lowerType == 'dynamic' || + lowerType == 'any') { return 'dynamic'; } else { return typeName; @@ -325,7 +358,8 @@ class YmlGeneratorConfig { //Maybe a generic final dartType = DartType(name); if (dartType.generics.isEmpty) { - throw Exception('getPathForName is null: because `$name` was not added to the config file'); + throw Exception( + 'getPathForName is null: because `$name` was not added to the config file'); } final paths = {}; for (final element in dartType.generics) { @@ -333,7 +367,8 @@ class YmlGeneratorConfig { } return paths; } else { - final baseDirectory = foundModel.baseDirectory ?? pubspecConfig.baseDirectory; + final baseDirectory = + foundModel.baseDirectory ?? pubspecConfig.baseDirectory; final path = foundModel.path; if (path == null) { return [baseDirectory]; @@ -387,22 +422,26 @@ class YmlGeneratorConfig { Model? getModelByName(ItemType itemType) { if (itemType is! ObjectType) return null; - final model = models.firstWhereOrNull((model) => model.name == itemType.name); + final model = + models.firstWhereOrNull((model) => model.name == itemType.name); if (model == null) { - throw Exception('getModelByName is null: because `${itemType.name}` was not added to the config file'); + throw Exception( + 'getModelByName is null: because `${itemType.name}` was not added to the config file'); } return model; } void checkTypesKnown(final Set names, String type) { if (!TypeChecker.isKnownDartType(type) && !names.contains(type)) { - throw Exception('Could not generate all models. `$type` is not added to the config file, but is extended. These types are known: ${names.join(',')}'); + throw Exception( + 'Could not generate all models. `$type` is not added to the config file, but is extended. These types are known: ${names.join(',')}'); } } ItemType _parseSimpleType(String type) { final listRegex = RegExp(r'^\s*[Ll]ist<\s*([a-zA-Z_0-9<>]*)\s*>\s*$'); - final mapRegex = RegExp(r'^\s*[Mm]ap<([a-zA-Z_0-9<>]*)\s*,\s*([a-zA-Z_0-9<>]*)\s*>\s*$'); + final mapRegex = + RegExp(r'^\s*[Mm]ap<([a-zA-Z_0-9<>]*)\s*,\s*([a-zA-Z_0-9<>]*)\s*>\s*$'); final lowerType = type.toLowerCase(); @@ -423,17 +462,21 @@ class YmlGeneratorConfig { return ArrayType(_makeGenericName(arrayType)); } else if (mapRegex.hasMatch(type)) { final match = mapRegex.firstMatch(type)!; - return MapType(key: _makeGenericName(match.group(1)!), valueName: _makeGenericName(match.group(2)!)); + return MapType( + key: _makeGenericName(match.group(1)!), + valueName: _makeGenericName(match.group(2)!)); } return ObjectType(type); } - YmlGeneratorConfig.merge(Iterable configs, String dirName) : fileName = dirName { + YmlGeneratorConfig.merge(Iterable configs, String dirName) + : fileName = dirName { final names = {}; for (final config in configs) { for (final model in config.models) { if (names.containsKey(model.name)) { - throw Exception('Model with same name ${model.name} found in multiple files: ${names[model.name]!.fileName} and ${config.fileName}'); + throw Exception( + 'Model with same name ${model.name} found in multiple files: ${names[model.name]!.fileName} and ${config.fileName}'); } names[model.name] = config; } diff --git a/lib/model/model/enum_model.dart b/lib/model/model/enum_model.dart index 0bfc9fc..deaf4f3 100644 --- a/lib/model/model/enum_model.dart +++ b/lib/model/model/enum_model.dart @@ -32,8 +32,12 @@ class EnumModel extends Model { String? validate() { for (final property in properties) { for (final field in fields) { - final value = field.values.firstWhereOrNull((value) => value.propertyName == property.name)?.value; - if (value == null && !property.isOptional && property.defaultValue == null) { + final value = field.values + .firstWhereOrNull((value) => value.propertyName == property.name) + ?.value; + if (value == null && + !property.isOptional && + property.defaultValue == null) { return 'There is no value defined for property ${property.name} for the enum value ${field.name} in model $name. Either make this property optional or give it a value'; } final toParseValue = value ?? property.defaultValue; diff --git a/lib/writer/enum_model_writer.dart b/lib/writer/enum_model_writer.dart index f0985d5..428d26b 100644 --- a/lib/writer/enum_model_writer.dart +++ b/lib/writer/enum_model_writer.dart @@ -24,15 +24,22 @@ class EnumModelWriter { final jsonModelName = CaseUtil(jsonModel.name); final properties = jsonModel.properties; - final keyProperty = properties.firstWhereOrNull((property) => property.isJsonKey); - final addDefaultJsonKey = keyProperty == null && jsonModel.addJsonKeyToProperties; + final keyProperty = + properties.firstWhereOrNull((property) => property.isJsonKey); + final addDefaultJsonKey = + keyProperty == null && jsonModel.addJsonKeyToProperties; final addProperties = properties.isNotEmpty || addDefaultJsonKey; sb.writeln('enum ${jsonModelName.pascalCase} {'); for (var key in jsonModel.fields) { - final jsonValue = key.values.firstWhereOrNull((value) => value.propertyName == keyProperty?.name)?.value ?? key.serializedName; + final jsonValue = key.values + .firstWhereOrNull( + (value) => value.propertyName == keyProperty?.name) + ?.value ?? + key.serializedName; final propertyType = keyProperty?.type; - final isLast = jsonModel.fields.indexOf(key) == (jsonModel.fields.length - 1); + final isLast = + jsonModel.fields.indexOf(key) == (jsonModel.fields.length - 1); if (key.description != null) { sb.writeln(' ///${key.description}'); diff --git a/test/config/yml_generator_config_test.dart b/test/config/yml_generator_config_test.dart index 8f237fc..6b08feb 100644 --- a/test/config/yml_generator_config_test.dart +++ b/test/config/yml_generator_config_test.dart @@ -12,19 +12,23 @@ void main() { group('YmlGeneratorConfig', () { group('Empty', () { test('Behaviour with empty file', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); final ymlConfig = YmlGeneratorConfig(pubspecConfig, '', ''); expect(ymlConfig.models.isEmpty, true); }); }); group('Object', () { test('Normal object', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-normal'), ''); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig = YmlGeneratorConfig(pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig('object-normal'), ''); ymlConfig.checkIfTypesAvailable(); expect(ymlConfig.models.length, 1); expect(ymlConfig.models.first is ObjectModel, true); - final objectModel = ymlConfig.models.first as ObjectModel; // ignore: avoid_as + final objectModel = + ymlConfig.models.first as ObjectModel; // ignore: avoid_as expect(objectModel.path, null); expect(objectModel.baseDirectory, 'model'); expect(objectModel.fileName, 'person'); @@ -33,12 +37,17 @@ void main() { }); test('Normal object with multiple fields', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-multiple-fields'), ''); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig = YmlGeneratorConfig( + pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig('object-multiple-fields'), + ''); ymlConfig.checkIfTypesAvailable(); expect(ymlConfig.models.length, 1); expect(ymlConfig.models.first is ObjectModel, true); - final objectModel = ymlConfig.models.first as ObjectModel; // ignore: avoid_as + final objectModel = + ymlConfig.models.first as ObjectModel; // ignore: avoid_as expect(objectModel.path, null); expect(objectModel.baseDirectory, 'model'); expect(objectModel.fileName, 'person'); @@ -47,12 +56,15 @@ void main() { }); test('Normal object with baseDirectory', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-base-dir'), ''); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig = YmlGeneratorConfig(pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig('object-base-dir'), ''); ymlConfig.checkIfTypesAvailable(); expect(ymlConfig.models.length, 1); expect(ymlConfig.models.first is ObjectModel, true); - final objectModel = ymlConfig.models.first as ObjectModel; // ignore: avoid_as + final objectModel = + ymlConfig.models.first as ObjectModel; // ignore: avoid_as expect(objectModel.path, null); expect(objectModel.baseDirectory, 'custom_base_dir'); expect(objectModel.fileName, 'person'); @@ -61,12 +73,15 @@ void main() { }); test('Normal object with all types', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-all-types'), ''); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig = YmlGeneratorConfig(pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig('object-all-types'), ''); ymlConfig.checkIfTypesAvailable(); expect(ymlConfig.models.length, 2); expect(ymlConfig.models.first is ObjectModel, true); - final objectModel = ymlConfig.models.first as ObjectModel; // ignore: avoid_as + final objectModel = + ymlConfig.models.first as ObjectModel; // ignore: avoid_as expect(objectModel.path, null); expect(objectModel.baseDirectory, 'model'); expect(objectModel.fileName, 'person'); @@ -75,11 +90,17 @@ void main() { }); test('Error property is no object', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); var hasError = false; var errorMessage = ''; try { - YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-error-no-object'), '').checkIfTypesAvailable(); + YmlGeneratorConfig( + pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig( + 'object-error-no-object'), + '') + .checkIfTypesAvailable(); } catch (e) { hasError = true; errorMessage = e.toString(); @@ -89,11 +110,17 @@ void main() { }); test('Error missing type', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); var hasError = false; var errorMessage = ''; try { - YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-error-missing-type'), '').checkIfTypesAvailable(); + YmlGeneratorConfig( + pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig( + 'object-error-missing-type'), + '') + .checkIfTypesAvailable(); } catch (e) { hasError = true; errorMessage = e.toString(); @@ -103,23 +130,32 @@ void main() { }); test('Error no properties', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); var hasError = false; var errorMessage = ''; try { - YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-error-no-properties'), '').checkIfTypesAvailable(); + YmlGeneratorConfig( + pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig( + 'object-error-no-properties'), + '') + .checkIfTypesAvailable(); } catch (e) { hasError = true; errorMessage = e.toString(); } expect(hasError, true); - expect(errorMessage, 'Exception: Properties can not be null. model: Person'); + expect(errorMessage, + 'Exception: Properties can not be null. model: Person'); }); }); group('Custom', () { test('Custom object', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('custom-normal'), ''); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig = YmlGeneratorConfig(pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig('custom-normal'), ''); ymlConfig.checkIfTypesAvailable(); expect(ymlConfig.models.length, 2); expect(ymlConfig.models.first is ObjectModel, true); @@ -128,8 +164,10 @@ void main() { }); group('Enum', () { test('Normal Enum', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('enum-normal'), ''); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig = YmlGeneratorConfig(pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig('enum-normal'), ''); ymlConfig.checkIfTypesAvailable(); expect(ymlConfig.models.length, 3); expect(ymlConfig.models.first is ObjectModel, true); @@ -178,11 +216,17 @@ void main() { }); test('Error Enum no properties map', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); var hasError = false; var errorMessage = ''; try { - YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('enum-error-no-object'), '').checkIfTypesAvailable(); + YmlGeneratorConfig( + pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig( + 'enum-error-no-object'), + '') + .checkIfTypesAvailable(); } catch (e) { hasError = true; errorMessage = e.toString(); @@ -192,54 +236,77 @@ void main() { }); test('Error Enum', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); var hasError = false; var errorMessage = ''; try { - YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('enum-error-no-properties-map'), '').checkIfTypesAvailable(); + YmlGeneratorConfig( + pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig( + 'enum-error-no-properties-map'), + '') + .checkIfTypesAvailable(); } catch (e) { hasError = true; errorMessage = e.toString(); } expect(hasError, true); - expect(errorMessage, 'Exception: Properties should be a map, right now you are using a String. model: Gender'); + expect(errorMessage, + 'Exception: Properties should be a map, right now you are using a String. model: Gender'); }); }); test('Error with not registered object', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); var hasError = false; var errorMessage = ''; try { - YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('error-not-registered'), '').checkIfTypesAvailable(); + YmlGeneratorConfig( + pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig('error-not-registered'), + '') + .checkIfTypesAvailable(); } catch (e) { hasError = true; errorMessage = e.toString(); } expect(hasError, true); - expect(errorMessage, 'Exception: Could not generate all models. `Address` is not added to the config file'); + expect(errorMessage, + 'Exception: Could not generate all models. `Address` is not added to the config file'); }); test('Error with not registered extend', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); var hasError = false; var errorMessage = ''; try { - YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('error-not-registered-extend'), '').checkIfTypesAvailable(); + YmlGeneratorConfig( + pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig( + 'error-not-registered-extend'), + '') + .checkIfTypesAvailable(); } catch (e) { hasError = true; errorMessage = e.toString(); } expect(hasError, true); - expect(errorMessage, 'Exception: Could not generate all models. `Address` is not added to the config file, but is extended. These types are known: Person'); + expect(errorMessage, + 'Exception: Could not generate all models. `Address` is not added to the config file, but is extended. These types are known: Person'); }); group('Getters', () { test('Get path with invalid model', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); var hasError = false; var errorMessage = ''; - final config = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-normal'), '')..checkIfTypesAvailable(); + final config = YmlGeneratorConfig(pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig('object-normal'), '') + ..checkIfTypesAvailable(); try { config.getPathsForName(pubspecConfig, 'TESTING'); } catch (e) { @@ -247,25 +314,33 @@ void main() { errorMessage = e.toString(); } expect(hasError, true); - expect(errorMessage, 'Exception: getPathForName is null: because `TESTING` was not added to the config file'); + expect(errorMessage, + 'Exception: getPathForName is null: because `TESTING` was not added to the config file'); }); test('Get paths with generic model', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final config = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('generics-normal'), ''); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final config = YmlGeneratorConfig(pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig('generics-normal'), ''); config.checkIfTypesAvailable(); - expect(config.getPathsForName(pubspecConfig, 'List').toList(), ['model']); + expect(config.getPathsForName(pubspecConfig, 'List').toList(), + ['model']); }); test('Get paths with dart:core model', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final config = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('custom-dart-core'), ''); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final config = YmlGeneratorConfig(pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig('custom-dart-core'), ''); config.checkIfTypesAvailable(); expect(config.getPathsForName(pubspecConfig, 'Address').toList(), []); }); test('Get path with invalid model', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); var hasError = false; var errorMessage = ''; - final config = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-normal'), ''); + final config = YmlGeneratorConfig(pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig('object-normal'), ''); config.checkIfTypesAvailable(); try { config.getModelByName(ObjectType('TESTING')); @@ -274,46 +349,76 @@ void main() { errorMessage = e.toString(); } expect(hasError, true); - expect(errorMessage, 'Exception: getModelByName is null: because `TESTING` was not added to the config file'); + expect(errorMessage, + 'Exception: getModelByName is null: because `TESTING` was not added to the config file'); }); }); group('Config merging tests', () { test('Test merge happy path', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig1 = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-normal'), ''); - final ymlConfig2 = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('enum-normal'), ''); - final merged = YmlGeneratorConfig.merge([ymlConfig1, ymlConfig2], 'dirName'); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig1 = YmlGeneratorConfig(pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig('object-normal'), ''); + final ymlConfig2 = YmlGeneratorConfig(pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig('enum-normal'), ''); + final merged = + YmlGeneratorConfig.merge([ymlConfig1, ymlConfig2], 'dirName'); expect(merged.models.length, 4); expect(merged.models.any((element) => element.name == 'Person'), true); expect(merged.models.any((element) => element.name == 'User'), true); expect(merged.models.any((element) => element.name == 'Gender'), true); - expect(merged.models.any((element) => element.name == 'Vehicles'), true); + expect( + merged.models.any((element) => element.name == 'Vehicles'), true); merged.checkIfTypesAvailable(); }); test('Test merge reference other file', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig1 = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-reference-other'), ''); - final ymlConfig2 = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('enum-normal'), ''); - final merged = YmlGeneratorConfig.merge([ymlConfig1, ymlConfig2], 'dirName'); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig1 = YmlGeneratorConfig( + pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig('object-reference-other'), + ''); + final ymlConfig2 = YmlGeneratorConfig(pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig('enum-normal'), ''); + final merged = + YmlGeneratorConfig.merge([ymlConfig1, ymlConfig2], 'dirName'); expect(merged.models.length, 4); expect(merged.models.any((element) => element.name == 'Person'), true); expect(merged.models.any((element) => element.name == 'User'), true); expect(merged.models.any((element) => element.name == 'Gender'), true); - expect(merged.models.any((element) => element.name == 'Vehicles'), true); + expect( + merged.models.any((element) => element.name == 'Vehicles'), true); merged.checkIfTypesAvailable(); }); test('Test merge reference not found', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig1 = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-reference-other-unknown'), ''); - final ymlConfig2 = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('enum-normal'), ''); - final merged = YmlGeneratorConfig.merge([ymlConfig1, ymlConfig2], 'dirName'); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig1 = YmlGeneratorConfig( + pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig( + 'object-reference-other-unknown'), + ''); + final ymlConfig2 = YmlGeneratorConfig(pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig('enum-normal'), ''); + final merged = + YmlGeneratorConfig.merge([ymlConfig1, ymlConfig2], 'dirName'); expect(() => merged.checkIfTypesAvailable(), throwsA(isA())); }); test('Test duplicate models', () { - final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - final ymlConfig1 = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-reference-other-unknown'), ''); - final ymlConfig2 = YmlGeneratorConfig(pubspecConfig, ConfigTestHelper.getYmlGeneratorConfig('object-reference-other'), ''); - expect(() => YmlGeneratorConfig.merge([ymlConfig1, ymlConfig2], 'dirName'), throwsA(isA())); + final pubspecConfig = + PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); + final ymlConfig1 = YmlGeneratorConfig( + pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig( + 'object-reference-other-unknown'), + ''); + final ymlConfig2 = YmlGeneratorConfig( + pubspecConfig, + ConfigTestHelper.getYmlGeneratorConfig('object-reference-other'), + ''); + expect( + () => YmlGeneratorConfig.merge([ymlConfig1, ymlConfig2], 'dirName'), + throwsA(isA())); }); }); }); diff --git a/test/writer/enum_model_reader_test.dart b/test/writer/enum_model_reader_test.dart index 44cc437..2871237 100644 --- a/test/writer/enum_model_reader_test.dart +++ b/test/writer/enum_model_reader_test.dart @@ -141,7 +141,8 @@ Gender: test( 'Test enum with unsupported type', () => testEnumError( - expectedError: 'Exception: list should have a type of integer, boolean, double or string', + expectedError: + 'Exception: list should have a type of integer, boolean, double or string', enumYml: """ Gender: path: user/person/ @@ -186,7 +187,8 @@ Gender: test( 'Test enum with incorrect type bool', () => testEnumError( - expectedError: 'Exception: Model: Gender, Property isMale is of type bool but the corresponding value on enum value MALE is not, make sure they have the same type', + expectedError: + 'Exception: Model: Gender, Property isMale is of type bool but the corresponding value on enum value MALE is not, make sure they have the same type', enumYml: """ Gender: path: user/person/ @@ -209,7 +211,8 @@ Gender: test( 'Test enum with incorrect type integer', () => testEnumError( - expectedError: 'Exception: Model: Gender, Property isMale is of type int but the corresponding value on enum value MALE is not, make sure they have the same type', + expectedError: + 'Exception: Model: Gender, Property isMale is of type int but the corresponding value on enum value MALE is not, make sure they have the same type', enumYml: """ Gender: path: user/person/ @@ -232,7 +235,8 @@ Gender: test( 'Test enum with incorrect type double', () => testEnumError( - expectedError: 'Exception: Model: Gender, Property isMale is of type double but the corresponding value on enum value MALE is not, make sure they have the same type', + expectedError: + 'Exception: Model: Gender, Property isMale is of type double but the corresponding value on enum value MALE is not, make sure they have the same type', enumYml: """ Gender: path: user/person/ @@ -255,7 +259,8 @@ Gender: test( 'item_type not supported anymore', () => testEnumError( - expectedError: 'Exception: item_type is removed, follow the migration to version 7.0.0', + expectedError: + 'Exception: item_type is removed, follow the migration to version 7.0.0', enumYml: """ Gender: path: user/person/ @@ -269,7 +274,8 @@ Gender: test( 'generate_map not supported anymore', () => testEnumError( - expectedError: 'Exception: generate_map is removed, follow the migration to version 7.0.0', + expectedError: + 'Exception: generate_map is removed, follow the migration to version 7.0.0', enumYml: """ Gender: path: user/person/ @@ -283,7 +289,8 @@ Gender: test( 'generate_extensions not supported anymore', () => testEnumError( - expectedError: 'Exception: generate_extensions is removed, follow the migration to version 7.0.0', + expectedError: + 'Exception: generate_extensions is removed, follow the migration to version 7.0.0', enumYml: """ Gender: path: user/person/ diff --git a/test/writer/enum_model_writer_test.dart b/test/writer/enum_model_writer_test.dart index c6d0ca1..670863c 100644 --- a/test/writer/enum_model_writer_test.dart +++ b/test/writer/enum_model_writer_test.dart @@ -14,7 +14,8 @@ void main() { ); final jsonModel = result.config.models.first; if (jsonModel is! EnumModel) { - throw Exception('The first model in the config file must be an object model and will be validated. The model is ${jsonModel.runtimeType}'); + throw Exception( + 'The first model in the config file must be an object model and will be validated. The model is ${jsonModel.runtimeType}'); } final generateActual = EnumModelWriter(jsonModel).write; diff --git a/test/writer/object_model_writer_test.dart b/test/writer/object_model_writer_test.dart index c8bae49..60b5e28 100644 --- a/test/writer/object_model_writer_test.dart +++ b/test/writer/object_model_writer_test.dart @@ -11,10 +11,12 @@ void main() { final result = WriterHelper.prepareWriterTest(path: path); final jsonModel = result.config.models.first; if (jsonModel is! ObjectModel) { - throw Exception('The first model in the config file must be an object model and will be validated. The model is ${jsonModel.runtimeType}'); + throw Exception( + 'The first model in the config file must be an object model and will be validated. The model is ${jsonModel.runtimeType}'); } - final generateActual = ObjectModelWriter(result.pubspecConfig, jsonModel, result.config).write; + final generateActual = + ObjectModelWriter(result.pubspecConfig, jsonModel, result.config).write; if (result.expected.startsWith('Exception')) { expect(generateActual, throwsA(isA())); } else { From ec11c8cf3957d88e0744231b823e300a7373ca58 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Wed, 6 Sep 2023 12:35:29 +0200 Subject: [PATCH 17/42] #130: fixed last tests --- lib/config/yml_generator_config.dart | 4 ++-- test/config/yml_generator_config_test.dart | 20 ------------------- .../unknown-enum-value/config.txt | 2 +- 3 files changed, 3 insertions(+), 23 deletions(-) diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index 98f71e3..1cabb48 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -92,7 +92,7 @@ class YmlGeneratorConfig { if (properties == null && type != 'enum') { throw Exception('Properties can not be null. model: $key'); } - if (properties is! YamlMap && type != 'enum') { + if (properties is! YamlMap?) { throw Exception( 'Properties should be a map, right now you are using a ${properties.runtimeType}. model: $key'); } @@ -213,7 +213,7 @@ class YmlGeneratorConfig { ? (value['disallow_null_for_defaults'] == true) : pubspecConfig.disallowNullForDefaults; final fields = []; - properties.forEach((propertyKey, propertyValue) { + properties?.forEach((propertyKey, propertyValue) { if (propertyValue is YamlMap) { fields.add(getField(propertyKey, propertyValue, disallowNullForDefaults: disallowNullForDefaults)); diff --git a/test/config/yml_generator_config_test.dart b/test/config/yml_generator_config_test.dart index 6b08feb..b7527b5 100644 --- a/test/config/yml_generator_config_test.dart +++ b/test/config/yml_generator_config_test.dart @@ -215,26 +215,6 @@ void main() { expect(enumModel.fields[3].values[0].propertyName, 'value'); }); - test('Error Enum no properties map', () { - final pubspecConfig = - PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); - var hasError = false; - var errorMessage = ''; - try { - YmlGeneratorConfig( - pubspecConfig, - ConfigTestHelper.getYmlGeneratorConfig( - 'enum-error-no-object'), - '') - .checkIfTypesAvailable(); - } catch (e) { - hasError = true; - errorMessage = e.toString(); - } - expect(hasError, true); - expect(errorMessage, 'Exception: MALE should be an object'); - }); - test('Error Enum', () { final pubspecConfig = PubspecConfig(ConfigTestHelper.getPubspecConfig('normal')); diff --git a/test/writer/object_model_writer/unknown-enum-value/config.txt b/test/writer/object_model_writer/unknown-enum-value/config.txt index 16c3d01..3541051 100644 --- a/test/writer/object_model_writer/unknown-enum-value/config.txt +++ b/test/writer/object_model_writer/unknown-enum-value/config.txt @@ -9,7 +9,7 @@ Person: Gender: path: user/person/ type: enum - properties: + values: MALE: FEMALE: X: \ No newline at end of file From fd9d9f876709b45aa297c227241d8e5ac54cdd5d Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Wed, 6 Sep 2023 12:51:59 +0200 Subject: [PATCH 18/42] #130: updated readme and changelog --- CHANGELOG.md | 1 + README.md | 84 +++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 64 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13be6ba..ca40268 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## [7.0.0] - 2023-08-14 - *BREAKING CHANGE*: Every type is now defined inline, this means that 'required' is no longer supported, if a field isn't nullable it is automatically required. This also means that the 'array' type is no longer supported and is instead just defined like 'List'. +- *BREAKING CHANGE*: The way enums are defined has changed, see readme for more information. You can now add properties to enums, optional and default values are supported. - Logs of build runner now get shown in real time. ## [6.3.0] - 2023-06-05 diff --git a/README.md b/README.md index 6cfb8e0..5be0bde 100755 --- a/README.md +++ b/README.md @@ -376,64 +376,106 @@ BookCase: Currently all basic types are supported, simple Lists and Maps (no nested types, no nullable generic parameters) as well as references to other objects. Items post-fixed with `?` will be marked optional. -## Enum support +## Enum support (as of v7.0.0 enums now support properties) -Add enums with custom values (can be mapped to String,double,int) +Add simple enums, the name of the enum value (MALE, FEMALE, X, Y) will be used when parsing from json ```yaml Gender: path: webservice/user type: enum - properties: + values: MALE: - value: _mAl3 FEMALE: - value: femAle X: - value: X Y: ``` -### Generate mapping - -For enums, it is also possible to have a map generated that maps from the enum value to its string representation and reverse. To enable this, use `generate_map: true` +Add enums with custom properties (currently supported types are int, double, bool and String) ```yaml Gender: path: webservice/user type: enum - generate_map: true properties: + abbreviation: String + values: MALE: - value: _mAl3 + properties: + abbreviation: m FEMALE: - value: femAle + properties: + abbreviation: f X: - value: X + properties: + abbreviation: x Y: + properties: + abbreviation: y ``` -### Generate mapping extensions +Define custom json key using is_json_key, the value of this property will then be used to parse from json + +```yaml +Gender: + path: webservice/user + type: enum + properties: + key: + type: String + is_json_key: true + abbreviation: String + values: + MALE: + properties: + key: male + abbreviation: m + FEMALE: + properties: + key: female + abbreviation: f + X: + properties: + key: x + abbreviation: x + Y: + properties: + key: y + abbreviation: y +``` -When generating maps, it is also possible to specify that special extension functions should be added that return either the string value or that takes a string value and tries to -convert it to the enum value. To enable this, use `generate_map: true` **AND** `generate_extensions: true` +Optional and default values are supported. If value isn't defined for a property then it will use the defaultValue. If a property is optional and no value is given it is null. ```yaml Gender: path: webservice/user type: enum - generate_map: true - generate_extensions: true properties: + key: + type: String + is_json_key: true + abbreviation: + type: String + default_value: m + lastName: String? + values: MALE: - value: _mAl3 + properties: + key: male FEMALE: - value: femAle + properties: + key: female + abbreviation: f X: - value: X + properties: + key: x Y: + properties: + key: y + lastName: lastName ``` +### Generate mapping extensions And Generate mapping are no longer supported as of V7.0.0, use properties instead ### Use unknownEnumValue ```yaml From ec35cb99f8d48c46b4cb629761d8d4054ddd13da Mon Sep 17 00:00:00 2001 From: Koen Van Looveren Date: Thu, 7 Sep 2023 13:06:16 +0200 Subject: [PATCH 19/42] Fixed some issues regarding tool scripts --- assets/example.gif | Bin 704995 -> 0 bytes tool/gen_coverage_report.sh | 9 ++++++++- tool/testLocal.sh | 9 ++++++++- ...e_helper.dart => test_coverage_helper.dart} | 0 4 files changed, 16 insertions(+), 2 deletions(-) delete mode 100644 assets/example.gif rename tool/{test_coverage_create_helper.dart => test_coverage_helper.dart} (100%) diff --git a/assets/example.gif b/assets/example.gif deleted file mode 100644 index 39a2a821a182df5dd90b8941d6af0e6816f41994..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 704995 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� 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

IHL(pBC+8B3X>J1rrLj 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

_{%4VysFaXDP}uOB{70uYplj4 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 Date: Thu, 7 Sep 2023 14:33:46 +0200 Subject: [PATCH 20/42] Added model_generator file --- example/tool/model_generator.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100755 example/tool/model_generator.sh diff --git a/example/tool/model_generator.sh b/example/tool/model_generator.sh new file mode 100755 index 0000000..4b3f793 --- /dev/null +++ b/example/tool/model_generator.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +CURRENT=`pwd` +DIR_NAME=`basename "$CURRENT"` +if [ $DIR_NAME == 'tool' ] +then + cd .. +fi + +fvm flutter packages run model_generator \ No newline at end of file From fe7f12a362a17c3acfa04c03cf03d0f148c73010 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Thu, 7 Sep 2023 15:15:54 +0200 Subject: [PATCH 21/42] #130: fixed error not throwing --- lib/model/model/enum_model.dart | 9 +++++--- test/writer/enum_model_reader_test.dart | 30 +++++++++++++++++-------- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/lib/model/model/enum_model.dart b/lib/model/model/enum_model.dart index deaf4f3..bbc22b2 100644 --- a/lib/model/model/enum_model.dart +++ b/lib/model/model/enum_model.dart @@ -41,8 +41,10 @@ class EnumModel extends Model { return 'There is no value defined for property ${property.name} for the enum value ${field.name} in model $name. Either make this property optional or give it a value'; } final toParseValue = value ?? property.defaultValue; + + String? error; if (property.type is DoubleType) { - return testValueType( + error = testValueType( parser: double.tryParse, typeName: DoubleType().name, toParseValue: toParseValue!, @@ -50,7 +52,7 @@ class EnumModel extends Model { fieldName: field.name, ); } else if (property.type is IntegerType) { - return testValueType( + error = testValueType( parser: int.tryParse, typeName: IntegerType().name, toParseValue: toParseValue!, @@ -58,7 +60,7 @@ class EnumModel extends Model { fieldName: field.name, ); } else if (property.type is BooleanType) { - return testValueType( + error = testValueType( parser: bool.tryParse, typeName: BooleanType().name, toParseValue: toParseValue!, @@ -66,6 +68,7 @@ class EnumModel extends Model { fieldName: field.name, ); } + if (error != null) return error; } } return null; diff --git a/test/writer/enum_model_reader_test.dart b/test/writer/enum_model_reader_test.dart index 2871237..aeac163 100644 --- a/test/writer/enum_model_reader_test.dart +++ b/test/writer/enum_model_reader_test.dart @@ -1,7 +1,9 @@ import 'package:model_generator/config/pubspec_config.dart'; import 'package:model_generator/config/yml_generator_config.dart'; import 'package:model_generator/model/item_type/boolean_type.dart'; +import 'package:model_generator/model/item_type/double_type.dart'; import 'package:model_generator/model/item_type/integer_type.dart'; +import 'package:model_generator/model/item_type/item_type.dart'; import 'package:model_generator/model/item_type/string_type.dart'; import 'package:model_generator/model/model/enum_model.dart'; import 'package:test/test.dart'; @@ -161,28 +163,38 @@ Gender: list: [] """, )); - - test( - 'Test enum with missing values', - () => testEnumError( - expectedError: - 'Exception: There is no value defined for property name for the enum value MALE in model Gender. Either make this property optional or give it a value', - enumYml: """ + void testEnumMissingValueForType({ + required ItemType type, + required String value, + }) { + testEnumError( + expectedError: + 'Exception: There is no value defined for property name for the enum value FEMALE in model Gender. Either make this property optional or give it a value', + enumYml: """ Gender: path: user/person/ type: enum description: this is an enum properties: - name: String + name: ${type.name} values: MALE: description: this is a enum of male properties: + name: $value FEMALE: description: this is a enum of female properties: """, - )); + ); + } + + test('Test enum with missing values', () { + testEnumMissingValueForType(type: StringType(), value: "'name'"); + testEnumMissingValueForType(type: IntegerType(), value: '1'); + testEnumMissingValueForType(type: DoubleType(), value: '1.1'); + testEnumMissingValueForType(type: BooleanType(), value: 'true'); + }); test( 'Test enum with incorrect type bool', From 5a1e7cff0c6770c3311edda72730d3d58e61f6ca Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Thu, 7 Sep 2023 15:17:41 +0200 Subject: [PATCH 22/42] #130: renamed json key to json value --- README.md | 6 +- example/model_generator/enums.yaml | 6 +- lib/config/yml_generator_config.dart | 121 ++++++------------ lib/model/model/enum_model.dart | 12 +- lib/writer/enum_model_writer.dart | 15 +-- .../yml_generator_config/enum-normal.txt | 4 +- test/writer/enum_model_reader_test.dart | 28 ++-- .../enum_model_writer/custom-value/config.txt | 2 +- .../enum_model_writer/double_type/config.txt | 2 +- .../enum_model_writer/full_enum/config.txt | 2 +- .../enum_model_writer/int_type/config.txt | 2 +- .../enum_model_writer/string_type/config.txt | 2 +- 12 files changed, 70 insertions(+), 132 deletions(-) diff --git a/README.md b/README.md index 5be0bde..d22ba89 100755 --- a/README.md +++ b/README.md @@ -414,7 +414,7 @@ Gender: abbreviation: y ``` -Define custom json key using is_json_key, the value of this property will then be used to parse from json +Define custom json key using is_json_value, the value of this property will then be used to parse from json ```yaml Gender: @@ -423,7 +423,7 @@ Gender: properties: key: type: String - is_json_key: true + is_json_value: true abbreviation: String values: MALE: @@ -453,7 +453,7 @@ Gender: properties: key: type: String - is_json_key: true + is_json_value: true abbreviation: type: String default_value: m diff --git a/example/model_generator/enums.yaml b/example/model_generator/enums.yaml index a2ca01a..87a7a21 100644 --- a/example/model_generator/enums.yaml +++ b/example/model_generator/enums.yaml @@ -4,7 +4,7 @@ Gender: properties: value: type: String - is_json_key: true + is_json_value: true values: MALE: properties: @@ -40,7 +40,7 @@ Status: properties: value: type: int - is_json_key: true + is_json_value: true values: status_0: properties: @@ -61,7 +61,7 @@ DoubleStatus: properties: value: type: double - is_json_key: true + is_json_value: true values: status_0: properties: diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index 1cabb48..84bc2c7 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -27,20 +27,16 @@ class YmlGeneratorConfig { List get models => _models; - YmlGeneratorConfig( - PubspecConfig pubspecConfig, String configContent, this.fileName) { + YmlGeneratorConfig(PubspecConfig pubspecConfig, String configContent, this.fileName) { final yamlContent = loadYaml(configContent); if (yamlContent == null) return; // Ignore empty file yamlContent.forEach((key, value) { - final String baseDirectory = - value['base_directory'] ?? pubspecConfig.baseDirectory; + final String baseDirectory = value['base_directory'] ?? pubspecConfig.baseDirectory; final String? path = value['path']; final String? extendsModel = value['extends']; - final bool generateForGenerics = - value['generate_for_generics'] ?? pubspecConfig.generateForGenerics; + final bool generateForGenerics = value['generate_for_generics'] ?? pubspecConfig.generateForGenerics; - final extraImports = - value.containsKey('extra_imports') ? [] : null; + final extraImports = value.containsKey('extra_imports') ? [] : null; final extraImportsVal = value['extra_imports']; extraImportsVal?.forEach((e) { if (e != null) { @@ -48,8 +44,7 @@ class YmlGeneratorConfig { } }); - final extraAnnotations = - value.containsKey('extra_annotations') ? [] : null; + final extraAnnotations = value.containsKey('extra_annotations') ? [] : null; final extraAnnotationsVal = value['extra_annotations']; extraAnnotationsVal?.forEach((e) { if (e != null) { @@ -93,35 +88,30 @@ class YmlGeneratorConfig { throw Exception('Properties can not be null. model: $key'); } if (properties is! YamlMap?) { - throw Exception( - 'Properties should be a map, right now you are using a ${properties.runtimeType}. model: $key'); + throw Exception('Properties should be a map, right now you are using a ${properties.runtimeType}. model: $key'); } if (type == 'enum') { final deprecatedItemType = value['item_type']; if (deprecatedItemType != null) { - throw Exception( - 'item_type is removed, follow the migration to version 7.0.0'); + throw Exception('item_type is removed, follow the migration to version 7.0.0'); } final deprecatedGenerateExtensions = value['generate_extensions']; if (deprecatedGenerateExtensions != null) { - throw Exception( - 'generate_extensions is removed, follow the migration to version 7.0.0'); + throw Exception('generate_extensions is removed, follow the migration to version 7.0.0'); } final deprecatedGenerateMap = value['generate_map']; if (deprecatedGenerateMap != null) { - throw Exception( - 'generate_map is removed, follow the migration to version 7.0.0'); + throw Exception('generate_map is removed, follow the migration to version 7.0.0'); } - final uppercaseEnums = - (value['uppercase_enums'] ?? pubspecConfig.uppercaseEnums) == true; + final uppercaseEnums = (value['uppercase_enums'] ?? pubspecConfig.uppercaseEnums) == true; final fields = []; final enumProperties = []; properties?.forEach((propertyKey, propertyValue) { - final bool isJsonKey; + final bool isJsonvalue; final String type; final String? defaultValue; final ItemType itemType; @@ -130,32 +120,27 @@ class YmlGeneratorConfig { if (propertyValue is YamlMap) { type = propertyValue['type']; - isJsonKey = propertyValue['is_json_key'] == true; + isJsonvalue = propertyValue['is_json_value'] == true; defaultValue = propertyValue['default_value']?.toString(); } else { type = propertyValue; - isJsonKey = false; + isJsonvalue = false; defaultValue = null; } final optional = type.endsWith('?'); - final typeString = - optional ? type.substring(0, type.length - 1) : type; + final typeString = optional ? type.substring(0, type.length - 1) : type; itemType = _parseSimpleType(typeString); - if (itemType is! StringType && - itemType is! DoubleType && - itemType is! IntegerType && - itemType is! BooleanType) { - throw Exception( - '$propertyKey should have a type of integer, boolean, double or string'); + if (itemType is! StringType && itemType is! DoubleType && itemType is! IntegerType && itemType is! BooleanType) { + throw Exception('$propertyKey should have a type of integer, boolean, double or string'); } enumProperties.add(EnumProperty( name: name, type: itemType, - isJsonKey: isJsonKey, + isJsonvalue: isJsonvalue, isOptional: optional, defaultValue: defaultValue, )); @@ -208,23 +193,18 @@ class YmlGeneratorConfig { models.add(enumModel); } else { final staticCreate = (value['static_create'] ?? false) == true; - final disallowNullForDefaults = - value.containsKey('disallow_null_for_defaults') - ? (value['disallow_null_for_defaults'] == true) - : pubspecConfig.disallowNullForDefaults; + final disallowNullForDefaults = value.containsKey('disallow_null_for_defaults') ? (value['disallow_null_for_defaults'] == true) : pubspecConfig.disallowNullForDefaults; final fields = []; properties?.forEach((propertyKey, propertyValue) { if (propertyValue is YamlMap) { - fields.add(getField(propertyKey, propertyValue, - disallowNullForDefaults: disallowNullForDefaults)); + fields.add(getField(propertyKey, propertyValue, disallowNullForDefaults: disallowNullForDefaults)); } else if (propertyValue is String) { fields.add(getSimpleField(name: propertyKey, value: propertyValue)); } else { throw Exception('$propertyKey should be an object'); } }); - final mappedConverters = - converters?.map((element) => element.toString()).toList(); + final mappedConverters = converters?.map((element) => element.toString()).toList(); models.add(ObjectModel( name: key, path: path, @@ -246,36 +226,25 @@ class YmlGeneratorConfig { }); } - Field getField(String name, YamlMap property, - {required bool disallowNullForDefaults}) { + Field getField(String name, YamlMap property, {required bool disallowNullForDefaults}) { try { if (property.containsKey('required')) { - throw ArgumentError( - 'required is removed, follow the migration to version 7.0.0'); + throw ArgumentError('required is removed, follow the migration to version 7.0.0'); } - final ignored = - property.containsKey('ignore') && property['ignore'] == true; - final includeFromJson = !property.containsKey('includeFromJson') || - property['includeFromJson'] == true; - final includeToJson = !property.containsKey('includeToJson') || - property['includeToJson'] == true; - final nonFinal = ignored || - property.containsKey('non_final') && property['non_final'] == true; - final includeIfNull = property.containsKey('include_if_null') && - property['include_if_null'] == true; + final ignored = property.containsKey('ignore') && property['ignore'] == true; + final includeFromJson = !property.containsKey('includeFromJson') || property['includeFromJson'] == true; + final includeToJson = !property.containsKey('includeToJson') || property['includeToJson'] == true; + final nonFinal = ignored || property.containsKey('non_final') && property['non_final'] == true; + final includeIfNull = property.containsKey('include_if_null') && property['include_if_null'] == true; final unknownEnumValue = property['unknown_enum_value']; final jsonKey = property['jsonKey'] ?? property['jsonkey']; final fromJson = property['fromJson']; final toJson = property['toJson']; - final description = property.containsKey('description') - ? property['description']!.toString() - : null; + final description = property.containsKey('description') ? property['description']!.toString() : null; final type = property['type'] as String?; final skipEquality = property['ignore_equality'] == true; final defaultValue = property['default_value']?.toString(); - final disallowNull = property.containsKey('disallow_null') - ? (property['disallow_null'] == true) - : disallowNullForDefaults; + final disallowNull = property.containsKey('disallow_null') ? (property['disallow_null'] == true) : disallowNullForDefaults; ItemType itemType; if (type == null) { @@ -341,9 +310,7 @@ class YmlGeneratorConfig { return 'DateTime'; } else if (lowerType == 'int' || lowerType == 'integer') { return 'int'; - } else if (lowerType == 'object' || - lowerType == 'dynamic' || - lowerType == 'any') { + } else if (lowerType == 'object' || lowerType == 'dynamic' || lowerType == 'any') { return 'dynamic'; } else { return typeName; @@ -358,8 +325,7 @@ class YmlGeneratorConfig { //Maybe a generic final dartType = DartType(name); if (dartType.generics.isEmpty) { - throw Exception( - 'getPathForName is null: because `$name` was not added to the config file'); + throw Exception('getPathForName is null: because `$name` was not added to the config file'); } final paths = {}; for (final element in dartType.generics) { @@ -367,8 +333,7 @@ class YmlGeneratorConfig { } return paths; } else { - final baseDirectory = - foundModel.baseDirectory ?? pubspecConfig.baseDirectory; + final baseDirectory = foundModel.baseDirectory ?? pubspecConfig.baseDirectory; final path = foundModel.path; if (path == null) { return [baseDirectory]; @@ -422,26 +387,22 @@ class YmlGeneratorConfig { Model? getModelByName(ItemType itemType) { if (itemType is! ObjectType) return null; - final model = - models.firstWhereOrNull((model) => model.name == itemType.name); + final model = models.firstWhereOrNull((model) => model.name == itemType.name); if (model == null) { - throw Exception( - 'getModelByName is null: because `${itemType.name}` was not added to the config file'); + throw Exception('getModelByName is null: because `${itemType.name}` was not added to the config file'); } return model; } void checkTypesKnown(final Set names, String type) { if (!TypeChecker.isKnownDartType(type) && !names.contains(type)) { - throw Exception( - 'Could not generate all models. `$type` is not added to the config file, but is extended. These types are known: ${names.join(',')}'); + throw Exception('Could not generate all models. `$type` is not added to the config file, but is extended. These types are known: ${names.join(',')}'); } } ItemType _parseSimpleType(String type) { final listRegex = RegExp(r'^\s*[Ll]ist<\s*([a-zA-Z_0-9<>]*)\s*>\s*$'); - final mapRegex = - RegExp(r'^\s*[Mm]ap<([a-zA-Z_0-9<>]*)\s*,\s*([a-zA-Z_0-9<>]*)\s*>\s*$'); + final mapRegex = RegExp(r'^\s*[Mm]ap<([a-zA-Z_0-9<>]*)\s*,\s*([a-zA-Z_0-9<>]*)\s*>\s*$'); final lowerType = type.toLowerCase(); @@ -462,21 +423,17 @@ class YmlGeneratorConfig { return ArrayType(_makeGenericName(arrayType)); } else if (mapRegex.hasMatch(type)) { final match = mapRegex.firstMatch(type)!; - return MapType( - key: _makeGenericName(match.group(1)!), - valueName: _makeGenericName(match.group(2)!)); + return MapType(key: _makeGenericName(match.group(1)!), valueName: _makeGenericName(match.group(2)!)); } return ObjectType(type); } - YmlGeneratorConfig.merge(Iterable configs, String dirName) - : fileName = dirName { + YmlGeneratorConfig.merge(Iterable configs, String dirName) : fileName = dirName { final names = {}; for (final config in configs) { for (final model in config.models) { if (names.containsKey(model.name)) { - throw Exception( - 'Model with same name ${model.name} found in multiple files: ${names[model.name]!.fileName} and ${config.fileName}'); + throw Exception('Model with same name ${model.name} found in multiple files: ${names[model.name]!.fileName} and ${config.fileName}'); } names[model.name] = config; } diff --git a/lib/model/model/enum_model.dart b/lib/model/model/enum_model.dart index bbc22b2..8dbe0b5 100644 --- a/lib/model/model/enum_model.dart +++ b/lib/model/model/enum_model.dart @@ -32,12 +32,8 @@ class EnumModel extends Model { String? validate() { for (final property in properties) { for (final field in fields) { - final value = field.values - .firstWhereOrNull((value) => value.propertyName == property.name) - ?.value; - if (value == null && - !property.isOptional && - property.defaultValue == null) { + final value = field.values.firstWhereOrNull((value) => value.propertyName == property.name)?.value; + if (value == null && !property.isOptional && property.defaultValue == null) { return 'There is no value defined for property ${property.name} for the enum value ${field.name} in model $name. Either make this property optional or give it a value'; } final toParseValue = value ?? property.defaultValue; @@ -117,7 +113,7 @@ class EnumField { } class EnumProperty { - final bool isJsonKey; + final bool isJsonvalue; final bool isOptional; final String name; String? defaultValue; @@ -128,7 +124,7 @@ class EnumProperty { required this.type, required this.isOptional, this.defaultValue, - this.isJsonKey = false, + this.isJsonvalue = false, }); } diff --git a/lib/writer/enum_model_writer.dart b/lib/writer/enum_model_writer.dart index 428d26b..d3455cf 100644 --- a/lib/writer/enum_model_writer.dart +++ b/lib/writer/enum_model_writer.dart @@ -24,22 +24,15 @@ class EnumModelWriter { final jsonModelName = CaseUtil(jsonModel.name); final properties = jsonModel.properties; - final keyProperty = - properties.firstWhereOrNull((property) => property.isJsonKey); - final addDefaultJsonKey = - keyProperty == null && jsonModel.addJsonKeyToProperties; + final keyProperty = properties.firstWhereOrNull((property) => property.isJsonvalue); + final addDefaultJsonKey = keyProperty == null && jsonModel.addJsonKeyToProperties; final addProperties = properties.isNotEmpty || addDefaultJsonKey; sb.writeln('enum ${jsonModelName.pascalCase} {'); for (var key in jsonModel.fields) { - final jsonValue = key.values - .firstWhereOrNull( - (value) => value.propertyName == keyProperty?.name) - ?.value ?? - key.serializedName; + final jsonValue = key.values.firstWhereOrNull((value) => value.propertyName == keyProperty?.name)?.value ?? key.serializedName; final propertyType = keyProperty?.type; - final isLast = - jsonModel.fields.indexOf(key) == (jsonModel.fields.length - 1); + final isLast = jsonModel.fields.indexOf(key) == (jsonModel.fields.length - 1); if (key.description != null) { sb.writeln(' ///${key.description}'); diff --git a/test/config/yml_generator_config/enum-normal.txt b/test/config/yml_generator_config/enum-normal.txt index 17f0735..efac2b8 100644 --- a/test/config/yml_generator_config/enum-normal.txt +++ b/test/config/yml_generator_config/enum-normal.txt @@ -9,7 +9,7 @@ Gender: properties: value: type: String - is_json_key: true + is_json_value: true values: MALE: properties: @@ -30,7 +30,7 @@ Vehicles: properties: value: type: String - is_json_key: true + is_json_value: true values: male: properties: diff --git a/test/writer/enum_model_reader_test.dart b/test/writer/enum_model_reader_test.dart index aeac163..5892b57 100644 --- a/test/writer/enum_model_reader_test.dart +++ b/test/writer/enum_model_reader_test.dart @@ -60,7 +60,7 @@ Gender: type: String? jsonKey: type: int - is_json_key: true + is_json_value: true values: MALE: description: this is a enum of male @@ -98,7 +98,7 @@ Gender: expect(model.properties[2].isOptional, true); expect(model.properties[3].isOptional, false); - expect(model.properties[3].isJsonKey, true); + expect(model.properties[3].isJsonvalue, true); expect(model.properties[3].type, isA()); expect(model.fields[0].description, 'this is a enum of male'); @@ -143,8 +143,7 @@ Gender: test( 'Test enum with unsupported type', () => testEnumError( - expectedError: - 'Exception: list should have a type of integer, boolean, double or string', + expectedError: 'Exception: list should have a type of integer, boolean, double or string', enumYml: """ Gender: path: user/person/ @@ -168,8 +167,7 @@ Gender: required String value, }) { testEnumError( - expectedError: - 'Exception: There is no value defined for property name for the enum value FEMALE in model Gender. Either make this property optional or give it a value', + expectedError: 'Exception: There is no value defined for property name for the enum value FEMALE in model Gender. Either make this property optional or give it a value', enumYml: """ Gender: path: user/person/ @@ -199,8 +197,7 @@ Gender: test( 'Test enum with incorrect type bool', () => testEnumError( - expectedError: - 'Exception: Model: Gender, Property isMale is of type bool but the corresponding value on enum value MALE is not, make sure they have the same type', + expectedError: 'Exception: Model: Gender, Property isMale is of type bool but the corresponding value on enum value MALE is not, make sure they have the same type', enumYml: """ Gender: path: user/person/ @@ -223,8 +220,7 @@ Gender: test( 'Test enum with incorrect type integer', () => testEnumError( - expectedError: - 'Exception: Model: Gender, Property isMale is of type int but the corresponding value on enum value MALE is not, make sure they have the same type', + expectedError: 'Exception: Model: Gender, Property isMale is of type int but the corresponding value on enum value MALE is not, make sure they have the same type', enumYml: """ Gender: path: user/person/ @@ -247,8 +243,7 @@ Gender: test( 'Test enum with incorrect type double', () => testEnumError( - expectedError: - 'Exception: Model: Gender, Property isMale is of type double but the corresponding value on enum value MALE is not, make sure they have the same type', + expectedError: 'Exception: Model: Gender, Property isMale is of type double but the corresponding value on enum value MALE is not, make sure they have the same type', enumYml: """ Gender: path: user/person/ @@ -271,8 +266,7 @@ Gender: test( 'item_type not supported anymore', () => testEnumError( - expectedError: - 'Exception: item_type is removed, follow the migration to version 7.0.0', + expectedError: 'Exception: item_type is removed, follow the migration to version 7.0.0', enumYml: """ Gender: path: user/person/ @@ -286,8 +280,7 @@ Gender: test( 'generate_map not supported anymore', () => testEnumError( - expectedError: - 'Exception: generate_map is removed, follow the migration to version 7.0.0', + expectedError: 'Exception: generate_map is removed, follow the migration to version 7.0.0', enumYml: """ Gender: path: user/person/ @@ -301,8 +294,7 @@ Gender: test( 'generate_extensions not supported anymore', () => testEnumError( - expectedError: - 'Exception: generate_extensions is removed, follow the migration to version 7.0.0', + expectedError: 'Exception: generate_extensions is removed, follow the migration to version 7.0.0', enumYml: """ Gender: path: user/person/ diff --git a/test/writer/enum_model_writer/custom-value/config.txt b/test/writer/enum_model_writer/custom-value/config.txt index 5bb2480..b53f275 100644 --- a/test/writer/enum_model_writer/custom-value/config.txt +++ b/test/writer/enum_model_writer/custom-value/config.txt @@ -3,7 +3,7 @@ Person: type: enum properties: jsonKey: - is_json_key: true + is_json_value: true type: int firstName: String lastName: String diff --git a/test/writer/enum_model_writer/double_type/config.txt b/test/writer/enum_model_writer/double_type/config.txt index 9b99fdd..04132a3 100644 --- a/test/writer/enum_model_writer/double_type/config.txt +++ b/test/writer/enum_model_writer/double_type/config.txt @@ -4,7 +4,7 @@ MyEnumModel: properties: value: type: double - is_json_key: true + is_json_value: true values: MY_VALUE_1: properties: diff --git a/test/writer/enum_model_writer/full_enum/config.txt b/test/writer/enum_model_writer/full_enum/config.txt index 16bc21c..b716cb3 100644 --- a/test/writer/enum_model_writer/full_enum/config.txt +++ b/test/writer/enum_model_writer/full_enum/config.txt @@ -4,7 +4,7 @@ Person: description: This is a enum of a person properties: jsonKey: - is_json_key: true + is_json_value: true type: int firstName: String lastName: diff --git a/test/writer/enum_model_writer/int_type/config.txt b/test/writer/enum_model_writer/int_type/config.txt index 2d2571a..e6412f6 100644 --- a/test/writer/enum_model_writer/int_type/config.txt +++ b/test/writer/enum_model_writer/int_type/config.txt @@ -4,7 +4,7 @@ MyEnumModel: properties: value: type: int - is_json_key: true + is_json_value: true values: MY_VALUE_1: properties: diff --git a/test/writer/enum_model_writer/string_type/config.txt b/test/writer/enum_model_writer/string_type/config.txt index 412f248..9705a77 100644 --- a/test/writer/enum_model_writer/string_type/config.txt +++ b/test/writer/enum_model_writer/string_type/config.txt @@ -4,7 +4,7 @@ MyEnumModel: properties: value: type: String - is_json_key: true + is_json_value: true values: MY_VALUE_1: properties: From 52102164f0ae947d6fa73b1424900815759fa105 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Thu, 7 Sep 2023 15:19:29 +0200 Subject: [PATCH 23/42] #130: updated default values --- lib/config/yml_generator_config.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index 84bc2c7..280838d 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -292,7 +292,7 @@ class YmlGeneratorConfig { ignore: false, includeToJson: true, includeFromJson: true, - includeIfNull: true, + includeIfNull: false, nonFinal: false, ignoreEquality: false, ); From 4790a0dc58ce235b8efc65efe861b53364aa350b Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Thu, 7 Sep 2023 15:42:59 +0200 Subject: [PATCH 24/42] #130: use jsonValue as default --- lib/writer/enum_model_writer.dart | 3 +- .../use_default_json_value/config.txt | 14 ++++++++++ .../use_default_json_value/output.txt | 28 +++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 test/writer/enum_model_writer/use_default_json_value/config.txt create mode 100644 test/writer/enum_model_writer/use_default_json_value/output.txt diff --git a/lib/writer/enum_model_writer.dart b/lib/writer/enum_model_writer.dart index d3455cf..77a43d9 100644 --- a/lib/writer/enum_model_writer.dart +++ b/lib/writer/enum_model_writer.dart @@ -57,7 +57,8 @@ class EnumModelWriter { var value = enumValue?.value ?? property.defaultValue; sb.write(' ${property.name}: '); - if (property.type is StringType && value != null) { + if (property.type is StringType && (value != null || property.isJsonvalue)) { + if (value == null && property.isJsonvalue) value = jsonValue; sb.writeln('\'$value\','); } else { sb.writeln('$value,'); diff --git a/test/writer/enum_model_writer/use_default_json_value/config.txt b/test/writer/enum_model_writer/use_default_json_value/config.txt new file mode 100644 index 0000000..9d2eee4 --- /dev/null +++ b/test/writer/enum_model_writer/use_default_json_value/config.txt @@ -0,0 +1,14 @@ +DoubleStatus: + path: status + type: enum + properties: + value: + type: String + is_json_value: true + values: + status_0: + properties: + value: customValue + status_1: + status_2: + status_3: diff --git a/test/writer/enum_model_writer/use_default_json_value/output.txt b/test/writer/enum_model_writer/use_default_json_value/output.txt new file mode 100644 index 0000000..77a6c9f --- /dev/null +++ b/test/writer/enum_model_writer/use_default_json_value/output.txt @@ -0,0 +1,28 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +import 'package:json_annotation/json_annotation.dart'; + +enum DoubleStatus { + @JsonValue('customValue') + STATUS_0( + value: 'customValue', + ), + @JsonValue('status_1') + STATUS_1( + value: 'status_1', + ), + @JsonValue('status_2') + STATUS_2( + value: 'status_2', + ), + @JsonValue('status_3') + STATUS_3( + value: 'status_3', + ); + + final String value; + + const DoubleStatus({ + required this.value, + }); +} From 6a4f1500c10ae4bd889407b7af057ac5855baf38 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Thu, 7 Sep 2023 15:43:33 +0200 Subject: [PATCH 25/42] #130: formatted --- lib/config/yml_generator_config.dart | 113 ++++++++++++++++-------- lib/model/model/enum_model.dart | 8 +- lib/writer/enum_model_writer.dart | 18 ++-- test/writer/enum_model_reader_test.dart | 24 +++-- 4 files changed, 113 insertions(+), 50 deletions(-) diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index 280838d..40f1599 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -27,16 +27,20 @@ class YmlGeneratorConfig { List get models => _models; - YmlGeneratorConfig(PubspecConfig pubspecConfig, String configContent, this.fileName) { + YmlGeneratorConfig( + PubspecConfig pubspecConfig, String configContent, this.fileName) { final yamlContent = loadYaml(configContent); if (yamlContent == null) return; // Ignore empty file yamlContent.forEach((key, value) { - final String baseDirectory = value['base_directory'] ?? pubspecConfig.baseDirectory; + final String baseDirectory = + value['base_directory'] ?? pubspecConfig.baseDirectory; final String? path = value['path']; final String? extendsModel = value['extends']; - final bool generateForGenerics = value['generate_for_generics'] ?? pubspecConfig.generateForGenerics; + final bool generateForGenerics = + value['generate_for_generics'] ?? pubspecConfig.generateForGenerics; - final extraImports = value.containsKey('extra_imports') ? [] : null; + final extraImports = + value.containsKey('extra_imports') ? [] : null; final extraImportsVal = value['extra_imports']; extraImportsVal?.forEach((e) { if (e != null) { @@ -44,7 +48,8 @@ class YmlGeneratorConfig { } }); - final extraAnnotations = value.containsKey('extra_annotations') ? [] : null; + final extraAnnotations = + value.containsKey('extra_annotations') ? [] : null; final extraAnnotationsVal = value['extra_annotations']; extraAnnotationsVal?.forEach((e) { if (e != null) { @@ -88,25 +93,30 @@ class YmlGeneratorConfig { throw Exception('Properties can not be null. model: $key'); } if (properties is! YamlMap?) { - throw Exception('Properties should be a map, right now you are using a ${properties.runtimeType}. model: $key'); + throw Exception( + 'Properties should be a map, right now you are using a ${properties.runtimeType}. model: $key'); } if (type == 'enum') { final deprecatedItemType = value['item_type']; if (deprecatedItemType != null) { - throw Exception('item_type is removed, follow the migration to version 7.0.0'); + throw Exception( + 'item_type is removed, follow the migration to version 7.0.0'); } final deprecatedGenerateExtensions = value['generate_extensions']; if (deprecatedGenerateExtensions != null) { - throw Exception('generate_extensions is removed, follow the migration to version 7.0.0'); + throw Exception( + 'generate_extensions is removed, follow the migration to version 7.0.0'); } final deprecatedGenerateMap = value['generate_map']; if (deprecatedGenerateMap != null) { - throw Exception('generate_map is removed, follow the migration to version 7.0.0'); + throw Exception( + 'generate_map is removed, follow the migration to version 7.0.0'); } - final uppercaseEnums = (value['uppercase_enums'] ?? pubspecConfig.uppercaseEnums) == true; + final uppercaseEnums = + (value['uppercase_enums'] ?? pubspecConfig.uppercaseEnums) == true; final fields = []; final enumProperties = []; @@ -129,12 +139,17 @@ class YmlGeneratorConfig { } final optional = type.endsWith('?'); - final typeString = optional ? type.substring(0, type.length - 1) : type; + final typeString = + optional ? type.substring(0, type.length - 1) : type; itemType = _parseSimpleType(typeString); - if (itemType is! StringType && itemType is! DoubleType && itemType is! IntegerType && itemType is! BooleanType) { - throw Exception('$propertyKey should have a type of integer, boolean, double or string'); + if (itemType is! StringType && + itemType is! DoubleType && + itemType is! IntegerType && + itemType is! BooleanType) { + throw Exception( + '$propertyKey should have a type of integer, boolean, double or string'); } enumProperties.add(EnumProperty( @@ -193,18 +208,23 @@ class YmlGeneratorConfig { models.add(enumModel); } else { final staticCreate = (value['static_create'] ?? false) == true; - final disallowNullForDefaults = value.containsKey('disallow_null_for_defaults') ? (value['disallow_null_for_defaults'] == true) : pubspecConfig.disallowNullForDefaults; + final disallowNullForDefaults = + value.containsKey('disallow_null_for_defaults') + ? (value['disallow_null_for_defaults'] == true) + : pubspecConfig.disallowNullForDefaults; final fields = []; properties?.forEach((propertyKey, propertyValue) { if (propertyValue is YamlMap) { - fields.add(getField(propertyKey, propertyValue, disallowNullForDefaults: disallowNullForDefaults)); + fields.add(getField(propertyKey, propertyValue, + disallowNullForDefaults: disallowNullForDefaults)); } else if (propertyValue is String) { fields.add(getSimpleField(name: propertyKey, value: propertyValue)); } else { throw Exception('$propertyKey should be an object'); } }); - final mappedConverters = converters?.map((element) => element.toString()).toList(); + final mappedConverters = + converters?.map((element) => element.toString()).toList(); models.add(ObjectModel( name: key, path: path, @@ -226,25 +246,36 @@ class YmlGeneratorConfig { }); } - Field getField(String name, YamlMap property, {required bool disallowNullForDefaults}) { + Field getField(String name, YamlMap property, + {required bool disallowNullForDefaults}) { try { if (property.containsKey('required')) { - throw ArgumentError('required is removed, follow the migration to version 7.0.0'); + throw ArgumentError( + 'required is removed, follow the migration to version 7.0.0'); } - final ignored = property.containsKey('ignore') && property['ignore'] == true; - final includeFromJson = !property.containsKey('includeFromJson') || property['includeFromJson'] == true; - final includeToJson = !property.containsKey('includeToJson') || property['includeToJson'] == true; - final nonFinal = ignored || property.containsKey('non_final') && property['non_final'] == true; - final includeIfNull = property.containsKey('include_if_null') && property['include_if_null'] == true; + final ignored = + property.containsKey('ignore') && property['ignore'] == true; + final includeFromJson = !property.containsKey('includeFromJson') || + property['includeFromJson'] == true; + final includeToJson = !property.containsKey('includeToJson') || + property['includeToJson'] == true; + final nonFinal = ignored || + property.containsKey('non_final') && property['non_final'] == true; + final includeIfNull = property.containsKey('include_if_null') && + property['include_if_null'] == true; final unknownEnumValue = property['unknown_enum_value']; final jsonKey = property['jsonKey'] ?? property['jsonkey']; final fromJson = property['fromJson']; final toJson = property['toJson']; - final description = property.containsKey('description') ? property['description']!.toString() : null; + final description = property.containsKey('description') + ? property['description']!.toString() + : null; final type = property['type'] as String?; final skipEquality = property['ignore_equality'] == true; final defaultValue = property['default_value']?.toString(); - final disallowNull = property.containsKey('disallow_null') ? (property['disallow_null'] == true) : disallowNullForDefaults; + final disallowNull = property.containsKey('disallow_null') + ? (property['disallow_null'] == true) + : disallowNullForDefaults; ItemType itemType; if (type == null) { @@ -310,7 +341,9 @@ class YmlGeneratorConfig { return 'DateTime'; } else if (lowerType == 'int' || lowerType == 'integer') { return 'int'; - } else if (lowerType == 'object' || lowerType == 'dynamic' || lowerType == 'any') { + } else if (lowerType == 'object' || + lowerType == 'dynamic' || + lowerType == 'any') { return 'dynamic'; } else { return typeName; @@ -325,7 +358,8 @@ class YmlGeneratorConfig { //Maybe a generic final dartType = DartType(name); if (dartType.generics.isEmpty) { - throw Exception('getPathForName is null: because `$name` was not added to the config file'); + throw Exception( + 'getPathForName is null: because `$name` was not added to the config file'); } final paths = {}; for (final element in dartType.generics) { @@ -333,7 +367,8 @@ class YmlGeneratorConfig { } return paths; } else { - final baseDirectory = foundModel.baseDirectory ?? pubspecConfig.baseDirectory; + final baseDirectory = + foundModel.baseDirectory ?? pubspecConfig.baseDirectory; final path = foundModel.path; if (path == null) { return [baseDirectory]; @@ -387,22 +422,26 @@ class YmlGeneratorConfig { Model? getModelByName(ItemType itemType) { if (itemType is! ObjectType) return null; - final model = models.firstWhereOrNull((model) => model.name == itemType.name); + final model = + models.firstWhereOrNull((model) => model.name == itemType.name); if (model == null) { - throw Exception('getModelByName is null: because `${itemType.name}` was not added to the config file'); + throw Exception( + 'getModelByName is null: because `${itemType.name}` was not added to the config file'); } return model; } void checkTypesKnown(final Set names, String type) { if (!TypeChecker.isKnownDartType(type) && !names.contains(type)) { - throw Exception('Could not generate all models. `$type` is not added to the config file, but is extended. These types are known: ${names.join(',')}'); + throw Exception( + 'Could not generate all models. `$type` is not added to the config file, but is extended. These types are known: ${names.join(',')}'); } } ItemType _parseSimpleType(String type) { final listRegex = RegExp(r'^\s*[Ll]ist<\s*([a-zA-Z_0-9<>]*)\s*>\s*$'); - final mapRegex = RegExp(r'^\s*[Mm]ap<([a-zA-Z_0-9<>]*)\s*,\s*([a-zA-Z_0-9<>]*)\s*>\s*$'); + final mapRegex = + RegExp(r'^\s*[Mm]ap<([a-zA-Z_0-9<>]*)\s*,\s*([a-zA-Z_0-9<>]*)\s*>\s*$'); final lowerType = type.toLowerCase(); @@ -423,17 +462,21 @@ class YmlGeneratorConfig { return ArrayType(_makeGenericName(arrayType)); } else if (mapRegex.hasMatch(type)) { final match = mapRegex.firstMatch(type)!; - return MapType(key: _makeGenericName(match.group(1)!), valueName: _makeGenericName(match.group(2)!)); + return MapType( + key: _makeGenericName(match.group(1)!), + valueName: _makeGenericName(match.group(2)!)); } return ObjectType(type); } - YmlGeneratorConfig.merge(Iterable configs, String dirName) : fileName = dirName { + YmlGeneratorConfig.merge(Iterable configs, String dirName) + : fileName = dirName { final names = {}; for (final config in configs) { for (final model in config.models) { if (names.containsKey(model.name)) { - throw Exception('Model with same name ${model.name} found in multiple files: ${names[model.name]!.fileName} and ${config.fileName}'); + throw Exception( + 'Model with same name ${model.name} found in multiple files: ${names[model.name]!.fileName} and ${config.fileName}'); } names[model.name] = config; } diff --git a/lib/model/model/enum_model.dart b/lib/model/model/enum_model.dart index 8dbe0b5..3895175 100644 --- a/lib/model/model/enum_model.dart +++ b/lib/model/model/enum_model.dart @@ -32,8 +32,12 @@ class EnumModel extends Model { String? validate() { for (final property in properties) { for (final field in fields) { - final value = field.values.firstWhereOrNull((value) => value.propertyName == property.name)?.value; - if (value == null && !property.isOptional && property.defaultValue == null) { + final value = field.values + .firstWhereOrNull((value) => value.propertyName == property.name) + ?.value; + if (value == null && + !property.isOptional && + property.defaultValue == null) { return 'There is no value defined for property ${property.name} for the enum value ${field.name} in model $name. Either make this property optional or give it a value'; } final toParseValue = value ?? property.defaultValue; diff --git a/lib/writer/enum_model_writer.dart b/lib/writer/enum_model_writer.dart index 77a43d9..69af5e5 100644 --- a/lib/writer/enum_model_writer.dart +++ b/lib/writer/enum_model_writer.dart @@ -24,15 +24,22 @@ class EnumModelWriter { final jsonModelName = CaseUtil(jsonModel.name); final properties = jsonModel.properties; - final keyProperty = properties.firstWhereOrNull((property) => property.isJsonvalue); - final addDefaultJsonKey = keyProperty == null && jsonModel.addJsonKeyToProperties; + final keyProperty = + properties.firstWhereOrNull((property) => property.isJsonvalue); + final addDefaultJsonKey = + keyProperty == null && jsonModel.addJsonKeyToProperties; final addProperties = properties.isNotEmpty || addDefaultJsonKey; sb.writeln('enum ${jsonModelName.pascalCase} {'); for (var key in jsonModel.fields) { - final jsonValue = key.values.firstWhereOrNull((value) => value.propertyName == keyProperty?.name)?.value ?? key.serializedName; + final jsonValue = key.values + .firstWhereOrNull( + (value) => value.propertyName == keyProperty?.name) + ?.value ?? + key.serializedName; final propertyType = keyProperty?.type; - final isLast = jsonModel.fields.indexOf(key) == (jsonModel.fields.length - 1); + final isLast = + jsonModel.fields.indexOf(key) == (jsonModel.fields.length - 1); if (key.description != null) { sb.writeln(' ///${key.description}'); @@ -57,7 +64,8 @@ class EnumModelWriter { var value = enumValue?.value ?? property.defaultValue; sb.write(' ${property.name}: '); - if (property.type is StringType && (value != null || property.isJsonvalue)) { + if (property.type is StringType && + (value != null || property.isJsonvalue)) { if (value == null && property.isJsonvalue) value = jsonValue; sb.writeln('\'$value\','); } else { diff --git a/test/writer/enum_model_reader_test.dart b/test/writer/enum_model_reader_test.dart index 5892b57..7975edf 100644 --- a/test/writer/enum_model_reader_test.dart +++ b/test/writer/enum_model_reader_test.dart @@ -143,7 +143,8 @@ Gender: test( 'Test enum with unsupported type', () => testEnumError( - expectedError: 'Exception: list should have a type of integer, boolean, double or string', + expectedError: + 'Exception: list should have a type of integer, boolean, double or string', enumYml: """ Gender: path: user/person/ @@ -167,7 +168,8 @@ Gender: required String value, }) { testEnumError( - expectedError: 'Exception: There is no value defined for property name for the enum value FEMALE in model Gender. Either make this property optional or give it a value', + expectedError: + 'Exception: There is no value defined for property name for the enum value FEMALE in model Gender. Either make this property optional or give it a value', enumYml: """ Gender: path: user/person/ @@ -197,7 +199,8 @@ Gender: test( 'Test enum with incorrect type bool', () => testEnumError( - expectedError: 'Exception: Model: Gender, Property isMale is of type bool but the corresponding value on enum value MALE is not, make sure they have the same type', + expectedError: + 'Exception: Model: Gender, Property isMale is of type bool but the corresponding value on enum value MALE is not, make sure they have the same type', enumYml: """ Gender: path: user/person/ @@ -220,7 +223,8 @@ Gender: test( 'Test enum with incorrect type integer', () => testEnumError( - expectedError: 'Exception: Model: Gender, Property isMale is of type int but the corresponding value on enum value MALE is not, make sure they have the same type', + expectedError: + 'Exception: Model: Gender, Property isMale is of type int but the corresponding value on enum value MALE is not, make sure they have the same type', enumYml: """ Gender: path: user/person/ @@ -243,7 +247,8 @@ Gender: test( 'Test enum with incorrect type double', () => testEnumError( - expectedError: 'Exception: Model: Gender, Property isMale is of type double but the corresponding value on enum value MALE is not, make sure they have the same type', + expectedError: + 'Exception: Model: Gender, Property isMale is of type double but the corresponding value on enum value MALE is not, make sure they have the same type', enumYml: """ Gender: path: user/person/ @@ -266,7 +271,8 @@ Gender: test( 'item_type not supported anymore', () => testEnumError( - expectedError: 'Exception: item_type is removed, follow the migration to version 7.0.0', + expectedError: + 'Exception: item_type is removed, follow the migration to version 7.0.0', enumYml: """ Gender: path: user/person/ @@ -280,7 +286,8 @@ Gender: test( 'generate_map not supported anymore', () => testEnumError( - expectedError: 'Exception: generate_map is removed, follow the migration to version 7.0.0', + expectedError: + 'Exception: generate_map is removed, follow the migration to version 7.0.0', enumYml: """ Gender: path: user/person/ @@ -294,7 +301,8 @@ Gender: test( 'generate_extensions not supported anymore', () => testEnumError( - expectedError: 'Exception: generate_extensions is removed, follow the migration to version 7.0.0', + expectedError: + 'Exception: generate_extensions is removed, follow the migration to version 7.0.0', enumYml: """ Gender: path: user/person/ From 811f62913a2ca810f042d94ecb30ee2c4aa4c992 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Thu, 7 Sep 2023 16:46:56 +0200 Subject: [PATCH 26/42] #130: implemented generate extension --- lib/config/yml_generator_config.dart | 9 ++--- lib/model/model/enum_model.dart | 11 ++++-- lib/writer/enum_model_writer.dart | 17 ++++++++-- test/model/model/enum_model_test.dart | 3 ++ test/writer/enum_model_reader_test.dart | 24 +++++++------ .../config.txt | 20 +++++++++++ .../output.txt | 34 +++++++++++++++++++ .../generate_extension_normal/config.txt | 7 ++++ .../generate_extension_normal/output.txt | 26 ++++++++++++++ .../normal_no_default_json_key/config.txt | 2 +- 10 files changed, 131 insertions(+), 22 deletions(-) create mode 100644 test/writer/enum_model_writer/generate_extension_custom_property/config.txt create mode 100644 test/writer/enum_model_writer/generate_extension_custom_property/output.txt create mode 100644 test/writer/enum_model_writer/generate_extension_normal/config.txt create mode 100644 test/writer/enum_model_writer/generate_extension_normal/output.txt diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index 40f1599..2dc5028 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -103,12 +103,6 @@ class YmlGeneratorConfig { 'item_type is removed, follow the migration to version 7.0.0'); } - final deprecatedGenerateExtensions = value['generate_extensions']; - if (deprecatedGenerateExtensions != null) { - throw Exception( - 'generate_extensions is removed, follow the migration to version 7.0.0'); - } - final deprecatedGenerateMap = value['generate_map']; if (deprecatedGenerateMap != null) { throw Exception( @@ -188,7 +182,8 @@ class YmlGeneratorConfig { }); final enumModel = EnumModel( - addJsonKeyToProperties: value['use_default_json_key'] ?? true, + addJsonValueToProperties: value['use_default_json_value'] ?? true, + generateExtension: value['generate_extension'] == true, name: key, path: path, baseDirectory: baseDirectory, diff --git a/lib/model/model/enum_model.dart b/lib/model/model/enum_model.dart index 3895175..eb7f3b0 100644 --- a/lib/model/model/enum_model.dart +++ b/lib/model/model/enum_model.dart @@ -8,13 +8,15 @@ import 'package:model_generator/util/list_extensions.dart'; class EnumModel extends Model { final List fields; final List properties; - final bool addJsonKeyToProperties; + final bool addJsonValueToProperties; + final bool generateExtension; EnumModel({ required String name, required this.fields, required this.properties, - this.addJsonKeyToProperties = true, + required this.generateExtension, + this.addJsonValueToProperties = true, String? path, String? baseDirectory, List? extraImports, @@ -71,6 +73,11 @@ class EnumModel extends Model { if (error != null) return error; } } + final keyProperty = + properties.firstWhereOrNull((property) => property.isJsonvalue); + if (!addJsonValueToProperties && keyProperty == null) { + return "Model: $name, a json value has to be defined when generating extensions for this model. Either enable a default json value by removing 'use_default_json_value: false' or define a property that is a json value by using 'is_json_value: true'"; + } return null; } diff --git a/lib/writer/enum_model_writer.dart b/lib/writer/enum_model_writer.dart index 69af5e5..62b0cc3 100644 --- a/lib/writer/enum_model_writer.dart +++ b/lib/writer/enum_model_writer.dart @@ -27,7 +27,7 @@ class EnumModelWriter { final keyProperty = properties.firstWhereOrNull((property) => property.isJsonvalue); final addDefaultJsonKey = - keyProperty == null && jsonModel.addJsonKeyToProperties; + keyProperty == null && jsonModel.addJsonValueToProperties; final addProperties = properties.isNotEmpty || addDefaultJsonKey; sb.writeln('enum ${jsonModelName.pascalCase} {'); @@ -112,7 +112,20 @@ class EnumModelWriter { sb.writeln(' });'); } - sb.writeln('}'); + if (jsonModel.generateExtension) { + final jsonValueName = addDefaultJsonKey ? 'jsonValue' : keyProperty?.name; + final jsonValueType = + addDefaultJsonKey ? StringType() : keyProperty?.type; + final name = jsonModelName.pascalCase; + sb.writeln('}'); + sb.writeln(); + sb.writeln('extension ${name}Extension on $name {'); + sb.writeln( + ' static $name fromJsonValue(${jsonValueType?.name} value) => $name.values.firstWhere((enumValue) => enumValue.$jsonValueName == value);'); + sb.writeln(''); + sb.writeln(' ${jsonValueType?.name} toJsonValue() => $jsonValueName;'); + sb.writeln('}'); + } return sb.toString(); } diff --git a/test/model/model/enum_model_test.dart b/test/model/model/enum_model_test.dart index ebf2bc2..9a85801 100644 --- a/test/model/model/enum_model_test.dart +++ b/test/model/model/enum_model_test.dart @@ -6,6 +6,7 @@ void main() { group('Default', () { test('Normal EnumModel', () { final model = EnumModel( + generateExtension: true, name: 'MyEnumModel', path: 'path_to_my_model', baseDirectory: 'base_dir', @@ -20,6 +21,7 @@ void main() { group('Custom Path', () { test('Normal Custom Path', () { final model = EnumModel( + generateExtension: true, name: 'MyEnumModel', path: 'path_to_my_model/', baseDirectory: 'base_dir', @@ -33,6 +35,7 @@ void main() { test('Normal Custom Base Dir', () { final model = EnumModel( + generateExtension: true, name: 'MyEnumModel', path: 'path_to_my_model', baseDirectory: 'base_dir/', diff --git a/test/writer/enum_model_reader_test.dart b/test/writer/enum_model_reader_test.dart index 7975edf..069ac3d 100644 --- a/test/writer/enum_model_reader_test.dart +++ b/test/writer/enum_model_reader_test.dart @@ -34,7 +34,7 @@ Gender: expect(model.properties, isEmpty); expect(model.fields.length, 2); - expect(model.addJsonKeyToProperties, true); + expect(model.addJsonValueToProperties, true); expect(model.description, 'this is an enum'); expect(model.fields[0].description, 'this is a enum of male'); @@ -50,7 +50,7 @@ Gender: path: user/person/ type: enum description: this is an enum - use_default_json_key: false + use_default_json_value: false properties: abbreviation: String isMale: @@ -84,7 +84,7 @@ Gender: expect(model.properties.length, 4); expect(model.fields.length, 2); - expect(model.addJsonKeyToProperties, false); + expect(model.addJsonValueToProperties, false); expect(model.description, 'this is an enum'); expect(model.properties[0].type, isA()); @@ -298,19 +298,23 @@ Gender: FEMALE: """, )); + test( - 'generate_extensions not supported anymore', + 'generate extension required jsonValue', () => testEnumError( expectedError: - 'Exception: generate_extensions is removed, follow the migration to version 7.0.0', + "Exception: Model: DoubleStatus, a json value has to be defined when generating extensions for this model. Either enable a default json value by removing 'use_default_json_value: false' or define a property that is a json value by using 'is_json_value: true'", enumYml: """ -Gender: - path: user/person/ +DoubleStatus: + path: status type: enum - generate_extensions: true + generate_extension: true + use_default_json_value: false values: - MALE: - FEMALE: + status_0: + status_1: + status_2: + status_3: """, )); }); diff --git a/test/writer/enum_model_writer/generate_extension_custom_property/config.txt b/test/writer/enum_model_writer/generate_extension_custom_property/config.txt new file mode 100644 index 0000000..b53f275 --- /dev/null +++ b/test/writer/enum_model_writer/generate_extension_custom_property/config.txt @@ -0,0 +1,20 @@ +Person: + path: test/enum/ + type: enum + properties: + jsonKey: + is_json_value: true + type: int + firstName: String + lastName: String + values: + MAN: + properties: + jsonKey: 1 + firstName: firstName1 + lastName: lastName1 + WOMAN: + properties: + jsonKey: 2 + firstName: firstName2 + lastName: lastName2 diff --git a/test/writer/enum_model_writer/generate_extension_custom_property/output.txt b/test/writer/enum_model_writer/generate_extension_custom_property/output.txt new file mode 100644 index 0000000..4f13e42 --- /dev/null +++ b/test/writer/enum_model_writer/generate_extension_custom_property/output.txt @@ -0,0 +1,34 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +import 'package:json_annotation/json_annotation.dart'; + +enum Person { + @JsonValue(1) + MAN( + jsonKey: 1, + firstName: 'firstName1', + lastName: 'lastName1', + ), + @JsonValue(2) + WOMAN( + jsonKey: 2, + firstName: 'firstName2', + lastName: 'lastName2', + ); + + final int jsonKey; + final String firstName; + final String lastName; + + const Person({ + required this.jsonKey, + required this.firstName, + required this.lastName, + }); +} + +extension PersonExtension on Person { + static Person fromJsonValue(int value) => Person.values.firstWhere((enumValue) => enumValue.jsonKey == value); + + int toJsonValue() => jsonKey; +} diff --git a/test/writer/enum_model_writer/generate_extension_normal/config.txt b/test/writer/enum_model_writer/generate_extension_normal/config.txt new file mode 100644 index 0000000..385f180 --- /dev/null +++ b/test/writer/enum_model_writer/generate_extension_normal/config.txt @@ -0,0 +1,7 @@ +MyEnumModel: + path: test/enum/ + type: enum + generate_extension: true + values: + MY_VALUE_1: + MY_VALUE_2: \ No newline at end of file diff --git a/test/writer/enum_model_writer/generate_extension_normal/output.txt b/test/writer/enum_model_writer/generate_extension_normal/output.txt new file mode 100644 index 0000000..ad122a0 --- /dev/null +++ b/test/writer/enum_model_writer/generate_extension_normal/output.txt @@ -0,0 +1,26 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +import 'package:json_annotation/json_annotation.dart'; + +enum MyEnumModel { + @JsonValue('MY_VALUE_1') + MY_VALUE_1( + jsonValue: 'MY_VALUE_1', + ), + @JsonValue('MY_VALUE_2') + MY_VALUE_2( + jsonValue: 'MY_VALUE_2', + ); + + final String jsonValue; + + const MyEnumModel({ + required this.jsonValue, + }); +} + +extension MyEnumModelExtension on MyEnumModel { + static MyEnumModel fromJsonValue(String value) => MyEnumModel.values.firstWhere((enumValue) => enumValue.jsonValue == value); + + String toJsonValue() => jsonValue; +} diff --git a/test/writer/enum_model_writer/normal_no_default_json_key/config.txt b/test/writer/enum_model_writer/normal_no_default_json_key/config.txt index f6368f0..de6bba7 100644 --- a/test/writer/enum_model_writer/normal_no_default_json_key/config.txt +++ b/test/writer/enum_model_writer/normal_no_default_json_key/config.txt @@ -1,6 +1,6 @@ MyEnumModel: path: test/enum/ - use_default_json_key: false + use_default_json_value: false type: enum values: MY_VALUE_1: From 87344ae7e5038ffafecd057f4495231dad44e1de Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Thu, 7 Sep 2023 17:07:45 +0200 Subject: [PATCH 27/42] #130: fixed tests --- lib/model/model/enum_model.dart | 57 ++++++++++--------- lib/writer/enum_model_writer.dart | 2 +- .../config.txt | 1 + .../custom-from-to/output.txt | 2 +- .../dart-import/output.txt | 2 +- .../dart-package-import/output.txt | 2 +- .../explicit-to-json-false-pubspec/output.txt | 2 +- .../explicit-to-json-false/output.txt | 2 +- .../extend-fields-twice/output.txt | 2 +- .../output.txt | 2 +- .../extend-fields/output.txt | 2 +- .../extra-imports-on-model/output.txt | 2 +- .../extra-imports/output.txt | 2 +- .../output.txt | 2 +- .../generate-for-generics-override/output.txt | 2 +- .../generate-for-generics/output.txt | 2 +- .../import_sorting/output.txt | 2 +- .../writer/object_model_writer/map/output.txt | 2 +- .../output.txt | 2 +- .../normal-to-string/output.txt | 2 +- .../object_model_writer/nullsafety/output.txt | 4 +- .../package-import/output.txt | 2 +- .../object_model_writer/required/output.txt | 2 +- .../object_model_writer/sort/output.txt | 6 +- .../without-path/output.txt | 2 +- 25 files changed, 58 insertions(+), 52 deletions(-) diff --git a/lib/model/model/enum_model.dart b/lib/model/model/enum_model.dart index eb7f3b0..0f6cecb 100644 --- a/lib/model/model/enum_model.dart +++ b/lib/model/model/enum_model.dart @@ -39,43 +39,48 @@ class EnumModel extends Model { ?.value; if (value == null && !property.isOptional && - property.defaultValue == null) { + property.defaultValue == null && + !property.isJsonvalue) { return 'There is no value defined for property ${property.name} for the enum value ${field.name} in model $name. Either make this property optional or give it a value'; } final toParseValue = value ?? property.defaultValue; String? error; - if (property.type is DoubleType) { - error = testValueType( - parser: double.tryParse, - typeName: DoubleType().name, - toParseValue: toParseValue!, - propertyName: property.name, - fieldName: field.name, - ); - } else if (property.type is IntegerType) { - error = testValueType( - parser: int.tryParse, - typeName: IntegerType().name, - toParseValue: toParseValue!, - propertyName: property.name, - fieldName: field.name, - ); - } else if (property.type is BooleanType) { - error = testValueType( - parser: bool.tryParse, - typeName: BooleanType().name, - toParseValue: toParseValue!, - propertyName: property.name, - fieldName: field.name, - ); + if (toParseValue != null) { + if (property.type is DoubleType) { + error = testValueType( + parser: double.tryParse, + typeName: DoubleType().name, + toParseValue: toParseValue, + propertyName: property.name, + fieldName: field.name, + ); + } else if (property.type is IntegerType) { + error = testValueType( + parser: int.tryParse, + typeName: IntegerType().name, + toParseValue: toParseValue, + propertyName: property.name, + fieldName: field.name, + ); + } else if (property.type is BooleanType) { + error = testValueType( + parser: bool.tryParse, + typeName: BooleanType().name, + toParseValue: toParseValue, + propertyName: property.name, + fieldName: field.name, + ); + } } + if (error != null) return error; } } final keyProperty = properties.firstWhereOrNull((property) => property.isJsonvalue); - if (!addJsonValueToProperties && keyProperty == null) { + if ((!addJsonValueToProperties && keyProperty == null) && + generateExtension) { return "Model: $name, a json value has to be defined when generating extensions for this model. Either enable a default json value by removing 'use_default_json_value: false' or define a property that is a json value by using 'is_json_value: true'"; } return null; diff --git a/lib/writer/enum_model_writer.dart b/lib/writer/enum_model_writer.dart index 62b0cc3..f3d3588 100644 --- a/lib/writer/enum_model_writer.dart +++ b/lib/writer/enum_model_writer.dart @@ -111,13 +111,13 @@ class EnumModelWriter { } sb.writeln(' });'); } + sb.writeln('}'); if (jsonModel.generateExtension) { final jsonValueName = addDefaultJsonKey ? 'jsonValue' : keyProperty?.name; final jsonValueType = addDefaultJsonKey ? StringType() : keyProperty?.type; final name = jsonModelName.pascalCase; - sb.writeln('}'); sb.writeln(); sb.writeln('extension ${name}Extension on $name {'); sb.writeln( diff --git a/test/writer/enum_model_writer/generate_extension_custom_property/config.txt b/test/writer/enum_model_writer/generate_extension_custom_property/config.txt index b53f275..6708548 100644 --- a/test/writer/enum_model_writer/generate_extension_custom_property/config.txt +++ b/test/writer/enum_model_writer/generate_extension_custom_property/config.txt @@ -1,6 +1,7 @@ Person: path: test/enum/ type: enum + generate_extension: true properties: jsonKey: is_json_value: true diff --git a/test/writer/object_model_writer/custom-from-to/output.txt b/test/writer/object_model_writer/custom-from-to/output.txt index cfed304..f66ea6a 100644 --- a/test/writer/object_model_writer/custom-from-to/output.txt +++ b/test/writer/object_model_writer/custom-from-to/output.txt @@ -7,7 +7,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'time', fromJson: handleTimeFromJson, toJson: handleTimeToJson) + @JsonKey(name: 'time', includeIfNull: false, fromJson: handleTimeFromJson, toJson: handleTimeToJson) final Time? time; const Person({ diff --git a/test/writer/object_model_writer/dart-import/output.txt b/test/writer/object_model_writer/dart-import/output.txt index aed5bf5..4601c28 100644 --- a/test/writer/object_model_writer/dart-import/output.txt +++ b/test/writer/object_model_writer/dart-import/output.txt @@ -7,7 +7,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'address', required: true) + @JsonKey(name: 'address', required: true, includeIfNull: false) final Address address; const Person({ diff --git a/test/writer/object_model_writer/dart-package-import/output.txt b/test/writer/object_model_writer/dart-package-import/output.txt index 420f6b6..1dd2b74 100644 --- a/test/writer/object_model_writer/dart-package-import/output.txt +++ b/test/writer/object_model_writer/dart-package-import/output.txt @@ -7,7 +7,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'address', required: true) + @JsonKey(name: 'address', required: true, includeIfNull: false) final Address address; const Person({ diff --git a/test/writer/object_model_writer/explicit-to-json-false-pubspec/output.txt b/test/writer/object_model_writer/explicit-to-json-false-pubspec/output.txt index 6471da8..a74903e 100644 --- a/test/writer/object_model_writer/explicit-to-json-false-pubspec/output.txt +++ b/test/writer/object_model_writer/explicit-to-json-false-pubspec/output.txt @@ -6,7 +6,7 @@ part 'person.g.dart'; @JsonSerializable() class Person { - @JsonKey(name: 'firstName') + @JsonKey(name: 'firstName', includeIfNull: false) final String? firstName; const Person({ diff --git a/test/writer/object_model_writer/explicit-to-json-false/output.txt b/test/writer/object_model_writer/explicit-to-json-false/output.txt index 6471da8..a74903e 100644 --- a/test/writer/object_model_writer/explicit-to-json-false/output.txt +++ b/test/writer/object_model_writer/explicit-to-json-false/output.txt @@ -6,7 +6,7 @@ part 'person.g.dart'; @JsonSerializable() class Person { - @JsonKey(name: 'firstName') + @JsonKey(name: 'firstName', includeIfNull: false) final String? firstName; const Person({ diff --git a/test/writer/object_model_writer/extend-fields-twice/output.txt b/test/writer/object_model_writer/extend-fields-twice/output.txt index 6c53aba..c1ed25b 100644 --- a/test/writer/object_model_writer/extend-fields-twice/output.txt +++ b/test/writer/object_model_writer/extend-fields-twice/output.txt @@ -7,7 +7,7 @@ part 'admin.g.dart'; @JsonSerializable(explicitToJson: true) class Admin extends User { - @JsonKey(name: 'permission', required: true) + @JsonKey(name: 'permission', required: true, includeIfNull: false) final String permission; const Admin({ diff --git a/test/writer/object_model_writer/extend-fields-with-non-dart-type/output.txt b/test/writer/object_model_writer/extend-fields-with-non-dart-type/output.txt index ea8d530..32d7f44 100644 --- a/test/writer/object_model_writer/extend-fields-with-non-dart-type/output.txt +++ b/test/writer/object_model_writer/extend-fields-with-non-dart-type/output.txt @@ -8,7 +8,7 @@ part 'user.g.dart'; @JsonSerializable(explicitToJson: true) class User extends Person { - @JsonKey(name: 'email', required: true) + @JsonKey(name: 'email', required: true, includeIfNull: false) final String email; const User({ diff --git a/test/writer/object_model_writer/extend-fields/output.txt b/test/writer/object_model_writer/extend-fields/output.txt index 05c7a39..2f1181c 100644 --- a/test/writer/object_model_writer/extend-fields/output.txt +++ b/test/writer/object_model_writer/extend-fields/output.txt @@ -7,7 +7,7 @@ part 'user.g.dart'; @JsonSerializable(explicitToJson: true) class User extends Person { - @JsonKey(name: 'email', required: true) + @JsonKey(name: 'email', required: true, includeIfNull: false) final String email; const User({ diff --git a/test/writer/object_model_writer/extra-imports-on-model/output.txt b/test/writer/object_model_writer/extra-imports-on-model/output.txt index 353f17b..93396fc 100644 --- a/test/writer/object_model_writer/extra-imports-on-model/output.txt +++ b/test/writer/object_model_writer/extra-imports-on-model/output.txt @@ -8,7 +8,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) @veryGood class Person { - @JsonKey(name: 'firstName') + @JsonKey(name: 'firstName', includeIfNull: false) final String? firstName; const Person({ diff --git a/test/writer/object_model_writer/extra-imports/output.txt b/test/writer/object_model_writer/extra-imports/output.txt index d20518d..a4daf3b 100644 --- a/test/writer/object_model_writer/extra-imports/output.txt +++ b/test/writer/object_model_writer/extra-imports/output.txt @@ -8,7 +8,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) @immutable class Person { - @JsonKey(name: 'firstName') + @JsonKey(name: 'firstName', includeIfNull: false) final String? firstName; const Person({ diff --git a/test/writer/object_model_writer/generate-for-generics-override-2/output.txt b/test/writer/object_model_writer/generate-for-generics-override-2/output.txt index 89d8f73..45ecac2 100644 --- a/test/writer/object_model_writer/generate-for-generics-override-2/output.txt +++ b/test/writer/object_model_writer/generate-for-generics-override-2/output.txt @@ -6,7 +6,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'firstName', required: true) + @JsonKey(name: 'firstName', required: true, includeIfNull: false) final String firstName; const Person({ diff --git a/test/writer/object_model_writer/generate-for-generics-override/output.txt b/test/writer/object_model_writer/generate-for-generics-override/output.txt index fc3a2e5..8888f33 100644 --- a/test/writer/object_model_writer/generate-for-generics-override/output.txt +++ b/test/writer/object_model_writer/generate-for-generics-override/output.txt @@ -6,7 +6,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'firstName', required: true) + @JsonKey(name: 'firstName', required: true, includeIfNull: false) final String firstName; const Person({ diff --git a/test/writer/object_model_writer/generate-for-generics/output.txt b/test/writer/object_model_writer/generate-for-generics/output.txt index fc3a2e5..8888f33 100644 --- a/test/writer/object_model_writer/generate-for-generics/output.txt +++ b/test/writer/object_model_writer/generate-for-generics/output.txt @@ -6,7 +6,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'firstName', required: true) + @JsonKey(name: 'firstName', required: true, includeIfNull: false) final String firstName; const Person({ diff --git a/test/writer/object_model_writer/import_sorting/output.txt b/test/writer/object_model_writer/import_sorting/output.txt index 761a1b6..494bf07 100644 --- a/test/writer/object_model_writer/import_sorting/output.txt +++ b/test/writer/object_model_writer/import_sorting/output.txt @@ -7,7 +7,7 @@ part 'b_model.g.dart'; @JsonSerializable(explicitToJson: true) class BModel { - @JsonKey(name: 'aModel') + @JsonKey(name: 'aModel', includeIfNull: false) final AModel? aModel; const BModel({ diff --git a/test/writer/object_model_writer/map/output.txt b/test/writer/object_model_writer/map/output.txt index 14bd8f3..8f4e6d5 100644 --- a/test/writer/object_model_writer/map/output.txt +++ b/test/writer/object_model_writer/map/output.txt @@ -6,7 +6,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'info', required: true) + @JsonKey(name: 'info', required: true, includeIfNull: false) final Map info; const Person({ diff --git a/test/writer/object_model_writer/normal-equals-hashcode-some-ignored/output.txt b/test/writer/object_model_writer/normal-equals-hashcode-some-ignored/output.txt index 270cc47..241a599 100644 --- a/test/writer/object_model_writer/normal-equals-hashcode-some-ignored/output.txt +++ b/test/writer/object_model_writer/normal-equals-hashcode-some-ignored/output.txt @@ -8,7 +8,7 @@ part 'person.g.dart'; class Person { @JsonKey(name: 'firstName', includeIfNull: false) final String? firstName; - @JsonKey(name: 'lastName') + @JsonKey(name: 'lastName', includeIfNull: false) final String? lastName; const Person({ diff --git a/test/writer/object_model_writer/normal-to-string/output.txt b/test/writer/object_model_writer/normal-to-string/output.txt index 6b85833..ec98bd9 100644 --- a/test/writer/object_model_writer/normal-to-string/output.txt +++ b/test/writer/object_model_writer/normal-to-string/output.txt @@ -6,7 +6,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'firstName') + @JsonKey(name: 'firstName', includeIfNull: false) final String? firstName; const Person({ diff --git a/test/writer/object_model_writer/nullsafety/output.txt b/test/writer/object_model_writer/nullsafety/output.txt index daea5a5..ba4613f 100644 --- a/test/writer/object_model_writer/nullsafety/output.txt +++ b/test/writer/object_model_writer/nullsafety/output.txt @@ -6,9 +6,9 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'firstName', required: true) + @JsonKey(name: 'firstName', required: true, includeIfNull: false) final String firstName; - @JsonKey(name: 'lastName') + @JsonKey(name: 'lastName', includeIfNull: false) final String? lastName; const Person({ diff --git a/test/writer/object_model_writer/package-import/output.txt b/test/writer/object_model_writer/package-import/output.txt index 5f1ccf9..607cac0 100644 --- a/test/writer/object_model_writer/package-import/output.txt +++ b/test/writer/object_model_writer/package-import/output.txt @@ -7,7 +7,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'address', required: true) + @JsonKey(name: 'address', required: true, includeIfNull: false) final Address address; const Person({ diff --git a/test/writer/object_model_writer/required/output.txt b/test/writer/object_model_writer/required/output.txt index 89d8f73..45ecac2 100644 --- a/test/writer/object_model_writer/required/output.txt +++ b/test/writer/object_model_writer/required/output.txt @@ -6,7 +6,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'firstName', required: true) + @JsonKey(name: 'firstName', required: true, includeIfNull: false) final String firstName; const Person({ diff --git a/test/writer/object_model_writer/sort/output.txt b/test/writer/object_model_writer/sort/output.txt index 02a8458..7f3d24f 100644 --- a/test/writer/object_model_writer/sort/output.txt +++ b/test/writer/object_model_writer/sort/output.txt @@ -6,11 +6,11 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'x', required: true) + @JsonKey(name: 'x', required: true, includeIfNull: false) final String x; - @JsonKey(name: 'a', required: true) + @JsonKey(name: 'a', required: true, includeIfNull: false) final String a; - @JsonKey(name: 'b') + @JsonKey(name: 'b', includeIfNull: false) final String? b; const Person({ diff --git a/test/writer/object_model_writer/without-path/output.txt b/test/writer/object_model_writer/without-path/output.txt index 941fe23..d68f1ff 100644 --- a/test/writer/object_model_writer/without-path/output.txt +++ b/test/writer/object_model_writer/without-path/output.txt @@ -7,7 +7,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'address', required: true) + @JsonKey(name: 'address', required: true, includeIfNull: false) final Address address; const Person({ From 1d3d09fba1927b67b8181e6eeb124c2049a6d8af Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Thu, 7 Sep 2023 17:12:41 +0200 Subject: [PATCH 28/42] #130: updated readme --- README.md | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d22ba89..d3d2f80 100755 --- a/README.md +++ b/README.md @@ -475,7 +475,45 @@ Gender: lastName: lastName ``` -### Generate mapping extensions And Generate mapping are no longer supported as of V7.0.0, use properties instead +### Generate mapping extensions + +It is possible to generate an extension for the enum that can turn the enum into it's corresponding jsonValue and the reverse. + +```yaml +Person: + path: test/enum/ + type: enum + generate_extension: true + properties: + jsonValue: + is_json_value: true + type: int + firstName: String + lastName: String + values: + MAN: + properties: + jsonKey: 1 + firstName: firstName1 + lastName: lastName1 + WOMAN: + properties: + jsonKey: 2 + firstName: firstName2 + lastName: lastName2 + +``` +The above configuration will generate an enum with this extension. + +```dart +extension PersonExtension on Person { + static Person fromJsonValue(int value) => Person.values.firstWhere((enumValue) => enumValue.jsonKey == value); + + int toJsonValue() => jsonKey; +} +``` + +### Generate mapping is no longer supported as of V7.0.0, use properties instead ### Use unknownEnumValue ```yaml From acbfe70a2af5e0579604b8495df824e68ef0eab6 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Fri, 8 Sep 2023 10:48:22 +0200 Subject: [PATCH 29/42] #130: added project wrapper --- example/lib/model/ogm.dart | 8 +-- example/lib/model/ogm.g.dart | 5 +- .../model/user/project/project_wrapper.dart | 51 +++++++++++++++++++ .../model/user/project/project_wrapper.g.dart | 26 ++++++++++ example/model_generator/config.yaml | 7 +++ 5 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 example/lib/model/user/project/project_wrapper.dart create mode 100644 example/lib/model/user/project/project_wrapper.g.dart diff --git a/example/lib/model/ogm.dart b/example/lib/model/ogm.dart index 149f048..7829194 100644 --- a/example/lib/model/ogm.dart +++ b/example/lib/model/ogm.dart @@ -19,11 +19,11 @@ class OGM { final String someThing; @JsonKey(name: 'some_ThinG_huGE', required: true, includeIfNull: false) final String someThinGHuGE; - @JsonKey(name: 'simpleFields', required: true) + @JsonKey(name: 'simpleFields', required: true, includeIfNull: false) final List simpleFields; - @JsonKey(name: 'listMap', required: true) + @JsonKey(name: 'listMap', required: true, includeIfNull: false) final Map> listMap; - @JsonKey(name: 'structuredMessage') + @JsonKey(name: 'structuredMessage', includeIfNull: false) final String? structuredMessage; @JsonKey(name: 'securityIndicator', includeIfNull: false) final String? securityRole; @@ -33,7 +33,7 @@ class OGM { final DateTime? dateChange; @JsonKey(name: 'fields', includeIfNull: false) final List>? fields; - @JsonKey(name: 'simpleMap') + @JsonKey(name: 'simpleMap', includeIfNull: false) final Map? simpleMap; OGM({ diff --git a/example/lib/model/ogm.g.dart b/example/lib/model/ogm.g.dart index eb15b2a..f5c2704 100644 --- a/example/lib/model/ogm.g.dart +++ b/example/lib/model/ogm.g.dart @@ -57,7 +57,6 @@ Map _$OGMToJson(OGM instance) { 'some_ThinG_huGE': instance.someThinGHuGE, 'simpleFields': instance.simpleFields.map((e) => e.toJson()).toList(), 'listMap': instance.listMap.map((k, e) => MapEntry(k.toString(), e)), - 'structuredMessage': instance.structuredMessage, }; void writeNotNull(String key, dynamic value) { @@ -66,6 +65,7 @@ Map _$OGMToJson(OGM instance) { } } + writeNotNull('structuredMessage', instance.structuredMessage); writeNotNull('securityIndicator', instance.securityRole); writeNotNull('mutableProperty', instance.mutableProperty); writeNotNull( @@ -74,7 +74,8 @@ Map _$OGMToJson(OGM instance) { instance.dateChange, const DateTimeConverter().toJson)); writeNotNull('fields', instance.fields?.map((e) => e.map((e) => e.toJson()).toList()).toList()); - val['simpleMap'] = instance.simpleMap?.map((k, e) => MapEntry(k, e.toJson())); + writeNotNull( + 'simpleMap', instance.simpleMap?.map((k, e) => MapEntry(k, e.toJson()))); return val; } diff --git a/example/lib/model/user/project/project_wrapper.dart b/example/lib/model/user/project/project_wrapper.dart new file mode 100644 index 0000000..c0965b7 --- /dev/null +++ b/example/lib/model/user/project/project_wrapper.dart @@ -0,0 +1,51 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +import 'package:flutter/foundation.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:model_generator_example/model/user/project/project.dart'; + +part 'project_wrapper.g.dart'; + +@JsonSerializable(explicitToJson: true) +@immutable +class ProjectWrapper { + @JsonKey(name: 'projectListById', required: true, includeIfNull: false) + final Map> projectListById; + + const ProjectWrapper({ + required this.projectListById, + }); + + factory ProjectWrapper.fromJson(Map json) => + _$ProjectWrapperFromJson(json); + + Map toJson() => _$ProjectWrapperToJson(this); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is ProjectWrapper && + runtimeType == other.runtimeType && + projectListById == other.projectListById; + + @override + int get hashCode => projectListById.hashCode; + + @override + String toString() => 'ProjectWrapper{' + 'projectListById: $projectListById' + '}'; +} + +const deserializeProjectWrapper = ProjectWrapper.fromJson; + +Map serializeProjectWrapper(ProjectWrapper object) => + object.toJson(); + +List deserializeProjectWrapperList( + List> jsonList) => + jsonList.map(ProjectWrapper.fromJson).toList(); + +List> serializeProjectWrapperList( + List objects) => + objects.map((object) => object.toJson()).toList(); diff --git a/example/lib/model/user/project/project_wrapper.g.dart b/example/lib/model/user/project/project_wrapper.g.dart new file mode 100644 index 0000000..f9f5c92 --- /dev/null +++ b/example/lib/model/user/project/project_wrapper.g.dart @@ -0,0 +1,26 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'project_wrapper.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ProjectWrapper _$ProjectWrapperFromJson(Map json) { + $checkKeys( + json, + requiredKeys: const ['projectListById'], + ); + return ProjectWrapper( + projectListById: (json['projectListById'] as Map).map( + (k, e) => + MapEntry(k, (e as List).map(Project.fromJson).toList()), + ), + ); +} + +Map _$ProjectWrapperToJson(ProjectWrapper instance) => + { + 'projectListById': instance.projectListById + .map((k, e) => MapEntry(k, e.map((e) => e.toJson()).toList())), + }; diff --git a/example/model_generator/config.yaml b/example/model_generator/config.yaml index c83a308..7ca741d 100644 --- a/example/model_generator/config.yaml +++ b/example/model_generator/config.yaml @@ -150,3 +150,10 @@ Project: status: type: Status? unknown_enum_value: STATUS_0 + +ProjectWrapper: + path: user/project/ + type: object + properties: + projectListById: + type: Map> From a78c87b32764ccada3f4a611fa103c548845f30f Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Fri, 8 Sep 2023 11:41:37 +0200 Subject: [PATCH 30/42] #130: implemented PR feedback --- README.md | 5 ++- .../list_in_map/config.txt | 32 +++++++++++++++ .../list_in_map/output.txt | 40 +++++++++++++++++++ .../list_in_map/pubspec.txt | 4 ++ 4 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 test/writer/object_model_writer/list_in_map/config.txt create mode 100644 test/writer/object_model_writer/list_in_map/output.txt create mode 100644 test/writer/object_model_writer/list_in_map/pubspec.txt diff --git a/README.md b/README.md index d3d2f80..a49cdd8 100755 --- a/README.md +++ b/README.md @@ -333,7 +333,7 @@ DateTimeConverter: ## Inline types (since 6.0.0) -In some cases, writing the full specification for simple fields is very verbose. Since 6.0.0 it is possible to write simple fields inline, without nesting below the field name: +In some cases, writing the full specification for simple fields is very verbose. Since 6.0.0 it is possible to write simple fields inline, without nesting below the field name, since 7.0.0 nested lists and list in maps is also supported: ```yaml UserModel: @@ -345,6 +345,7 @@ UserModel: created_at: DateTime roles: List customProperties: Map? + customPropertiesList: Map>? ``` since 7.0.0 inline types are supported now even when adding extra configuration: @@ -373,7 +374,7 @@ BookCase: include_if_null: false ``` -Currently all basic types are supported, simple Lists and Maps (no nested types, no nullable generic parameters) as well as references to other objects. +Currently all basic types are supported, simple Lists and Maps (no nullable generic parameters) as well as references to other objects. Items post-fixed with `?` will be marked optional. ## Enum support (as of v7.0.0 enums now support properties) diff --git a/test/writer/object_model_writer/list_in_map/config.txt b/test/writer/object_model_writer/list_in_map/config.txt new file mode 100644 index 0000000..5c46021 --- /dev/null +++ b/test/writer/object_model_writer/list_in_map/config.txt @@ -0,0 +1,32 @@ +ProjectWrapper: + path: user/person/ + type: object + properties: + projectByInt: Map> + projectByString: Map> + projectByEnum: Map> + StringsByString: Map> + intsByString: Map> + intsByDateTime: Map> + intsBydynamic: Map> + +Project: + path: user/project/ + type: object + generate_for_generics: true + static_create: true + properties: + name: + type: String + default_value: "'test'" + cost: + type: double? + default_value: 0.2 + +ProjectEnum: + path: user/project + type: enum + values: + smallProject: + mediumProject: + bigProject: \ No newline at end of file diff --git a/test/writer/object_model_writer/list_in_map/output.txt b/test/writer/object_model_writer/list_in_map/output.txt new file mode 100644 index 0000000..2456aac --- /dev/null +++ b/test/writer/object_model_writer/list_in_map/output.txt @@ -0,0 +1,40 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +import 'package:json_annotation/json_annotation.dart'; +import 'package:model_generator_example/model/user/project/project.dart'; +import 'package:model_generator_example/model/user/project/project_enum.dart'; + +part 'project_wrapper.g.dart'; + +@JsonSerializable(explicitToJson: true) +class ProjectWrapper { + @JsonKey(name: 'projectByInt', required: true, includeIfNull: false) + final Map> projectByInt; + @JsonKey(name: 'projectByString', required: true, includeIfNull: false) + final Map> projectByString; + @JsonKey(name: 'projectByEnum', required: true, includeIfNull: false) + final Map> projectByEnum; + @JsonKey(name: 'StringsByString', required: true, includeIfNull: false) + final Map> stringsByString; + @JsonKey(name: 'intsByString', required: true, includeIfNull: false) + final Map> intsByString; + @JsonKey(name: 'intsByDateTime', required: true, includeIfNull: false) + final Map> intsByDateTime; + @JsonKey(name: 'intsBydynamic', required: true, includeIfNull: false) + final Map> intsBydynamic; + + const ProjectWrapper({ + required this.projectByInt, + required this.projectByString, + required this.projectByEnum, + required this.stringsByString, + required this.intsByString, + required this.intsByDateTime, + required this.intsBydynamic, + }); + + factory ProjectWrapper.fromJson(Map json) => _$ProjectWrapperFromJson(json); + + Map toJson() => _$ProjectWrapperToJson(this); + +} diff --git a/test/writer/object_model_writer/list_in_map/pubspec.txt b/test/writer/object_model_writer/list_in_map/pubspec.txt new file mode 100644 index 0000000..95f3114 --- /dev/null +++ b/test/writer/object_model_writer/list_in_map/pubspec.txt @@ -0,0 +1,4 @@ +name: model_generator_example + +model_generator: + config_path: model_generator/config.yaml From 534d60c0ff249075d86d5bb572fb3133f8e8c518 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Fri, 8 Sep 2023 11:47:22 +0200 Subject: [PATCH 31/42] #130: added extra test to model reader --- test/writer/model_reader_test.dart | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/test/writer/model_reader_test.dart b/test/writer/model_reader_test.dart index 90d43c3..f715df7 100644 --- a/test/writer/model_reader_test.dart +++ b/test/writer/model_reader_test.dart @@ -94,8 +94,7 @@ TestModel: expect(error, isNotNull); expect(error, isArgumentError); if (error is ArgumentError) { - expect(error.message, - 'required is removed, follow the migration to version 7.0.0'); + expect(error.message, 'required is removed, follow the migration to version 7.0.0'); } }); @@ -121,8 +120,7 @@ TestModel: expect(error, isNotNull); expect(error, isException); if (error is Exception) { - expect(error.toString(), - 'Exception: Could not generate all models. `array` is not added to the config file'); + expect(error.toString(), 'Exception: Could not generate all models. `array` is not added to the config file'); } }); @@ -149,8 +147,7 @@ TestModel: expect(error, isNotNull); expect(error, isException); if (error is Exception) { - expect(error.toString(), - 'Exception: Could not generate all models. `map` is not added to the config file'); + expect(error.toString(), 'Exception: Could not generate all models. `map` is not added to the config file'); } }); @@ -164,6 +161,7 @@ TestModel: simpleStringList: List nullableStringList: List? simpleMap: Map + nestedMap: Map> """, ''); final models = config.models; @@ -181,6 +179,7 @@ TestModel: final simpleStringList = model.fields.getByName("simpleStringList"); final nullableStringList = model.fields.getByName("nullableStringList"); final simpleMap = model.fields.getByName("simpleMap"); + final nestedMap = model.fields.getByName("nestedMap"); expect(simpleStringList.type, isA()); expect(simpleStringList.isRequired, true); @@ -191,6 +190,13 @@ TestModel: expect(simpleMap.type, isA()); expect(simpleMap.isRequired, true); + expect(nestedMap.type, isA()); + if (nestedMap.type is MapType) { + final type = nestedMap.type as MapType; + expect(type.valueName, 'List'); + } + expect(nestedMap.isRequired, true); + expect(error, isNull); }); test('Test simple object reference fields', () { From 94d7355880b104c16c31951061e5ac25ee88665e Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Fri, 8 Sep 2023 14:56:01 +0200 Subject: [PATCH 32/42] #130: added first where or null --- lib/util/extension/list_extension.dart | 8 ++++++++ lib/writer/enum_model_writer.dart | 11 ++++++++--- .../generate_extension_custom_property/output.txt | 3 ++- .../generate_extension_normal/output.txt | 3 ++- test/writer/model_reader_test.dart | 9 ++++++--- 5 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 lib/util/extension/list_extension.dart diff --git a/lib/util/extension/list_extension.dart b/lib/util/extension/list_extension.dart new file mode 100644 index 0000000..2980bc5 --- /dev/null +++ b/lib/util/extension/list_extension.dart @@ -0,0 +1,8 @@ +extension ListExtension on List { + T? firstWhereOrNull(bool Function(T element) test) { + for (var element in this) { + if (test(element)) return element; + } + return null; + } +} diff --git a/lib/writer/enum_model_writer.dart b/lib/writer/enum_model_writer.dart index f3d3588..1bf6068 100644 --- a/lib/writer/enum_model_writer.dart +++ b/lib/writer/enum_model_writer.dart @@ -14,8 +14,13 @@ class EnumModelWriter { final sb = StringBuffer() ..writeln(ObjectModelWriter.autoGeneratedWarning) ..writeln() - ..writeln("import 'package:json_annotation/json_annotation.dart';") - ..writeln(); + ..writeln("import 'package:json_annotation/json_annotation.dart';"); + if (jsonModel.generateExtension) { + sb.writeln( + "import 'package:model_generator/util/extension/list_extension.dart';"); + } + + sb.writeln(); final modelDescription = jsonModel.description?.trim(); if (modelDescription != null && modelDescription.isNotEmpty) { @@ -121,7 +126,7 @@ class EnumModelWriter { sb.writeln(); sb.writeln('extension ${name}Extension on $name {'); sb.writeln( - ' static $name fromJsonValue(${jsonValueType?.name} value) => $name.values.firstWhere((enumValue) => enumValue.$jsonValueName == value);'); + ' static $name? fromJsonValue(${jsonValueType?.name} value) => $name.values.firstWhereOrNull((enumValue) => enumValue.$jsonValueName == value);'); sb.writeln(''); sb.writeln(' ${jsonValueType?.name} toJsonValue() => $jsonValueName;'); sb.writeln('}'); diff --git a/test/writer/enum_model_writer/generate_extension_custom_property/output.txt b/test/writer/enum_model_writer/generate_extension_custom_property/output.txt index 4f13e42..3100105 100644 --- a/test/writer/enum_model_writer/generate_extension_custom_property/output.txt +++ b/test/writer/enum_model_writer/generate_extension_custom_property/output.txt @@ -1,6 +1,7 @@ // GENERATED CODE - DO NOT MODIFY BY HAND import 'package:json_annotation/json_annotation.dart'; +import 'package:model_generator/util/extension/list_extension.dart'; enum Person { @JsonValue(1) @@ -28,7 +29,7 @@ enum Person { } extension PersonExtension on Person { - static Person fromJsonValue(int value) => Person.values.firstWhere((enumValue) => enumValue.jsonKey == value); + static Person? fromJsonValue(int value) => Person.values.firstWhereOrNull((enumValue) => enumValue.jsonKey == value); int toJsonValue() => jsonKey; } diff --git a/test/writer/enum_model_writer/generate_extension_normal/output.txt b/test/writer/enum_model_writer/generate_extension_normal/output.txt index ad122a0..6bea381 100644 --- a/test/writer/enum_model_writer/generate_extension_normal/output.txt +++ b/test/writer/enum_model_writer/generate_extension_normal/output.txt @@ -1,6 +1,7 @@ // GENERATED CODE - DO NOT MODIFY BY HAND import 'package:json_annotation/json_annotation.dart'; +import 'package:model_generator/util/extension/list_extension.dart'; enum MyEnumModel { @JsonValue('MY_VALUE_1') @@ -20,7 +21,7 @@ enum MyEnumModel { } extension MyEnumModelExtension on MyEnumModel { - static MyEnumModel fromJsonValue(String value) => MyEnumModel.values.firstWhere((enumValue) => enumValue.jsonValue == value); + static MyEnumModel? fromJsonValue(String value) => MyEnumModel.values.firstWhereOrNull((enumValue) => enumValue.jsonValue == value); String toJsonValue() => jsonValue; } diff --git a/test/writer/model_reader_test.dart b/test/writer/model_reader_test.dart index f715df7..d85897a 100644 --- a/test/writer/model_reader_test.dart +++ b/test/writer/model_reader_test.dart @@ -94,7 +94,8 @@ TestModel: expect(error, isNotNull); expect(error, isArgumentError); if (error is ArgumentError) { - expect(error.message, 'required is removed, follow the migration to version 7.0.0'); + expect(error.message, + 'required is removed, follow the migration to version 7.0.0'); } }); @@ -120,7 +121,8 @@ TestModel: expect(error, isNotNull); expect(error, isException); if (error is Exception) { - expect(error.toString(), 'Exception: Could not generate all models. `array` is not added to the config file'); + expect(error.toString(), + 'Exception: Could not generate all models. `array` is not added to the config file'); } }); @@ -147,7 +149,8 @@ TestModel: expect(error, isNotNull); expect(error, isException); if (error is Exception) { - expect(error.toString(), 'Exception: Could not generate all models. `map` is not added to the config file'); + expect(error.toString(), + 'Exception: Could not generate all models. `map` is not added to the config file'); } }); From 333ad21c69987458fa11be9c52ea8e4123b5fc3a Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Fri, 8 Sep 2023 15:03:49 +0200 Subject: [PATCH 33/42] #130: removed include if null when value is not nullable --- lib/config/yml_generator_config.dart | 114 ++++++------------ .../object_model_writer/array/output.txt | 2 +- .../dart-import/output.txt | 2 +- .../dart-package-import/output.txt | 2 +- .../output.txt | 2 +- .../default-field-required/output.txt | 2 +- .../extend-fields-twice/output.txt | 2 +- .../output.txt | 2 +- .../extend-fields/output.txt | 2 +- .../output.txt | 2 +- .../generate-for-generics-override/output.txt | 2 +- .../generate-for-generics/output.txt | 2 +- .../list_in_map/output.txt | 14 +-- .../writer/object_model_writer/map/output.txt | 2 +- .../object_model_writer/nullsafety/output.txt | 2 +- .../package-import/output.txt | 2 +- .../object_model_writer/required/output.txt | 2 +- .../object_model_writer/sort/output.txt | 4 +- .../to-json-from-json-handler/output.txt | 2 +- .../to-json-from-json/output.txt | 2 +- .../unknown-enum-value/output.txt | 2 +- .../without-path/output.txt | 2 +- 22 files changed, 64 insertions(+), 106 deletions(-) diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index 2dc5028..d50601c 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -27,20 +27,16 @@ class YmlGeneratorConfig { List get models => _models; - YmlGeneratorConfig( - PubspecConfig pubspecConfig, String configContent, this.fileName) { + YmlGeneratorConfig(PubspecConfig pubspecConfig, String configContent, this.fileName) { final yamlContent = loadYaml(configContent); if (yamlContent == null) return; // Ignore empty file yamlContent.forEach((key, value) { - final String baseDirectory = - value['base_directory'] ?? pubspecConfig.baseDirectory; + final String baseDirectory = value['base_directory'] ?? pubspecConfig.baseDirectory; final String? path = value['path']; final String? extendsModel = value['extends']; - final bool generateForGenerics = - value['generate_for_generics'] ?? pubspecConfig.generateForGenerics; + final bool generateForGenerics = value['generate_for_generics'] ?? pubspecConfig.generateForGenerics; - final extraImports = - value.containsKey('extra_imports') ? [] : null; + final extraImports = value.containsKey('extra_imports') ? [] : null; final extraImportsVal = value['extra_imports']; extraImportsVal?.forEach((e) { if (e != null) { @@ -48,8 +44,7 @@ class YmlGeneratorConfig { } }); - final extraAnnotations = - value.containsKey('extra_annotations') ? [] : null; + final extraAnnotations = value.containsKey('extra_annotations') ? [] : null; final extraAnnotationsVal = value['extra_annotations']; extraAnnotationsVal?.forEach((e) { if (e != null) { @@ -93,24 +88,20 @@ class YmlGeneratorConfig { throw Exception('Properties can not be null. model: $key'); } if (properties is! YamlMap?) { - throw Exception( - 'Properties should be a map, right now you are using a ${properties.runtimeType}. model: $key'); + throw Exception('Properties should be a map, right now you are using a ${properties.runtimeType}. model: $key'); } if (type == 'enum') { final deprecatedItemType = value['item_type']; if (deprecatedItemType != null) { - throw Exception( - 'item_type is removed, follow the migration to version 7.0.0'); + throw Exception('item_type is removed, follow the migration to version 7.0.0'); } final deprecatedGenerateMap = value['generate_map']; if (deprecatedGenerateMap != null) { - throw Exception( - 'generate_map is removed, follow the migration to version 7.0.0'); + throw Exception('generate_map is removed, follow the migration to version 7.0.0'); } - final uppercaseEnums = - (value['uppercase_enums'] ?? pubspecConfig.uppercaseEnums) == true; + final uppercaseEnums = (value['uppercase_enums'] ?? pubspecConfig.uppercaseEnums) == true; final fields = []; final enumProperties = []; @@ -133,17 +124,12 @@ class YmlGeneratorConfig { } final optional = type.endsWith('?'); - final typeString = - optional ? type.substring(0, type.length - 1) : type; + final typeString = optional ? type.substring(0, type.length - 1) : type; itemType = _parseSimpleType(typeString); - if (itemType is! StringType && - itemType is! DoubleType && - itemType is! IntegerType && - itemType is! BooleanType) { - throw Exception( - '$propertyKey should have a type of integer, boolean, double or string'); + if (itemType is! StringType && itemType is! DoubleType && itemType is! IntegerType && itemType is! BooleanType) { + throw Exception('$propertyKey should have a type of integer, boolean, double or string'); } enumProperties.add(EnumProperty( @@ -203,23 +189,18 @@ class YmlGeneratorConfig { models.add(enumModel); } else { final staticCreate = (value['static_create'] ?? false) == true; - final disallowNullForDefaults = - value.containsKey('disallow_null_for_defaults') - ? (value['disallow_null_for_defaults'] == true) - : pubspecConfig.disallowNullForDefaults; + final disallowNullForDefaults = value.containsKey('disallow_null_for_defaults') ? (value['disallow_null_for_defaults'] == true) : pubspecConfig.disallowNullForDefaults; final fields = []; properties?.forEach((propertyKey, propertyValue) { if (propertyValue is YamlMap) { - fields.add(getField(propertyKey, propertyValue, - disallowNullForDefaults: disallowNullForDefaults)); + fields.add(getField(propertyKey, propertyValue, disallowNullForDefaults: disallowNullForDefaults)); } else if (propertyValue is String) { fields.add(getSimpleField(name: propertyKey, value: propertyValue)); } else { throw Exception('$propertyKey should be an object'); } }); - final mappedConverters = - converters?.map((element) => element.toString()).toList(); + final mappedConverters = converters?.map((element) => element.toString()).toList(); models.add(ObjectModel( name: key, path: path, @@ -241,36 +222,25 @@ class YmlGeneratorConfig { }); } - Field getField(String name, YamlMap property, - {required bool disallowNullForDefaults}) { + Field getField(String name, YamlMap property, {required bool disallowNullForDefaults}) { try { if (property.containsKey('required')) { - throw ArgumentError( - 'required is removed, follow the migration to version 7.0.0'); + throw ArgumentError('required is removed, follow the migration to version 7.0.0'); } - final ignored = - property.containsKey('ignore') && property['ignore'] == true; - final includeFromJson = !property.containsKey('includeFromJson') || - property['includeFromJson'] == true; - final includeToJson = !property.containsKey('includeToJson') || - property['includeToJson'] == true; - final nonFinal = ignored || - property.containsKey('non_final') && property['non_final'] == true; - final includeIfNull = property.containsKey('include_if_null') && - property['include_if_null'] == true; + final ignored = property.containsKey('ignore') && property['ignore'] == true; + final includeFromJson = !property.containsKey('includeFromJson') || property['includeFromJson'] == true; + final includeToJson = !property.containsKey('includeToJson') || property['includeToJson'] == true; + final nonFinal = ignored || property.containsKey('non_final') && property['non_final'] == true; + final includeIfNull = property.containsKey('include_if_null') && property['include_if_null'] == true; final unknownEnumValue = property['unknown_enum_value']; final jsonKey = property['jsonKey'] ?? property['jsonkey']; final fromJson = property['fromJson']; final toJson = property['toJson']; - final description = property.containsKey('description') - ? property['description']!.toString() - : null; + final description = property.containsKey('description') ? property['description']!.toString() : null; final type = property['type'] as String?; final skipEquality = property['ignore_equality'] == true; final defaultValue = property['default_value']?.toString(); - final disallowNull = property.containsKey('disallow_null') - ? (property['disallow_null'] == true) - : disallowNullForDefaults; + final disallowNull = property.containsKey('disallow_null') ? (property['disallow_null'] == true) : disallowNullForDefaults; ItemType itemType; if (type == null) { @@ -291,7 +261,7 @@ class YmlGeneratorConfig { jsonKey: jsonKey, nonFinal: nonFinal, description: description, - includeIfNull: includeIfNull, + includeIfNull: optional ? includeIfNull : true, unknownEnumValue: unknownEnumValue, fromJson: fromJson, toJson: toJson, @@ -318,7 +288,7 @@ class YmlGeneratorConfig { ignore: false, includeToJson: true, includeFromJson: true, - includeIfNull: false, + includeIfNull: optional ? false : true, nonFinal: false, ignoreEquality: false, ); @@ -336,9 +306,7 @@ class YmlGeneratorConfig { return 'DateTime'; } else if (lowerType == 'int' || lowerType == 'integer') { return 'int'; - } else if (lowerType == 'object' || - lowerType == 'dynamic' || - lowerType == 'any') { + } else if (lowerType == 'object' || lowerType == 'dynamic' || lowerType == 'any') { return 'dynamic'; } else { return typeName; @@ -353,8 +321,7 @@ class YmlGeneratorConfig { //Maybe a generic final dartType = DartType(name); if (dartType.generics.isEmpty) { - throw Exception( - 'getPathForName is null: because `$name` was not added to the config file'); + throw Exception('getPathForName is null: because `$name` was not added to the config file'); } final paths = {}; for (final element in dartType.generics) { @@ -362,8 +329,7 @@ class YmlGeneratorConfig { } return paths; } else { - final baseDirectory = - foundModel.baseDirectory ?? pubspecConfig.baseDirectory; + final baseDirectory = foundModel.baseDirectory ?? pubspecConfig.baseDirectory; final path = foundModel.path; if (path == null) { return [baseDirectory]; @@ -417,26 +383,22 @@ class YmlGeneratorConfig { Model? getModelByName(ItemType itemType) { if (itemType is! ObjectType) return null; - final model = - models.firstWhereOrNull((model) => model.name == itemType.name); + final model = models.firstWhereOrNull((model) => model.name == itemType.name); if (model == null) { - throw Exception( - 'getModelByName is null: because `${itemType.name}` was not added to the config file'); + throw Exception('getModelByName is null: because `${itemType.name}` was not added to the config file'); } return model; } void checkTypesKnown(final Set names, String type) { if (!TypeChecker.isKnownDartType(type) && !names.contains(type)) { - throw Exception( - 'Could not generate all models. `$type` is not added to the config file, but is extended. These types are known: ${names.join(',')}'); + throw Exception('Could not generate all models. `$type` is not added to the config file, but is extended. These types are known: ${names.join(',')}'); } } ItemType _parseSimpleType(String type) { final listRegex = RegExp(r'^\s*[Ll]ist<\s*([a-zA-Z_0-9<>]*)\s*>\s*$'); - final mapRegex = - RegExp(r'^\s*[Mm]ap<([a-zA-Z_0-9<>]*)\s*,\s*([a-zA-Z_0-9<>]*)\s*>\s*$'); + final mapRegex = RegExp(r'^\s*[Mm]ap<([a-zA-Z_0-9<>]*)\s*,\s*([a-zA-Z_0-9<>]*)\s*>\s*$'); final lowerType = type.toLowerCase(); @@ -457,21 +419,17 @@ class YmlGeneratorConfig { return ArrayType(_makeGenericName(arrayType)); } else if (mapRegex.hasMatch(type)) { final match = mapRegex.firstMatch(type)!; - return MapType( - key: _makeGenericName(match.group(1)!), - valueName: _makeGenericName(match.group(2)!)); + return MapType(key: _makeGenericName(match.group(1)!), valueName: _makeGenericName(match.group(2)!)); } return ObjectType(type); } - YmlGeneratorConfig.merge(Iterable configs, String dirName) - : fileName = dirName { + YmlGeneratorConfig.merge(Iterable configs, String dirName) : fileName = dirName { final names = {}; for (final config in configs) { for (final model in config.models) { if (names.containsKey(model.name)) { - throw Exception( - 'Model with same name ${model.name} found in multiple files: ${names[model.name]!.fileName} and ${config.fileName}'); + throw Exception('Model with same name ${model.name} found in multiple files: ${names[model.name]!.fileName} and ${config.fileName}'); } names[model.name] = config; } diff --git a/test/writer/object_model_writer/array/output.txt b/test/writer/object_model_writer/array/output.txt index 604ce9c..2b9ef7f 100644 --- a/test/writer/object_model_writer/array/output.txt +++ b/test/writer/object_model_writer/array/output.txt @@ -6,7 +6,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'info', required: true, includeIfNull: false) + @JsonKey(name: 'info', required: true) final List info; const Person({ diff --git a/test/writer/object_model_writer/dart-import/output.txt b/test/writer/object_model_writer/dart-import/output.txt index 4601c28..aed5bf5 100644 --- a/test/writer/object_model_writer/dart-import/output.txt +++ b/test/writer/object_model_writer/dart-import/output.txt @@ -7,7 +7,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'address', required: true, includeIfNull: false) + @JsonKey(name: 'address', required: true) final Address address; const Person({ diff --git a/test/writer/object_model_writer/dart-package-import/output.txt b/test/writer/object_model_writer/dart-package-import/output.txt index 1dd2b74..420f6b6 100644 --- a/test/writer/object_model_writer/dart-package-import/output.txt +++ b/test/writer/object_model_writer/dart-package-import/output.txt @@ -7,7 +7,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'address', required: true, includeIfNull: false) + @JsonKey(name: 'address', required: true) final Address address; const Person({ diff --git a/test/writer/object_model_writer/default-field-required-null-disallowed/output.txt b/test/writer/object_model_writer/default-field-required-null-disallowed/output.txt index e4ba12c..ab50d35 100644 --- a/test/writer/object_model_writer/default-field-required-null-disallowed/output.txt +++ b/test/writer/object_model_writer/default-field-required-null-disallowed/output.txt @@ -7,7 +7,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { ///A good description - @JsonKey(name: 'firstName', required: false, disallowNullValue: true, includeIfNull: false) + @JsonKey(name: 'firstName', required: false, disallowNullValue: true) final String firstName; const Person({ diff --git a/test/writer/object_model_writer/default-field-required/output.txt b/test/writer/object_model_writer/default-field-required/output.txt index c3c1300..bfd7965 100644 --- a/test/writer/object_model_writer/default-field-required/output.txt +++ b/test/writer/object_model_writer/default-field-required/output.txt @@ -7,7 +7,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { ///A good description - @JsonKey(name: 'firstName', required: false, disallowNullValue: false, includeIfNull: false) + @JsonKey(name: 'firstName', required: false, disallowNullValue: false) final String firstName; const Person({ diff --git a/test/writer/object_model_writer/extend-fields-twice/output.txt b/test/writer/object_model_writer/extend-fields-twice/output.txt index c1ed25b..6c53aba 100644 --- a/test/writer/object_model_writer/extend-fields-twice/output.txt +++ b/test/writer/object_model_writer/extend-fields-twice/output.txt @@ -7,7 +7,7 @@ part 'admin.g.dart'; @JsonSerializable(explicitToJson: true) class Admin extends User { - @JsonKey(name: 'permission', required: true, includeIfNull: false) + @JsonKey(name: 'permission', required: true) final String permission; const Admin({ diff --git a/test/writer/object_model_writer/extend-fields-with-non-dart-type/output.txt b/test/writer/object_model_writer/extend-fields-with-non-dart-type/output.txt index 32d7f44..ea8d530 100644 --- a/test/writer/object_model_writer/extend-fields-with-non-dart-type/output.txt +++ b/test/writer/object_model_writer/extend-fields-with-non-dart-type/output.txt @@ -8,7 +8,7 @@ part 'user.g.dart'; @JsonSerializable(explicitToJson: true) class User extends Person { - @JsonKey(name: 'email', required: true, includeIfNull: false) + @JsonKey(name: 'email', required: true) final String email; const User({ diff --git a/test/writer/object_model_writer/extend-fields/output.txt b/test/writer/object_model_writer/extend-fields/output.txt index 2f1181c..05c7a39 100644 --- a/test/writer/object_model_writer/extend-fields/output.txt +++ b/test/writer/object_model_writer/extend-fields/output.txt @@ -7,7 +7,7 @@ part 'user.g.dart'; @JsonSerializable(explicitToJson: true) class User extends Person { - @JsonKey(name: 'email', required: true, includeIfNull: false) + @JsonKey(name: 'email', required: true) final String email; const User({ diff --git a/test/writer/object_model_writer/generate-for-generics-override-2/output.txt b/test/writer/object_model_writer/generate-for-generics-override-2/output.txt index 45ecac2..89d8f73 100644 --- a/test/writer/object_model_writer/generate-for-generics-override-2/output.txt +++ b/test/writer/object_model_writer/generate-for-generics-override-2/output.txt @@ -6,7 +6,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'firstName', required: true, includeIfNull: false) + @JsonKey(name: 'firstName', required: true) final String firstName; const Person({ diff --git a/test/writer/object_model_writer/generate-for-generics-override/output.txt b/test/writer/object_model_writer/generate-for-generics-override/output.txt index 8888f33..fc3a2e5 100644 --- a/test/writer/object_model_writer/generate-for-generics-override/output.txt +++ b/test/writer/object_model_writer/generate-for-generics-override/output.txt @@ -6,7 +6,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'firstName', required: true, includeIfNull: false) + @JsonKey(name: 'firstName', required: true) final String firstName; const Person({ diff --git a/test/writer/object_model_writer/generate-for-generics/output.txt b/test/writer/object_model_writer/generate-for-generics/output.txt index 8888f33..fc3a2e5 100644 --- a/test/writer/object_model_writer/generate-for-generics/output.txt +++ b/test/writer/object_model_writer/generate-for-generics/output.txt @@ -6,7 +6,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'firstName', required: true, includeIfNull: false) + @JsonKey(name: 'firstName', required: true) final String firstName; const Person({ diff --git a/test/writer/object_model_writer/list_in_map/output.txt b/test/writer/object_model_writer/list_in_map/output.txt index 2456aac..5e81d69 100644 --- a/test/writer/object_model_writer/list_in_map/output.txt +++ b/test/writer/object_model_writer/list_in_map/output.txt @@ -8,19 +8,19 @@ part 'project_wrapper.g.dart'; @JsonSerializable(explicitToJson: true) class ProjectWrapper { - @JsonKey(name: 'projectByInt', required: true, includeIfNull: false) + @JsonKey(name: 'projectByInt', required: true) final Map> projectByInt; - @JsonKey(name: 'projectByString', required: true, includeIfNull: false) + @JsonKey(name: 'projectByString', required: true) final Map> projectByString; - @JsonKey(name: 'projectByEnum', required: true, includeIfNull: false) + @JsonKey(name: 'projectByEnum', required: true) final Map> projectByEnum; - @JsonKey(name: 'StringsByString', required: true, includeIfNull: false) + @JsonKey(name: 'StringsByString', required: true) final Map> stringsByString; - @JsonKey(name: 'intsByString', required: true, includeIfNull: false) + @JsonKey(name: 'intsByString', required: true) final Map> intsByString; - @JsonKey(name: 'intsByDateTime', required: true, includeIfNull: false) + @JsonKey(name: 'intsByDateTime', required: true) final Map> intsByDateTime; - @JsonKey(name: 'intsBydynamic', required: true, includeIfNull: false) + @JsonKey(name: 'intsBydynamic', required: true) final Map> intsBydynamic; const ProjectWrapper({ diff --git a/test/writer/object_model_writer/map/output.txt b/test/writer/object_model_writer/map/output.txt index 8f4e6d5..14bd8f3 100644 --- a/test/writer/object_model_writer/map/output.txt +++ b/test/writer/object_model_writer/map/output.txt @@ -6,7 +6,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'info', required: true, includeIfNull: false) + @JsonKey(name: 'info', required: true) final Map info; const Person({ diff --git a/test/writer/object_model_writer/nullsafety/output.txt b/test/writer/object_model_writer/nullsafety/output.txt index ba4613f..2bd57d7 100644 --- a/test/writer/object_model_writer/nullsafety/output.txt +++ b/test/writer/object_model_writer/nullsafety/output.txt @@ -6,7 +6,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'firstName', required: true, includeIfNull: false) + @JsonKey(name: 'firstName', required: true) final String firstName; @JsonKey(name: 'lastName', includeIfNull: false) final String? lastName; diff --git a/test/writer/object_model_writer/package-import/output.txt b/test/writer/object_model_writer/package-import/output.txt index 607cac0..5f1ccf9 100644 --- a/test/writer/object_model_writer/package-import/output.txt +++ b/test/writer/object_model_writer/package-import/output.txt @@ -7,7 +7,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'address', required: true, includeIfNull: false) + @JsonKey(name: 'address', required: true) final Address address; const Person({ diff --git a/test/writer/object_model_writer/required/output.txt b/test/writer/object_model_writer/required/output.txt index 45ecac2..89d8f73 100644 --- a/test/writer/object_model_writer/required/output.txt +++ b/test/writer/object_model_writer/required/output.txt @@ -6,7 +6,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'firstName', required: true, includeIfNull: false) + @JsonKey(name: 'firstName', required: true) final String firstName; const Person({ diff --git a/test/writer/object_model_writer/sort/output.txt b/test/writer/object_model_writer/sort/output.txt index 7f3d24f..b96ff33 100644 --- a/test/writer/object_model_writer/sort/output.txt +++ b/test/writer/object_model_writer/sort/output.txt @@ -6,9 +6,9 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'x', required: true, includeIfNull: false) + @JsonKey(name: 'x', required: true) final String x; - @JsonKey(name: 'a', required: true, includeIfNull: false) + @JsonKey(name: 'a', required: true) final String a; @JsonKey(name: 'b', includeIfNull: false) final String? b; diff --git a/test/writer/object_model_writer/to-json-from-json-handler/output.txt b/test/writer/object_model_writer/to-json-from-json-handler/output.txt index 9c31fe6..96843e6 100644 --- a/test/writer/object_model_writer/to-json-from-json-handler/output.txt +++ b/test/writer/object_model_writer/to-json-from-json-handler/output.txt @@ -8,7 +8,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'address', required: true, includeIfNull: false, fromJson: Handler.handleFromJson, toJson: Handler.handleToJson) + @JsonKey(name: 'address', required: true, fromJson: Handler.handleFromJson, toJson: Handler.handleToJson) final Address address; const Person({ diff --git a/test/writer/object_model_writer/to-json-from-json/output.txt b/test/writer/object_model_writer/to-json-from-json/output.txt index 8ae9c03..cf0af9d 100644 --- a/test/writer/object_model_writer/to-json-from-json/output.txt +++ b/test/writer/object_model_writer/to-json-from-json/output.txt @@ -7,7 +7,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'address', required: true, includeIfNull: false, fromJson: handleFromJson, toJson: handleToJson) + @JsonKey(name: 'address', required: true, fromJson: handleFromJson, toJson: handleToJson) final Address address; const Person({ diff --git a/test/writer/object_model_writer/unknown-enum-value/output.txt b/test/writer/object_model_writer/unknown-enum-value/output.txt index 3174953..b6260ac 100644 --- a/test/writer/object_model_writer/unknown-enum-value/output.txt +++ b/test/writer/object_model_writer/unknown-enum-value/output.txt @@ -7,7 +7,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'gender', required: true, includeIfNull: false, unknownEnumValue: Gender.X) + @JsonKey(name: 'gender', required: true, unknownEnumValue: Gender.X) final Gender gender; const Person({ diff --git a/test/writer/object_model_writer/without-path/output.txt b/test/writer/object_model_writer/without-path/output.txt index d68f1ff..941fe23 100644 --- a/test/writer/object_model_writer/without-path/output.txt +++ b/test/writer/object_model_writer/without-path/output.txt @@ -7,7 +7,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { - @JsonKey(name: 'address', required: true, includeIfNull: false) + @JsonKey(name: 'address', required: true) final Address address; const Person({ From ba64675610ae8d09461d093f8c2b1d9d1c29d5c1 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Fri, 8 Sep 2023 15:04:47 +0200 Subject: [PATCH 34/42] #130: ran model gen --- example/lib/model/ogm.dart | 14 +-- example/lib/model/user/person/person.dart | 8 +- .../user/profile/admin_profile_data.dart | 2 +- .../model/user/profile/user_profile_data.dart | 14 +-- .../profile/user_profile_data_extended.dart | 2 +- example/lib/model/user/project/project.dart | 6 +- .../model/user/project/project_wrapper.dart | 2 +- example/lib/model/user/testing.dart | 2 +- lib/config/yml_generator_config.dart | 110 ++++++++++++------ 9 files changed, 97 insertions(+), 63 deletions(-) diff --git a/example/lib/model/ogm.dart b/example/lib/model/ogm.dart index 7829194..aebfd7e 100644 --- a/example/lib/model/ogm.dart +++ b/example/lib/model/ogm.dart @@ -9,19 +9,19 @@ part 'ogm.g.dart'; @JsonSerializable(explicitToJson: true) @DateTimeConverter() class OGM { - @JsonKey(name: 'beneficiary', required: true, includeIfNull: false) + @JsonKey(name: 'beneficiary', required: true) final String beneficiary; - @JsonKey(name: 'beneficiaryIBAN', required: true, includeIfNull: false) + @JsonKey(name: 'beneficiaryIBAN', required: true) final String beneficiaryIBAN; - @JsonKey(name: 'test_Test', required: true, includeIfNull: false) + @JsonKey(name: 'test_Test', required: true) final String testTest; - @JsonKey(name: 'some_Thing', required: true, includeIfNull: false) + @JsonKey(name: 'some_Thing', required: true) final String someThing; - @JsonKey(name: 'some_ThinG_huGE', required: true, includeIfNull: false) + @JsonKey(name: 'some_ThinG_huGE', required: true) final String someThinGHuGE; - @JsonKey(name: 'simpleFields', required: true, includeIfNull: false) + @JsonKey(name: 'simpleFields', required: true) final List simpleFields; - @JsonKey(name: 'listMap', required: true, includeIfNull: false) + @JsonKey(name: 'listMap', required: true) final Map> listMap; @JsonKey(name: 'structuredMessage', includeIfNull: false) final String? structuredMessage; diff --git a/example/lib/model/user/person/person.dart b/example/lib/model/user/person/person.dart index 1606912..bcc2d21 100644 --- a/example/lib/model/user/person/person.dart +++ b/example/lib/model/user/person/person.dart @@ -9,13 +9,9 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) @immutable class Person { - @JsonKey(name: 'firstName', required: true, includeIfNull: false) + @JsonKey(name: 'firstName', required: true) final String firstName; - @JsonKey( - name: 'gender', - required: true, - includeIfNull: false, - unknownEnumValue: Gender.X) + @JsonKey(name: 'gender', required: true, unknownEnumValue: Gender.X) final Gender gender; const Person({ diff --git a/example/lib/model/user/profile/admin_profile_data.dart b/example/lib/model/user/profile/admin_profile_data.dart index ac5a8af..fbcb67c 100644 --- a/example/lib/model/user/profile/admin_profile_data.dart +++ b/example/lib/model/user/profile/admin_profile_data.dart @@ -12,7 +12,7 @@ part 'admin_profile_data.g.dart'; @JsonSerializable(explicitToJson: true) @immutable class AdminProfileData extends UserProfileDataExtended { - @JsonKey(name: 'privileges', required: true, includeIfNull: false) + @JsonKey(name: 'privileges', required: true) final String privileges; const AdminProfileData({ diff --git a/example/lib/model/user/profile/user_profile_data.dart b/example/lib/model/user/profile/user_profile_data.dart index 84b9c2d..ebd73d8 100644 --- a/example/lib/model/user/profile/user_profile_data.dart +++ b/example/lib/model/user/profile/user_profile_data.dart @@ -11,19 +11,19 @@ part 'user_profile_data.g.dart'; @JsonSerializable(explicitToJson: true) @immutable class UserProfileData { - @JsonKey(name: 'firstName', required: true, includeIfNull: false) + @JsonKey(name: 'firstName', required: true) final String firstName; - @JsonKey(name: 'lastName', required: true, includeIfNull: false) + @JsonKey(name: 'lastName', required: true) final String lastName; - @JsonKey(name: 'standardLanguage', required: true, includeIfNull: false) + @JsonKey(name: 'standardLanguage', required: true) final String standardLanguage; - @JsonKey(name: 'mainAccountNumber', required: true, includeIfNull: false) + @JsonKey(name: 'mainAccountNumber', required: true) final String mainAccountNumber; - @JsonKey(name: 'legalEmail', required: true, includeIfNull: false) + @JsonKey(name: 'legalEmail', required: true) final String legalEmail; - @JsonKey(name: 'phones', required: true, includeIfNull: false) + @JsonKey(name: 'phones', required: true) final Testing phones; - @JsonKey(name: 'legalAddress', required: true, includeIfNull: false) + @JsonKey(name: 'legalAddress', required: true) final OGM legalAddress; @JsonKey(name: 'offTrack', includeIfNull: false) final List? offTrack; diff --git a/example/lib/model/user/profile/user_profile_data_extended.dart b/example/lib/model/user/profile/user_profile_data_extended.dart index c0e77fb..a4c6f19 100644 --- a/example/lib/model/user/profile/user_profile_data_extended.dart +++ b/example/lib/model/user/profile/user_profile_data_extended.dart @@ -12,7 +12,7 @@ part 'user_profile_data_extended.g.dart'; @JsonSerializable(explicitToJson: true) @immutable class UserProfileDataExtended extends UserProfileData { - @JsonKey(name: 'additionalField', required: true, includeIfNull: false) + @JsonKey(name: 'additionalField', required: true) final String additionalField; const UserProfileDataExtended({ diff --git a/example/lib/model/user/project/project.dart b/example/lib/model/user/project/project.dart index b9afa89..80bbf7d 100644 --- a/example/lib/model/user/project/project.dart +++ b/example/lib/model/user/project/project.dart @@ -9,11 +9,7 @@ part 'project.g.dart'; @JsonSerializable(explicitToJson: true) @immutable class Project { - @JsonKey( - name: 'name', - required: false, - disallowNullValue: false, - includeIfNull: false) + @JsonKey(name: 'name', required: false, disallowNullValue: false) final String name; @JsonKey(name: 'cost', includeIfNull: false) final double? cost; diff --git a/example/lib/model/user/project/project_wrapper.dart b/example/lib/model/user/project/project_wrapper.dart index c0965b7..27b1859 100644 --- a/example/lib/model/user/project/project_wrapper.dart +++ b/example/lib/model/user/project/project_wrapper.dart @@ -9,7 +9,7 @@ part 'project_wrapper.g.dart'; @JsonSerializable(explicitToJson: true) @immutable class ProjectWrapper { - @JsonKey(name: 'projectListById', required: true, includeIfNull: false) + @JsonKey(name: 'projectListById', required: true) final Map> projectListById; const ProjectWrapper({ diff --git a/example/lib/model/user/testing.dart b/example/lib/model/user/testing.dart index d99ceed..e6f8e2b 100644 --- a/example/lib/model/user/testing.dart +++ b/example/lib/model/user/testing.dart @@ -8,7 +8,7 @@ part 'testing.g.dart'; @JsonSerializable(explicitToJson: true) class Testing { - @JsonKey(name: 'beneficiary', required: true, includeIfNull: false) + @JsonKey(name: 'beneficiary', required: true) final String beneficiary; @JsonKey( name: 'isFavourite', diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index d50601c..063c3b5 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -27,16 +27,20 @@ class YmlGeneratorConfig { List get models => _models; - YmlGeneratorConfig(PubspecConfig pubspecConfig, String configContent, this.fileName) { + YmlGeneratorConfig( + PubspecConfig pubspecConfig, String configContent, this.fileName) { final yamlContent = loadYaml(configContent); if (yamlContent == null) return; // Ignore empty file yamlContent.forEach((key, value) { - final String baseDirectory = value['base_directory'] ?? pubspecConfig.baseDirectory; + final String baseDirectory = + value['base_directory'] ?? pubspecConfig.baseDirectory; final String? path = value['path']; final String? extendsModel = value['extends']; - final bool generateForGenerics = value['generate_for_generics'] ?? pubspecConfig.generateForGenerics; + final bool generateForGenerics = + value['generate_for_generics'] ?? pubspecConfig.generateForGenerics; - final extraImports = value.containsKey('extra_imports') ? [] : null; + final extraImports = + value.containsKey('extra_imports') ? [] : null; final extraImportsVal = value['extra_imports']; extraImportsVal?.forEach((e) { if (e != null) { @@ -44,7 +48,8 @@ class YmlGeneratorConfig { } }); - final extraAnnotations = value.containsKey('extra_annotations') ? [] : null; + final extraAnnotations = + value.containsKey('extra_annotations') ? [] : null; final extraAnnotationsVal = value['extra_annotations']; extraAnnotationsVal?.forEach((e) { if (e != null) { @@ -88,20 +93,24 @@ class YmlGeneratorConfig { throw Exception('Properties can not be null. model: $key'); } if (properties is! YamlMap?) { - throw Exception('Properties should be a map, right now you are using a ${properties.runtimeType}. model: $key'); + throw Exception( + 'Properties should be a map, right now you are using a ${properties.runtimeType}. model: $key'); } if (type == 'enum') { final deprecatedItemType = value['item_type']; if (deprecatedItemType != null) { - throw Exception('item_type is removed, follow the migration to version 7.0.0'); + throw Exception( + 'item_type is removed, follow the migration to version 7.0.0'); } final deprecatedGenerateMap = value['generate_map']; if (deprecatedGenerateMap != null) { - throw Exception('generate_map is removed, follow the migration to version 7.0.0'); + throw Exception( + 'generate_map is removed, follow the migration to version 7.0.0'); } - final uppercaseEnums = (value['uppercase_enums'] ?? pubspecConfig.uppercaseEnums) == true; + final uppercaseEnums = + (value['uppercase_enums'] ?? pubspecConfig.uppercaseEnums) == true; final fields = []; final enumProperties = []; @@ -124,12 +133,17 @@ class YmlGeneratorConfig { } final optional = type.endsWith('?'); - final typeString = optional ? type.substring(0, type.length - 1) : type; + final typeString = + optional ? type.substring(0, type.length - 1) : type; itemType = _parseSimpleType(typeString); - if (itemType is! StringType && itemType is! DoubleType && itemType is! IntegerType && itemType is! BooleanType) { - throw Exception('$propertyKey should have a type of integer, boolean, double or string'); + if (itemType is! StringType && + itemType is! DoubleType && + itemType is! IntegerType && + itemType is! BooleanType) { + throw Exception( + '$propertyKey should have a type of integer, boolean, double or string'); } enumProperties.add(EnumProperty( @@ -189,18 +203,23 @@ class YmlGeneratorConfig { models.add(enumModel); } else { final staticCreate = (value['static_create'] ?? false) == true; - final disallowNullForDefaults = value.containsKey('disallow_null_for_defaults') ? (value['disallow_null_for_defaults'] == true) : pubspecConfig.disallowNullForDefaults; + final disallowNullForDefaults = + value.containsKey('disallow_null_for_defaults') + ? (value['disallow_null_for_defaults'] == true) + : pubspecConfig.disallowNullForDefaults; final fields = []; properties?.forEach((propertyKey, propertyValue) { if (propertyValue is YamlMap) { - fields.add(getField(propertyKey, propertyValue, disallowNullForDefaults: disallowNullForDefaults)); + fields.add(getField(propertyKey, propertyValue, + disallowNullForDefaults: disallowNullForDefaults)); } else if (propertyValue is String) { fields.add(getSimpleField(name: propertyKey, value: propertyValue)); } else { throw Exception('$propertyKey should be an object'); } }); - final mappedConverters = converters?.map((element) => element.toString()).toList(); + final mappedConverters = + converters?.map((element) => element.toString()).toList(); models.add(ObjectModel( name: key, path: path, @@ -222,25 +241,36 @@ class YmlGeneratorConfig { }); } - Field getField(String name, YamlMap property, {required bool disallowNullForDefaults}) { + Field getField(String name, YamlMap property, + {required bool disallowNullForDefaults}) { try { if (property.containsKey('required')) { - throw ArgumentError('required is removed, follow the migration to version 7.0.0'); + throw ArgumentError( + 'required is removed, follow the migration to version 7.0.0'); } - final ignored = property.containsKey('ignore') && property['ignore'] == true; - final includeFromJson = !property.containsKey('includeFromJson') || property['includeFromJson'] == true; - final includeToJson = !property.containsKey('includeToJson') || property['includeToJson'] == true; - final nonFinal = ignored || property.containsKey('non_final') && property['non_final'] == true; - final includeIfNull = property.containsKey('include_if_null') && property['include_if_null'] == true; + final ignored = + property.containsKey('ignore') && property['ignore'] == true; + final includeFromJson = !property.containsKey('includeFromJson') || + property['includeFromJson'] == true; + final includeToJson = !property.containsKey('includeToJson') || + property['includeToJson'] == true; + final nonFinal = ignored || + property.containsKey('non_final') && property['non_final'] == true; + final includeIfNull = property.containsKey('include_if_null') && + property['include_if_null'] == true; final unknownEnumValue = property['unknown_enum_value']; final jsonKey = property['jsonKey'] ?? property['jsonkey']; final fromJson = property['fromJson']; final toJson = property['toJson']; - final description = property.containsKey('description') ? property['description']!.toString() : null; + final description = property.containsKey('description') + ? property['description']!.toString() + : null; final type = property['type'] as String?; final skipEquality = property['ignore_equality'] == true; final defaultValue = property['default_value']?.toString(); - final disallowNull = property.containsKey('disallow_null') ? (property['disallow_null'] == true) : disallowNullForDefaults; + final disallowNull = property.containsKey('disallow_null') + ? (property['disallow_null'] == true) + : disallowNullForDefaults; ItemType itemType; if (type == null) { @@ -306,7 +336,9 @@ class YmlGeneratorConfig { return 'DateTime'; } else if (lowerType == 'int' || lowerType == 'integer') { return 'int'; - } else if (lowerType == 'object' || lowerType == 'dynamic' || lowerType == 'any') { + } else if (lowerType == 'object' || + lowerType == 'dynamic' || + lowerType == 'any') { return 'dynamic'; } else { return typeName; @@ -321,7 +353,8 @@ class YmlGeneratorConfig { //Maybe a generic final dartType = DartType(name); if (dartType.generics.isEmpty) { - throw Exception('getPathForName is null: because `$name` was not added to the config file'); + throw Exception( + 'getPathForName is null: because `$name` was not added to the config file'); } final paths = {}; for (final element in dartType.generics) { @@ -329,7 +362,8 @@ class YmlGeneratorConfig { } return paths; } else { - final baseDirectory = foundModel.baseDirectory ?? pubspecConfig.baseDirectory; + final baseDirectory = + foundModel.baseDirectory ?? pubspecConfig.baseDirectory; final path = foundModel.path; if (path == null) { return [baseDirectory]; @@ -383,22 +417,26 @@ class YmlGeneratorConfig { Model? getModelByName(ItemType itemType) { if (itemType is! ObjectType) return null; - final model = models.firstWhereOrNull((model) => model.name == itemType.name); + final model = + models.firstWhereOrNull((model) => model.name == itemType.name); if (model == null) { - throw Exception('getModelByName is null: because `${itemType.name}` was not added to the config file'); + throw Exception( + 'getModelByName is null: because `${itemType.name}` was not added to the config file'); } return model; } void checkTypesKnown(final Set names, String type) { if (!TypeChecker.isKnownDartType(type) && !names.contains(type)) { - throw Exception('Could not generate all models. `$type` is not added to the config file, but is extended. These types are known: ${names.join(',')}'); + throw Exception( + 'Could not generate all models. `$type` is not added to the config file, but is extended. These types are known: ${names.join(',')}'); } } ItemType _parseSimpleType(String type) { final listRegex = RegExp(r'^\s*[Ll]ist<\s*([a-zA-Z_0-9<>]*)\s*>\s*$'); - final mapRegex = RegExp(r'^\s*[Mm]ap<([a-zA-Z_0-9<>]*)\s*,\s*([a-zA-Z_0-9<>]*)\s*>\s*$'); + final mapRegex = + RegExp(r'^\s*[Mm]ap<([a-zA-Z_0-9<>]*)\s*,\s*([a-zA-Z_0-9<>]*)\s*>\s*$'); final lowerType = type.toLowerCase(); @@ -419,17 +457,21 @@ class YmlGeneratorConfig { return ArrayType(_makeGenericName(arrayType)); } else if (mapRegex.hasMatch(type)) { final match = mapRegex.firstMatch(type)!; - return MapType(key: _makeGenericName(match.group(1)!), valueName: _makeGenericName(match.group(2)!)); + return MapType( + key: _makeGenericName(match.group(1)!), + valueName: _makeGenericName(match.group(2)!)); } return ObjectType(type); } - YmlGeneratorConfig.merge(Iterable configs, String dirName) : fileName = dirName { + YmlGeneratorConfig.merge(Iterable configs, String dirName) + : fileName = dirName { final names = {}; for (final config in configs) { for (final model in config.models) { if (names.containsKey(model.name)) { - throw Exception('Model with same name ${model.name} found in multiple files: ${names[model.name]!.fileName} and ${config.fileName}'); + throw Exception( + 'Model with same name ${model.name} found in multiple files: ${names[model.name]!.fileName} and ${config.fileName}'); } names[model.name] = config; } From 37c7f16600ced06ed1c1c3dda409b36bcf812b3a Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Fri, 8 Sep 2023 15:34:12 +0200 Subject: [PATCH 35/42] #130: force enum to lowercase by default --- CHANGELOG.md | 1 + README.md | 10 +++++----- example/lib/model/status/double_status.dart | 8 ++++---- example/lib/model/status/status.dart | 8 ++++---- example/lib/model/user/person/gender.dart | 18 ++++++++--------- example/lib/model/user/person/person.dart | 2 +- example/lib/model/user/person/person.g.dart | 20 +++++++++---------- example/lib/model/user/project/project.dart | 2 +- example/lib/model/user/project/project.g.dart | 10 +++++----- example/model_generator/config.yaml | 4 ++-- lib/config/pubspec_config.dart | 4 ++-- lib/config/yml_generator_config.dart | 2 +- 12 files changed, 45 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca40268..be73234 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## [7.0.0] - 2023-08-14 - *BREAKING CHANGE*: Every type is now defined inline, this means that 'required' is no longer supported, if a field isn't nullable it is automatically required. This also means that the 'array' type is no longer supported and is instead just defined like 'List'. - *BREAKING CHANGE*: The way enums are defined has changed, see readme for more information. You can now add properties to enums, optional and default values are supported. +- *BREAKING CHANGE*: Enums are now by default not uppercase anymore, you can still enable this my adding 'uppercase_enums: true' to your pubspec or enum configuration - Logs of build runner now get shown in real time. ## [6.3.0] - 2023-06-05 diff --git a/README.md b/README.md index a49cdd8..0772925 100755 --- a/README.md +++ b/README.md @@ -526,14 +526,14 @@ UnknownEnumTestObject: type: Gender ``` -### Automatic case conversion +### Automatic case conversion(v7.0.0) -By default all fields will be converted into uppercase. You can control this behavior globally for all enums or per-enum by setting the `uppercase_enums` property to `true` ( -default) or `false` +As of v7.0.0 by default all fields will be converted into lowercase instead of uppercase like before. You can control this behavior globally for all enums or per-enum by setting the `uppercase_enums` property to `false` ( +default) or `true` ```yaml model_generator: - uppercase_enums: false + uppercase_enums: true ``` or @@ -541,7 +541,7 @@ or ```yaml UnknownEnumTestObject: path: webservice - uppercase_enums: false + uppercase_enums: true properties: path: ``` diff --git a/example/lib/model/status/double_status.dart b/example/lib/model/status/double_status.dart index 7e31ce2..8eb8001 100644 --- a/example/lib/model/status/double_status.dart +++ b/example/lib/model/status/double_status.dart @@ -4,19 +4,19 @@ import 'package:json_annotation/json_annotation.dart'; enum DoubleStatus { @JsonValue(0.1) - STATUS_0( + status_0( value: 0.1, ), @JsonValue(1.1) - STATUS_1( + status_1( value: 1.1, ), @JsonValue(2.2) - STATUS_2( + status_2( value: 2.2, ), @JsonValue(3.3) - STATUS_3( + status_3( value: 3.3, ); diff --git a/example/lib/model/status/status.dart b/example/lib/model/status/status.dart index 0fc4231..7e87587 100644 --- a/example/lib/model/status/status.dart +++ b/example/lib/model/status/status.dart @@ -4,19 +4,19 @@ import 'package:json_annotation/json_annotation.dart'; enum Status { @JsonValue(0) - STATUS_0( + status_0( value: 0, ), @JsonValue(1) - STATUS_1( + status_1( value: 1, ), @JsonValue(2) - STATUS_2( + status_2( value: 2, ), @JsonValue(3) - STATUS_3( + status_3( value: 3, ); diff --git a/example/lib/model/user/person/gender.dart b/example/lib/model/user/person/gender.dart index 8019bc4..f589180 100644 --- a/example/lib/model/user/person/gender.dart +++ b/example/lib/model/user/person/gender.dart @@ -4,39 +4,39 @@ import 'package:json_annotation/json_annotation.dart'; enum Gender { @JsonValue('_mAl3') - MALE( + male( value: '_mAl3', ), @JsonValue('femAle') - FEMALE( + female( value: 'femAle', ), @JsonValue('X') - X( + x( value: 'X', ), @JsonValue('gender_x') - GENDER_X( + gender_x( value: 'gender_x', ), @JsonValue('gender_y') - GENDER_Y( + gender_y( value: 'gender_y', ), @JsonValue('gender_z') - GENDER_Z( + gender_z( value: 'gender_z', ), @JsonValue('gender_abc') - GENDER_ABC( + gender_abc( value: 'gender_abc', ), @JsonValue('gender_def') - GENDER_DEF( + gender_def( value: 'gender_def', ), @JsonValue('GENDER_lap') - GENDER_LAP( + gender_lap( value: 'GENDER_lap', ); diff --git a/example/lib/model/user/person/person.dart b/example/lib/model/user/person/person.dart index bcc2d21..ef92c5e 100644 --- a/example/lib/model/user/person/person.dart +++ b/example/lib/model/user/person/person.dart @@ -11,7 +11,7 @@ part 'person.g.dart'; class Person { @JsonKey(name: 'firstName', required: true) final String firstName; - @JsonKey(name: 'gender', required: true, unknownEnumValue: Gender.X) + @JsonKey(name: 'gender', required: true, unknownEnumValue: Gender.x) final Gender gender; const Person({ diff --git a/example/lib/model/user/person/person.g.dart b/example/lib/model/user/person/person.g.dart index 5b0b759..91e1f0a 100644 --- a/example/lib/model/user/person/person.g.dart +++ b/example/lib/model/user/person/person.g.dart @@ -14,7 +14,7 @@ Person _$PersonFromJson(Map json) { return Person( firstName: json['firstName'] as String, gender: - $enumDecode(_$GenderEnumMap, json['gender'], unknownValue: Gender.X), + $enumDecode(_$GenderEnumMap, json['gender'], unknownValue: Gender.x), ); } @@ -24,13 +24,13 @@ Map _$PersonToJson(Person instance) => { }; const _$GenderEnumMap = { - Gender.MALE: '_mAl3', - Gender.FEMALE: 'femAle', - Gender.X: 'X', - Gender.GENDER_X: 'gender_x', - Gender.GENDER_Y: 'gender_y', - Gender.GENDER_Z: 'gender_z', - Gender.GENDER_ABC: 'gender_abc', - Gender.GENDER_DEF: 'gender_def', - Gender.GENDER_LAP: 'GENDER_lap', + Gender.male: '_mAl3', + Gender.female: 'femAle', + Gender.x: 'X', + Gender.gender_x: 'gender_x', + Gender.gender_y: 'gender_y', + Gender.gender_z: 'gender_z', + Gender.gender_abc: 'gender_abc', + Gender.gender_def: 'gender_def', + Gender.gender_lap: 'GENDER_lap', }; diff --git a/example/lib/model/user/project/project.dart b/example/lib/model/user/project/project.dart index 80bbf7d..f338270 100644 --- a/example/lib/model/user/project/project.dart +++ b/example/lib/model/user/project/project.dart @@ -14,7 +14,7 @@ class Project { @JsonKey(name: 'cost', includeIfNull: false) final double? cost; @JsonKey( - name: 'status', includeIfNull: false, unknownEnumValue: Status.STATUS_0) + name: 'status', includeIfNull: false, unknownEnumValue: Status.status_0) final Status? status; const Project({ diff --git a/example/lib/model/user/project/project.g.dart b/example/lib/model/user/project/project.g.dart index bd63dd7..3fc44e7 100644 --- a/example/lib/model/user/project/project.g.dart +++ b/example/lib/model/user/project/project.g.dart @@ -10,7 +10,7 @@ Project _$ProjectFromJson(Map json) => Project( name: json['name'] as String? ?? 'test', cost: (json['cost'] as num?)?.toDouble() ?? 0.2, status: $enumDecodeNullable(_$StatusEnumMap, json['status'], - unknownValue: Status.STATUS_0), + unknownValue: Status.status_0), ); Map _$ProjectToJson(Project instance) { @@ -30,8 +30,8 @@ Map _$ProjectToJson(Project instance) { } const _$StatusEnumMap = { - Status.STATUS_0: 0, - Status.STATUS_1: 1, - Status.STATUS_2: 2, - Status.STATUS_3: 3, + Status.status_0: 0, + Status.status_1: 1, + Status.status_2: 2, + Status.status_3: 3, }; diff --git a/example/model_generator/config.yaml b/example/model_generator/config.yaml index 7ca741d..df234b7 100644 --- a/example/model_generator/config.yaml +++ b/example/model_generator/config.yaml @@ -107,7 +107,7 @@ Person: firstName: type: String gender: - unknown_enum_value: X + unknown_enum_value: x type: Gender Duration: @@ -149,7 +149,7 @@ Project: default_value: 0.2 status: type: Status? - unknown_enum_value: STATUS_0 + unknown_enum_value: status_0 ProjectWrapper: path: user/project/ diff --git a/lib/config/pubspec_config.dart b/lib/config/pubspec_config.dart index f5c1990..f151cde 100644 --- a/lib/config/pubspec_config.dart +++ b/lib/config/pubspec_config.dart @@ -50,7 +50,7 @@ class PubspecConfig { explicitToJson = true; generateToString = false; staticCreate = false; - uppercaseEnums = true; + uppercaseEnums = false; retrofitMappers = false; disallowNullForDefaults = false; return; @@ -64,7 +64,7 @@ class PubspecConfig { explicitToJson = (config['explicit_to_json'] ?? true) == true; generateToString = (config['to_string'] ?? false) == true; staticCreate = (config['static_create'] ?? false) == true; - uppercaseEnums = (config['uppercase_enums'] ?? true) == true; + uppercaseEnums = (config['uppercase_enums'] ?? false) == true; retrofitMappers = (config['retrofit_compute'] ?? false) == true; disallowNullForDefaults = (config['disallow_null_for_defaults'] ?? false) == true; diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index 063c3b5..f8f52ef 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -174,7 +174,7 @@ class YmlGeneratorConfig { ); }); fields.add(EnumField( - name: uppercaseEnums ? key.toUpperCase() : key, + name: uppercaseEnums ? key.toUpperCase() : key.toLowerCase(), rawName: key, values: enumValues, description: description, From 8b76a6461c2c6e9529adeef7efbc39919a6161c7 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Fri, 8 Sep 2023 15:38:56 +0200 Subject: [PATCH 36/42] #130: fixed tests --- test/writer/enum_model_writer/custom-value/output.txt | 4 ++-- test/writer/enum_model_writer/default_values/output.txt | 6 +++--- test/writer/enum_model_writer/description/output.txt | 4 ++-- test/writer/enum_model_writer/double_type/output.txt | 4 ++-- .../writer/enum_model_writer/field_description/output.txt | 4 ++-- test/writer/enum_model_writer/full_enum/output.txt | 6 +++--- .../generate_extension_custom_property/output.txt | 4 ++-- .../generate_extension_normal/output.txt | 4 ++-- test/writer/enum_model_writer/int_type/output.txt | 4 ++-- test/writer/enum_model_writer/normal/output.txt | 4 ++-- .../normal_no_default_json_key/output.txt | 4 ++-- test/writer/enum_model_writer/optional_values/output.txt | 4 ++-- .../enum_model_writer/optional_values_default/output.txt | 4 ++-- test/writer/enum_model_writer/string_type/output.txt | 4 ++-- .../enum_model_writer/use_default_json_value/output.txt | 8 ++++---- 15 files changed, 34 insertions(+), 34 deletions(-) diff --git a/test/writer/enum_model_writer/custom-value/output.txt b/test/writer/enum_model_writer/custom-value/output.txt index 773563d..5a59d1a 100644 --- a/test/writer/enum_model_writer/custom-value/output.txt +++ b/test/writer/enum_model_writer/custom-value/output.txt @@ -4,13 +4,13 @@ import 'package:json_annotation/json_annotation.dart'; enum Person { @JsonValue(1) - MAN( + man( jsonKey: 1, firstName: 'firstName1', lastName: 'lastName1', ), @JsonValue(2) - WOMAN( + woman( jsonKey: 2, firstName: 'firstName2', lastName: 'lastName2', diff --git a/test/writer/enum_model_writer/default_values/output.txt b/test/writer/enum_model_writer/default_values/output.txt index 8fad0e6..8eb0617 100644 --- a/test/writer/enum_model_writer/default_values/output.txt +++ b/test/writer/enum_model_writer/default_values/output.txt @@ -4,19 +4,19 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { @JsonValue('MY_VALUE_1') - MY_VALUE_1( + my_value_1( jsonValue: 'MY_VALUE_1', firstName: 'firstName', lastName: 'lastName', ), @JsonValue('MY_VALUE_2') - MY_VALUE_2( + my_value_2( jsonValue: 'MY_VALUE_2', firstName: 'firstName', lastName: 'lastName', ), @JsonValue('MY_VALUE_3') - MY_VALUE_3( + my_value_3( jsonValue: 'MY_VALUE_3', firstName: 'firstName', lastName: 'specifiedLastName', diff --git a/test/writer/enum_model_writer/description/output.txt b/test/writer/enum_model_writer/description/output.txt index 5ad103e..3eabd2c 100644 --- a/test/writer/enum_model_writer/description/output.txt +++ b/test/writer/enum_model_writer/description/output.txt @@ -5,11 +5,11 @@ import 'package:json_annotation/json_annotation.dart'; ///A good description of this enum enum MyEnumModel { @JsonValue('MY_VALUE_1') - MY_VALUE_1( + my_value_1( jsonValue: 'MY_VALUE_1', ), @JsonValue('MY_VALUE_2') - MY_VALUE_2( + my_value_2( jsonValue: 'MY_VALUE_2', ); diff --git a/test/writer/enum_model_writer/double_type/output.txt b/test/writer/enum_model_writer/double_type/output.txt index 65b28dc..e7f305f 100644 --- a/test/writer/enum_model_writer/double_type/output.txt +++ b/test/writer/enum_model_writer/double_type/output.txt @@ -4,11 +4,11 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { @JsonValue(1.2) - MY_VALUE_1( + my_value_1( value: 1.2, ), @JsonValue(2.2) - MY_VALUE_2( + my_value_2( value: 2.2, ); diff --git a/test/writer/enum_model_writer/field_description/output.txt b/test/writer/enum_model_writer/field_description/output.txt index 6d3944a..09db5a0 100644 --- a/test/writer/enum_model_writer/field_description/output.txt +++ b/test/writer/enum_model_writer/field_description/output.txt @@ -5,12 +5,12 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { ///This is value 1 @JsonValue('MY_VALUE_1') - MY_VALUE_1( + my_value_1( jsonValue: 'MY_VALUE_1', ), ///This is value 2 @JsonValue('MY_VALUE_2') - MY_VALUE_2( + my_value_2( jsonValue: 'MY_VALUE_2', ); diff --git a/test/writer/enum_model_writer/full_enum/output.txt b/test/writer/enum_model_writer/full_enum/output.txt index 2410327..20ae616 100644 --- a/test/writer/enum_model_writer/full_enum/output.txt +++ b/test/writer/enum_model_writer/full_enum/output.txt @@ -6,7 +6,7 @@ import 'package:json_annotation/json_annotation.dart'; enum Person { ///enum of a man @JsonValue(1) - MAN( + man( jsonKey: 1, firstName: 'firstName1', lastName: 'lastName', @@ -15,7 +15,7 @@ enum Person { ), ///enum of a woman @JsonValue(2) - WOMAN( + woman( jsonKey: 2, firstName: 'firstName2', lastName: 'lastName', @@ -24,7 +24,7 @@ enum Person { ), ///enum of a other @JsonValue(3) - OTHER( + other( jsonKey: 3, firstName: 'firstName3', lastName: 'SpecifiedLastName', diff --git a/test/writer/enum_model_writer/generate_extension_custom_property/output.txt b/test/writer/enum_model_writer/generate_extension_custom_property/output.txt index 3100105..19ffd54 100644 --- a/test/writer/enum_model_writer/generate_extension_custom_property/output.txt +++ b/test/writer/enum_model_writer/generate_extension_custom_property/output.txt @@ -5,13 +5,13 @@ import 'package:model_generator/util/extension/list_extension.dart'; enum Person { @JsonValue(1) - MAN( + man( jsonKey: 1, firstName: 'firstName1', lastName: 'lastName1', ), @JsonValue(2) - WOMAN( + woman( jsonKey: 2, firstName: 'firstName2', lastName: 'lastName2', diff --git a/test/writer/enum_model_writer/generate_extension_normal/output.txt b/test/writer/enum_model_writer/generate_extension_normal/output.txt index 6bea381..db8132f 100644 --- a/test/writer/enum_model_writer/generate_extension_normal/output.txt +++ b/test/writer/enum_model_writer/generate_extension_normal/output.txt @@ -5,11 +5,11 @@ import 'package:model_generator/util/extension/list_extension.dart'; enum MyEnumModel { @JsonValue('MY_VALUE_1') - MY_VALUE_1( + my_value_1( jsonValue: 'MY_VALUE_1', ), @JsonValue('MY_VALUE_2') - MY_VALUE_2( + my_value_2( jsonValue: 'MY_VALUE_2', ); diff --git a/test/writer/enum_model_writer/int_type/output.txt b/test/writer/enum_model_writer/int_type/output.txt index 58d7bd9..3485330 100644 --- a/test/writer/enum_model_writer/int_type/output.txt +++ b/test/writer/enum_model_writer/int_type/output.txt @@ -4,11 +4,11 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { @JsonValue(1) - MY_VALUE_1( + my_value_1( value: 1, ), @JsonValue(2) - MY_VALUE_2( + my_value_2( value: 2, ); diff --git a/test/writer/enum_model_writer/normal/output.txt b/test/writer/enum_model_writer/normal/output.txt index b069d4d..f646cc7 100644 --- a/test/writer/enum_model_writer/normal/output.txt +++ b/test/writer/enum_model_writer/normal/output.txt @@ -4,11 +4,11 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { @JsonValue('MY_VALUE_1') - MY_VALUE_1( + my_value_1( jsonValue: 'MY_VALUE_1', ), @JsonValue('MY_VALUE_2') - MY_VALUE_2( + my_value_2( jsonValue: 'MY_VALUE_2', ); diff --git a/test/writer/enum_model_writer/normal_no_default_json_key/output.txt b/test/writer/enum_model_writer/normal_no_default_json_key/output.txt index 0b50f98..0a1383e 100644 --- a/test/writer/enum_model_writer/normal_no_default_json_key/output.txt +++ b/test/writer/enum_model_writer/normal_no_default_json_key/output.txt @@ -4,7 +4,7 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { @JsonValue('MY_VALUE_1') - MY_VALUE_1, + my_value_1, @JsonValue('MY_VALUE_2') - MY_VALUE_2, + my_value_2, } diff --git a/test/writer/enum_model_writer/optional_values/output.txt b/test/writer/enum_model_writer/optional_values/output.txt index 236d2bd..6644930 100644 --- a/test/writer/enum_model_writer/optional_values/output.txt +++ b/test/writer/enum_model_writer/optional_values/output.txt @@ -4,13 +4,13 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { @JsonValue('MY_VALUE_1') - MY_VALUE_1( + my_value_1( jsonValue: 'MY_VALUE_1', firstName: 'firstName', lastName: 'lastName', ), @JsonValue('MY_VALUE_2') - MY_VALUE_2( + my_value_2( jsonValue: 'MY_VALUE_2', firstName: 'firstName', lastName: 'lastName', diff --git a/test/writer/enum_model_writer/optional_values_default/output.txt b/test/writer/enum_model_writer/optional_values_default/output.txt index 978c0a7..32cc7f7 100644 --- a/test/writer/enum_model_writer/optional_values_default/output.txt +++ b/test/writer/enum_model_writer/optional_values_default/output.txt @@ -4,13 +4,13 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { @JsonValue('MY_VALUE_1') - MY_VALUE_1( + my_value_1( jsonValue: 'MY_VALUE_1', firstName: 'firstName', lastName: null, ), @JsonValue('MY_VALUE_2') - MY_VALUE_2( + my_value_2( jsonValue: 'MY_VALUE_2', firstName: 'firstName', lastName: null, diff --git a/test/writer/enum_model_writer/string_type/output.txt b/test/writer/enum_model_writer/string_type/output.txt index f958f6f..a9b3ad7 100644 --- a/test/writer/enum_model_writer/string_type/output.txt +++ b/test/writer/enum_model_writer/string_type/output.txt @@ -4,11 +4,11 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { @JsonValue('my_value1') - MY_VALUE_1( + my_value_1( value: 'my_value1', ), @JsonValue('my_value2') - MY_VALUE_2( + my_value_2( value: 'my_value2', ); diff --git a/test/writer/enum_model_writer/use_default_json_value/output.txt b/test/writer/enum_model_writer/use_default_json_value/output.txt index 77a6c9f..c2b4057 100644 --- a/test/writer/enum_model_writer/use_default_json_value/output.txt +++ b/test/writer/enum_model_writer/use_default_json_value/output.txt @@ -4,19 +4,19 @@ import 'package:json_annotation/json_annotation.dart'; enum DoubleStatus { @JsonValue('customValue') - STATUS_0( + status_0( value: 'customValue', ), @JsonValue('status_1') - STATUS_1( + status_1( value: 'status_1', ), @JsonValue('status_2') - STATUS_2( + status_2( value: 'status_2', ), @JsonValue('status_3') - STATUS_3( + status_3( value: 'status_3', ); From c224aa3f814eabe14b33df1b4848ba1c325842d7 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Fri, 8 Sep 2023 15:43:06 +0200 Subject: [PATCH 37/42] #130: fixed remaining tests --- .../yml_generator_config/enum-normal.txt | 2 +- test/config/yml_generator_config_test.dart | 18 +++++++++--------- test/writer/enum_model_reader_test.dart | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/test/config/yml_generator_config/enum-normal.txt b/test/config/yml_generator_config/enum-normal.txt index efac2b8..c7a063d 100644 --- a/test/config/yml_generator_config/enum-normal.txt +++ b/test/config/yml_generator_config/enum-normal.txt @@ -26,7 +26,7 @@ Gender: Vehicles: type: enum - uppercase_enums: false + uppercase_enums: true properties: value: type: String diff --git a/test/config/yml_generator_config_test.dart b/test/config/yml_generator_config_test.dart index b7527b5..c66e501 100644 --- a/test/config/yml_generator_config_test.dart +++ b/test/config/yml_generator_config_test.dart @@ -173,43 +173,43 @@ void main() { expect(ymlConfig.models.first is ObjectModel, true); expect(ymlConfig.models[1] is EnumModel, true); expect(ymlConfig.models.last is EnumModel, true); - expect(pubspecConfig.uppercaseEnums, true); + expect(pubspecConfig.uppercaseEnums, false); final enumModel = ymlConfig.models[1] as EnumModel; // ignore: avoid_as final enumModel2 = ymlConfig.models[2] as EnumModel; // ignore: avoid_as expect(enumModel.fields, isNotNull); expect(enumModel.fields.length, 4); - expect(enumModel.fields[0].name, 'MALE'); + expect(enumModel.fields[0].name, 'male'); expect(enumModel.fields[0].serializedName, 'MALE'); expect(enumModel.fields[0].values[0].value, 'male'); expect(enumModel.fields[0].values[0].propertyName, 'value'); - expect(enumModel.fields[1].name, 'FEMALE'); + expect(enumModel.fields[1].name, 'female'); expect(enumModel.fields[1].serializedName, 'FEMALE'); expect(enumModel.fields[1].values[0].value, 'femAle'); expect(enumModel.fields[1].values[0].propertyName, 'value'); - expect(enumModel.fields[2].name, 'OTHER'); + expect(enumModel.fields[2].name, 'other'); expect(enumModel.fields[2].serializedName, 'other'); expect(enumModel.fields[2].values[0].value, 'other'); expect(enumModel.fields[2].values[0].propertyName, 'value'); - expect(enumModel.fields[3].name, 'X'); + expect(enumModel.fields[3].name, 'x'); expect(enumModel.fields[3].serializedName, 'X'); expect(enumModel.fields[3].values[0].value, 'x'); expect(enumModel.fields[3].values[0].propertyName, 'value'); expect(enumModel2.fields, isNotNull); expect(enumModel2.fields.length, 4); - expect(enumModel2.fields[0].name, 'male'); + expect(enumModel2.fields[0].name, 'MALE'); expect(enumModel2.fields[0].serializedName, 'male'); expect(enumModel.fields[0].values[0].value, 'male'); expect(enumModel.fields[0].values[0].propertyName, 'value'); - expect(enumModel2.fields[1].name, 'female'); + expect(enumModel2.fields[1].name, 'FEMALE'); expect(enumModel2.fields[1].serializedName, 'female'); expect(enumModel.fields[1].values[0].value, 'femAle'); expect(enumModel.fields[1].values[0].propertyName, 'value'); - expect(enumModel2.fields[2].name, 'other'); + expect(enumModel2.fields[2].name, 'OTHER'); expect(enumModel2.fields[2].serializedName, 'other'); expect(enumModel.fields[2].values[0].value, 'other'); expect(enumModel.fields[2].values[0].propertyName, 'value'); - expect(enumModel2.fields[3].name, 'x'); + expect(enumModel2.fields[3].name, 'X'); expect(enumModel2.fields[3].serializedName, 'x'); expect(enumModel.fields[3].values[0].value, 'x'); expect(enumModel.fields[3].values[0].propertyName, 'value'); diff --git a/test/writer/enum_model_reader_test.dart b/test/writer/enum_model_reader_test.dart index 069ac3d..00adc8c 100644 --- a/test/writer/enum_model_reader_test.dart +++ b/test/writer/enum_model_reader_test.dart @@ -169,7 +169,7 @@ Gender: }) { testEnumError( expectedError: - 'Exception: There is no value defined for property name for the enum value FEMALE in model Gender. Either make this property optional or give it a value', + 'Exception: There is no value defined for property name for the enum value female in model Gender. Either make this property optional or give it a value', enumYml: """ Gender: path: user/person/ @@ -200,7 +200,7 @@ Gender: 'Test enum with incorrect type bool', () => testEnumError( expectedError: - 'Exception: Model: Gender, Property isMale is of type bool but the corresponding value on enum value MALE is not, make sure they have the same type', + 'Exception: Model: Gender, Property isMale is of type bool but the corresponding value on enum value male is not, make sure they have the same type', enumYml: """ Gender: path: user/person/ @@ -224,7 +224,7 @@ Gender: 'Test enum with incorrect type integer', () => testEnumError( expectedError: - 'Exception: Model: Gender, Property isMale is of type int but the corresponding value on enum value MALE is not, make sure they have the same type', + 'Exception: Model: Gender, Property isMale is of type int but the corresponding value on enum value male is not, make sure they have the same type', enumYml: """ Gender: path: user/person/ @@ -248,7 +248,7 @@ Gender: 'Test enum with incorrect type double', () => testEnumError( expectedError: - 'Exception: Model: Gender, Property isMale is of type double but the corresponding value on enum value MALE is not, make sure they have the same type', + 'Exception: Model: Gender, Property isMale is of type double but the corresponding value on enum value male is not, make sure they have the same type', enumYml: """ Gender: path: user/person/ From 102ccbd1d9222e403a35aa961e8ca268568b9f49 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Fri, 8 Sep 2023 15:52:56 +0200 Subject: [PATCH 38/42] #130: updated readme --- README.md | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0772925..79a1c9e 100755 --- a/README.md +++ b/README.md @@ -392,6 +392,20 @@ Gender: Y: ``` +By default enums will be generated with a property called jsonValue. this is the value of the enum used when parsing from json. This will only be used when there isn't already a custom jsonValue defined using 'is_json_value: true' in the properties of the enum. To turn this behavior of you can use 'use_default_json_value: false'. + +```yaml +Gender: + path: webservice/user + use_default_json_value: false + type: enum + values: + MALE: + FEMALE: + X: + Y: +``` + Add enums with custom properties (currently supported types are int, double, bool and String) ```yaml @@ -508,7 +522,7 @@ The above configuration will generate an enum with this extension. ```dart extension PersonExtension on Person { - static Person fromJsonValue(int value) => Person.values.firstWhere((enumValue) => enumValue.jsonKey == value); + static Person? fromJsonValue(int value) => Person.values.firstWhereOrNull((enumValue) => enumValue.jsonKey == value); int toJsonValue() => jsonKey; } @@ -529,7 +543,7 @@ UnknownEnumTestObject: ### Automatic case conversion(v7.0.0) As of v7.0.0 by default all fields will be converted into lowercase instead of uppercase like before. You can control this behavior globally for all enums or per-enum by setting the `uppercase_enums` property to `false` ( -default) or `true` +default) or `true`. This only affects the name of the enum when using it in dart code. the jsonValue will still be the name you type in the config. ```yaml model_generator: @@ -627,6 +641,8 @@ DateTimeConverter: You can specify `description` on models, enum, fields and on enum entries. This description will be used verbatim to generate a code comment for that class/enum/field +Example for a class: + ```yaml UserModel: path: webservice/user @@ -638,6 +654,23 @@ UserModel: changedAt: DateTime ``` +Example for a enum: + +```yaml +Person: + path: test/enum/ + type: enum + description: This is a enum of a person + values: + MAN: + description: enum of a man + WOMAN: + description: enum of a woman + OTHER: + description: enum of a other +``` + + ## Static creator support You can specify `static_create` on objects or globally in the `pubspec.yaml` file. If this is specified, a static creator method called `create` will be generated referencing the From 4cdc535ea11a4c7fa5f42b2b5669ec7a0b8e72bf Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Mon, 11 Sep 2023 16:38:55 +0200 Subject: [PATCH 39/42] #130: don't include disallow null if it's not true --- example/lib/model/user/project/project.dart | 2 +- lib/writer/object_model_writer.dart | 5 ++++- .../object_model_writer/default-field-required/output.txt | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/example/lib/model/user/project/project.dart b/example/lib/model/user/project/project.dart index f338270..b4e0fe1 100644 --- a/example/lib/model/user/project/project.dart +++ b/example/lib/model/user/project/project.dart @@ -9,7 +9,7 @@ part 'project.g.dart'; @JsonSerializable(explicitToJson: true) @immutable class Project { - @JsonKey(name: 'name', required: false, disallowNullValue: false) + @JsonKey(name: 'name', required: false) final String name; @JsonKey(name: 'cost', includeIfNull: false) final double? cost; diff --git a/lib/writer/object_model_writer.dart b/lib/writer/object_model_writer.dart index 41748e3..337ec5a 100644 --- a/lib/writer/object_model_writer.dart +++ b/lib/writer/object_model_writer.dart @@ -104,7 +104,10 @@ class ObjectModelWriter { sb.write(" @JsonKey(name: '${key.serializedName}'"); if (key.isRequired) { if (key.hasDefaultValue) { - sb.write(', required: false, disallowNullValue: ${key.disallowNull}'); + sb.write(', required: false'); + if (key.disallowNull) { + sb.write(', disallowNullValue: ${key.disallowNull}'); + } } else { sb.write(', required: true'); } diff --git a/test/writer/object_model_writer/default-field-required/output.txt b/test/writer/object_model_writer/default-field-required/output.txt index bfd7965..4c11921 100644 --- a/test/writer/object_model_writer/default-field-required/output.txt +++ b/test/writer/object_model_writer/default-field-required/output.txt @@ -7,7 +7,7 @@ part 'person.g.dart'; @JsonSerializable(explicitToJson: true) class Person { ///A good description - @JsonKey(name: 'firstName', required: false, disallowNullValue: false) + @JsonKey(name: 'firstName', required: false) final String firstName; const Person({ From 523e7ec0b244489842ec25283a808d0750dca3bf Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Mon, 11 Sep 2023 16:56:49 +0200 Subject: [PATCH 40/42] #130: fix naming --- example/lib/model/status/double_status.dart | 8 ++++---- example/lib/model/status/status.dart | 8 ++++---- example/lib/model/user/person/gender.dart | 12 ++++++------ example/lib/model/user/person/person.g.dart | 12 ++++++------ example/lib/model/user/project/project.dart | 2 +- example/lib/model/user/project/project.g.dart | 10 +++++----- example/model_generator/config.yaml | 2 +- lib/config/yml_generator_config.dart | 5 ++++- .../enum_model_writer/default_values/output.txt | 6 +++--- test/writer/enum_model_writer/description/output.txt | 4 ++-- test/writer/enum_model_writer/double_type/output.txt | 4 ++-- .../enum_model_writer/field_description/output.txt | 4 ++-- .../generate_extension_normal/output.txt | 4 ++-- test/writer/enum_model_writer/int_type/output.txt | 4 ++-- test/writer/enum_model_writer/normal/output.txt | 4 ++-- .../normal_no_default_json_key/output.txt | 4 ++-- .../enum_model_writer/optional_values/output.txt | 4 ++-- .../optional_values_default/output.txt | 4 ++-- test/writer/enum_model_writer/string_type/output.txt | 4 ++-- .../use_default_json_value/output.txt | 8 ++++---- 20 files changed, 58 insertions(+), 55 deletions(-) diff --git a/example/lib/model/status/double_status.dart b/example/lib/model/status/double_status.dart index 8eb8001..47fe45d 100644 --- a/example/lib/model/status/double_status.dart +++ b/example/lib/model/status/double_status.dart @@ -4,19 +4,19 @@ import 'package:json_annotation/json_annotation.dart'; enum DoubleStatus { @JsonValue(0.1) - status_0( + status0( value: 0.1, ), @JsonValue(1.1) - status_1( + status1( value: 1.1, ), @JsonValue(2.2) - status_2( + status2( value: 2.2, ), @JsonValue(3.3) - status_3( + status3( value: 3.3, ); diff --git a/example/lib/model/status/status.dart b/example/lib/model/status/status.dart index 7e87587..678b9b5 100644 --- a/example/lib/model/status/status.dart +++ b/example/lib/model/status/status.dart @@ -4,19 +4,19 @@ import 'package:json_annotation/json_annotation.dart'; enum Status { @JsonValue(0) - status_0( + status0( value: 0, ), @JsonValue(1) - status_1( + status1( value: 1, ), @JsonValue(2) - status_2( + status2( value: 2, ), @JsonValue(3) - status_3( + status3( value: 3, ); diff --git a/example/lib/model/user/person/gender.dart b/example/lib/model/user/person/gender.dart index f589180..65bcadf 100644 --- a/example/lib/model/user/person/gender.dart +++ b/example/lib/model/user/person/gender.dart @@ -16,27 +16,27 @@ enum Gender { value: 'X', ), @JsonValue('gender_x') - gender_x( + genderX( value: 'gender_x', ), @JsonValue('gender_y') - gender_y( + genderY( value: 'gender_y', ), @JsonValue('gender_z') - gender_z( + genderZ( value: 'gender_z', ), @JsonValue('gender_abc') - gender_abc( + genderAbc( value: 'gender_abc', ), @JsonValue('gender_def') - gender_def( + genderDef( value: 'gender_def', ), @JsonValue('GENDER_lap') - gender_lap( + genderLap( value: 'GENDER_lap', ); diff --git a/example/lib/model/user/person/person.g.dart b/example/lib/model/user/person/person.g.dart index 91e1f0a..ce41c07 100644 --- a/example/lib/model/user/person/person.g.dart +++ b/example/lib/model/user/person/person.g.dart @@ -27,10 +27,10 @@ const _$GenderEnumMap = { Gender.male: '_mAl3', Gender.female: 'femAle', Gender.x: 'X', - Gender.gender_x: 'gender_x', - Gender.gender_y: 'gender_y', - Gender.gender_z: 'gender_z', - Gender.gender_abc: 'gender_abc', - Gender.gender_def: 'gender_def', - Gender.gender_lap: 'GENDER_lap', + Gender.genderX: 'gender_x', + Gender.genderY: 'gender_y', + Gender.genderZ: 'gender_z', + Gender.genderAbc: 'gender_abc', + Gender.genderDef: 'gender_def', + Gender.genderLap: 'GENDER_lap', }; diff --git a/example/lib/model/user/project/project.dart b/example/lib/model/user/project/project.dart index b4e0fe1..0360843 100644 --- a/example/lib/model/user/project/project.dart +++ b/example/lib/model/user/project/project.dart @@ -14,7 +14,7 @@ class Project { @JsonKey(name: 'cost', includeIfNull: false) final double? cost; @JsonKey( - name: 'status', includeIfNull: false, unknownEnumValue: Status.status_0) + name: 'status', includeIfNull: false, unknownEnumValue: Status.status0) final Status? status; const Project({ diff --git a/example/lib/model/user/project/project.g.dart b/example/lib/model/user/project/project.g.dart index 3fc44e7..27c8f40 100644 --- a/example/lib/model/user/project/project.g.dart +++ b/example/lib/model/user/project/project.g.dart @@ -10,7 +10,7 @@ Project _$ProjectFromJson(Map json) => Project( name: json['name'] as String? ?? 'test', cost: (json['cost'] as num?)?.toDouble() ?? 0.2, status: $enumDecodeNullable(_$StatusEnumMap, json['status'], - unknownValue: Status.status_0), + unknownValue: Status.status0), ); Map _$ProjectToJson(Project instance) { @@ -30,8 +30,8 @@ Map _$ProjectToJson(Project instance) { } const _$StatusEnumMap = { - Status.status_0: 0, - Status.status_1: 1, - Status.status_2: 2, - Status.status_3: 3, + Status.status0: 0, + Status.status1: 1, + Status.status2: 2, + Status.status3: 3, }; diff --git a/example/model_generator/config.yaml b/example/model_generator/config.yaml index df234b7..d276b2b 100644 --- a/example/model_generator/config.yaml +++ b/example/model_generator/config.yaml @@ -149,7 +149,7 @@ Project: default_value: 0.2 status: type: Status? - unknown_enum_value: status_0 + unknown_enum_value: status0 ProjectWrapper: path: user/project/ diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index f8f52ef..09e0650 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -16,6 +16,7 @@ import 'package:model_generator/model/model/enum_model.dart'; import 'package:model_generator/model/model/json_converter_model.dart'; import 'package:model_generator/model/model/model.dart'; import 'package:model_generator/model/model/object_model.dart'; +import 'package:model_generator/util/case_util.dart'; import 'package:model_generator/util/generic_type.dart'; import 'package:model_generator/util/list_extensions.dart'; import 'package:model_generator/util/type_checker.dart'; @@ -174,7 +175,9 @@ class YmlGeneratorConfig { ); }); fields.add(EnumField( - name: uppercaseEnums ? key.toUpperCase() : key.toLowerCase(), + name: uppercaseEnums + ? key.toUpperCase() + : CaseUtil(key.toLowerCase()).camelCase, rawName: key, values: enumValues, description: description, diff --git a/test/writer/enum_model_writer/default_values/output.txt b/test/writer/enum_model_writer/default_values/output.txt index 8eb0617..a0229f2 100644 --- a/test/writer/enum_model_writer/default_values/output.txt +++ b/test/writer/enum_model_writer/default_values/output.txt @@ -4,19 +4,19 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { @JsonValue('MY_VALUE_1') - my_value_1( + myValue1( jsonValue: 'MY_VALUE_1', firstName: 'firstName', lastName: 'lastName', ), @JsonValue('MY_VALUE_2') - my_value_2( + myValue2( jsonValue: 'MY_VALUE_2', firstName: 'firstName', lastName: 'lastName', ), @JsonValue('MY_VALUE_3') - my_value_3( + myValue3( jsonValue: 'MY_VALUE_3', firstName: 'firstName', lastName: 'specifiedLastName', diff --git a/test/writer/enum_model_writer/description/output.txt b/test/writer/enum_model_writer/description/output.txt index 3eabd2c..5c96261 100644 --- a/test/writer/enum_model_writer/description/output.txt +++ b/test/writer/enum_model_writer/description/output.txt @@ -5,11 +5,11 @@ import 'package:json_annotation/json_annotation.dart'; ///A good description of this enum enum MyEnumModel { @JsonValue('MY_VALUE_1') - my_value_1( + myValue1( jsonValue: 'MY_VALUE_1', ), @JsonValue('MY_VALUE_2') - my_value_2( + myValue2( jsonValue: 'MY_VALUE_2', ); diff --git a/test/writer/enum_model_writer/double_type/output.txt b/test/writer/enum_model_writer/double_type/output.txt index e7f305f..89c5beb 100644 --- a/test/writer/enum_model_writer/double_type/output.txt +++ b/test/writer/enum_model_writer/double_type/output.txt @@ -4,11 +4,11 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { @JsonValue(1.2) - my_value_1( + myValue1( value: 1.2, ), @JsonValue(2.2) - my_value_2( + myValue2( value: 2.2, ); diff --git a/test/writer/enum_model_writer/field_description/output.txt b/test/writer/enum_model_writer/field_description/output.txt index 09db5a0..a1082ce 100644 --- a/test/writer/enum_model_writer/field_description/output.txt +++ b/test/writer/enum_model_writer/field_description/output.txt @@ -5,12 +5,12 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { ///This is value 1 @JsonValue('MY_VALUE_1') - my_value_1( + myValue1( jsonValue: 'MY_VALUE_1', ), ///This is value 2 @JsonValue('MY_VALUE_2') - my_value_2( + myValue2( jsonValue: 'MY_VALUE_2', ); diff --git a/test/writer/enum_model_writer/generate_extension_normal/output.txt b/test/writer/enum_model_writer/generate_extension_normal/output.txt index db8132f..f21bf4c 100644 --- a/test/writer/enum_model_writer/generate_extension_normal/output.txt +++ b/test/writer/enum_model_writer/generate_extension_normal/output.txt @@ -5,11 +5,11 @@ import 'package:model_generator/util/extension/list_extension.dart'; enum MyEnumModel { @JsonValue('MY_VALUE_1') - my_value_1( + myValue1( jsonValue: 'MY_VALUE_1', ), @JsonValue('MY_VALUE_2') - my_value_2( + myValue2( jsonValue: 'MY_VALUE_2', ); diff --git a/test/writer/enum_model_writer/int_type/output.txt b/test/writer/enum_model_writer/int_type/output.txt index 3485330..149346f 100644 --- a/test/writer/enum_model_writer/int_type/output.txt +++ b/test/writer/enum_model_writer/int_type/output.txt @@ -4,11 +4,11 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { @JsonValue(1) - my_value_1( + myValue1( value: 1, ), @JsonValue(2) - my_value_2( + myValue2( value: 2, ); diff --git a/test/writer/enum_model_writer/normal/output.txt b/test/writer/enum_model_writer/normal/output.txt index f646cc7..6ea8685 100644 --- a/test/writer/enum_model_writer/normal/output.txt +++ b/test/writer/enum_model_writer/normal/output.txt @@ -4,11 +4,11 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { @JsonValue('MY_VALUE_1') - my_value_1( + myValue1( jsonValue: 'MY_VALUE_1', ), @JsonValue('MY_VALUE_2') - my_value_2( + myValue2( jsonValue: 'MY_VALUE_2', ); diff --git a/test/writer/enum_model_writer/normal_no_default_json_key/output.txt b/test/writer/enum_model_writer/normal_no_default_json_key/output.txt index 0a1383e..9ba7c83 100644 --- a/test/writer/enum_model_writer/normal_no_default_json_key/output.txt +++ b/test/writer/enum_model_writer/normal_no_default_json_key/output.txt @@ -4,7 +4,7 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { @JsonValue('MY_VALUE_1') - my_value_1, + myValue1, @JsonValue('MY_VALUE_2') - my_value_2, + myValue2, } diff --git a/test/writer/enum_model_writer/optional_values/output.txt b/test/writer/enum_model_writer/optional_values/output.txt index 6644930..e6d8401 100644 --- a/test/writer/enum_model_writer/optional_values/output.txt +++ b/test/writer/enum_model_writer/optional_values/output.txt @@ -4,13 +4,13 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { @JsonValue('MY_VALUE_1') - my_value_1( + myValue1( jsonValue: 'MY_VALUE_1', firstName: 'firstName', lastName: 'lastName', ), @JsonValue('MY_VALUE_2') - my_value_2( + myValue2( jsonValue: 'MY_VALUE_2', firstName: 'firstName', lastName: 'lastName', diff --git a/test/writer/enum_model_writer/optional_values_default/output.txt b/test/writer/enum_model_writer/optional_values_default/output.txt index 32cc7f7..9dd18fe 100644 --- a/test/writer/enum_model_writer/optional_values_default/output.txt +++ b/test/writer/enum_model_writer/optional_values_default/output.txt @@ -4,13 +4,13 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { @JsonValue('MY_VALUE_1') - my_value_1( + myValue1( jsonValue: 'MY_VALUE_1', firstName: 'firstName', lastName: null, ), @JsonValue('MY_VALUE_2') - my_value_2( + myValue2( jsonValue: 'MY_VALUE_2', firstName: 'firstName', lastName: null, diff --git a/test/writer/enum_model_writer/string_type/output.txt b/test/writer/enum_model_writer/string_type/output.txt index a9b3ad7..da684a6 100644 --- a/test/writer/enum_model_writer/string_type/output.txt +++ b/test/writer/enum_model_writer/string_type/output.txt @@ -4,11 +4,11 @@ import 'package:json_annotation/json_annotation.dart'; enum MyEnumModel { @JsonValue('my_value1') - my_value_1( + myValue1( value: 'my_value1', ), @JsonValue('my_value2') - my_value_2( + myValue2( value: 'my_value2', ); diff --git a/test/writer/enum_model_writer/use_default_json_value/output.txt b/test/writer/enum_model_writer/use_default_json_value/output.txt index c2b4057..1f9a12e 100644 --- a/test/writer/enum_model_writer/use_default_json_value/output.txt +++ b/test/writer/enum_model_writer/use_default_json_value/output.txt @@ -4,19 +4,19 @@ import 'package:json_annotation/json_annotation.dart'; enum DoubleStatus { @JsonValue('customValue') - status_0( + status0( value: 'customValue', ), @JsonValue('status_1') - status_1( + status1( value: 'status_1', ), @JsonValue('status_2') - status_2( + status2( value: 'status_2', ), @JsonValue('status_3') - status_3( + status3( value: 'status_3', ); From 64ca8e20ce8b9a7c2620777d6115c4d01166ab00 Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Mon, 11 Sep 2023 16:57:52 +0200 Subject: [PATCH 41/42] #130: updated readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 79a1c9e..74545ae 100755 --- a/README.md +++ b/README.md @@ -542,7 +542,7 @@ UnknownEnumTestObject: ### Automatic case conversion(v7.0.0) -As of v7.0.0 by default all fields will be converted into lowercase instead of uppercase like before. You can control this behavior globally for all enums or per-enum by setting the `uppercase_enums` property to `false` ( +As of v7.0.0 by default all fields will be converted into lowercase camelcase instead of uppercase like before. You can control this behavior globally for all enums or per-enum by setting the `uppercase_enums` property to `false` ( default) or `true`. This only affects the name of the enum when using it in dart code. the jsonValue will still be the name you type in the config. ```yaml From 7271d7d8e99f57183e42c7a62154580f99ac750f Mon Sep 17 00:00:00 2001 From: Jordy de Jonghe Date: Thu, 14 Sep 2023 10:31:29 +0200 Subject: [PATCH 42/42] #130: fixed enum case --- example/model_generator/enums.yaml | 8 ++++---- lib/config/yml_generator_config.dart | 4 +--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/example/model_generator/enums.yaml b/example/model_generator/enums.yaml index 87a7a21..beed7ea 100644 --- a/example/model_generator/enums.yaml +++ b/example/model_generator/enums.yaml @@ -21,16 +21,16 @@ Gender: GENDER_Y: properties: value: gender_y - GENDER_z: + GENDER_Z: properties: value: gender_z - GENDER_abC: + GENDER_ABC: properties: value: gender_abc - GENDER_def: + GENDER_DEF: properties: value: gender_def - GENDER_lap: + GENDER_LAP: properties: value: GENDER_lap diff --git a/lib/config/yml_generator_config.dart b/lib/config/yml_generator_config.dart index 09e0650..f91bf37 100644 --- a/lib/config/yml_generator_config.dart +++ b/lib/config/yml_generator_config.dart @@ -175,9 +175,7 @@ class YmlGeneratorConfig { ); }); fields.add(EnumField( - name: uppercaseEnums - ? key.toUpperCase() - : CaseUtil(key.toLowerCase()).camelCase, + name: uppercaseEnums ? key.toUpperCase() : CaseUtil(key).camelCase, rawName: key, values: enumValues, description: description,