Skip to content

Commit aaf3ea2

Browse files
[FIX][typescript-fetch] Fix duplicate imports for models with a discriminator (#19195)
* add new typescript-fetch self import issue sample * add a new typescript-fetch self import issue config * generate sample * regenerate sample * Prevent duplicate typescript imports * Update generated samples * Filter imports instead of discriminators mapped models * Update generated samples --------- Co-authored-by: GeroSchaarmann <[email protected]>
1 parent e59a4ab commit aaf3ea2

File tree

13 files changed

+797
-1
lines changed

13 files changed

+797
-1
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
generatorName: typescript-fetch
2+
outputDir: samples/client/others/typescript-fetch/self-import-issue
3+
inputSpec: modules/openapi-generator/src/test/resources/3_0/typescript-fetch/self-import-issue.yaml
4+
templateDir: modules/openapi-generator/src/main/resources/typescript-fetch
5+
additionalProperties:
6+
typescriptThreePlus: "true"
7+
legacyDiscriminatorBehavior: "false"

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

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import java.util.*;
4242
import java.util.stream.Collectors;
4343

44+
import static java.util.Objects.nonNull;
4445
import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER;
4546
import static org.openapitools.codegen.utils.StringUtils.*;
4647

@@ -387,8 +388,32 @@ public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs)
387388
for (ModelsMap entry : result.values()) {
388389
for (ModelMap model : entry.getModels()) {
389390
ExtendedCodegenModel codegenModel = (ExtendedCodegenModel) model.getModel();
390-
model.put("hasImports", codegenModel.imports.size() > 0);
391+
boolean importsPresent = !codegenModel.imports.isEmpty();
392+
393+
// When legacyDiscriminatorBehaviour = false, DefaultCodegen will add the mapped models of the
394+
// discriminator to codegenModel.imports, causing us to duplicate the import if we don't remove them
395+
CodegenDiscriminator discriminator = codegenModel.discriminator;
396+
boolean mappedDiscriminatorModelsPresent = nonNull(discriminator)
397+
&& nonNull(discriminator.getMappedModels());
398+
if (importsPresent && mappedDiscriminatorModelsPresent) {
399+
Set<String> mappedDiscriminatorModelNames = discriminator.getMappedModels()
400+
.stream()
401+
.map(CodegenDiscriminator.MappedModel::getModelName)
402+
.collect(Collectors.toSet());
403+
Set<String> filteredImports = codegenModel.imports
404+
.stream()
405+
.filter(modelImport ->
406+
!mappedDiscriminatorModelNames.contains(modelImport))
407+
.collect(Collectors.toSet());
408+
409+
codegenModel.imports.clear();
410+
codegenModel.imports.addAll(filteredImports);
411+
}
412+
413+
model.put("hasImports", importsPresent);
391414
model.put("tsImports", toTsImports(codegenModel, parseImports(codegenModel)));
415+
416+
392417
allModels.add(codegenModel);
393418
if (codegenModel.isEntity) {
394419
entityModelClassnames.add(codegenModel.classname);
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
openapi: "3.0.1"
2+
info:
3+
title: Example
4+
version: "1"
5+
paths: {}
6+
components:
7+
schemas:
8+
BranchDto:
9+
type: object
10+
properties:
11+
name:
12+
type: string
13+
AbstractUserDto:
14+
type: object
15+
properties:
16+
username:
17+
type: string
18+
branch:
19+
"$ref": "#/components/schemas/BranchDto"
20+
type:
21+
type: string
22+
discriminator:
23+
propertyName: type
24+
mapping:
25+
internal-authenticated: "#/components/schemas/InternalAuthenticatedUserDto"
26+
remote-authenticated: "#/components/schemas/RemoteAuthenticatedUserDto"
27+
InternalAuthenticatedUserDto:
28+
type: object
29+
allOf:
30+
- "$ref": "#/components/schemas/AbstractUserDto"
31+
RemoteAuthenticatedUserDto:
32+
type: object
33+
allOf:
34+
- "$ref": "#/components/schemas/AbstractUserDto"
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# OpenAPI Generator Ignore
2+
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
3+
4+
# Use this file to prevent files from being overwritten by the generator.
5+
# The patterns follow closely to .gitignore or .dockerignore.
6+
7+
# As an example, the C# client generator defines ApiClient.cs.
8+
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
9+
#ApiClient.cs
10+
11+
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
12+
#foo/*/qux
13+
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
14+
15+
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
16+
#foo/**/qux
17+
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
18+
19+
# You can also negate patterns with an exclamation (!).
20+
# For example, you can ignore all files in a docs folder with the file extension .md:
21+
#docs/*.md
22+
# Then explicitly reverse the ignore rule for a single file:
23+
#!docs/README.md
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
index.ts
2+
models/AbstractUserDto.ts
3+
models/BranchDto.ts
4+
models/InternalAuthenticatedUserDto.ts
5+
models/RemoteAuthenticatedUserDto.ts
6+
models/index.ts
7+
runtime.ts
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
7.8.0-SNAPSHOT
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/* tslint:disable */
2+
/* eslint-disable */
3+
export * from './runtime';
4+
export * from './models/index';
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/* tslint:disable */
2+
/* eslint-disable */
3+
/**
4+
* Example
5+
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
6+
*
7+
* The version of the OpenAPI document: 1
8+
*
9+
*
10+
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
11+
* https://openapi-generator.tech
12+
* Do not edit the class manually.
13+
*/
14+
15+
import { mapValues } from '../runtime';
16+
import type { BranchDto } from './BranchDto';
17+
import {
18+
BranchDtoFromJSON,
19+
BranchDtoFromJSONTyped,
20+
BranchDtoToJSON,
21+
} from './BranchDto';
22+
23+
import { InternalAuthenticatedUserDtoFromJSONTyped } from './InternalAuthenticatedUserDto';
24+
import { RemoteAuthenticatedUserDtoFromJSONTyped } from './RemoteAuthenticatedUserDto';
25+
/**
26+
*
27+
* @export
28+
* @interface AbstractUserDto
29+
*/
30+
export interface AbstractUserDto {
31+
/**
32+
*
33+
* @type {string}
34+
* @memberof AbstractUserDto
35+
*/
36+
username?: string;
37+
/**
38+
*
39+
* @type {BranchDto}
40+
* @memberof AbstractUserDto
41+
*/
42+
branch?: BranchDto;
43+
/**
44+
*
45+
* @type {string}
46+
* @memberof AbstractUserDto
47+
*/
48+
type?: string;
49+
}
50+
51+
/**
52+
* Check if a given object implements the AbstractUserDto interface.
53+
*/
54+
export function instanceOfAbstractUserDto(value: object): value is AbstractUserDto {
55+
return true;
56+
}
57+
58+
export function AbstractUserDtoFromJSON(json: any): AbstractUserDto {
59+
return AbstractUserDtoFromJSONTyped(json, false);
60+
}
61+
62+
export function AbstractUserDtoFromJSONTyped(json: any, ignoreDiscriminator: boolean): AbstractUserDto {
63+
if (json == null) {
64+
return json;
65+
}
66+
if (!ignoreDiscriminator) {
67+
if (json['type'] === 'internal-authenticated') {
68+
return InternalAuthenticatedUserDtoFromJSONTyped(json, true);
69+
}
70+
if (json['type'] === 'remote-authenticated') {
71+
return RemoteAuthenticatedUserDtoFromJSONTyped(json, true);
72+
}
73+
}
74+
return {
75+
76+
'username': json['username'] == null ? undefined : json['username'],
77+
'branch': json['branch'] == null ? undefined : BranchDtoFromJSON(json['branch']),
78+
'type': json['type'] == null ? undefined : json['type'],
79+
};
80+
}
81+
82+
export function AbstractUserDtoToJSON(value?: AbstractUserDto | null): any {
83+
if (value == null) {
84+
return value;
85+
}
86+
return {
87+
88+
'username': value['username'],
89+
'branch': BranchDtoToJSON(value['branch']),
90+
'type': value['type'],
91+
};
92+
}
93+
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/* tslint:disable */
2+
/* eslint-disable */
3+
/**
4+
* Example
5+
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
6+
*
7+
* The version of the OpenAPI document: 1
8+
*
9+
*
10+
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
11+
* https://openapi-generator.tech
12+
* Do not edit the class manually.
13+
*/
14+
15+
import { mapValues } from '../runtime';
16+
/**
17+
*
18+
* @export
19+
* @interface BranchDto
20+
*/
21+
export interface BranchDto {
22+
/**
23+
*
24+
* @type {string}
25+
* @memberof BranchDto
26+
*/
27+
name?: string;
28+
}
29+
30+
/**
31+
* Check if a given object implements the BranchDto interface.
32+
*/
33+
export function instanceOfBranchDto(value: object): value is BranchDto {
34+
return true;
35+
}
36+
37+
export function BranchDtoFromJSON(json: any): BranchDto {
38+
return BranchDtoFromJSONTyped(json, false);
39+
}
40+
41+
export function BranchDtoFromJSONTyped(json: any, ignoreDiscriminator: boolean): BranchDto {
42+
if (json == null) {
43+
return json;
44+
}
45+
return {
46+
47+
'name': json['name'] == null ? undefined : json['name'],
48+
};
49+
}
50+
51+
export function BranchDtoToJSON(value?: BranchDto | null): any {
52+
if (value == null) {
53+
return value;
54+
}
55+
return {
56+
57+
'name': value['name'],
58+
};
59+
}
60+
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/* tslint:disable */
2+
/* eslint-disable */
3+
/**
4+
* Example
5+
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
6+
*
7+
* The version of the OpenAPI document: 1
8+
*
9+
*
10+
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
11+
* https://openapi-generator.tech
12+
* Do not edit the class manually.
13+
*/
14+
15+
import { mapValues } from '../runtime';
16+
import type { BranchDto } from './BranchDto';
17+
import {
18+
BranchDtoFromJSON,
19+
BranchDtoFromJSONTyped,
20+
BranchDtoToJSON,
21+
} from './BranchDto';
22+
import type { AbstractUserDto } from './AbstractUserDto';
23+
import {
24+
AbstractUserDtoFromJSON,
25+
AbstractUserDtoFromJSONTyped,
26+
AbstractUserDtoToJSON,
27+
} from './AbstractUserDto';
28+
29+
/**
30+
*
31+
* @export
32+
* @interface InternalAuthenticatedUserDto
33+
*/
34+
export interface InternalAuthenticatedUserDto extends AbstractUserDto {
35+
}
36+
37+
/**
38+
* Check if a given object implements the InternalAuthenticatedUserDto interface.
39+
*/
40+
export function instanceOfInternalAuthenticatedUserDto(value: object): value is InternalAuthenticatedUserDto {
41+
return true;
42+
}
43+
44+
export function InternalAuthenticatedUserDtoFromJSON(json: any): InternalAuthenticatedUserDto {
45+
return InternalAuthenticatedUserDtoFromJSONTyped(json, false);
46+
}
47+
48+
export function InternalAuthenticatedUserDtoFromJSONTyped(json: any, ignoreDiscriminator: boolean): InternalAuthenticatedUserDto {
49+
return json;
50+
}
51+
52+
export function InternalAuthenticatedUserDtoToJSON(value?: InternalAuthenticatedUserDto | null): any {
53+
return value;
54+
}
55+

0 commit comments

Comments
 (0)