Skip to content

Commit 81acbbc

Browse files
Improve type safety and error reporting for oneOf schema resolution
1 parent eee422e commit 81acbbc

212 files changed

Lines changed: 694 additions & 694 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ public TypeScriptClientCodegen() {
176176
setModelPackage("models");
177177
supportingFiles.add(new SupportingFile("model" + File.separator + "ObjectSerializer.mustache", "models", "ObjectSerializer.ts"));
178178
supportingFiles.add(new SupportingFile("model" + File.separator + "TypeMatcher.mustache", "models", "TypeMatcher.ts"));
179+
supportingFiles.add(new SupportingFile("model" + File.separator + "ModelTypes.mustache", "models", "ModelTypes.ts"));
179180

180181
modelTemplateFiles.put("model" + File.separator + "model.mustache", ".ts");
181182

@@ -1193,7 +1194,6 @@ public ExtendedCodegenModel(CodegenModel cm) {
11931194
this.xmlName = cm.xmlName;
11941195
this.classFilename = cm.classFilename;
11951196
this.unescapedDescription = cm.unescapedDescription;
1196-
this.discriminator = cm.discriminator;
11971197
this.defaultValue = cm.defaultValue;
11981198
this.arrayModelType = cm.arrayModelType;
11991199
this.isAlias = cm.isAlias;
@@ -1256,6 +1256,7 @@ public ExtendedCodegenModel(CodegenModel cm) {
12561256
this.setAdditionalProperties(cm.getAdditionalProperties());
12571257
this.setIsModel(cm.getIsModel());
12581258
this.setComposedSchemas(cm.getComposedSchemas());
1259+
this.setDiscriminator(cm.getDiscriminator());
12591260
}
12601261

12611262
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* Represents a single attribute/property metadata entry in the attributeTypeMap.
3+
* Used for validation and type matching in oneOf scenarios.
4+
*/
5+
export type AttributeTypeMapEntry = {
6+
name: string;
7+
baseName: string;
8+
type: string;
9+
format: string;
10+
required: boolean;
11+
};

modules/openapi-generator/src/main/resources/typescript/model/ObjectSerializer.mustache

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export class ObjectSerializer {
127127
128128
// Check the discriminator
129129
let discriminatorProperty = typeMap[expectedType].discriminator;
130-
if (discriminatorProperty == null) {
130+
if (discriminatorProperty == null || !data[discriminatorProperty]) {
131131
if (this.hasFindMatchingTypeMethod(typeMap[expectedType])) {
132132
const foundType = typeMap[expectedType].findMatchingType(data);
133133
if (foundType == undefined) {
@@ -138,18 +138,14 @@ export class ObjectSerializer {
138138
}
139139
return expectedType; // the type does not have a discriminator and findMatchingType method. use it.
140140
} else {
141-
if (data[discriminatorProperty]) {
142-
var discriminatorType = data[discriminatorProperty];
143-
let mapping = typeMap[expectedType].mapping;
144-
if (mapping != undefined && mapping[discriminatorType]) {
145-
return mapping[discriminatorType]; // use the type given in the discriminator
146-
} else if(typeMap[discriminatorType]) {
147-
return discriminatorType;
148-
} else {
149-
return expectedType; // discriminator did not map to a type
150-
}
141+
let discriminatorType = data[discriminatorProperty];
142+
let mapping = typeMap[expectedType].mapping;
143+
if (mapping != undefined && mapping[discriminatorType]) {
144+
return mapping[discriminatorType]; // use the type given in the discriminator
145+
} else if(typeMap[discriminatorType]) {
146+
return discriminatorType;
151147
} else {
152-
return expectedType; // discriminator was not present (or an empty string)
148+
throw new Error(`Discriminator property '${discriminatorProperty}' has value '${discriminatorType}' which does not map to any known type in '${expectedType}'.`);
153149
}
154150
}
155151
}

modules/openapi-generator/src/main/resources/typescript/model/TypeMatcher.mustache

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
import { AttributeTypeMapEntry } from '../models/ModelTypes{{importFileExtension}}';
2+
13
/**
24
* Validates if data contains all required attributes from the attributeTypeMap.
35
*
46
* @param data - The data object to validate
57
* @param attributeTypeMap - Array of attribute metadata including required flag
68
* @returns true if all required attributes are present in data, false otherwise
79
*/
8-
export function instanceOfType(data: any, attributeTypeMap: Array<{name: string, baseName: string, type: string, format: string, required: boolean}>): boolean {
10+
export function instanceOfType(data: any, attributeTypeMap: Array<AttributeTypeMapEntry>): boolean {
911
for (const attribute of attributeTypeMap) {
1012
if (attribute.required) {
1113
// Check both that the property exists AND that it's not undefined.

modules/openapi-generator/src/main/resources/typescript/model/model.mustache

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { findMatchingType } from '../models/TypeMatcher{{importFileExtension}}';
1010
{{/-first}}
1111
{{/oneOf}}
1212
{{^oneOf}}
13+
import { AttributeTypeMapEntry } from '../models/ModelTypes{{importFileExtension}}';
1314
import { HttpFile } from '../http/http{{importFileExtension}}';
1415
{{/oneOf}}
1516

@@ -53,7 +54,7 @@ export class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{
5354
{{/hasDiscriminatorWithNonEmptyMapping}}
5455

5556
{{^isArray}}
56-
static {{#parent}}override {{/parent}}readonly attributeTypeMap: Array<{name: string, baseName: string, type: string, format: string, required: boolean}> = [
57+
static {{#parent}}override {{/parent}}readonly attributeTypeMap: Array<AttributeTypeMapEntry> = [
5758
{{#vars}}
5859
{
5960
"name": "{{name}}",

modules/openapi-generator/src/main/resources/typescript/model/models_all.mustache

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22
{{#model}}
33
export * from '{{{ importPath }}}{{importFileExtension}}'
44
{{/model}}
5-
{{/models}}
5+
{{/models}}
6+
export * from './TypeMatcher{{importFileExtension}}'
7+
export * from './ModelTypes{{importFileExtension}}'

samples/client/echo_api/typescript/build/.openapi-generator/FILES

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

samples/client/echo_api/typescript/build/models/Bird.ts

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

samples/client/echo_api/typescript/build/models/Category.ts

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

samples/client/echo_api/typescript/build/models/DataQuery.ts

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)