From 0c17e094959b43dbeba594e84e44610b6c735c06 Mon Sep 17 00:00:00 2001 From: Lee Ween Jiann <16207788+lwj5@users.noreply.github.com> Date: Fri, 31 Mar 2023 22:52:06 +0800 Subject: [PATCH 1/8] Make TypeScriptClientCodegen extend AbstractTypeScriptClientCodegen --- .../AbstractTypeScriptClientCodegen.java | 12 +- .../languages/TypeScriptClientCodegen.java | 578 ++---------------- 2 files changed, 46 insertions(+), 544 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractTypeScriptClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractTypeScriptClientCodegen.java index 779a71ccf60f..9550e01de0da 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractTypeScriptClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractTypeScriptClientCodegen.java @@ -25,10 +25,10 @@ import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; import org.checkerframework.checker.nullness.qual.Nullable; +import org.openapitools.codegen.*; import org.openapitools.codegen.CodegenConstants.ENUM_PROPERTY_NAMING_TYPE; import org.openapitools.codegen.CodegenConstants.MODEL_PROPERTY_NAMING_TYPE; import org.openapitools.codegen.CodegenConstants.PARAM_NAMING_TYPE; -import org.openapitools.codegen.*; import org.openapitools.codegen.meta.features.*; import org.openapitools.codegen.model.ModelMap; import org.openapitools.codegen.model.ModelsMap; @@ -46,7 +46,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.openapitools.codegen.languages.AbstractTypeScriptClientCodegen.ParameterExpander.ParamStyle.*; +import static org.openapitools.codegen.languages.AbstractTypeScriptClientCodegen.ParameterExpander.ParamStyle.form; +import static org.openapitools.codegen.languages.AbstractTypeScriptClientCodegen.ParameterExpander.ParamStyle.simple; import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER; import static org.openapitools.codegen.utils.StringUtils.camelize; import static org.openapitools.codegen.utils.StringUtils.underscore; @@ -392,10 +393,7 @@ public void processOpts() { setParamNaming((String) additionalProperties.get(CodegenConstants.PARAM_NAMING)); } - if (additionalProperties.containsKey(CodegenConstants.SUPPORTS_ES6)) { - setSupportsES6(Boolean.valueOf(additionalProperties.get(CodegenConstants.SUPPORTS_ES6).toString())); - additionalProperties.put("supportsES6", getSupportsES6()); - } + convertPropertyToBooleanAndWriteBack(CodegenConstants.SUPPORTS_ES6); if (additionalProperties.containsKey(NULL_SAFE_ADDITIONAL_PROPS)) { setNullSafeAdditionalProps(Boolean.valueOf(additionalProperties.get(NULL_SAFE_ADDITIONAL_PROPS).toString())); @@ -839,7 +837,7 @@ public String toEnumValue(String value, String datatype) { if ("number".equals(datatype) || "boolean".equals(datatype)) { return value; } else { - return "\'" + escapeText(value) + "\'"; + return "'" + escapeText(value) + "'"; } } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java index d346d9030635..419561e8a590 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java @@ -17,17 +17,12 @@ package org.openapitools.codegen.languages; +import com.github.curiousoddman.rgxgen.RgxGen; import com.google.common.collect.Sets; - import io.swagger.v3.core.util.Json; import io.swagger.v3.oas.models.media.*; -import io.swagger.v3.oas.models.media.MediaType; -import io.swagger.v3.oas.models.parameters.RequestBody; -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 io.swagger.v3.oas.models.parameters.RequestBody; import org.apache.commons.lang3.StringUtils; import org.openapitools.codegen.*; import org.openapitools.codegen.CodegenDiscriminator.MappedModel; @@ -40,42 +35,31 @@ import org.openapitools.codegen.utils.ModelUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.github.curiousoddman.rgxgen.RgxGen; -import com.github.curiousoddman.rgxgen.config.RgxGenOption; -import com.github.curiousoddman.rgxgen.config.RgxGenProperties; import java.io.File; +import java.text.SimpleDateFormat; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; -import java.util.regex.Pattern; -import java.util.regex.Matcher; -import java.text.SimpleDateFormat; import java.util.*; -import java.util.stream.Collectors; - -import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER; -import static org.openapitools.codegen.utils.StringUtils.camelize; -import static org.openapitools.codegen.utils.StringUtils.underscore; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static org.openapitools.codegen.utils.OnceLogger.once; -public class TypeScriptClientCodegen extends DefaultCodegen implements CodegenConfig { +public class TypeScriptClientCodegen extends AbstractTypeScriptClientCodegen implements CodegenConfig { private final Logger LOGGER = LoggerFactory.getLogger(TypeScriptClientCodegen.class); - private static final String X_DISCRIMINATOR_TYPE = "x-discriminator-value"; - private static final String UNDEFINED_VALUE = "undefined"; - private static final String FRAMEWORK_SWITCH = "framework"; private static final String FRAMEWORK_SWITCH_DESC = "Specify the framework which should be used in the client code."; - private static final String[] FRAMEWORKS = { "fetch-api", "jquery" }; + private static final String[] FRAMEWORKS = {"fetch-api", "jquery"}; private static final String PLATFORM_SWITCH = "platform"; private static final String PLATFORM_SWITCH_DESC = "Specifies the platform the code should run on. The default is 'node' for the 'request' framework and 'browser' otherwise."; - private static final String[] PLATFORMS = { "browser", "node", "deno" }; + private static final String[] PLATFORMS = {"browser", "node", "deno"}; private static final String IMPORT_FILE_EXTENSION_SWITCH = "importFileExtension"; private static final String IMPORT_FILE_EXTENSION_SWITCH_DESC = "File extension to use with relative imports. Set it to '.js' or '.mjs' when using [ESM](https://nodejs.org/api/esm.html). Defaults to '.ts' when 'platform' is set to 'deno'."; - private static final String FILE_CONTENT_DATA_TYPE= "fileContentDataType"; + private static final String FILE_CONTENT_DATA_TYPE = "fileContentDataType"; private static final String FILE_CONTENT_DATA_TYPE_DESC = "Specifies the type to use for the content of a file - i.e. Blob (Browser, Deno) / Buffer (node)"; private static final String USE_RXJS_SWITCH = "useRxJS"; private static final String USE_RXJS_SWITCH_DESC = "Enable this to internally use rxjs observables. If disabled, a stub is used instead. This is required for the 'angular' framework."; @@ -85,27 +69,19 @@ public class TypeScriptClientCodegen extends DefaultCodegen implements CodegenCo private static final String USE_OBJECT_PARAMS_SWITCH = "useObjectParameters"; private static final String USE_OBJECT_PARAMS_DESC = "Use aggregate parameter objects as function arguments for api operations instead of passing each parameter as a separate function argument."; - private final Map frameworkToHttpLibMap; // NPM Options - private static final String SNAPSHOT = "snapshot"; - @SuppressWarnings("squid:S5164") - protected static final ThreadLocal SNAPSHOT_SUFFIX_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMMddHHmm", Locale.ROOT)); private static final String NPM_REPOSITORY = "npmRepository"; - private static final String NPM_NAME = "npmName"; - private static final String NPM_VERSION = "npmVersion"; // NPM Option Values protected String npmRepository = null; protected String snapshot = null; - protected String npmName = null; - protected String npmVersion = "1.0.0"; + protected String modelPropertyNaming = "camelCase"; - protected HashSet languageGenericTypes; - private DateTimeFormatter iso8601Date = DateTimeFormatter.ISO_DATE; - private DateTimeFormatter iso8601DateTime = DateTimeFormatter.ISO_DATE_TIME; + private final DateTimeFormatter iso8601Date = DateTimeFormatter.ISO_DATE; + private final DateTimeFormatter iso8601DateTime = DateTimeFormatter.ISO_DATE_TIME; public TypeScriptClientCodegen() { super(); @@ -120,82 +96,19 @@ public TypeScriptClientCodegen() { outputFolder = "generated-code" + File.separator + "typescript"; embeddedTemplateDir = templateDir = "typescript"; - supportsInheritance = true; - // NOTE: TypeScript uses camel cased reserved words, while models are title cased. We don't want lowercase comparisons. reservedWords.addAll(Arrays.asList( // local variable names used in API methods (endpoints) - "varLocalPath", "queryParameters", "headerParams", "formParams", "useFormData", "varLocalDeferred", - "requestOptions", "from", + "from", // Typescript reserved words - "abstract", "await", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "constructor", "continue", "debugger", "default", "delete", "do", "double", "else", "enum", "export", "extends", "false", "final", "finally", "float", "for", "function", "goto", "if", "implements", "import", "in", "instanceof", "int", "interface", "let", "long", "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static", "super", "switch", "synchronized", "this", "throw", "transient", "true", "try", "typeof", "var", "void", "volatile", "while", "with", "yield")); - - languageSpecificPrimitives = new HashSet<>(Arrays.asList( - "string", - "String", - "boolean", - "Boolean", - "Double", - "Integer", - "Long", - "Float", - "Object", - "Array", - "Date", - "number", - "any", - "File", - "Error", - "Map", - "Set" - )); - - languageGenericTypes = new HashSet<>(Arrays.asList( - "Array" - )); - - instantiationTypes.put("array", "Array"); + "constructor")); - typeMapping = new HashMap<>(); - typeMapping.put("Array", "Array"); - typeMapping.put("array", "Array"); typeMapping.put("List", "Array"); - typeMapping.put("boolean", "boolean"); - typeMapping.put("string", "string"); - typeMapping.put("int", "number"); - typeMapping.put("float", "number"); - typeMapping.put("number", "number"); - typeMapping.put("long", "number"); - typeMapping.put("short", "number"); - typeMapping.put("char", "string"); - typeMapping.put("double", "number"); typeMapping.put("object", "any"); - typeMapping.put("integer", "number"); - typeMapping.put("Map", "any"); - typeMapping.put("map", "any"); - typeMapping.put("Set", "Set"); - typeMapping.put("set", "Set"); - 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"); - typeMapping.put("AnyType", "any"); - - - cliOptions.add(new CliOption(NPM_NAME, "The name under which you want to publish generated npm package." + - " Required to generate a full package")); - cliOptions.add(new CliOption(NPM_VERSION, "The version of your npm package. If not provided, using the version from the OpenAPI specification file.").defaultValue(this.getNpmVersion())); - cliOptions.add(new CliOption(NPM_REPOSITORY, "Use this property to set an url your private npmRepo in the package.json")); - cliOptions.add(CliOption.newBoolean(SNAPSHOT, - "When setting this property to true, the version will be suffixed with -SNAPSHOT." + SNAPSHOT_SUFFIX_FORMAT.get().toPattern(), - false)); - - cliOptions.add(new CliOption(CodegenConstants.MODEL_PROPERTY_NAMING, CodegenConstants.MODEL_PROPERTY_NAMING_DESC).defaultValue("camelCase")); - cliOptions.add(new CliOption(CodegenConstants.SUPPORTS_ES6, CodegenConstants.SUPPORTS_ES6_DESC).defaultValue("false")); + +cliOptions.add(new CliOption(NPM_REPOSITORY, "Use this property to set an url your private npmRepo in the package.json")); +// cliOptions.add(new CliOption(CodegenConstants.MODEL_PROPERTY_NAMING, CodegenConstants.MODEL_PROPERTY_NAMING_DESC).defaultValue("camelCase")); cliOptions.add(new CliOption(TypeScriptClientCodegen.FILE_CONTENT_DATA_TYPE, TypeScriptClientCodegen.FILE_CONTENT_DATA_TYPE_DESC).defaultValue("Buffer")); cliOptions.add(new CliOption(TypeScriptClientCodegen.USE_RXJS_SWITCH, TypeScriptClientCodegen.USE_RXJS_SWITCH_DESC).defaultValue("false")); cliOptions.add(new CliOption(TypeScriptClientCodegen.USE_OBJECT_PARAMS_SWITCH, TypeScriptClientCodegen.USE_OBJECT_PARAMS_DESC).defaultValue("false")); @@ -203,14 +116,14 @@ public TypeScriptClientCodegen() { cliOptions.add(new CliOption(TypeScriptClientCodegen.IMPORT_FILE_EXTENSION_SWITCH, TypeScriptClientCodegen.IMPORT_FILE_EXTENSION_SWITCH_DESC)); CliOption frameworkOption = new CliOption(TypeScriptClientCodegen.FRAMEWORK_SWITCH, TypeScriptClientCodegen.FRAMEWORK_SWITCH_DESC); - for (String option: TypeScriptClientCodegen.FRAMEWORKS) { + for (String option : TypeScriptClientCodegen.FRAMEWORKS) { frameworkOption.addEnum(option, option); } frameworkOption.defaultValue(FRAMEWORKS[0]); cliOptions.add(frameworkOption); CliOption platformOption = new CliOption(TypeScriptClientCodegen.PLATFORM_SWITCH, TypeScriptClientCodegen.PLATFORM_SWITCH_DESC); - for (String option: TypeScriptClientCodegen.PLATFORMS) { + for (String option : TypeScriptClientCodegen.PLATFORMS) { platformOption.addEnum(option, option); } platformOption.defaultValue(PLATFORMS[0]); @@ -274,42 +187,12 @@ public void setNpmVersion(String npmVersion) { this.npmVersion = npmVersion; } - @Override - public CodegenType getTag() { - return CodegenType.CLIENT; - } - - @Override - public void preprocessOpenAPI(OpenAPI openAPI) { - - if (additionalProperties.containsKey(NPM_NAME)) { - - // If no npmVersion is provided in additional properties, version from API specification is used. - // If none of them is provided then fallbacks to default version - if (additionalProperties.containsKey(NPM_VERSION)) { - this.setNpmVersion(additionalProperties.get(NPM_VERSION).toString()); - } else if (openAPI.getInfo() != null && openAPI.getInfo().getVersion() != null) { - this.setNpmVersion(openAPI.getInfo().getVersion()); - } - - if (additionalProperties.containsKey(SNAPSHOT) && Boolean.parseBoolean(additionalProperties.get(SNAPSHOT).toString())) { - if (npmVersion.toUpperCase(Locale.ROOT).matches("^.*-SNAPSHOT$")) { - this.setNpmVersion(npmVersion + "." + SNAPSHOT_SUFFIX_FORMAT.get().format(new Date())); - } else { - this.setNpmVersion(npmVersion + "-SNAPSHOT." + SNAPSHOT_SUFFIX_FORMAT.get().format(new Date())); - } - } - additionalProperties.put(NPM_VERSION, npmVersion); - - } - } - @Override public Map postProcessSupportingFileData(Map objs) { final Object propFramework = additionalProperties.get(FRAMEWORK_SWITCH); Map frameworks = new HashMap<>(); - for (String framework: FRAMEWORKS) { + for (String framework : FRAMEWORKS) { frameworks.put(framework, framework.equals(propFramework)); } objs.put("framework", propFramework); @@ -331,7 +214,7 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap operations, L OperationMap operationsMap = operations.getOperations(); List operationList = operationsMap.getOperation(); - for (CodegenOperation operation: operationList) { + for (CodegenOperation operation : operationList) { List responses = operation.responses; operation.returnType = this.getReturnType(responses); } @@ -340,12 +223,13 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap operations, L /** * Returns the correct return type based on all 2xx HTTP responses defined for an operation. + * * @param responses all CodegenResponses defined for one operation * @return TypeScript return type */ private String getReturnType(List responses) { Set returnTypes = new HashSet<>(); - for (CodegenResponse response: responses) { + for (CodegenResponse response : responses) { if (response.is2xx) { if (response.dataType != null) { returnTypes.add(response.dataType); @@ -362,22 +246,8 @@ private String getReturnType(List responses) { return String.join(" | ", returnTypes); } - @Override - public String escapeReservedWord(String name) { - if (this.reservedWordsMappings().containsKey(name)) { - return this.reservedWordsMappings().get(name); - } - return "_" + name; - } - @Override public String toParamName(String name) { - // should be the same as variable name - return toVarName(name); - } - - @Override - public String toVarName(String name) { // sanitize name name = sanitizeName(name); @@ -390,213 +260,30 @@ public String toVarName(String name) { return name; } - name = getNameUsingModelPropertyNaming(name); - - // for reserved word or word starting with number, append _ - if (isReservedWord(name) || name.matches("^\\d.*")) { - name = escapeReservedWord(name); - } - - return name; - } - - @Override - public String toModelName(final String name) { - String fullModelName = name; - fullModelName = addPrefix(fullModelName, modelNamePrefix); - fullModelName = addSuffix(fullModelName, modelNameSuffix); - return toTypescriptTypeName(fullModelName, "Model"); - } - - @Override - public String toModelImport(String name) { - // Use `/` instead of `File.Separator`. `File.Separator` is `\` in Windows, which is invalid Typescript. - return "../" + modelPackage() + "/" + toModelName(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; - } - - return name; - } - - protected String toTypescriptTypeName(final String name, String safePrefix) { - ArrayList exceptions = new ArrayList<>(Arrays.asList("\\|", " ")); - String sanName = sanitizeName(name, "(?![| ])\\W", exceptions); - - sanName = camelize(sanName); - - // model name cannot use reserved keyword, e.g. return - // this is unlikely to happen, because we have just camelized the name, while reserved words are usually all lowercase - if (isReservedWord(sanName)) { - String modelName = safePrefix + sanName; - LOGGER.warn("{} (reserved word) cannot be used as model name. Renamed to {}", sanName, modelName); - return modelName; - } - - // model name starts with number - if (sanName.matches("^\\d.*")) { - String modelName = safePrefix + sanName; // e.g. 200Response => Model200Response - LOGGER.warn("{} (model name starts with number) cannot be used as model name. Renamed to {}", sanName, - modelName); - return modelName; - } - - if (languageSpecificPrimitives.contains(sanName)) { - String modelName = safePrefix + sanName; - LOGGER.warn("{} (model name matches existing language type) cannot be used as a model name. Renamed to {}", - sanName, modelName); - return modelName; - } - - return sanName; - } - - @Override - public String toModelFilename(String name) { - // should be the same as the model name - return toModelName(name); + return super.toParamName(name); } @Override - protected String getParameterDataType(Parameter parameter, Schema p) { - // handle enums of various data types - Schema inner; - if (ModelUtils.isArraySchema(p)) { - ArraySchema mp1 = (ArraySchema) p; - inner = mp1.getItems(); - return this.getSchemaType(p) + "<" + this.getParameterDataType(parameter, inner) + ">"; - } else if (ModelUtils.isMapSchema(p)) { - inner = (Schema) p.getAdditionalProperties(); - return "{ [key: string]: " + this.getParameterDataType(parameter, inner) + "; }"; - } else if (ModelUtils.isStringSchema(p)) { - // Handle string enums - if (p.getEnum() != null) { - return enumValuesToEnumTypeUnion(p.getEnum(), "string"); - } - } else if (ModelUtils.isIntegerSchema(p)) { - // Handle integer enums - if (p.getEnum() != null) { - return numericEnumValuesToEnumTypeUnion(new ArrayList(p.getEnum())); - } - } else if (ModelUtils.isNumberSchema(p)) { - // Handle double enums - if (p.getEnum() != null) { - return numericEnumValuesToEnumTypeUnion(new ArrayList(p.getEnum())); - } - } - return this.getTypeDeclaration(p); - } - - /** - * Converts a list of strings to a literal union for representing enum values as a type. - * Example output: 'available' | 'pending' | 'sold' - * - * @param values list of allowed enum values - * @param dataType either "string" or "number" - * @return a literal union for representing enum values as a type - */ - protected String enumValuesToEnumTypeUnion(List values, String dataType) { - StringBuilder b = new StringBuilder(); - boolean isFirst = true; - for (String value : values) { - if (!isFirst) { - b.append(" | "); - } - b.append(toEnumValue(value, dataType)); - isFirst = false; - } - return b.toString(); - } + public String toVarName(String name) { + // sanitize name + name = sanitizeName(name); - /** - * Converts a list of numbers to a literal union for representing enum values as a type. - * Example output: 3 | 9 | 55 - * - * @param values a list of numbers - * @return a literal union for representing enum values as a type - */ - protected String numericEnumValuesToEnumTypeUnion(List values) { - List stringValues = new ArrayList<>(); - for (Number value : values) { - stringValues.add(value.toString()); + if ("_".equals(name)) { + name = "_u"; } - return enumValuesToEnumTypeUnion(stringValues, "number"); - } - @Override - public String toDefaultValue(Schema p) { - if (ModelUtils.isBooleanSchema(p)) { - return UNDEFINED_VALUE; - } else if (ModelUtils.isDateSchema(p)) { - return UNDEFINED_VALUE; - } else if (ModelUtils.isDateTimeSchema(p)) { - return UNDEFINED_VALUE; - } else if (ModelUtils.isNumberSchema(p)) { - if (p.getDefault() != null) { - return p.getDefault().toString(); - } - return UNDEFINED_VALUE; - } else if (ModelUtils.isIntegerSchema(p)) { - if (p.getDefault() != null) { - return p.getDefault().toString(); - } - return UNDEFINED_VALUE; - } else if (ModelUtils.isStringSchema(p)) { - if (p.getDefault() != null) { - return "'" + (String) p.getDefault() + "'"; - } - return UNDEFINED_VALUE; - } else { - return UNDEFINED_VALUE; + // if it's all upper case, do nothing + if (name.matches("^[A-Z_]*$")) { + return name; } + return super.toVarName(name); } @Override - protected boolean isReservedWord(String word) { - // NOTE: This differs from super's implementation in that TypeScript does _not_ want case insensitive matching. - return reservedWords.contains(word); - } - - @Override - public String getSchemaType(Schema p) { - String openAPIType = super.getSchemaType(p); - String type = null; - if (ModelUtils.isComposedSchema(p)) { - return openAPIType; - } else if (typeMapping.containsKey(openAPIType)) { - type = typeMapping.get(openAPIType); - if (languageSpecificPrimitives.contains(type)) - return type; - } else - type = openAPIType; - return toModelName(type); - } - - @Override - public String toOperationId(String operationId) { - // throw exception if method name is empty - if (StringUtils.isEmpty(operationId)) { - throw new RuntimeException("Empty method name (operationId) not allowed"); - } - - // method name cannot use reserved keyword, e.g. return - // append _ at the beginning, e.g. _return - if (isReservedWord(operationId)) { - return escapeReservedWord(camelize(sanitizeName(operationId), LOWERCASE_FIRST_LETTER)); - } - - return camelize(sanitizeName(operationId), LOWERCASE_FIRST_LETTER); + public String toModelImport(String name) { + // Use `/` instead of `File.Separator`. `File.Separator` is `\` in Windows, which is invalid Typescript. + return "../" + modelPackage() + "/" + toModelName(name); } public void setModelPropertyNaming(String naming) { @@ -610,76 +297,12 @@ public void setModelPropertyNaming(String naming) { } } - public String getModelPropertyNaming() { - return this.modelPropertyNaming; - } - - public String getNameUsingModelPropertyNaming(String name) { - switch (CodegenConstants.MODEL_PROPERTY_NAMING_TYPE.valueOf(getModelPropertyNaming())) { - case original: - return name; - case camelCase: - return camelize(name, LOWERCASE_FIRST_LETTER); - case PascalCase: - return camelize(name); - case snake_case: - return underscore(name); - default: - throw new IllegalArgumentException("Invalid model property naming '" + - name + "'. Must be 'original', 'camelCase', " + - "'PascalCase' or 'snake_case'"); - } - - } - @Override public String toEnumValue(String value, String datatype) { if ("number".equals(datatype)) { return value; } else { - return "\'" + escapeText(value) + "\'"; - } - } - - @Override - public String toEnumDefaultValue(String value, String datatype) { - return datatype + "_" + value; - } - - @Override - public String toEnumVarName(String name, String datatype) { - if (name.length() == 0) { - return "Empty"; - } - - // for symbol, e.g. $, # - if (getSymbolName(name) != null) { - return camelize(getSymbolName(name)); - } - - // number - if ("number".equals(datatype)) { - String varName = "NUMBER_" + name; - - varName = varName.replaceAll("-", "MINUS_"); - varName = varName.replaceAll("\\+", "PLUS_"); - varName = varName.replaceAll("\\.", "_DOT_"); - return varName; - } - - // string - String enumName = sanitizeName(name); - enumName = enumName.replaceFirst("^_", ""); - enumName = enumName.replaceFirst("_$", ""); - - // camelize the enum variable name - // ref: https://basarat.gitbooks.io/typescript/content/docs/enums.html - enumName = camelize(enumName); - - if (enumName.matches("\\d.*")) { // starts with number - return "_" + enumName; - } else { - return enumName; + return "'" + escapeText(value) + "'"; } } @@ -738,53 +361,6 @@ private List> toTsImports(CodegenModel cm, Set impor return tsImports; } - @Override - public Map postProcessAllModels(Map objs) { - Map result = super.postProcessAllModels(objs); - - for (ModelsMap entry : result.values()) { - for (ModelMap mo : entry.getModels()) { - CodegenModel cm = mo.getModel(); - if (cm.discriminator != null && cm.children != null) { - for (CodegenModel child : cm.children) { - this.setDiscriminatorValue(child, cm.discriminator.getPropertyName(), this.getDiscriminatorValue(child)); - } - } - } - } - return result; - } - - private void setDiscriminatorValue(CodegenModel model, String baseName, String value) { - for (CodegenProperty prop : model.allVars) { - if (prop.baseName.equals(baseName)) { - prop.discriminatorValue = value; - } - } - if (model.children != null) { - final boolean newDiscriminator = model.discriminator != null; - for (CodegenModel child : model.children) { - this.setDiscriminatorValue(child, baseName, newDiscriminator ? value : this.getDiscriminatorValue(child)); - } - } - } - - private String getDiscriminatorValue(CodegenModel model) { - return model.vendorExtensions.containsKey(X_DISCRIMINATOR_TYPE) ? - (String) model.vendorExtensions.get(X_DISCRIMINATOR_TYPE) : model.classname; - } - - @Override - public String escapeQuotationMark(String input) { - // remove ', " to avoid code injection - return input.replace("\"", "").replace("'", ""); - } - - @Override - public String escapeUnsafeCharacters(String input) { - return input.replace("*/", "*_/").replace("/*", "/_*"); - } - @Override public String getName() { return "typescript"; @@ -795,15 +371,10 @@ public String getHelp() { return "Generates a TypeScript client library using Fetch API (beta)."; } - @Override public void processOpts() { super.processOpts(); - if (additionalProperties.containsKey(CodegenConstants.MODEL_PROPERTY_NAMING)) { - setModelPropertyNaming((String) additionalProperties.get(CodegenConstants.MODEL_PROPERTY_NAMING)); - } - convertPropertyToBooleanAndWriteBack(CodegenConstants.SUPPORTS_ES6); // change package names @@ -815,8 +386,8 @@ public void processOpts() { String httpLibName = this.getHttpLibForFramework(additionalProperties.get(FRAMEWORK_SWITCH).toString()); supportingFiles.add(new SupportingFile( - "http" + File.separator + httpLibName + ".mustache", - "http", httpLibName + ".ts" + "http" + File.separator + httpLibName + ".mustache", + "http", httpLibName + ".ts" )); Object propPlatform = additionalProperties.get(PLATFORM_SWITCH); @@ -826,7 +397,7 @@ public void processOpts() { } Map platforms = new HashMap<>(); - for (String platform: PLATFORMS) { + for (String platform : PLATFORMS) { platforms.put(platform, platform.equals(propPlatform)); } additionalProperties.put("platforms", platforms); @@ -861,10 +432,6 @@ public void processOpts() { } // NPM Settings - if (additionalProperties.containsKey(NPM_NAME)) { - setNpmName(additionalProperties.get(NPM_NAME).toString()); - } - if (additionalProperties.containsKey(NPM_VERSION)) { setNpmVersion(additionalProperties.get(NPM_VERSION).toString()); } @@ -1396,9 +963,7 @@ protected String setPropertyExampleValue(CodegenProperty p) { return example; } - /*** - * * Set the codegenParameter example value * We have a custom version of this function so we can invoke toExampleValue * @@ -1489,64 +1054,6 @@ public CodegenParameter fromFormProperty(String name, Schema propertySchema, Set return cp; } - @Override - public String toAnyOfName(List names, ComposedSchema composedSchema) { - List types = getTypesFromSchemas(composedSchema.getAnyOf()); - - return String.join(" | ", types); - } - - @Override - public String toOneOfName(List names, ComposedSchema composedSchema) { - List types = getTypesFromSchemas(composedSchema.getOneOf()); - - return String.join(" | ", types); - } - - @Override - public String toAllOfName(List names, ComposedSchema composedSchema) { - List types = getTypesFromSchemas(composedSchema.getAllOf()); - - 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 getTypesFromSchemas(List schemas) { - List 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 = splitComposedType(type); - for (String s : parts) { - if (needToImport(s)) { - m.imports.add(s); - } - } - } - @Override protected void addImport(Set importsToBeAddedTo, String type) { if (type == null) { @@ -1567,9 +1074,6 @@ protected void addImport(Set importsToBeAddedTo, String type) { * @return list of types */ protected String[] splitComposedType(String type) { - return type.replace(" ","").split("[|&<>]"); + return type.replace(" ", "").split("[|&<>]"); } - - @Override - public GeneratorLanguage generatorLanguage() { return GeneratorLanguage.TYPESCRIPT; } } From 63123f409005b775ae9684607fb99884e8cfe27e Mon Sep 17 00:00:00 2001 From: Lee Ween Jiann <16207788+lwj5@users.noreply.github.com> Date: Fri, 31 Mar 2023 22:56:59 +0800 Subject: [PATCH 2/8] Regenerate samples --- .../builds/with-unique-items/models/Response.ts | 8 ++++---- .../builds/composed-schemas/models/PetByType.ts | 4 ++-- .../composed-schemas/models/PetsFilteredPatchRequest.ts | 4 ++-- .../builds/composed-schemas/models/PetsPatchRequest.ts | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/samples/client/others/typescript/builds/with-unique-items/models/Response.ts b/samples/client/others/typescript/builds/with-unique-items/models/Response.ts index 6a53fbd9f9d0..06d67e04cbc9 100644 --- a/samples/client/others/typescript/builds/with-unique-items/models/Response.ts +++ b/samples/client/others/typescript/builds/with-unique-items/models/Response.ts @@ -13,20 +13,20 @@ import { HttpFile } from '../http/http'; export class Response { - 'nonUniqueArray'?: Array; - 'uniqueArray'?: Set; + 'non_unique_array'?: Array; + 'unique_array'?: Set; static readonly discriminator: string | undefined = undefined; static readonly attributeTypeMap: Array<{name: string, baseName: string, type: string, format: string}> = [ { - "name": "nonUniqueArray", + "name": "non_unique_array", "baseName": "non-unique-array", "type": "Array", "format": "" }, { - "name": "uniqueArray", + "name": "unique_array", "baseName": "unique-array", "type": "Set", "format": "" diff --git a/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetByType.ts b/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetByType.ts index aef39d9d6018..6d24b7be0d03 100644 --- a/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetByType.ts +++ b/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetByType.ts @@ -13,14 +13,14 @@ import { HttpFile } from '../http/http'; export class PetByType { - 'petType': PetByTypePetTypeEnum; + 'pet_type': PetByTypePetTypeEnum; 'hunts'?: boolean; static readonly discriminator: string | undefined = undefined; static readonly attributeTypeMap: Array<{name: string, baseName: string, type: string, format: string}> = [ { - "name": "petType", + "name": "pet_type", "baseName": "pet_type", "type": "PetByTypePetTypeEnum", "format": "" diff --git a/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetsFilteredPatchRequest.ts b/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetsFilteredPatchRequest.ts index 12ae18d6b74e..11fd9c3254db 100644 --- a/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetsFilteredPatchRequest.ts +++ b/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetsFilteredPatchRequest.ts @@ -17,7 +17,7 @@ import { HttpFile } from '../http/http'; export class PetsFilteredPatchRequest { 'age': number; 'nickname'?: string; - 'petType': PetsFilteredPatchRequestPetTypeEnum; + 'pet_type': PetsFilteredPatchRequestPetTypeEnum; 'hunts'?: boolean; static readonly discriminator: string | undefined = undefined; @@ -36,7 +36,7 @@ export class PetsFilteredPatchRequest { "format": "" }, { - "name": "petType", + "name": "pet_type", "baseName": "pet_type", "type": "PetsFilteredPatchRequestPetTypeEnum", "format": "" diff --git a/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetsPatchRequest.ts b/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetsPatchRequest.ts index c68b69a32965..bd4625f69d87 100644 --- a/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetsPatchRequest.ts +++ b/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetsPatchRequest.ts @@ -20,7 +20,7 @@ export class PetsPatchRequest { 'bark'?: boolean; 'breed'?: PetsPatchRequestBreedEnum; - static readonly discriminator: string | undefined = "petType"; + static readonly discriminator: string | undefined = "pet_type"; static readonly attributeTypeMap: Array<{name: string, baseName: string, type: string, format: string}> = [ { @@ -53,7 +53,7 @@ export class PetsPatchRequest { } public constructor() { - this.petType = "PetsPatchRequest"; + this.pet_type = "PetsPatchRequest"; } } From a6be0edcc5c431eb2f621bb0fb575029c4dd0a13 Mon Sep 17 00:00:00 2001 From: Lee Ween Jiann <16207788+lwj5@users.noreply.github.com> Date: Fri, 31 Mar 2023 23:18:52 +0800 Subject: [PATCH 3/8] Update docs --- docs/generators/typescript.md | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/docs/generators/typescript.md b/docs/generators/typescript.md index 58e50f191f29..4768f763cd3a 100644 --- a/docs/generators/typescript.md +++ b/docs/generators/typescript.md @@ -21,15 +21,19 @@ These options may be applied as additional-properties (cli) or configOptions (pl |allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false| |disallowAdditionalPropertiesIfNotPresent|If false, the 'additionalProperties' implementation (set to true by default) is compliant with the OAS and JSON schema specifications. If true (default), keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.|
**false**
The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications.
**true**
Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.
|true| |ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true| +|enumNameSuffix|Suffix that will be appended to all enum names.| |Enum| +|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |PascalCase| |enumUnknownDefaultCase|If the server adds new enum cases, that are unknown by an old spec/client, the client will fail to parse the network response.With this option enabled, each enum will have a new case, 'unknown_default_open_api', so that when the server sends an enum case that is not known by the client/spec, they can safely fallback to this case.|
**false**
No changes to the enum's are made, this is the default option.
**true**
With this option enabled, each enum will have a new case, 'unknown_default_open_api', so that when the enum case sent by the server is not known by the client/spec, can safely be decoded to this case.
|false| |fileContentDataType|Specifies the type to use for the content of a file - i.e. Blob (Browser, Deno) / Buffer (node)| |Buffer| |framework|Specify the framework which should be used in the client code.|
**fetch-api**
fetch-api
**jquery**
jquery
|fetch-api| |importFileExtension|File extension to use with relative imports. Set it to '.js' or '.mjs' when using [ESM](https://nodejs.org/api/esm.html). Defaults to '.ts' when 'platform' is set to 'deno'.| |null| |legacyDiscriminatorBehavior|Set to false for generators with better support for discriminators. (Python, Java, Go, PowerShell, C# have this enabled by default).|
**true**
The mapping in the discriminator includes descendent schemas that allOf inherit from self and the discriminator mapping schemas in the OAS document.
**false**
The mapping in the discriminator includes any descendent schemas that allOf inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values, and the discriminator mapping schemas in the OAS document AND Codegen validates that oneOf and anyOf schemas contain the required discriminator and throws an error if the discriminator is missing.
|true| -|modelPropertyNaming|Naming convention for the property: 'camelCase', 'PascalCase', 'snake_case' and 'original', which keeps the original name| |camelCase| +|modelPropertyNaming|Naming convention for the property: 'camelCase', 'PascalCase', 'snake_case' and 'original', which keeps the original name. Only change it if you provide your own run-time code for (de-)serialization of models| |original| |npmName|The name under which you want to publish generated npm package. Required to generate a full package| |null| |npmRepository|Use this property to set an url your private npmRepo in the package.json| |null| |npmVersion|The version of your npm package. If not provided, using the version from the OpenAPI specification file.| |1.0.0| +|nullSafeAdditionalProps|Set to make additional properties types declare that their indexer may return undefined| |false| +|paramNaming|Naming convention for parameters: 'camelCase', 'PascalCase', 'snake_case' and 'original', which keeps the original name| |camelCase| |platform|Specifies the platform the code should run on. The default is 'node' for the 'request' framework and 'browser' otherwise.|
**browser**
browser
**node**
node
**deno**
deno
|browser| |prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false| |snapshot|When setting this property to true, the version will be suffixed with -SNAPSHOT.yyyyMMddHHmm| |false| @@ -67,11 +71,13 @@ These options may be applied as additional-properties (cli) or configOptions (pl
  • Long
  • Map
  • Object
  • +
  • ReadonlyArray
  • Set
  • String
  • any
  • boolean
  • number
  • +
  • object
  • string
  • @@ -156,7 +162,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl ### Client Modification Feature | Name | Supported | Defined By | | ---- | --------- | ---------- | -|BasePath|✗|ToolingExtension +|BasePath|✓|ToolingExtension |Authorizations|✗|ToolingExtension |UserAgent|✗|ToolingExtension |MockServer|✗|ToolingExtension @@ -201,7 +207,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl ### Documentation Feature | Name | Supported | Defined By | | ---- | --------- | ---------- | -|Readme|✗|ToolingExtension +|Readme|✓|ToolingExtension |Model|✓|ToolingExtension |Api|✓|ToolingExtension @@ -221,7 +227,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |MultiServer|✗|OAS3 |ParameterizedServer|✗|OAS3 |ParameterStyling|✗|OAS3 -|Callbacks|✓|OAS3 +|Callbacks|✗|OAS3 |LinkObjects|✗|OAS3 ### Parameter Feature @@ -250,14 +256,14 @@ These options may be applied as additional-properties (cli) or configOptions (pl ### Security Feature | Name | Supported | Defined By | | ---- | --------- | ---------- | -|BasicAuth|✓|OAS2,OAS3 -|ApiKey|✓|OAS2,OAS3 +|BasicAuth|✗|OAS2,OAS3 +|ApiKey|✗|OAS2,OAS3 |OpenIDConnect|✗|OAS3 -|BearerToken|✓|OAS3 -|OAuth2_Implicit|✓|OAS2,OAS3 -|OAuth2_Password|✓|OAS2,OAS3 -|OAuth2_ClientCredentials|✓|OAS2,OAS3 -|OAuth2_AuthorizationCode|✓|OAS2,OAS3 +|BearerToken|✗|OAS3 +|OAuth2_Implicit|✗|OAS2,OAS3 +|OAuth2_Password|✗|OAS2,OAS3 +|OAuth2_ClientCredentials|✗|OAS2,OAS3 +|OAuth2_AuthorizationCode|✗|OAS2,OAS3 ### Wire Format Feature | Name | Supported | Defined By | From 0e7c491c7957b00fe0cb15ac30eee031cce78abd Mon Sep 17 00:00:00 2001 From: Lee Ween Jiann <16207788+lwj5@users.noreply.github.com> Date: Fri, 31 Mar 2023 23:48:09 +0800 Subject: [PATCH 4/8] Clean up --- .../languages/TypeScriptClientCodegen.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java index 419561e8a590..b03c87c53df4 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java @@ -78,8 +78,6 @@ public class TypeScriptClientCodegen extends AbstractTypeScriptClientCodegen imp protected String npmRepository = null; protected String snapshot = null; - protected String modelPropertyNaming = "camelCase"; - private final DateTimeFormatter iso8601Date = DateTimeFormatter.ISO_DATE; private final DateTimeFormatter iso8601DateTime = DateTimeFormatter.ISO_DATE_TIME; @@ -286,17 +284,6 @@ public String toModelImport(String name) { return "../" + modelPackage() + "/" + toModelName(name); } - public void setModelPropertyNaming(String naming) { - if ("original".equals(naming) || "camelCase".equals(naming) || - "PascalCase".equals(naming) || "snake_case".equals(naming)) { - this.modelPropertyNaming = naming; - } else { - throw new IllegalArgumentException("Invalid model property naming '" + - naming + "'. Must be 'original', 'camelCase', " + - "'PascalCase' or 'snake_case'"); - } - } - @Override public String toEnumValue(String value, String datatype) { if ("number".equals(datatype)) { @@ -375,8 +362,6 @@ public String getHelp() { public void processOpts() { super.processOpts(); - convertPropertyToBooleanAndWriteBack(CodegenConstants.SUPPORTS_ES6); - // change package names apiPackage = this.apiPackage + ".apis"; testPackage = this.testPackage + ".tests"; From 000c32d77655cb465a911e045827d153d321d53d Mon Sep 17 00:00:00 2001 From: Lee Ween Jiann <16207788+lwj5@users.noreply.github.com> Date: Mon, 3 Apr 2023 12:27:58 +0800 Subject: [PATCH 5/8] Remove updated toEnumName --- .../languages/TypeScriptClientCodegen.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java index b03c87c53df4..89320342c929 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java @@ -37,7 +37,6 @@ import org.slf4j.LoggerFactory; import java.io.File; -import java.text.SimpleDateFormat; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; @@ -293,17 +292,6 @@ public String toEnumValue(String value, String datatype) { } } - @Override - public String toEnumName(CodegenProperty property) { - String enumName = toModelName(property.name) + "Enum"; - - if (enumName.matches("\\d.*")) { // starts with number - return "_" + enumName; - } else { - return enumName; - } - } - @Override public ModelsMap postProcessModels(ModelsMap objs) { // process enum in models @@ -417,10 +405,6 @@ public void processOpts() { } // NPM Settings - if (additionalProperties.containsKey(NPM_VERSION)) { - setNpmVersion(additionalProperties.get(NPM_VERSION).toString()); - } - if (additionalProperties.containsKey(NPM_REPOSITORY)) { setNpmRepository(additionalProperties.get(NPM_REPOSITORY).toString()); } From efe520f10b1681a98dc5771d232a42d5a6249605 Mon Sep 17 00:00:00 2001 From: Lee Ween Jiann <16207788+lwj5@users.noreply.github.com> Date: Mon, 3 Apr 2023 14:09:42 +0800 Subject: [PATCH 6/8] Fix: SUPPORTS_ES6 --- .../codegen/languages/AbstractTypeScriptClientCodegen.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractTypeScriptClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractTypeScriptClientCodegen.java index 9550e01de0da..89ac30bb52d8 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractTypeScriptClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractTypeScriptClientCodegen.java @@ -393,7 +393,7 @@ public void processOpts() { setParamNaming((String) additionalProperties.get(CodegenConstants.PARAM_NAMING)); } - convertPropertyToBooleanAndWriteBack(CodegenConstants.SUPPORTS_ES6); + setSupportsES6(convertPropertyToBooleanAndWriteBack(CodegenConstants.SUPPORTS_ES6)); if (additionalProperties.containsKey(NULL_SAFE_ADDITIONAL_PROPS)) { setNullSafeAdditionalProps(Boolean.valueOf(additionalProperties.get(NULL_SAFE_ADDITIONAL_PROPS).toString())); From 578d3b90bd55add3e7edfa2da0ea341a3d783796 Mon Sep 17 00:00:00 2001 From: Lee Ween Jiann <16207788+lwj5@users.noreply.github.com> Date: Mon, 3 Apr 2023 14:35:59 +0800 Subject: [PATCH 7/8] Fix: `setSupportsES6` should not be set directly in unit tests --- .../typescript/axios/TypeScriptAxiosClientCodegenTest.java | 4 ++-- .../typescript/fetch/TypeScriptFetchClientCodegenTest.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/axios/TypeScriptAxiosClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/axios/TypeScriptAxiosClientCodegenTest.java index da55a175fbc9..8a229bf14ff3 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/axios/TypeScriptAxiosClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/axios/TypeScriptAxiosClientCodegenTest.java @@ -89,7 +89,7 @@ public void containsESMTSConfigFileInCaseOfES6AndNPM() { codegen.additionalProperties().put("npmName", "@openapi/typescript-axios-petstore"); codegen.additionalProperties().put("snapshot", false); codegen.additionalProperties().put("npmVersion", "1.0.0-SNAPSHOT"); - codegen.setSupportsES6(true); + codegen.additionalProperties().put("supportsES6", true); codegen.processOpts(); @@ -104,7 +104,7 @@ public void doesNotContainESMTSConfigFileInCaseOfES5AndNPM() { codegen.additionalProperties().put("npmName", "@openapi/typescript-axios-petstore"); codegen.additionalProperties().put("snapshot", false); codegen.additionalProperties().put("npmVersion", "1.0.0-SNAPSHOT"); - codegen.setSupportsES6(false); + codegen.additionalProperties().put("supportsES6", false); codegen.processOpts(); diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/fetch/TypeScriptFetchClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/fetch/TypeScriptFetchClientCodegenTest.java index 34e67404179e..0f19827b4483 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/fetch/TypeScriptFetchClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/fetch/TypeScriptFetchClientCodegenTest.java @@ -116,7 +116,7 @@ public void containsESMTSConfigFileInCaseOfES6AndNPM() { codegen.additionalProperties().put("npmName", "@openapi/typescript-fetch-petstore"); codegen.additionalProperties().put("snapshot", false); codegen.additionalProperties().put("npmVersion", "1.0.0-SNAPSHOT"); - codegen.setSupportsES6(true); + codegen.additionalProperties().put("supportsES6", true); codegen.processOpts(); @@ -131,7 +131,7 @@ public void doesNotContainESMTSConfigFileInCaseOfES5AndNPM() { codegen.additionalProperties().put("npmName", "@openapi/typescript-fetch-petstore"); codegen.additionalProperties().put("snapshot", false); codegen.additionalProperties().put("npmVersion", "1.0.0-SNAPSHOT"); - codegen.setSupportsES6(false); + codegen.additionalProperties().put("supportsES6", false); codegen.processOpts(); From b52dd901bb9cb00664fdf64ab052cc635fe7a452 Mon Sep 17 00:00:00 2001 From: Lee Ween Jiann <16207788+lwj5@users.noreply.github.com> Date: Mon, 3 Apr 2023 16:44:13 +0800 Subject: [PATCH 8/8] Set modelPropertyNaming to camelCase --- docs/generators/typescript.md | 2 +- .../codegen/languages/TypeScriptClientCodegen.java | 7 ++++--- .../builds/with-unique-items/models/Response.ts | 8 ++++---- .../builds/composed-schemas/models/PetByType.ts | 4 ++-- .../composed-schemas/models/PetsFilteredPatchRequest.ts | 4 ++-- .../builds/composed-schemas/models/PetsPatchRequest.ts | 4 ++-- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/docs/generators/typescript.md b/docs/generators/typescript.md index 4768f763cd3a..a5ff44cf2b35 100644 --- a/docs/generators/typescript.md +++ b/docs/generators/typescript.md @@ -28,7 +28,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |framework|Specify the framework which should be used in the client code.|
    **fetch-api**
    fetch-api
    **jquery**
    jquery
    |fetch-api| |importFileExtension|File extension to use with relative imports. Set it to '.js' or '.mjs' when using [ESM](https://nodejs.org/api/esm.html). Defaults to '.ts' when 'platform' is set to 'deno'.| |null| |legacyDiscriminatorBehavior|Set to false for generators with better support for discriminators. (Python, Java, Go, PowerShell, C# have this enabled by default).|
    **true**
    The mapping in the discriminator includes descendent schemas that allOf inherit from self and the discriminator mapping schemas in the OAS document.
    **false**
    The mapping in the discriminator includes any descendent schemas that allOf inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values, and the discriminator mapping schemas in the OAS document AND Codegen validates that oneOf and anyOf schemas contain the required discriminator and throws an error if the discriminator is missing.
    |true| -|modelPropertyNaming|Naming convention for the property: 'camelCase', 'PascalCase', 'snake_case' and 'original', which keeps the original name. Only change it if you provide your own run-time code for (de-)serialization of models| |original| +|modelPropertyNaming|Naming convention for the property: 'camelCase', 'PascalCase', 'snake_case' and 'original', which keeps the original name| |camelCase| |npmName|The name under which you want to publish generated npm package. Required to generate a full package| |null| |npmRepository|Use this property to set an url your private npmRepo in the package.json| |null| |npmVersion|The version of your npm package. If not provided, using the version from the OpenAPI specification file.| |1.0.0| diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java index 89320342c929..62887e2cf617 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java @@ -87,7 +87,6 @@ public TypeScriptClientCodegen() { this.frameworkToHttpLibMap.put("fetch-api", "isomorphic-fetch"); this.frameworkToHttpLibMap.put("jquery", "jquery"); - this.generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata).stability(Stability.EXPERIMENTAL).build(); outputFolder = "generated-code" + File.separator + "typescript"; @@ -104,8 +103,7 @@ public TypeScriptClientCodegen() { typeMapping.put("object", "any"); typeMapping.put("DateTime", "Date"); -cliOptions.add(new CliOption(NPM_REPOSITORY, "Use this property to set an url your private npmRepo in the package.json")); -// cliOptions.add(new CliOption(CodegenConstants.MODEL_PROPERTY_NAMING, CodegenConstants.MODEL_PROPERTY_NAMING_DESC).defaultValue("camelCase")); + cliOptions.add(new CliOption(NPM_REPOSITORY, "Use this property to set an url your private npmRepo in the package.json")); cliOptions.add(new CliOption(TypeScriptClientCodegen.FILE_CONTENT_DATA_TYPE, TypeScriptClientCodegen.FILE_CONTENT_DATA_TYPE_DESC).defaultValue("Buffer")); cliOptions.add(new CliOption(TypeScriptClientCodegen.USE_RXJS_SWITCH, TypeScriptClientCodegen.USE_RXJS_SWITCH_DESC).defaultValue("false")); cliOptions.add(new CliOption(TypeScriptClientCodegen.USE_OBJECT_PARAMS_SWITCH, TypeScriptClientCodegen.USE_OBJECT_PARAMS_DESC).defaultValue("false")); @@ -127,6 +125,9 @@ public TypeScriptClientCodegen() { cliOptions.add(platformOption); + // Set property naming to camelCase + supportModelPropertyNaming(CodegenConstants.MODEL_PROPERTY_NAMING_TYPE.camelCase); + // Git supportingFiles.add(new SupportingFile(".gitignore.mustache", "", ".gitignore")); supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh")); diff --git a/samples/client/others/typescript/builds/with-unique-items/models/Response.ts b/samples/client/others/typescript/builds/with-unique-items/models/Response.ts index 06d67e04cbc9..6a53fbd9f9d0 100644 --- a/samples/client/others/typescript/builds/with-unique-items/models/Response.ts +++ b/samples/client/others/typescript/builds/with-unique-items/models/Response.ts @@ -13,20 +13,20 @@ import { HttpFile } from '../http/http'; export class Response { - 'non_unique_array'?: Array; - 'unique_array'?: Set; + 'nonUniqueArray'?: Array; + 'uniqueArray'?: Set; static readonly discriminator: string | undefined = undefined; static readonly attributeTypeMap: Array<{name: string, baseName: string, type: string, format: string}> = [ { - "name": "non_unique_array", + "name": "nonUniqueArray", "baseName": "non-unique-array", "type": "Array", "format": "" }, { - "name": "unique_array", + "name": "uniqueArray", "baseName": "unique-array", "type": "Set", "format": "" diff --git a/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetByType.ts b/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetByType.ts index 6d24b7be0d03..aef39d9d6018 100644 --- a/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetByType.ts +++ b/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetByType.ts @@ -13,14 +13,14 @@ import { HttpFile } from '../http/http'; export class PetByType { - 'pet_type': PetByTypePetTypeEnum; + 'petType': PetByTypePetTypeEnum; 'hunts'?: boolean; static readonly discriminator: string | undefined = undefined; static readonly attributeTypeMap: Array<{name: string, baseName: string, type: string, format: string}> = [ { - "name": "pet_type", + "name": "petType", "baseName": "pet_type", "type": "PetByTypePetTypeEnum", "format": "" diff --git a/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetsFilteredPatchRequest.ts b/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetsFilteredPatchRequest.ts index 11fd9c3254db..12ae18d6b74e 100644 --- a/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetsFilteredPatchRequest.ts +++ b/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetsFilteredPatchRequest.ts @@ -17,7 +17,7 @@ import { HttpFile } from '../http/http'; export class PetsFilteredPatchRequest { 'age': number; 'nickname'?: string; - 'pet_type': PetsFilteredPatchRequestPetTypeEnum; + 'petType': PetsFilteredPatchRequestPetTypeEnum; 'hunts'?: boolean; static readonly discriminator: string | undefined = undefined; @@ -36,7 +36,7 @@ export class PetsFilteredPatchRequest { "format": "" }, { - "name": "pet_type", + "name": "petType", "baseName": "pet_type", "type": "PetsFilteredPatchRequestPetTypeEnum", "format": "" diff --git a/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetsPatchRequest.ts b/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetsPatchRequest.ts index bd4625f69d87..c68b69a32965 100644 --- a/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetsPatchRequest.ts +++ b/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetsPatchRequest.ts @@ -20,7 +20,7 @@ export class PetsPatchRequest { 'bark'?: boolean; 'breed'?: PetsPatchRequestBreedEnum; - static readonly discriminator: string | undefined = "pet_type"; + static readonly discriminator: string | undefined = "petType"; static readonly attributeTypeMap: Array<{name: string, baseName: string, type: string, format: string}> = [ { @@ -53,7 +53,7 @@ export class PetsPatchRequest { } public constructor() { - this.pet_type = "PetsPatchRequest"; + this.petType = "PetsPatchRequest"; } }