quicktype
quicktype copied to clipboard
Ancestor alternative names should include the whole lineage
When trying to generate TypeScript types from our json schemas (that follow jsonapi design), I noticed that ambiguous type names are resolved using the parent's name, but not the grandparent's.
Since in jsonapi most properties are wrapped in an object called "attributes", this leads to a lot of fun prefixes being used.
It would be nice if the whole ancestry lineage is considered for finding unique names.
This should be easily fixable in GatherNames/processType(). I can provide a pull request if this is something that might be considered.
Example JSON Schema
Here is a simple example (open on quicktype.io):
{
"$schema": "https://json-schema.org/draft/2019-09/schema#",
"definitions": {
"Foo": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string",
"enum": [
"foo"
]
},
"attributes": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"active",
"inactive"
]
}
},
"required": [
"status"
]
}
},
"required": [
"id",
"type",
"attributes"
]
},
"Bar": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string",
"enum": [
"bar"
]
},
"attributes": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"enabled",
"disabled"
]
}
},
"required": [
"status"
]
}
},
"required": [
"id",
"type",
"attributes"
]
}
},
"properties": {
"foo": {
"$ref": "#/definitions/Foo"
},
"bar": {
"$ref": "#/definitions/Bar"
}
}
}
Actual output
export interface Bar {
attributes: BarAttributes;
id: string;
type: BarType;
}
export interface BarAttributes {
status: PurpleStatus;
}
export enum PurpleStatus {
Disabled = "disabled",
Enabled = "enabled",
}
export enum BarType {
Bar = "bar",
}
export interface Foo {
attributes: FooAttributes;
id: string;
type: FooType;
}
export interface FooAttributes {
status: FluffyStatus;
}
export enum FluffyStatus {
Active = "active",
Inactive = "inactive",
}
export enum FooType {
Foo = "foo",
}
Note how the "type" properties get qualified nicely, whereas the "status" properties get fun prefixes.
Expected/desired output
export interface Bar {
attributes: BarAttributes;
id: string;
type: BarType;
}
export interface BarAttributes {
status: BarAttributesStatus;
}
export enum BarAttributesStatus {
Disabled = "disabled",
Enabled = "enabled",
}
export enum BarType {
Bar = "bar",
}
export interface Foo {
attributes: FooAttributes;
id: string;
type: FooType;
}
export interface FooAttributes {
status: FooAttributesStatus;
}
export enum FooAttributesStatus {
Active = "active",
Inactive = "inactive",
}
export enum FooType {
Foo = "foo",
}
Getting "FooStatus" instead of "FooAttributesStatus" could be nice as well, but that might depend on personal taste and circumstances.
An alternative to using the whole lineage would be to qualify the type name with the ancestor's finally chosen name. AFAICT, this would require to generate the ancestorAlternativName in the Namer. The results would be identical to the example mentioned above, since "status" would no longer be ancestor-qualified with "attributes"/"attributes", but with "foo_attributes"/"bar_attributes".
LOL @ "Fluffy" :rofl: