Skip to content

Commit d29a4be

Browse files
[Bug][typescript-fetch] Typescript fetch one of addtl props imports (#21656)
* Add unit tests for bug in imports for oneOf schemas with additional properties set to true #21587 * Fix bug in filtering primitive, built-in types from model imports in TypeScriptFetchClientCodegen * Add YAML OAS file for #21587 * Revert change to issue_21259.yaml * Remove comment from issue_21259.yaml * Filter out arrays from oneOfModels along with primitive types * Update issue_21587 unit test to catch the Array<Model> case --------- Co-authored-by: Chris Gual <[email protected]>
1 parent 657f5fb commit d29a4be

File tree

3 files changed

+129
-2
lines changed

3 files changed

+129
-2
lines changed

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -787,21 +787,26 @@ private ExtendedCodegenModel processCodeGenModel(ExtendedCodegenModel cm) {
787787
.map(CodegenComposedSchemas::getOneOf)
788788
.orElse(Collections.emptyList());
789789

790+
// create a set of any non-primitive, non-array types used in the oneOf schemas which will
791+
// need to be imported.
790792
cm.oneOfModels = oneOfsList.stream()
791-
.filter(CodegenProperty::getIsModel)
793+
.filter(cp -> !cp.getIsPrimitiveType() && !cp.getIsArray())
792794
.map(CodegenProperty::getBaseType)
793795
.filter(Objects::nonNull)
794796
.collect(Collectors.toCollection(TreeSet::new));
795797

798+
// create a set of any complex, inner types used by arrays in the oneOf schema (e.g. if
799+
// the oneOf uses Array<Foo>, Foo needs to be imported).
796800
cm.oneOfArrays = oneOfsList.stream()
797801
.filter(CodegenProperty::getIsArray)
798802
.map(CodegenProperty::getComplexType)
799803
.filter(Objects::nonNull)
800804
.collect(Collectors.toCollection(TreeSet::new));
801805

806+
// create a set of primitive types used in the oneOf schemas for use in the to & from
807+
// typed JSON methods.
802808
cm.oneOfPrimitives = oneOfsList.stream()
803809
.filter(CodegenProperty::getIsPrimitiveType)
804-
.filter(Objects::nonNull)
805810
.collect(Collectors.toCollection(HashSet::new));
806811

807812
if (!cm.oneOf.isEmpty()) {
@@ -1485,6 +1490,9 @@ public class ExtendedCodegenModel extends CodegenModel {
14851490
@Getter @Setter
14861491
public Set<String> modelImports = new TreeSet<String>();
14871492

1493+
// oneOfModels, oneOfArrays & oneOfPrimitives contain a list of types used in schemas
1494+
// composed with oneOf and are used to define the import list and the to & from
1495+
// 'TypedJSON' conversion methods in the composed model classes.
14881496
@Getter @Setter
14891497
public Set<String> oneOfModels = new TreeSet<>();
14901498
@Getter @Setter

modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/fetch/TypeScriptFetchClientCodegenTest.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import io.swagger.v3.oas.models.media.Schema;
88
import io.swagger.v3.oas.models.media.StringSchema;
99
import java.util.Collections;
10+
import java.util.Locale;
11+
import java.util.stream.Stream;
1012
import org.apache.commons.lang3.StringUtils;
1113
import org.openapitools.codegen.*;
1214
import org.openapitools.codegen.config.CodegenConfigurator;
@@ -404,6 +406,44 @@ public void testOneOfModelsDoNotImportPrimitiveTypes() throws IOException {
404406
TestUtils.assertFileContains(testDiscriminatorResponse, "export type TestDiscriminatorResponse = { discriminatorField: 'optionOne' } & OptionOne | { discriminatorField: 'optionTwo' } & OptionTwo");
405407
}
406408

409+
/**
410+
* Issue #21587
411+
* When using oneOf, the Typescript Fetch generator should import modelled types except for
412+
* types built-in primitive types, even those marked with additional properties.
413+
*/
414+
@Test()
415+
public void testOneOfModelsImportNonPrimitiveTypes() throws IOException {
416+
File output = generate(
417+
Collections.emptyMap(),
418+
"src/test/resources/3_0/typescript-fetch/issue_21587.yaml"
419+
);
420+
421+
Path testResponse = Paths.get(output + "/models/OneOfResponse.ts");
422+
TestUtils.assertFileExists(testResponse);
423+
424+
// Primitive built-in types should not be included. This list is based off the type mappings
425+
// and language specific primitive keywords established in the AbstractTypeScriptClientCodegen
426+
Stream.of(
427+
"Set",
428+
"Array",
429+
"boolean",
430+
"string",
431+
"number",
432+
"object",
433+
"any",
434+
"Date",
435+
"Error"
436+
).forEach(primitiveType ->
437+
TestUtils.assertFileNotContains(
438+
testResponse,
439+
String.format(Locale.ROOT, "import type { %s } from './%s'", primitiveType, primitiveType)
440+
)
441+
);
442+
TestUtils.assertFileContains(testResponse, "import type { OptionOne } from './OptionOne'");
443+
TestUtils.assertFileContains(testResponse, "import type { OptionTwo } from './OptionTwo'");
444+
TestUtils.assertFileContains(testResponse, "import type { OptionThree } from './OptionThree'");
445+
}
446+
407447
private static File generate(
408448
Map<String, Object> properties
409449
) throws IOException {
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
openapi: 3.0.1
2+
info:
3+
title: Example API
4+
version: 1.0.0
5+
paths:
6+
/api/endpoint:
7+
get:
8+
operationId: GetEndpoint
9+
summary: Get endpoint
10+
tags:
11+
- Examples
12+
responses:
13+
'200':
14+
description: Successful response
15+
content:
16+
application/json:
17+
schema:
18+
type: object
19+
title: OneOfResponse
20+
oneOf:
21+
- $ref: '#/components/schemas/OptionOne'
22+
- $ref: '#/components/schemas/OptionTwo'
23+
- type: array
24+
items:
25+
$ref: '#/components/schemas/OptionThree'
26+
- type: string
27+
enum:
28+
- "fixed-value-a"
29+
- "fixed-value-b"
30+
- "fixed-value-c"
31+
- type: boolean
32+
- type: number
33+
- type: string
34+
format: date
35+
- type: string
36+
format: date-time
37+
- type: integer
38+
format: int64
39+
enum: [10, 20, 30]
40+
- type: array
41+
items:
42+
type: number
43+
- type: array
44+
items:
45+
type: object
46+
- type: array
47+
items:
48+
type: string
49+
enum:
50+
- "oneof-array-enum-a"
51+
- "oneof-array-enum-b"
52+
- "oneof-array-enum-c"
53+
- type: array
54+
items:
55+
type: number
56+
uniqueItems: true
57+
58+
components:
59+
schemas:
60+
OptionOne:
61+
type: object
62+
title: OptionOne
63+
properties:
64+
propOne:
65+
type: number
66+
additionalProperties: true
67+
OptionTwo:
68+
type: object
69+
title: OptionTwo
70+
properties:
71+
propTwo:
72+
type: string
73+
OptionThree:
74+
type: object
75+
title: OptionThree
76+
properties:
77+
propThree:
78+
type: boolean
79+
additionalProperties: true

0 commit comments

Comments
 (0)