From 0dc83ca7afe95f4e38fd0dcbdfaada8d3dee93b1 Mon Sep 17 00:00:00 2001 From: Pol Vallverdu <86187892+polvallverdu@users.noreply.github.com> Date: Tue, 19 Nov 2024 18:08:56 +0100 Subject: [PATCH] Fix Dart Freezed naming for nested objects Fixes #2660 Modify the naming convention for nested objects in Dart Freezed class generation to include the parent object name. * **DartRenderer.ts** - Update `dartType` method to include the parent object name for nested objects. - Adjust `emitFreezedClassDefinition` and `emitClassDefinition` methods to handle the new naming convention for nested objects. - Modify `_emitVariables` method to use the new naming convention for nested objects. * **parser.dart** - Add tests for the new functionality to ensure nested objects include the parent object name. - Implement `testNestedObjectNaming` function to validate the new naming convention for nested objects. TODO: - [ ] Make sure tests work - [ ] Make sure this offers backwards compatibility --- For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/glideapps/quicktype/issues/2660?shareId=XXXX-XXXX-XXXX-XXXX). --- .../src/language/Dart/DartRenderer.ts | 26 +++++++++++++------ test/fixtures/dart/parser.dart | 22 ++++++++++++++++ 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/packages/quicktype-core/src/language/Dart/DartRenderer.ts b/packages/quicktype-core/src/language/Dart/DartRenderer.ts index 75508c7b8..21a6b0801 100644 --- a/packages/quicktype-core/src/language/Dart/DartRenderer.ts +++ b/packages/quicktype-core/src/language/Dart/DartRenderer.ts @@ -192,7 +192,7 @@ export class DartRenderer extends ConvenienceRenderer { this.emitLine("}"); } - protected dartType(t: Type, withIssues = false, forceNullable = false): Sourcelike { + protected dartType(t: Type, withIssues = false, forceNullable = false, parentName?: Name): Sourcelike { const nullable = forceNullable || (this._options.nullSafety && t.isNullable && !this._options.requiredProperties); const withNullable = (s: Sourcelike): Sourcelike => (nullable ? [s, "?"] : s); @@ -205,7 +205,10 @@ export class DartRenderer extends ConvenienceRenderer { _doubleType => withNullable("double"), _stringType => withNullable("String"), arrayType => withNullable(["List<", this.dartType(arrayType.items, withIssues), ">"]), - classType => withNullable(this.nameForNamedType(classType)), + classType => { + const className = parentName ? [parentName, "_", this.nameForNamedType(classType)] : this.nameForNamedType(classType); + return withNullable(className); + }, mapType => withNullable(["Map"]), enumType => withNullable(this.nameForNamedType(enumType)), unionType => { @@ -441,7 +444,7 @@ export class DartRenderer extends ConvenienceRenderer { this.ensureBlankLine(); } - private _emitVariables(c: ClassType): void { + private _emitVariables(c: ClassType, parentName?: Name): void { this.forEachClassProperty(c, "none", (name, jsonName, p) => { const description = this.descriptionForClassProperty(c, jsonName); if (description !== undefined) { @@ -458,7 +461,7 @@ export class DartRenderer extends ConvenienceRenderer { this.emitLine(`@JsonKey(name: "${jsonName}")`); } - this.emitLine(this._options.finalProperties ? "final " : "", this.dartType(p.type, true), " ", name, ";"); + this.emitLine(this._options.finalProperties ? "final " : "", this.dartType(p.type, true, false, parentName), " ", name, ";"); }); } @@ -544,7 +547,7 @@ export class DartRenderer extends ConvenienceRenderer { this.emitLine("};"); } - protected emitClassDefinition(c: ClassType, className: Name): void { + protected emitClassDefinition(c: ClassType, className: Name, parentName?: Name): void { this.emitDescription(this.descriptionForType(c)); if (this._options.useHive) { this.classCounter++; @@ -560,7 +563,7 @@ export class DartRenderer extends ConvenienceRenderer { if (c.getProperties().size === 0) { this._emitEmptyConstructor(className); } else { - this._emitVariables(c); + this._emitVariables(c, parentName); this.ensureBlankLine(); this._emitConstructor(c, className); } @@ -601,7 +604,7 @@ export class DartRenderer extends ConvenienceRenderer { }); } - protected emitFreezedClassDefinition(c: ClassType, className: Name): void { + protected emitFreezedClassDefinition(c: ClassType, className: Name, parentName?: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitLine("@freezed"); @@ -625,7 +628,7 @@ export class DartRenderer extends ConvenienceRenderer { this.emitLine(`@JsonKey(name: "${jsonName}")`); } - this.emitLine(required ? "required " : "", this.dartType(prop.type, true), " ", name, ","); + this.emitLine(required ? "required " : "", this.dartType(prop.type, true, false, parentName), " ", name, ","); }); }); this.emitLine("}) = _", className, ";"); @@ -644,6 +647,13 @@ export class DartRenderer extends ConvenienceRenderer { "FromJson(json);" ); }); + + this.forEachClassProperty(c, "none", (name, jsonName, prop) => { + if (prop.type instanceof ClassType) { + const nestedClassName = [className, "_", this.nameForNamedType(prop.type)].join(""); + this.emitFreezedClassDefinition(prop.type, nestedClassName, className); + } + }); } protected emitEnumDefinition(e: EnumType, enumName: Name): void { diff --git a/test/fixtures/dart/parser.dart b/test/fixtures/dart/parser.dart index 24d59a77b..a8a7abc16 100644 --- a/test/fixtures/dart/parser.dart +++ b/test/fixtures/dart/parser.dart @@ -9,3 +9,25 @@ void main(List arguments) async { stdout.write(result); }); } + +void testNestedObjectNaming() { + final json = ''' + { + "hello": "world", + "works": { + "yes": true, + "no": false + } + } + '''; + + final fasfasfsa = Fasfasfsa.fromJson(jsonDecode(json)); + assert(fasfasfsa.works is Fasfasfsa_Works); + assert(fasfasfsa.works.yes == true); + assert(fasfasfsa.works.no == false); +} + +void main() { + testNestedObjectNaming(); + print('All tests passed.'); +}