From b2f164db0231c1bf1a65f4df71bf3a79b7ed3a74 Mon Sep 17 00:00:00 2001 From: Gregory Merlet Date: Tue, 8 Apr 2025 14:49:47 +0200 Subject: [PATCH 1/6] feat: add test-array endpoint and TestArrayResponse schema to oneOf.yaml --- .../resources/3_0/typescript-fetch/oneOf.yaml | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/modules/openapi-generator/src/test/resources/3_0/typescript-fetch/oneOf.yaml b/modules/openapi-generator/src/test/resources/3_0/typescript-fetch/oneOf.yaml index 244139a28d36..ba0dd51d792f 100644 --- a/modules/openapi-generator/src/test/resources/3_0/typescript-fetch/oneOf.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/typescript-fetch/oneOf.yaml @@ -15,12 +15,34 @@ paths: application/json: schema: $ref: '#/components/schemas/TestResponse' + /test-array: + get: + operationId: testArray + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/TestArrayResponse' components: schemas: + TestArrayResponse: + oneOf: + - type: array + items: + $ref: "#/components/schemas/TestA" + - type: array + items: + $ref: "#/components/schemas/TestB" + - type: array + items: + type: string TestResponse: oneOf: - $ref: "#/components/schemas/TestA" - $ref: "#/components/schemas/TestB" + - type: string TestA: type: object properties: @@ -34,4 +56,4 @@ components: bar: type: string required: - - bar + - bar \ No newline at end of file From a0de89f8f7b5690b7edf8b64ac82bafa21353e74 Mon Sep 17 00:00:00 2001 From: Gregory Merlet Date: Tue, 8 Apr 2025 15:30:23 +0200 Subject: [PATCH 2/6] feat: enhance oneOf handling in TypeScript code generators with string and array support --- .../openapitools/codegen/CodegenProperty.java | 13 ++++ .../openapitools/codegen/DefaultCodegen.java | 12 ++++ .../TypeScriptFetchClientCodegen.java | 48 +++++++++++-- .../TypeScriptReduxQueryClientCodegen.java | 11 ++- .../typescript-fetch/modelOneOf.mustache | 70 +++++++++++++++++-- 5 files changed, 134 insertions(+), 20 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenProperty.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenProperty.java index cdf9bc95977d..e40d93331658 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenProperty.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenProperty.java @@ -961,6 +961,19 @@ public void setIsEnum(boolean isEnum) { this.isEnum = isEnum; } + @SuppressWarnings("unchecked") + public List getAllowableValuesList() { + return Optional.ofNullable(this.getAllowableValues()) + .map(allowableValues -> allowableValues.get("values")) + .flatMap(valuesList -> { + try { + return Optional.ofNullable((List)valuesList); + } catch (ClassCastException e) { + return Optional.empty(); + } + }) + .orElse(Collections.emptyList()); + } @Override public String toString() { diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index 3bb9d43238d5..f23e446b3b80 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -2716,6 +2716,11 @@ protected void updateModelForComposedSchema(CodegenModel m, Schema schema, Map "\"" + (String)enumName + "\"") + .collect(Collectors.joining(" | ")); + } + /** * Combines all previously-detected type entries for a schema with newly-discovered ones, to ensure * that schema for items like enum include all possible values. diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java index ab15af74c3c1..df17d64b4307 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java @@ -782,16 +782,39 @@ private ExtendedCodegenModel processCodeGenModel(ExtendedCodegenModel cm) { } } } + + cm.hasStringOneOf = cm.oneOf.contains("string"); + cm.hasStringArrayOneOf = cm.oneOf.contains("Array"); + + List oneOfsList = Optional.ofNullable(cm.getComposedSchemas()) + .map(CodegenComposedSchemas::getOneOf) + .orElse(Collections.emptyList()); + + cm.oneOfModels = oneOfsList.stream() + .filter(CodegenProperty::getIsModel) + .map(CodegenProperty::getBaseType) + .filter(Objects::nonNull) + .collect(Collectors.toCollection(TreeSet::new)); + + cm.oneOfStringEnums = oneOfsList.stream() + .filter(CodegenProperty::getIsEnum) + .map(CodegenProperty::getAllowableValuesList) + .flatMap(Collection::stream) + .collect(Collectors.toCollection(TreeSet::new)); + + cm.oneOfArrays = oneOfsList.stream() + .filter(CodegenProperty::getIsArray) + .map(CodegenProperty::getComplexType) + .filter(Objects::nonNull) + .collect(Collectors.toCollection(TreeSet::new)); + if (!cm.oneOf.isEmpty()) { // For oneOfs only import $refs within the oneOf - TreeSet oneOfRefs = new TreeSet<>(); - for (String im : cm.imports) { - if (cm.oneOf.contains(im)) { - oneOfRefs.add(im); - } - } - cm.imports = oneOfRefs; + cm.imports = cm.imports.stream() + .filter(im -> cm.oneOfModels.contains(im) || cm.oneOfArrays.contains(im)) + .collect(Collectors.toCollection(TreeSet::new)); } + return cm; } @@ -1474,6 +1497,16 @@ public String toString() { public class ExtendedCodegenModel extends CodegenModel { @Getter @Setter public Set modelImports = new TreeSet(); + + @Getter @Setter + public Set oneOfModels = new TreeSet<>(); + @Getter @Setter + public Set oneOfStringEnums = new TreeSet<>(); + @Getter @Setter + public Set oneOfArrays = new TreeSet<>(); + + public boolean hasStringOneOf; + public boolean hasStringArrayOneOf; public boolean isEntity; // Is a model containing an "id" property marked as isUniqueId public String returnPassthrough; public boolean hasReturnPassthroughVoid; @@ -1570,6 +1603,7 @@ public ExtendedCodegenModel(CodegenModel cm) { this.setItems(cm.getItems()); this.setAdditionalProperties(cm.getAdditionalProperties()); this.setIsModel(cm.getIsModel()); + this.setComposedSchemas(cm.getComposedSchemas()); } @Override diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptReduxQueryClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptReduxQueryClientCodegen.java index 71cfb61f710e..3d94b9d64c54 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptReduxQueryClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptReduxQueryClientCodegen.java @@ -32,6 +32,7 @@ import java.util.List; import java.util.Map; import java.util.TreeSet; +import java.util.stream.Collectors; public class TypeScriptReduxQueryClientCodegen extends AbstractTypeScriptClientCodegen { @@ -145,13 +146,9 @@ public ModelsMap postProcessModels(ModelsMap objs) { } if (!cm.oneOf.isEmpty()) { // For oneOfs only import $refs within the oneOf - TreeSet oneOfRefs = new TreeSet<>(); - for (String im : cm.imports) { - if (cm.oneOf.contains(im)) { - oneOfRefs.add(im); - } - } - cm.imports = oneOfRefs; + cm.imports = cm.imports.stream() + .filter(cm.oneOf::contains) + .collect(Collectors.toCollection(TreeSet::new)); } } diff --git a/modules/openapi-generator/src/main/resources/typescript-fetch/modelOneOf.mustache b/modules/openapi-generator/src/main/resources/typescript-fetch/modelOneOf.mustache index b516da670e1f..186c859edea9 100644 --- a/modules/openapi-generator/src/main/resources/typescript-fetch/modelOneOf.mustache +++ b/modules/openapi-generator/src/main/resources/typescript-fetch/modelOneOf.mustache @@ -1,5 +1,5 @@ {{#hasImports}} -{{#oneOf}} +{{#imports}} import type { {{{.}}} } from './{{.}}{{importFileExtension}}'; import { instanceOf{{{.}}}, @@ -7,7 +7,7 @@ import { {{{.}}}FromJSONTyped, {{{.}}}ToJSON, } from './{{.}}{{importFileExtension}}'; -{{/oneOf}} +{{/imports}} {{/hasImports}} {{>modelOneOfInterfaces}} @@ -31,11 +31,40 @@ export function {{classname}}FromJSONTyped(json: any, ignoreDiscriminator: boole } {{/discriminator}} {{^discriminator}} - {{#oneOf}} + {{#oneOfStringEnums}} + if (json === "{{{.}}}") { + return json; + } + {{/oneOfStringEnums}} + {{#hasStringOneOf}} + if (json instanceof String) { + return json as {{classname}}; + } + {{/hasStringOneOf}} + if (!(json instanceof Object)){ + return {} as any; + } + {{#hasStringArrayOneOf}} + if (Array.isArray(json) && json.every(item => item instanceof String)) { + return json as Array; + } + {{/hasStringArrayOneOf}} + {{#oneOfModels}} if (instanceOf{{{.}}}(json)) { return {{{.}}}FromJSONTyped(json, true); } - {{/oneOf}} + {{/oneOfModels}} + {{#oneOfArrays}} + {{#-first}} + if (Array.isArray(json) && json.every(item => item instanceof Object)) { + {{/-first}} + if (json.every(item => instanceOf{{{.}}}(item as Object))) { + return json.map(value => {{{.}}}FromJSONTyped(value, true)); + } + {{#-last}} + } + {{/-last}} + {{/oneOfArrays}} return {} as any; {{/discriminator}} @@ -61,11 +90,40 @@ export function {{classname}}ToJSONTyped(value?: {{classname}} | null, ignoreDis {{/discriminator}} {{^discriminator}} - {{#oneOf}} + {{#oneOfStringEnums}} + if (value === "{{{.}}}") { + return value; + } + {{/oneOfStringEnums}} + {{#hasStringOneOf}} + if (value instanceof String) { + return value; + } + {{/hasStringOneOf}} + if (!(value instanceof Object)){ + return {}; + } + {{#hasStringArrayOneOf}} + if (Array.isArray(value) && value.every(item => item instanceof String)) { + return value; + } + {{/hasStringArrayOneOf}} + {{#oneOfModels}} if (instanceOf{{{.}}}(value)) { return {{{.}}}ToJSON(value as {{{.}}}); } - {{/oneOf}} + {{/oneOfModels}} + {{#oneOfArrays}} + {{#-first}} + if (Array.isArray(value) && value.every(item => item instanceof Object)) { + {{/-first}} + if (value.every(item => instanceOf{{{.}}}(item as Object))) { + return value.map(value => {{{.}}}ToJSON(value as {{{.}}})); + } + {{#-last}} + } + {{/-last}} + {{/oneOfArrays}} return {}; {{/discriminator}} From 8fb543de2a56e0b52b5aabf1555eb3ffc0e3bb9f Mon Sep 17 00:00:00 2001 From: Gregory Merlet Date: Tue, 8 Apr 2025 16:22:18 +0200 Subject: [PATCH 3/6] fix: correct type checks for string and object arrays in modelOneOf.mustache --- .../resources/typescript-fetch/modelOneOf.mustache | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/typescript-fetch/modelOneOf.mustache b/modules/openapi-generator/src/main/resources/typescript-fetch/modelOneOf.mustache index 186c859edea9..b75b1bced556 100644 --- a/modules/openapi-generator/src/main/resources/typescript-fetch/modelOneOf.mustache +++ b/modules/openapi-generator/src/main/resources/typescript-fetch/modelOneOf.mustache @@ -45,8 +45,8 @@ export function {{classname}}FromJSONTyped(json: any, ignoreDiscriminator: boole return {} as any; } {{#hasStringArrayOneOf}} - if (Array.isArray(json) && json.every(item => item instanceof String)) { - return json as Array; + if (Array.isArray(json) && json.every(item => typeof item === 'string')) { + return json; } {{/hasStringArrayOneOf}} {{#oneOfModels}} @@ -56,9 +56,9 @@ export function {{classname}}FromJSONTyped(json: any, ignoreDiscriminator: boole {{/oneOfModels}} {{#oneOfArrays}} {{#-first}} - if (Array.isArray(json) && json.every(item => item instanceof Object)) { + if (Array.isArray(json) && json.every(item => typeof item === 'object')) { {{/-first}} - if (json.every(item => instanceOf{{{.}}}(item as Object))) { + if (json.every(item => instanceOf{{{.}}}(item))) { return json.map(value => {{{.}}}FromJSONTyped(value, true)); } {{#-last}} @@ -104,7 +104,7 @@ export function {{classname}}ToJSONTyped(value?: {{classname}} | null, ignoreDis return {}; } {{#hasStringArrayOneOf}} - if (Array.isArray(value) && value.every(item => item instanceof String)) { + if (Array.isArray(value) && value.every(item => typeof item === 'string')) { return value; } {{/hasStringArrayOneOf}} @@ -115,9 +115,9 @@ export function {{classname}}ToJSONTyped(value?: {{classname}} | null, ignoreDis {{/oneOfModels}} {{#oneOfArrays}} {{#-first}} - if (Array.isArray(value) && value.every(item => item instanceof Object)) { + if (Array.isArray(value) && value.every(item => typeof item === 'object')) { {{/-first}} - if (value.every(item => instanceOf{{{.}}}(item as Object))) { + if (value.every(item => instanceOf{{{.}}}(item))) { return value.map(value => {{{.}}}ToJSON(value as {{{.}}})); } {{#-last}} From a04602fbb728bf12385ce43716ea2a7228fbdf4d Mon Sep 17 00:00:00 2001 From: Gregory Merlet Date: Tue, 8 Apr 2025 18:21:53 +0200 Subject: [PATCH 4/6] refactor: remove oneOfStringEnums handling and simplify oneOf logic in TypeScript code generators --- .../openapitools/codegen/CodegenProperty.java | 13 ---- .../openapitools/codegen/DefaultCodegen.java | 12 ---- .../TypeScriptFetchClientCodegen.java | 8 --- .../TypeScriptReduxQueryClientCodegen.java | 11 ++-- .../typescript-fetch/modelOneOf.mustache | 65 +++++++------------ 5 files changed, 29 insertions(+), 80 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenProperty.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenProperty.java index e40d93331658..cdf9bc95977d 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenProperty.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenProperty.java @@ -961,19 +961,6 @@ public void setIsEnum(boolean isEnum) { this.isEnum = isEnum; } - @SuppressWarnings("unchecked") - public List getAllowableValuesList() { - return Optional.ofNullable(this.getAllowableValues()) - .map(allowableValues -> allowableValues.get("values")) - .flatMap(valuesList -> { - try { - return Optional.ofNullable((List)valuesList); - } catch (ClassCastException e) { - return Optional.empty(); - } - }) - .orElse(Collections.emptyList()); - } @Override public String toString() { diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index f23e446b3b80..3bb9d43238d5 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -2716,11 +2716,6 @@ protected void updateModelForComposedSchema(CodegenModel m, Schema schema, Map "\"" + (String)enumName + "\"") - .collect(Collectors.joining(" | ")); - } - /** * Combines all previously-detected type entries for a schema with newly-discovered ones, to ensure * that schema for items like enum include all possible values. diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java index df17d64b4307..977e35d0740d 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java @@ -796,12 +796,6 @@ private ExtendedCodegenModel processCodeGenModel(ExtendedCodegenModel cm) { .filter(Objects::nonNull) .collect(Collectors.toCollection(TreeSet::new)); - cm.oneOfStringEnums = oneOfsList.stream() - .filter(CodegenProperty::getIsEnum) - .map(CodegenProperty::getAllowableValuesList) - .flatMap(Collection::stream) - .collect(Collectors.toCollection(TreeSet::new)); - cm.oneOfArrays = oneOfsList.stream() .filter(CodegenProperty::getIsArray) .map(CodegenProperty::getComplexType) @@ -1501,8 +1495,6 @@ public class ExtendedCodegenModel extends CodegenModel { @Getter @Setter public Set oneOfModels = new TreeSet<>(); @Getter @Setter - public Set oneOfStringEnums = new TreeSet<>(); - @Getter @Setter public Set oneOfArrays = new TreeSet<>(); public boolean hasStringOneOf; diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptReduxQueryClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptReduxQueryClientCodegen.java index 3d94b9d64c54..71cfb61f710e 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptReduxQueryClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptReduxQueryClientCodegen.java @@ -32,7 +32,6 @@ import java.util.List; import java.util.Map; import java.util.TreeSet; -import java.util.stream.Collectors; public class TypeScriptReduxQueryClientCodegen extends AbstractTypeScriptClientCodegen { @@ -146,9 +145,13 @@ public ModelsMap postProcessModels(ModelsMap objs) { } if (!cm.oneOf.isEmpty()) { // For oneOfs only import $refs within the oneOf - cm.imports = cm.imports.stream() - .filter(cm.oneOf::contains) - .collect(Collectors.toCollection(TreeSet::new)); + TreeSet oneOfRefs = new TreeSet<>(); + for (String im : cm.imports) { + if (cm.oneOf.contains(im)) { + oneOfRefs.add(im); + } + } + cm.imports = oneOfRefs; } } diff --git a/modules/openapi-generator/src/main/resources/typescript-fetch/modelOneOf.mustache b/modules/openapi-generator/src/main/resources/typescript-fetch/modelOneOf.mustache index b75b1bced556..721f0fc7b767 100644 --- a/modules/openapi-generator/src/main/resources/typescript-fetch/modelOneOf.mustache +++ b/modules/openapi-generator/src/main/resources/typescript-fetch/modelOneOf.mustache @@ -31,37 +31,27 @@ export function {{classname}}FromJSONTyped(json: any, ignoreDiscriminator: boole } {{/discriminator}} {{^discriminator}} - {{#oneOfStringEnums}} - if (json === "{{{.}}}") { - return json; - } - {{/oneOfStringEnums}} - {{#hasStringOneOf}} - if (json instanceof String) { - return json as {{classname}}; - } - {{/hasStringOneOf}} - if (!(json instanceof Object)){ - return {} as any; - } - {{#hasStringArrayOneOf}} - if (Array.isArray(json) && json.every(item => typeof item === 'string')) { + {{#oneOfModels}} + {{#-first}} + if (typeof json !== 'object') { return json; } - {{/hasStringArrayOneOf}} - {{#oneOfModels}} + {{/-first}} if (instanceOf{{{.}}}(json)) { return {{{.}}}FromJSONTyped(json, true); } {{/oneOfModels}} {{#oneOfArrays}} {{#-first}} - if (Array.isArray(json) && json.every(item => typeof item === 'object')) { + if (Array.isArray(json)) { + if (json.every(item => typeof item === 'object')) { {{/-first}} - if (json.every(item => instanceOf{{{.}}}(item))) { - return json.map(value => {{{.}}}FromJSONTyped(value, true)); - } + if (json.every(item => instanceOf{{{.}}}(item))) { + return json.map(value => {{{.}}}FromJSONTyped(value, true)); + } {{#-last}} + } + return json; } {{/-last}} {{/oneOfArrays}} @@ -88,39 +78,28 @@ export function {{classname}}ToJSONTyped(value?: {{classname}} | null, ignoreDis return json; } {{/discriminator}} - {{^discriminator}} - {{#oneOfStringEnums}} - if (value === "{{{.}}}") { - return value; - } - {{/oneOfStringEnums}} - {{#hasStringOneOf}} - if (value instanceof String) { - return value; - } - {{/hasStringOneOf}} - if (!(value instanceof Object)){ - return {}; - } - {{#hasStringArrayOneOf}} - if (Array.isArray(value) && value.every(item => typeof item === 'string')) { + {{#oneOfModels}} + {{#-first}} + if (typeof value !== 'object') { return value; } - {{/hasStringArrayOneOf}} - {{#oneOfModels}} + {{/-first}} if (instanceOf{{{.}}}(value)) { return {{{.}}}ToJSON(value as {{{.}}}); } {{/oneOfModels}} {{#oneOfArrays}} {{#-first}} - if (Array.isArray(value) && value.every(item => typeof item === 'object')) { + if (Array.isArray(value)) { + if (value.every(item => typeof item === 'object')) { {{/-first}} - if (value.every(item => instanceOf{{{.}}}(item))) { - return value.map(value => {{{.}}}ToJSON(value as {{{.}}})); - } + if (value.every(item => instanceOf{{{.}}}(item))) { + return value.map(value => {{{.}}}ToJSON(value as {{{.}}})); + } {{#-last}} + } + return value; } {{/-last}} {{/oneOfArrays}} From 515df60cd67eb935502fad86e164c79fec873f2a Mon Sep 17 00:00:00 2001 From: Gregory Merlet Date: Tue, 8 Apr 2025 18:22:14 +0200 Subject: [PATCH 5/6] chore: update samples --- .../builds/oneOf/.openapi-generator/FILES | 1 + .../builds/oneOf/apis/DefaultApi.ts | 27 ++++++ .../builds/oneOf/models/TestArrayResponse.ts | 82 +++++++++++++++++++ .../builds/oneOf/models/TestResponse.ts | 9 +- .../builds/oneOf/models/index.ts | 1 + 5 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 samples/client/petstore/typescript-fetch/builds/oneOf/models/TestArrayResponse.ts diff --git a/samples/client/petstore/typescript-fetch/builds/oneOf/.openapi-generator/FILES b/samples/client/petstore/typescript-fetch/builds/oneOf/.openapi-generator/FILES index 1e29c70aedaa..6bb15a3adfc7 100644 --- a/samples/client/petstore/typescript-fetch/builds/oneOf/.openapi-generator/FILES +++ b/samples/client/petstore/typescript-fetch/builds/oneOf/.openapi-generator/FILES @@ -2,6 +2,7 @@ apis/DefaultApi.ts apis/index.ts index.ts models/TestA.ts +models/TestArrayResponse.ts models/TestB.ts models/TestResponse.ts models/index.ts diff --git a/samples/client/petstore/typescript-fetch/builds/oneOf/apis/DefaultApi.ts b/samples/client/petstore/typescript-fetch/builds/oneOf/apis/DefaultApi.ts index 3383adf93dfd..f7e1936ab80c 100644 --- a/samples/client/petstore/typescript-fetch/builds/oneOf/apis/DefaultApi.ts +++ b/samples/client/petstore/typescript-fetch/builds/oneOf/apis/DefaultApi.ts @@ -15,9 +15,12 @@ import * as runtime from '../runtime'; import type { + TestArrayResponse, TestResponse, } from '../models/index'; import { + TestArrayResponseFromJSON, + TestArrayResponseToJSON, TestResponseFromJSON, TestResponseToJSON, } from '../models/index'; @@ -51,4 +54,28 @@ export class DefaultApi extends runtime.BaseAPI { return await response.value(); } + /** + */ + async testArrayRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + const response = await this.request({ + path: `/test-array`, + method: 'GET', + headers: headerParameters, + query: queryParameters, + }, initOverrides); + + return new runtime.JSONApiResponse(response, (jsonValue) => TestArrayResponseFromJSON(jsonValue)); + } + + /** + */ + async testArray(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise { + const response = await this.testArrayRaw(initOverrides); + return await response.value(); + } + } diff --git a/samples/client/petstore/typescript-fetch/builds/oneOf/models/TestArrayResponse.ts b/samples/client/petstore/typescript-fetch/builds/oneOf/models/TestArrayResponse.ts new file mode 100644 index 000000000000..0848d99781c3 --- /dev/null +++ b/samples/client/petstore/typescript-fetch/builds/oneOf/models/TestArrayResponse.ts @@ -0,0 +1,82 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * testing oneOf without discriminator + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 1.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import type { TestA } from './TestA'; +import { + instanceOfTestA, + TestAFromJSON, + TestAFromJSONTyped, + TestAToJSON, +} from './TestA'; +import type { TestB } from './TestB'; +import { + instanceOfTestB, + TestBFromJSON, + TestBFromJSONTyped, + TestBToJSON, +} from './TestB'; + +/** + * @type TestArrayResponse + * + * @export + */ +export type TestArrayResponse = Array | Array | Array; + +export function TestArrayResponseFromJSON(json: any): TestArrayResponse { + return TestArrayResponseFromJSONTyped(json, false); +} + +export function TestArrayResponseFromJSONTyped(json: any, ignoreDiscriminator: boolean): TestArrayResponse { + if (json == null) { + return json; + } + if (Array.isArray(json)) { + if (json.every(item => typeof item === 'object')) { + if (json.every(item => instanceOfTestA(item))) { + return json.map(value => TestAFromJSONTyped(value, true)); + } + if (json.every(item => instanceOfTestB(item))) { + return json.map(value => TestBFromJSONTyped(value, true)); + } + } + return json; + } + + return {} as any; +} + +export function TestArrayResponseToJSON(json: any): any { + return TestArrayResponseToJSONTyped(json, false); +} + +export function TestArrayResponseToJSONTyped(value?: TestArrayResponse | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + if (Array.isArray(value)) { + if (value.every(item => typeof item === 'object')) { + if (value.every(item => instanceOfTestA(item))) { + return value.map(value => TestAToJSON(value as TestA)); + } + if (value.every(item => instanceOfTestB(item))) { + return value.map(value => TestBToJSON(value as TestB)); + } + } + return value; + } + + return {}; +} + diff --git a/samples/client/petstore/typescript-fetch/builds/oneOf/models/TestResponse.ts b/samples/client/petstore/typescript-fetch/builds/oneOf/models/TestResponse.ts index e228a3e9f73d..09d1da131560 100644 --- a/samples/client/petstore/typescript-fetch/builds/oneOf/models/TestResponse.ts +++ b/samples/client/petstore/typescript-fetch/builds/oneOf/models/TestResponse.ts @@ -32,7 +32,7 @@ import { * * @export */ -export type TestResponse = TestA | TestB; +export type TestResponse = TestA | TestB | string; export function TestResponseFromJSON(json: any): TestResponse { return TestResponseFromJSONTyped(json, false); @@ -42,6 +42,9 @@ export function TestResponseFromJSONTyped(json: any, ignoreDiscriminator: boolea if (json == null) { return json; } + if (typeof json !== 'object') { + return json; + } if (instanceOfTestA(json)) { return TestAFromJSONTyped(json, true); } @@ -60,7 +63,9 @@ export function TestResponseToJSONTyped(value?: TestResponse | null, ignoreDiscr if (value == null) { return value; } - + if (typeof value !== 'object') { + return value; + } if (instanceOfTestA(value)) { return TestAToJSON(value as TestA); } diff --git a/samples/client/petstore/typescript-fetch/builds/oneOf/models/index.ts b/samples/client/petstore/typescript-fetch/builds/oneOf/models/index.ts index 8da6963476f2..7ba8efbbf0ef 100644 --- a/samples/client/petstore/typescript-fetch/builds/oneOf/models/index.ts +++ b/samples/client/petstore/typescript-fetch/builds/oneOf/models/index.ts @@ -1,5 +1,6 @@ /* tslint:disable */ /* eslint-disable */ export * from './TestA'; +export * from './TestArrayResponse'; export * from './TestB'; export * from './TestResponse'; From c7ce0c41808143165a9d97e07f816aa5ad49c04e Mon Sep 17 00:00:00 2001 From: Gregory Merlet Date: Tue, 8 Apr 2025 18:34:15 +0200 Subject: [PATCH 6/6] refactor: remove unnecessary string oneOf checks in TypeScriptFetchClientCodegen --- .../codegen/languages/TypeScriptFetchClientCodegen.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java index 977e35d0740d..0d3668e67035 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java @@ -783,9 +783,6 @@ private ExtendedCodegenModel processCodeGenModel(ExtendedCodegenModel cm) { } } - cm.hasStringOneOf = cm.oneOf.contains("string"); - cm.hasStringArrayOneOf = cm.oneOf.contains("Array"); - List oneOfsList = Optional.ofNullable(cm.getComposedSchemas()) .map(CodegenComposedSchemas::getOneOf) .orElse(Collections.emptyList()); @@ -1497,8 +1494,6 @@ public class ExtendedCodegenModel extends CodegenModel { @Getter @Setter public Set oneOfArrays = new TreeSet<>(); - public boolean hasStringOneOf; - public boolean hasStringArrayOneOf; public boolean isEntity; // Is a model containing an "id" property marked as isUniqueId public String returnPassthrough; public boolean hasReturnPassthroughVoid;