Skip to content

Commit e17e024

Browse files
authored
[typescript] Fix missing model imports for container types in oneOf schemas (#23286) (#25173)
1 parent 782ef0b commit e17e024

4 files changed

Lines changed: 62 additions & 12 deletions

File tree

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -407,13 +407,16 @@ public ModelsMap postProcessModels(ModelsMap objs) {
407407
}
408408
if (!cm.oneOf.isEmpty()) {
409409
// For oneOfs only import $refs within the oneOf
410-
TreeSet<String> oneOfRefs = new TreeSet<>();
411-
for (String im : cm.imports) {
412-
if (cm.oneOf.contains(im)) {
413-
oneOfRefs.add(im);
414-
}
410+
TreeSet<String> oneOfRefs = new TreeSet<>(cm.oneOf);
411+
List<CodegenProperty> oneOfProperties = Optional.ofNullable(cm.getComposedSchemas())
412+
.map(CodegenComposedSchemas::getOneOf)
413+
.orElse(Collections.emptyList());
414+
for (CodegenProperty oneOfProperty : oneOfProperties) {
415+
// resolve the types referenced by each branch so that inner types of
416+
// container types (e.g. Foo in Array<Foo>) keep their model import
417+
oneOfRefs.addAll(oneOfProperty.getImports(false, true, generatorMetadata.getFeatureSet()));
415418
}
416-
cm.imports = oneOfRefs;
419+
cm.imports = new TreeSet<>(Sets.intersection(cm.imports, oneOfRefs));
417420
}
418421
}
419422
for (ModelMap mo : models) {

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@
2929
import org.openapitools.codegen.utils.ModelUtils;
3030

3131
import java.io.File;
32+
import java.util.Collections;
3233
import java.util.List;
3334
import java.util.Map;
35+
import java.util.Optional;
3436
import java.util.TreeSet;
3537

3638
/**
@@ -148,13 +150,14 @@ public ModelsMap postProcessModels(ModelsMap objs) {
148150
}
149151
if (!cm.oneOf.isEmpty()) {
150152
// For oneOfs only import $refs within the oneOf
151-
TreeSet<String> oneOfRefs = new TreeSet<>();
152-
for (String im : cm.imports) {
153-
if (cm.oneOf.contains(im)) {
154-
oneOfRefs.add(im);
155-
}
153+
TreeSet<String> oneOfRefs = new TreeSet<>(cm.oneOf);
154+
List<CodegenProperty> oneOfProperties = Optional.ofNullable(cm.getComposedSchemas())
155+
.map(CodegenComposedSchemas::getOneOf)
156+
.orElse(Collections.emptyList());
157+
for (CodegenProperty oneOfProperty : oneOfProperties) {
158+
oneOfRefs.addAll(oneOfProperty.getImports(false, true, generatorMetadata.getFeatureSet()));
156159
}
157-
cm.imports = oneOfRefs;
160+
cm.imports.retainAll(oneOfRefs);
158161
}
159162
}
160163

‎modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/TypeScriptClientCodegenTest.java‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,34 @@ public void testDeprecatedAttribute() throws Exception {
293293
assertEquals(1, TestUtils.countOccurrences(content, "@deprecated"));
294294
}
295295

296+
@Test
297+
public void testCircularOneOfGeneratesImports() throws Exception {
298+
final File output = Files.createTempDirectory("typescriptclient_").toFile();
299+
output.deleteOnExit();
300+
301+
final CodegenConfigurator configurator = new CodegenConfigurator()
302+
.setGeneratorName("typescript")
303+
.setInputSpec("src/test/resources/bugs/issue_23286.yaml")
304+
.setOutputDir(output.getAbsolutePath().replace("\\", "/"));
305+
306+
final ClientOptInput clientOptInput = configurator.toClientOptInput();
307+
final DefaultGenerator generator = new DefaultGenerator();
308+
final List<File> files = generator.opts(clientOptInput).generate();
309+
files.forEach(File::deleteOnExit);
310+
311+
// model with a circular oneOf branch (Array<Repro>) must import Repro
312+
TestUtils.assertFileContains(
313+
Paths.get(output + "/models/ReproContent.ts"),
314+
"import { Repro } from '../models/Repro';",
315+
"export type ReproContent = Array<Repro> | string;"
316+
);
317+
318+
configurator.setGeneratorName("typescript-redux-query");
319+
generator.opts(configurator.toClientOptInput()).generate().forEach(File::deleteOnExit);
320+
TestUtils.assertFileContains(Paths.get(output + "/src/models/ReproContent.ts"),
321+
"Repro,", "export type ReproContent = Array<Repro> | string;");
322+
}
323+
296324
@Test(description = "Verify useErasableSyntax config parameter generates erasable code")
297325
public void testUseErasableSyntaxConfig() throws IOException {
298326
boolean[] options = {true, false};
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
openapi: 3.0.3
2+
info:
3+
title: Repro
4+
version: 1.0.0
5+
paths: {}
6+
components:
7+
schemas:
8+
Repro:
9+
type: object
10+
properties:
11+
content:
12+
oneOf:
13+
- type: string
14+
- type: array
15+
items:
16+
$ref: '#/components/schemas/Repro'

0 commit comments

Comments
 (0)