Skip to content

Commit eee422e

Browse files
Improve oneOf type categorization in ExtendedCodegenModel
1 parent 97a775d commit eee422e

6 files changed

Lines changed: 152 additions & 19 deletions

File tree

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

Lines changed: 148 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import java.util.*;
5151
import java.util.regex.Matcher;
5252
import java.util.regex.Pattern;
53+
import java.util.stream.Collectors;
5354

5455
import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER;
5556
import static org.openapitools.codegen.utils.OnceLogger.once;
@@ -362,12 +363,22 @@ private String getNameWithEnumPropertyNaming(String name) {
362363
}
363364
}
364365

366+
@Override
367+
public CodegenModel fromModel(String name, Schema schema) {
368+
CodegenModel codegenModel = super.fromModel(name, schema);
369+
return new ExtendedCodegenModel(codegenModel);
370+
}
371+
365372
@Override
366373
public ModelsMap postProcessModels(ModelsMap objs) {
367374
// process enum in models
368375
List<ModelMap> models = postProcessModelsEnum(objs).getModels();
369376
for (ModelMap mo : models) {
370-
CodegenModel cm = mo.getModel();
377+
CodegenModel model = mo.getModel();
378+
// Convert to ExtendedCodegenModel if it's not already one (e.g., in tests)
379+
ExtendedCodegenModel cm = model instanceof ExtendedCodegenModel
380+
? (ExtendedCodegenModel) model
381+
: new ExtendedCodegenModel(model);
371382
cm.imports = new TreeSet<>(cm.imports);
372383
// name enum with model name, e.g. StatusEnum => Pet.StatusEnum
373384
for (CodegenProperty var : cm.vars) {
@@ -383,15 +394,37 @@ public ModelsMap postProcessModels(ModelsMap objs) {
383394
}
384395
}
385396
}
397+
398+
List<CodegenProperty> oneOfsList = Optional.ofNullable(cm.getComposedSchemas())
399+
.map(CodegenComposedSchemas::getOneOf)
400+
.orElse(Collections.emptyList());
401+
402+
// create a set of any non-primitive, non-array types used in the oneOf schemas which will
403+
// need to be imported.
404+
cm.oneOfModels = oneOfsList.stream()
405+
.filter(cp -> !cp.getIsPrimitiveType() && !cp.getIsArray())
406+
.map(CodegenProperty::getBaseType)
407+
.filter(Objects::nonNull)
408+
.collect(Collectors.toCollection(TreeSet::new));
409+
410+
// create a set of any complex, inner types used by arrays in the oneOf schema (e.g. if
411+
// the oneOf uses Array<Foo>, Foo needs to be imported).
412+
cm.oneOfArrays = oneOfsList.stream()
413+
.filter(CodegenProperty::getIsArray)
414+
.map(CodegenProperty::getComplexType)
415+
.filter(Objects::nonNull)
416+
.collect(Collectors.toCollection(TreeSet::new));
417+
418+
// create a set of primitive types used in the oneOf schemas for the deserialization process.
419+
cm.oneOfPrimitives = oneOfsList.stream()
420+
.filter(CodegenProperty::getIsPrimitiveType)
421+
.collect(Collectors.toCollection(HashSet::new));
422+
386423
if (!cm.oneOf.isEmpty()) {
387424
// For oneOfs only import $refs within the oneOf
388-
TreeSet<String> oneOfRefs = new TreeSet<>();
389-
for (String im : cm.imports) {
390-
if (cm.oneOf.contains(im)) {
391-
oneOfRefs.add(im);
392-
}
393-
}
394-
cm.imports = oneOfRefs;
425+
cm.imports = cm.imports.stream()
426+
.filter(im -> cm.oneOfModels.contains(im) || cm.oneOfArrays.contains(im))
427+
.collect(Collectors.toCollection(TreeSet::new));
395428
}
396429
}
397430
for (ModelMap mo : models) {
@@ -1119,4 +1152,111 @@ protected void addImport(Set<String> importsToBeAddedTo, String type) {
11191152
protected String[] splitComposedTypes(String type) {
11201153
return type.replace(" ", "").split("[|&<>]");
11211154
}
1155+
1156+
public class ExtendedCodegenModel extends CodegenModel {
1157+
// oneOfModels contains a list of non-primitive, non-array types referenced in oneOf schemas that need to be
1158+
// imported.
1159+
// oneOfArrays contains a list of complex inner types used in arrays within oneOf schemas (e.g. if
1160+
// oneOf uses Array<Foo>, Foo needs to be imported).
1161+
// oneOfPrimitives contains a list of primitive types used in oneOf schemas for the deserialization process.
1162+
@Getter @Setter
1163+
public Set<String> oneOfModels = new TreeSet<>();
1164+
@Getter @Setter
1165+
public Set<String> oneOfArrays = new TreeSet<>();
1166+
@Getter @Setter
1167+
public Set<CodegenProperty> oneOfPrimitives = new HashSet<>();
1168+
1169+
public ExtendedCodegenModel(CodegenModel cm) {
1170+
super();
1171+
1172+
this.parent = cm.parent;
1173+
this.parentSchema = cm.parentSchema;
1174+
this.interfaces = cm.interfaces;
1175+
this.allParents = cm.allParents;
1176+
this.parentModel = cm.parentModel;
1177+
this.interfaceModels = cm.interfaceModels;
1178+
this.children = cm.children;
1179+
this.anyOf = cm.anyOf;
1180+
this.oneOf = cm.oneOf;
1181+
this.allOf = cm.allOf;
1182+
this.permits = cm.permits;
1183+
this.name = cm.name;
1184+
this.schemaName = cm.schemaName;
1185+
this.classname = cm.classname;
1186+
this.title = cm.title;
1187+
this.description = cm.description;
1188+
this.classVarName = cm.classVarName;
1189+
this.modelJson = cm.modelJson;
1190+
this.dataType = cm.dataType;
1191+
this.xmlPrefix = cm.xmlPrefix;
1192+
this.xmlNamespace = cm.xmlNamespace;
1193+
this.xmlName = cm.xmlName;
1194+
this.classFilename = cm.classFilename;
1195+
this.unescapedDescription = cm.unescapedDescription;
1196+
this.discriminator = cm.discriminator;
1197+
this.defaultValue = cm.defaultValue;
1198+
this.arrayModelType = cm.arrayModelType;
1199+
this.isAlias = cm.isAlias;
1200+
this.isString = cm.isString;
1201+
this.isInteger = cm.isInteger;
1202+
this.isLong = cm.isLong;
1203+
this.isNumber = cm.isNumber;
1204+
this.isNumeric = cm.isNumeric;
1205+
this.isFloat = cm.isFloat;
1206+
this.isDouble = cm.isDouble;
1207+
this.isDate = cm.isDate;
1208+
this.isDateTime = cm.isDateTime;
1209+
this.vars = cm.vars;
1210+
this.allVars = cm.allVars;
1211+
this.requiredVars = cm.requiredVars;
1212+
this.optionalVars = cm.optionalVars;
1213+
this.hasReadOnly = cm.hasReadOnly;
1214+
this.readOnlyVars = cm.readOnlyVars;
1215+
this.readWriteVars = cm.readWriteVars;
1216+
this.parentVars = cm.parentVars;
1217+
this.parentRequiredVars = cm.parentRequiredVars;
1218+
this.nonNullableVars = cm.nonNullableVars;
1219+
this.allowableValues = cm.allowableValues;
1220+
this.mandatory = cm.mandatory;
1221+
this.allMandatory = cm.allMandatory;
1222+
this.imports = cm.imports;
1223+
this.hasVars = cm.hasVars;
1224+
this.emptyVars = cm.emptyVars;
1225+
this.hasMoreModels = cm.hasMoreModels;
1226+
this.hasEnums = cm.hasEnums;
1227+
this.isEnum = cm.isEnum;
1228+
this.hasValidation = cm.hasValidation;
1229+
this.isNullable = cm.isNullable;
1230+
this.hasRequired = cm.hasRequired;
1231+
this.hasOptional = cm.hasOptional;
1232+
this.isArray = cm.isArray;
1233+
this.hasChildren = cm.hasChildren;
1234+
this.isMap = cm.isMap;
1235+
this.isDeprecated = cm.isDeprecated;
1236+
this.hasOnlyReadOnly = cm.hasOnlyReadOnly;
1237+
this.externalDocumentation = cm.externalDocumentation;
1238+
1239+
this.vendorExtensions = cm.vendorExtensions;
1240+
this.additionalPropertiesType = cm.additionalPropertiesType;
1241+
this.isAdditionalPropertiesTrue = cm.isAdditionalPropertiesTrue;
1242+
this.setMaxProperties(cm.getMaxProperties());
1243+
this.setMinProperties(cm.getMinProperties());
1244+
this.setUniqueItems(cm.getUniqueItems());
1245+
this.setMaxItems(cm.getMaxItems());
1246+
this.setMinItems(cm.getMinItems());
1247+
this.setMaxLength(cm.getMaxLength());
1248+
this.setMinLength(cm.getMinLength());
1249+
this.setExclusiveMinimum(cm.getExclusiveMinimum());
1250+
this.setExclusiveMaximum(cm.getExclusiveMaximum());
1251+
this.setMinimum(cm.getMinimum());
1252+
this.setMaximum(cm.getMaximum());
1253+
this.setPattern(cm.getPattern());
1254+
this.setMultipleOf(cm.getMultipleOf());
1255+
this.setItems(cm.getItems());
1256+
this.setAdditionalProperties(cm.getAdditionalProperties());
1257+
this.setIsModel(cm.getIsModel());
1258+
this.setComposedSchemas(cm.getComposedSchemas());
1259+
}
1260+
1261+
}
11221262
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export class {{classname}}Class {
3030
static readonly mapping: {[index: string]: string} | undefined = undefined;
3131
{{/hasDiscriminatorWithNonEmptyMapping}}
3232

33-
private static readonly arrayOfTypes: Array<{{#oneOf}}typeof {{{.}}}{{^-last}} | {{/-last}}{{/oneOf}}> = [{{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}}];
33+
private static readonly arrayOfTypes: Array<{{#oneOfModels}}typeof {{{.}}}{{^-last}} | {{/-last}}{{/oneOfModels}}> = [{{#oneOfModels}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOfModels}}];
3434

3535
/**
3636
* Determines which oneOf schema matches the provided data.

samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetsPatchRequest.ts

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

samples/openapi3/client/petstore/typescript/builds/explode-query/models/Animal.ts

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

samples/openapi3/client/petstore/typescript/builds/one-of/.openapi-generator/FILES

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

samples/openapi3/client/petstore/typescript/builds/one-of/models/PetDiscriminatorResponse.ts

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

0 commit comments

Comments
 (0)