[typescript] Clean up modelPropertyNaming across generators (#5427)

* [typescript] Clean up modelPropertyNaming across generators
Fixes https://github.com/OpenAPITools/openapi-generator/issues/2976

Generators without runtime models conversion use "original" property naming by default. It's still possible to change it via cli options

Generators with runtime conversion keep using "camelCase"

* Refactoring: use enum instead of string for modelPropertyNaming

* Restore the original camelCase for var names, decouple it from property names

* Swap toParamName and toVarName logic (looks like I've mistaken them)

* Regenerate docs

* Remove a no longer used private method
This commit is contained in:
Alexey Makhrov
2020-02-27 22:31:19 -08:00
committed by GitHub
parent a4fc319502
commit 0edb628633
17 changed files with 82 additions and 63 deletions

View File

@@ -9,7 +9,7 @@ sidebar_label: javascript-flowtyped
|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. A special 'v4-compat' value enables the backward-compatible behavior (as pre v4.2.3)| |v4-compat|
|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |PascalCase|
|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|

View File

@@ -12,7 +12,7 @@ sidebar_label: typescript-angular
|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |PascalCase|
|fileNaming|Naming convention for the output files: 'camelCase', 'kebab-case'.| |camelCase|
|modelFileSuffix|The suffix of the file of the generated model (model<suffix>.ts).| |null|
|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|
|modelSuffix|The suffix of the generated model.| |null|
|ngVersion|The version of Angular.| |9.0.0|
|npmName|The name under which you want to publish generated npm package. Required to generate a full package| |null|

View File

@@ -9,7 +9,7 @@ sidebar_label: typescript-angularjs
|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. A special 'v4-compat' value enables the backward-compatible behavior (as pre v4.2.3)| |v4-compat|
|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |PascalCase|
|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|
|nullSafeAdditionalProps|Set to make additional properties types declare that their indexer may return undefined| |false|
|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|
|sortModelPropertiesByRequiredFlag|Sort model properties to place required parameters before optional parameters.| |true|

View File

@@ -9,7 +9,7 @@ sidebar_label: typescript-aurelia
|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. A special 'v4-compat' value enables the backward-compatible behavior (as pre v4.2.3)| |v4-compat|
|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |PascalCase|
|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|
|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|

View File

@@ -9,7 +9,7 @@ sidebar_label: typescript-axios
|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. A special 'v4-compat' value enables the backward-compatible behavior (as pre v4.2.3)| |v4-compat|
|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |PascalCase|
|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 of 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|

View File

@@ -9,7 +9,7 @@ sidebar_label: typescript-inversify
|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. A special 'v4-compat' value enables the backward-compatible behavior (as pre v4.2.3)| |v4-compat|
|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |PascalCase|
|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|

View File

@@ -10,7 +10,7 @@ sidebar_label: typescript-jquery
|enumNameSuffix|Suffix that will be appended to all enum names. A special 'v4-compat' value enables the backward-compatible behavior (as pre v4.2.3)| |v4-compat|
|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |PascalCase|
|jqueryAlreadyImported|When using this in legacy app using mix of typescript and javascript, this will only declare jquery and not import it| |false|
|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|

View File

@@ -9,7 +9,7 @@ sidebar_label: typescript-rxjs
|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. A special 'v4-compat' value enables the backward-compatible behavior (as pre v4.2.3)| |v4-compat|
|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |PascalCase|
|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|

View File

@@ -25,6 +25,7 @@ import io.swagger.v3.oas.models.parameters.Parameter;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.CodegenConstants.ENUM_PROPERTY_NAMING_TYPE;
import org.openapitools.codegen.CodegenConstants.MODEL_PROPERTY_NAMING_TYPE;
import org.openapitools.codegen.*;
import org.openapitools.codegen.meta.features.*;
import org.openapitools.codegen.utils.ModelUtils;
@@ -55,6 +56,9 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
public static final String ENUM_NAME_SUFFIX_DESC_CUSTOMIZED = CodegenConstants.ENUM_NAME_SUFFIX_DESC
+ " A special '" + ENUM_NAME_SUFFIX_V4_COMPAT + "' value enables the backward-compatible behavior (as pre v4.2.3)";
public static final String MODEL_PROPERTY_NAMING_DESC_WITH_WARNING = CodegenConstants.MODEL_PROPERTY_NAMING_DESC
+ ". Only change it if you provide your own run-time code for (de-)serialization of models";
public static final String NULL_SAFE_ADDITIONAL_PROPS = "nullSafeAdditionalProps";
public static final String NULL_SAFE_ADDITIONAL_PROPS_DESC = "Set to make additional properties types declare that their indexer may return undefined";
@@ -62,7 +66,7 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
@SuppressWarnings("squid:S5164")
protected static final ThreadLocal<SimpleDateFormat> SNAPSHOT_SUFFIX_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMMddHHmm", Locale.ROOT));
protected String modelPropertyNaming = "camelCase";
protected MODEL_PROPERTY_NAMING_TYPE modelPropertyNaming = MODEL_PROPERTY_NAMING_TYPE.original;
protected ENUM_PROPERTY_NAMING_TYPE enumPropertyNaming = ENUM_PROPERTY_NAMING_TYPE.PascalCase;
protected Boolean supportsES6 = false;
protected Boolean nullSafeAdditionalProps = false;
@@ -170,7 +174,7 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
cliOptions.add(new CliOption(CodegenConstants.ENUM_NAME_SUFFIX, ENUM_NAME_SUFFIX_DESC_CUSTOMIZED).defaultValue(this.enumSuffix));
cliOptions.add(new CliOption(CodegenConstants.ENUM_PROPERTY_NAMING, CodegenConstants.ENUM_PROPERTY_NAMING_DESC).defaultValue(this.enumPropertyNaming.name()));
cliOptions.add(new CliOption(CodegenConstants.MODEL_PROPERTY_NAMING, CodegenConstants.MODEL_PROPERTY_NAMING_DESC).defaultValue(this.modelPropertyNaming));
cliOptions.add(new CliOption(CodegenConstants.MODEL_PROPERTY_NAMING, MODEL_PROPERTY_NAMING_DESC_WITH_WARNING).defaultValue(this.modelPropertyNaming.name()));
cliOptions.add(new CliOption(CodegenConstants.SUPPORTS_ES6, CodegenConstants.SUPPORTS_ES6_DESC).defaultValue(String.valueOf(this.getSupportsES6())));
this.cliOptions.add(new CliOption(NPM_NAME, "The name under which you want to publish generated npm package." +
" Required to generate a full package"));
@@ -179,7 +183,12 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
"When setting this property to true, the version will be suffixed with -SNAPSHOT." + this.SNAPSHOT_SUFFIX_FORMAT.get().toPattern(),
false));
this.cliOptions.add(new CliOption(NULL_SAFE_ADDITIONAL_PROPS, NULL_SAFE_ADDITIONAL_PROPS_DESC).defaultValue(String.valueOf(this.getNullSafeAdditionalProps())));
}
protected void supportModelPropertyNaming(MODEL_PROPERTY_NAMING_TYPE defaultModelPropertyNaming) {
removeOption(CodegenConstants.MODEL_PROPERTY_NAMING);
modelPropertyNaming = defaultModelPropertyNaming;
cliOptions.add(new CliOption(CodegenConstants.MODEL_PROPERTY_NAMING, CodegenConstants.MODEL_PROPERTY_NAMING_DESC).defaultValue(modelPropertyNaming.name()));
}
@Override
@@ -274,52 +283,37 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
@Override
public String toParamName(String name) {
// sanitize name
name = sanitizeName(name, "[^\\w$]");
if ("_".equals(name)) {
name = "_u";
}
// if it's all uppper case, do nothing
if (name.matches("^[A-Z_]*$")) {
return name;
}
name = getNameUsingModelPropertyNaming(name);
// for reserved word or word starting with number, append _
if (isReservedWord(name) || name.matches("^\\d.*")) {
name = escapeReservedWord(name);
}
name = camelize(name, true);
name = toSafeIdentifier(name);
return name;
}
@Override
public String toVarName(String name) {
name = this.toParamName(name);
// if the property name has any breaking characters such as :, ;, . etc.
// then wrap the name within single quotes.
// my:interface:property: string; => 'my:interface:property': string;
if (propertyHasBreakingCharacters(name)) {
name = "\'" + name + "\'";
name = sanitizeName(name, "[^\\w$]");
if ("_".equals(name)) {
name = "_u";
}
name = getNameUsingModelPropertyNaming(name);
name = toSafeIdentifier(name);
return name;
}
/**
* Checks whether property names have breaking characters like ':', '-'.
* @param str string to check for breaking characters
* @return <code>true</code> if breaking characters are present and <code>false</code> if not
*/
private boolean propertyHasBreakingCharacters(String str) {
final String regex = "^.*[+*:;,.()-]+.*$";
final Pattern pattern = Pattern.compile(regex);
final Matcher matcher = pattern.matcher(str);
return matcher.matches();
private String toSafeIdentifier(String name) {
if (isReservedWord(name) || name.matches("^\\d.*")) {
name = escapeReservedWord(name);
}
return name;
}
@Override
@@ -533,32 +527,31 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
throw new RuntimeException("Empty method name (operationId) not allowed");
}
// method name cannot use reserved keyword or word starting with number, e.g. return or 123return
// append _ at the beginning, e.g. _return or _123return
if (isReservedWord(operationId) || operationId.matches("^\\d.*")) {
return escapeReservedWord(camelize(sanitizeName(operationId), true));
}
operationId = camelize(sanitizeName(operationId), true);
operationId = toSafeIdentifier(operationId);
return camelize(sanitizeName(operationId), true);
return operationId;
}
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'");
try {
modelPropertyNaming = MODEL_PROPERTY_NAMING_TYPE.valueOf(naming);
} catch (IllegalArgumentException e) {
String values = Stream.of(MODEL_PROPERTY_NAMING_TYPE.values())
.map(value -> "'" + value.name() + "'")
.collect(Collectors.joining(", "));
String msg = String.format(Locale.ROOT, "Invalid model property naming '%s'. Must be one of %s.", naming, values);
throw new IllegalArgumentException(msg);
}
}
public String getModelPropertyNaming() {
return this.modelPropertyNaming;
public MODEL_PROPERTY_NAMING_TYPE getModelPropertyNaming() {
return modelPropertyNaming;
}
private String getNameUsingModelPropertyNaming(String name) {
switch (CodegenConstants.MODEL_PROPERTY_NAMING_TYPE.valueOf(getModelPropertyNaming())) {
switch (getModelPropertyNaming()) {
case original:
return name;
case camelCase:

View File

@@ -456,7 +456,7 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
// Add the more complicated component instead of just the brace.
CodegenParameter parameter = findPathParameterByName(op, parameterName.toString());
pathBuffer.append(toVarName(parameterName.toString()));
pathBuffer.append(toParamName(parameterName.toString()));
if (parameter != null && parameter.isDateTime) {
pathBuffer.append(".toISOString()");
}

View File

@@ -66,6 +66,7 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
typeMapping.put("date", "Date");
typeMapping.put("DateTime", "Date");
supportModelPropertyNaming(CodegenConstants.MODEL_PROPERTY_NAMING_TYPE.camelCase);
this.cliOptions.add(new CliOption(NPM_REPOSITORY, "Use this property to set an url your private npmRepo in the package.json"));
this.cliOptions.add(new CliOption(WITH_INTERFACES, "Setting this property to true will generate interfaces next to the default class implementations.", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString()));
this.cliOptions.add(new CliOption(USE_SINGLE_REQUEST_PARAMETER, "Setting this property to true will generate functions with a single argument containing all API endpoint parameters instead of one argument per parameter.", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.TRUE.toString()));
@@ -102,8 +103,8 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
@Override
public void processOpts() {
super.processOpts();
additionalProperties.put("isOriginalModelPropertyNaming", getModelPropertyNaming().equals("original"));
additionalProperties.put("modelPropertyNaming", getModelPropertyNaming());
additionalProperties.put("isOriginalModelPropertyNaming", getModelPropertyNaming() == CodegenConstants.MODEL_PROPERTY_NAMING_TYPE.original);
additionalProperties.put("modelPropertyNaming", getModelPropertyNaming().name());
String sourceDir = "";
if (additionalProperties.containsKey(NPM_NAME)) {

View File

@@ -225,7 +225,7 @@ public class TypeScriptInversifyClientCodegen extends AbstractTypeScriptClientCo
insideCurly--;
// Add the more complicated component instead of just the brace.
pathBuffer.append(toVarName(parameterName.toString()));
pathBuffer.append(toParamName(parameterName.toString()));
pathBuffer.append("))}");
parameterName.setLength(0);
break;

View File

@@ -64,6 +64,7 @@ public class TypeScriptNodeClientCodegen extends AbstractTypeScriptClientCodegen
modelPackage = "model";
apiPackage = "api";
supportModelPropertyNaming(CodegenConstants.MODEL_PROPERTY_NAMING_TYPE.camelCase);
this.cliOptions.add(new CliOption(NPM_REPOSITORY, "Use this property to set an url your private npmRepo in the package.json"));
}

View File

@@ -61,6 +61,7 @@ public class TypeScriptReduxQueryClientCodegen extends AbstractTypeScriptClientC
typeMapping.put("date", "Date");
typeMapping.put("DateTime", "Date");
supportModelPropertyNaming(CodegenConstants.MODEL_PROPERTY_NAMING_TYPE.camelCase);
this.cliOptions.add(new CliOption(NPM_REPOSITORY, "Use this property to set an url your private npmRepo in the package.json"));
this.cliOptions.add(new CliOption(WITH_INTERFACES, "Setting this property to true will generate interfaces next to the default class implementations.", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString()));
this.cliOptions.add(new CliOption(USE_SINGLE_REQUEST_PARAMETER, "Setting this property to true will generate functions with a single argument containing all API endpoint parameters instead of one argument per parameter.", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.TRUE.toString()));
@@ -87,8 +88,8 @@ public class TypeScriptReduxQueryClientCodegen extends AbstractTypeScriptClientC
@Override
public void processOpts() {
super.processOpts();
additionalProperties.put("isOriginalModelPropertyNaming", getModelPropertyNaming().equals("original"));
additionalProperties.put("modelPropertyNaming", getModelPropertyNaming());
additionalProperties.put("isOriginalModelPropertyNaming", getModelPropertyNaming() == CodegenConstants.MODEL_PROPERTY_NAMING_TYPE.original);
additionalProperties.put("modelPropertyNaming", getModelPropertyNaming().name());
supportingFiles.add(new SupportingFile("index.mustache", "src", "index.ts"));
supportingFiles.add(new SupportingFile("runtime.mustache", "src", "runtime.ts"));
supportingFiles.add(new SupportingFile("tsconfig.mustache", "", "tsconfig.json"));

View File

@@ -89,8 +89,6 @@ public class TypeScriptRxjsClientCodegen extends AbstractTypeScriptClientCodegen
@Override
public void processOpts() {
super.processOpts();
additionalProperties.put("isOriginalModelPropertyNaming", getModelPropertyNaming().equals("original"));
additionalProperties.put("modelPropertyNaming", getModelPropertyNaming());
supportingFiles.add(new SupportingFile("index.mustache", "", "index.ts"));
supportingFiles.add(new SupportingFile("runtime.mustache", "", "runtime.ts"));
supportingFiles.add(new SupportingFile("apis.index.mustache", apiPackage().replace('.', File.separatorChar), "index.ts"));

View File

@@ -1,6 +1,7 @@
package org.openapitools.codegen.typescript.fetch;
import io.swagger.v3.oas.models.OpenAPI;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.TestUtils;
import org.openapitools.codegen.languages.TypeScriptFetchClientCodegen;
import org.testng.Assert;
@@ -56,4 +57,16 @@ public class TypeScriptFetchClientCodegenTest {
}
@Test
public void toVarName() {
TypeScriptFetchClientCodegen codegen = new TypeScriptFetchClientCodegen();
codegen.processOpts();
Assert.assertEquals(codegen.toVarName("valid_var"), "validVar");
codegen = new TypeScriptFetchClientCodegen();
codegen.additionalProperties().put(CodegenConstants.MODEL_PROPERTY_NAMING, "original");
codegen.processOpts();
Assert.assertEquals(codegen.toVarName("valid_var"), "valid_var");
}
}

View File

@@ -18,6 +18,18 @@ import org.testng.annotations.Test;
public class TypeScriptAngularClientCodegenTest {
@Test
public void toVarName() {
TypeScriptAngularClientCodegen codegen = new TypeScriptAngularClientCodegen();
codegen.processOpts();
Assert.assertEquals(codegen.toVarName("valid_var"), "valid_var");
codegen = new TypeScriptAngularClientCodegen();
codegen.additionalProperties().put(CodegenConstants.MODEL_PROPERTY_NAMING, "camelCase");
codegen.processOpts();
Assert.assertEquals(codegen.toVarName("valid_var"), "validVar");
}
@Test
public void toEnumVarName() {
TypeScriptAngularClientCodegen codegen = new TypeScriptAngularClientCodegen();