forked from loafle/openapi-generator-original
[Typescript] Fix oneOf (#9628)
* on of * fix map * samples * file to any * samples * add unit tests * clear code
This commit is contained in:
@@ -19,6 +19,7 @@ package org.openapitools.codegen.languages;
|
||||
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.media.ArraySchema;
|
||||
import io.swagger.v3.oas.models.media.ComposedSchema;
|
||||
import io.swagger.v3.oas.models.media.Schema;
|
||||
import io.swagger.v3.oas.models.parameters.Parameter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -32,6 +33,8 @@ import org.slf4j.LoggerFactory;
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.openapitools.codegen.utils.StringUtils.camelize;
|
||||
import static org.openapitools.codegen.utils.StringUtils.underscore;
|
||||
|
||||
@@ -144,10 +147,12 @@ public class TypeScriptClientCodegen extends DefaultCodegen implements CodegenCo
|
||||
typeMapping.put("object", "any");
|
||||
typeMapping.put("integer", "number");
|
||||
typeMapping.put("Map", "any");
|
||||
typeMapping.put("map", "any");
|
||||
typeMapping.put("date", "string");
|
||||
typeMapping.put("DateTime", "Date");
|
||||
typeMapping.put("binary", "any");
|
||||
typeMapping.put("File", "any");
|
||||
typeMapping.put("file", "any");
|
||||
typeMapping.put("ByteArray", "string");
|
||||
typeMapping.put("UUID", "string");
|
||||
typeMapping.put("Error", "Error");
|
||||
@@ -373,40 +378,56 @@ public class TypeScriptClientCodegen extends DefaultCodegen implements CodegenCo
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toModelName(String name) {
|
||||
name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
|
||||
public String toModelName(final String name) {
|
||||
String fullModelName = name;
|
||||
fullModelName = addPrefix(fullModelName, modelNamePrefix);
|
||||
fullModelName = addSuffix(fullModelName, modelNameSuffix);
|
||||
return toTypescriptTypeName(fullModelName, "Model");
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(modelNamePrefix)) {
|
||||
name = modelNamePrefix + "_" + name;
|
||||
protected String addPrefix(String name, String prefix) {
|
||||
if (!StringUtils.isEmpty(prefix)) {
|
||||
name = prefix + "_" + name;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
protected String addSuffix(String name, String suffix) {
|
||||
if (!StringUtils.isEmpty(suffix)) {
|
||||
name = name + "_" + suffix;
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(modelNameSuffix)) {
|
||||
name = name + "_" + modelNameSuffix;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
protected String toTypescriptTypeName(final String name, String safePrefix) {
|
||||
ArrayList<String> exceptions = new ArrayList<String>(Arrays.asList("\\|", " "));
|
||||
String sanName = sanitizeName(name, "(?![| ])\\W", exceptions);
|
||||
|
||||
sanName = camelize(sanName);
|
||||
|
||||
// model name cannot use reserved keyword, e.g. return
|
||||
if (isReservedWord(name)) {
|
||||
String modelName = camelize("model_" + name);
|
||||
LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + modelName);
|
||||
// this is unlikely to happen, because we have just camelized the name, while reserved words are usually all lowcase
|
||||
if (isReservedWord(sanName)) {
|
||||
String modelName = safePrefix + sanName;
|
||||
LOGGER.warn(sanName + " (reserved word) cannot be used as model name. Renamed to " + modelName);
|
||||
return modelName;
|
||||
}
|
||||
|
||||
// model name starts with number
|
||||
if (name.matches("^\\d.*")) {
|
||||
String modelName = camelize("model_" + name); // e.g. 200Response => Model200Response (after camelize)
|
||||
LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + modelName);
|
||||
if (sanName.matches("^\\d.*")) {
|
||||
String modelName = safePrefix + sanName; // e.g. 200Response => Model200Response
|
||||
LOGGER.warn(sanName + " (model name starts with number) cannot be used as model name. Renamed to " + modelName);
|
||||
return modelName;
|
||||
}
|
||||
|
||||
if (languageSpecificPrimitives.contains(name)) {
|
||||
String modelName = camelize("model_" + name);
|
||||
LOGGER.warn(name + " (model name matches existing language type) cannot be used as a model name. Renamed to " + modelName);
|
||||
if (languageSpecificPrimitives.contains(sanName)) {
|
||||
String modelName = safePrefix + sanName;
|
||||
LOGGER.warn(sanName + " (model name matches existing language type) cannot be used as a model name. Renamed to " + modelName);
|
||||
return modelName;
|
||||
}
|
||||
|
||||
// camelize the model name
|
||||
// phone_number => PhoneNumber
|
||||
return camelize(name);
|
||||
return sanName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -521,7 +542,9 @@ public class TypeScriptClientCodegen extends DefaultCodegen implements CodegenCo
|
||||
public String getSchemaType(Schema p) {
|
||||
String openAPIType = super.getSchemaType(p);
|
||||
String type = null;
|
||||
if (typeMapping.containsKey(openAPIType)) {
|
||||
if (ModelUtils.isComposedSchema(p)) {
|
||||
return openAPIType;
|
||||
} else if (typeMapping.containsKey(openAPIType)) {
|
||||
type = typeMapping.get(openAPIType);
|
||||
if (languageSpecificPrimitives.contains(type))
|
||||
return type;
|
||||
@@ -853,4 +876,55 @@ public class TypeScriptClientCodegen extends DefaultCodegen implements CodegenCo
|
||||
codegenModel.additionalPropertiesType = getTypeDeclaration((Schema) schema.getAdditionalProperties());
|
||||
addImport(codegenModel, codegenModel.additionalPropertiesType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAnyOfName(List<String> names, ComposedSchema composedSchema) {
|
||||
List<String> types = getTypesFromSchemas(composedSchema.getAnyOf());
|
||||
|
||||
return String.join(" | ", types);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toOneOfName(List<String> names, ComposedSchema composedSchema) {
|
||||
List<String> types = getTypesFromSchemas(composedSchema.getOneOf());
|
||||
|
||||
return String.join(" | ", types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the list of type names from a list of schemas.
|
||||
* Excludes `AnyType` if there are other valid types extracted.
|
||||
*
|
||||
* @param schemas list of schemas
|
||||
* @return list of types
|
||||
*/
|
||||
protected List<String> getTypesFromSchemas(List<Schema> schemas) {
|
||||
List<Schema> filteredSchemas = schemas.size() > 1
|
||||
? schemas.stream().filter(schema -> !"AnyType".equals(super.getSchemaType(schema))).collect(Collectors.toList())
|
||||
: schemas;
|
||||
|
||||
return filteredSchemas.stream().map(schema -> {
|
||||
String schemaType = getSchemaType(schema);
|
||||
if (ModelUtils.isArraySchema(schema)) {
|
||||
ArraySchema ap = (ArraySchema) schema;
|
||||
Schema inner = ap.getItems();
|
||||
schemaType = schemaType + "<" + getSchemaType(inner) + ">";
|
||||
}
|
||||
return schemaType;
|
||||
}).distinct().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addImport(CodegenModel m, String type) {
|
||||
if (type == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String[] parts = type.split("( [|&] )|[<>]");
|
||||
for (String s : parts) {
|
||||
if (needToImport(s)) {
|
||||
m.imports.add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.openapitools.codegen.typescript;
|
||||
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.media.*;
|
||||
import org.openapitools.codegen.CodegenModel;
|
||||
import org.openapitools.codegen.DefaultCodegen;
|
||||
import org.openapitools.codegen.TestUtils;
|
||||
import org.openapitools.codegen.languages.TypeScriptClientCodegen;
|
||||
import org.openapitools.codegen.utils.ModelUtils;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
|
||||
public class TypeScriptClientModelTest {
|
||||
|
||||
@Test(description = "convert an array oneof model")
|
||||
public void arrayOneOfModelTest() {
|
||||
final Schema schema = new ArraySchema()
|
||||
.items(new ComposedSchema()
|
||||
.addOneOfItem(new StringSchema())
|
||||
.addOneOfItem(new IntegerSchema().format("int64")))
|
||||
.description("an array oneof model");
|
||||
final DefaultCodegen codegen = new TypeScriptClientCodegen();
|
||||
OpenAPI openAPI = TestUtils.createOpenAPIWithOneSchema("sample", schema);
|
||||
codegen.setOpenAPI(openAPI);
|
||||
final CodegenModel cm = codegen.fromModel("sample", schema);
|
||||
|
||||
|
||||
Assert.assertEquals(cm.name, "sample");
|
||||
Assert.assertEquals(cm.classname, "Sample");
|
||||
Assert.assertEquals(cm.description, "an array oneof model");
|
||||
Assert.assertEquals(cm.arrayModelType, "string | number");
|
||||
Assert.assertEquals(cm.vars.size(), 0);
|
||||
}
|
||||
|
||||
@Test(description = "convert an any of with array oneof model")
|
||||
public void objectPropertyAnyOfWithArrayOneOfModelTest() {
|
||||
final Schema schema = new ObjectSchema().addProperties("value",
|
||||
new ComposedSchema().addAnyOfItem(new StringSchema()).addAnyOfItem(new ArraySchema()
|
||||
.items(new ComposedSchema()
|
||||
.addOneOfItem(new StringSchema())
|
||||
.addOneOfItem(new IntegerSchema().format("int64")))))
|
||||
.description("an any of with array oneof model");
|
||||
final DefaultCodegen codegen = new TypeScriptClientCodegen();
|
||||
OpenAPI openAPI = TestUtils.createOpenAPIWithOneSchema("sample", schema);
|
||||
codegen.setOpenAPI(openAPI);
|
||||
final CodegenModel cm = codegen.fromModel("sample", schema);
|
||||
|
||||
String s = codegen.getSchemaType((Schema)schema.getProperties().get("value"));
|
||||
|
||||
Assert.assertEquals(cm.name, "sample");
|
||||
Assert.assertEquals(cm.classname, "Sample");
|
||||
Assert.assertEquals(cm.description, "an any of with array oneof model");
|
||||
Assert.assertEquals(cm.vars.size(), 1);
|
||||
Assert.assertEquals(s, "string | Array<string | number>");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user