diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptAngularClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptAngularClientCodegen.java index 2ccd6706501d..2e038b556196 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptAngularClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptAngularClientCodegen.java @@ -34,6 +34,8 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode private static final SimpleDateFormat SNAPSHOT_SUFFIX_FORMAT = new SimpleDateFormat("yyyyMMddHHmm"); private static final String X_DISCRIMINATOR_TYPE = "x-discriminator-value"; + private static String CLASS_NAME_SUFFIX_PATTERN = "^[a-zA-Z0-9]*$"; + private static String FILE_NAME_SUFFIX_PATTERN = "^[a-zA-Z0-9.-]*$"; public static final String NPM_NAME = "npmName"; public static final String NPM_VERSION = "npmVersion"; @@ -42,15 +44,19 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode public static final String WITH_INTERFACES = "withInterfaces"; public static final String TAGGED_UNIONS = "taggedUnions"; public static final String NG_VERSION = "ngVersion"; - public static final String PROVIDED_IN_ROOT ="providedInRoot"; + public static final String PROVIDED_IN_ROOT = "providedInRoot"; public static final String SERVICE_SUFFIX = "serviceSuffix"; public static final String SERVICE_FILE_SUFFIX = "serviceFileSuffix"; + public static final String MODEL_SUFFIX = "modelSuffix"; + public static final String MODEL_FILE_SUFFIX = "modelFileSuffix"; protected String npmName = null; protected String npmVersion = "1.0.0"; protected String npmRepository = null; protected String serviceSuffix = "Service"; protected String serviceFileSuffix = ".service"; + protected String modelSuffix = ""; + protected String modelFileSuffix = ""; private boolean taggedUnions = false; @@ -86,6 +92,8 @@ public TypeScriptAngularClientCodegen() { this.cliOptions.add(new CliOption(NG_VERSION, "The version of Angular. Default is '4.3'")); this.cliOptions.add(new CliOption(SERVICE_SUFFIX, "The suffix of the generated service. Default is 'Service'.")); this.cliOptions.add(new CliOption(SERVICE_FILE_SUFFIX, "The suffix of the file of the generated service (service.ts). Default is '.service'.")); + this.cliOptions.add(new CliOption(MODEL_SUFFIX, "The suffix of the generated model. Default is ''.")); + this.cliOptions.add(new CliOption(MODEL_FILE_SUFFIX, "The suffix of the file of the generated model (model.ts). Default is ''.")); } @Override @@ -146,14 +154,14 @@ public void processOpts() { } if (ngVersion.atLeast("6.0.0")) { - if (!additionalProperties.containsKey(PROVIDED_IN_ROOT)){ - additionalProperties.put(PROVIDED_IN_ROOT,true); - }else { - additionalProperties.put(PROVIDED_IN_ROOT,Boolean.valueOf( - (String) additionalProperties.get(PROVIDED_IN_ROOT))); + if (!additionalProperties.containsKey(PROVIDED_IN_ROOT)) { + additionalProperties.put(PROVIDED_IN_ROOT, true); + } else { + additionalProperties.put(PROVIDED_IN_ROOT, Boolean.valueOf( + (String) additionalProperties.get(PROVIDED_IN_ROOT))); } - }else { - additionalProperties.put(PROVIDED_IN_ROOT,false); + } else { + additionalProperties.put(PROVIDED_IN_ROOT, false); } additionalProperties.put(NG_VERSION, ngVersion); @@ -166,9 +174,19 @@ public void processOpts() { } if (additionalProperties.containsKey(SERVICE_SUFFIX)) { serviceSuffix = additionalProperties.get(SERVICE_SUFFIX).toString(); + validateClassSuffixArgument("Service", serviceSuffix); } if (additionalProperties.containsKey(SERVICE_FILE_SUFFIX)) { serviceFileSuffix = additionalProperties.get(SERVICE_FILE_SUFFIX).toString(); + validateFileSuffixArgument("Service", serviceFileSuffix); + } + if (additionalProperties.containsKey(MODEL_SUFFIX)) { + modelSuffix = additionalProperties.get(MODEL_SUFFIX).toString(); + validateClassSuffixArgument("Model", modelSuffix); + } + if (additionalProperties.containsKey(MODEL_FILE_SUFFIX)) { + modelFileSuffix = additionalProperties.get(MODEL_FILE_SUFFIX).toString(); + validateFileSuffixArgument("Model", modelFileSuffix); } } @@ -364,12 +382,13 @@ public Map postProcessOperations(Map operations) /** * Finds and returns a path parameter of an operation by its name + * * @param operation * @param parameterName * @return */ private CodegenParameter findPathParameterByName(CodegenOperation operation, String parameterName) { - for(CodegenParameter param : operation.pathParams) { + for (CodegenParameter param : operation.pathParams) { if (param.baseName.equals(parameterName)) { return param; } @@ -380,14 +399,12 @@ private CodegenParameter findPathParameterByName(CodegenOperation operation, Str @Override public Map postProcessModels(Map objs) { Map result = super.postProcessModels(objs); - return postProcessModelsEnum(result); } @Override public Map postProcessAllModels(Map objs) { Map result = super.postProcessAllModels(objs); - for (Map.Entry entry : result.entrySet()) { Map inner = (Map) entry.getValue(); List> models = (List>) inner.get("models"); @@ -416,8 +433,9 @@ private List> toTsImports(CodegenModel cm, Set impor for (String im : imports) { if (!im.equals(cm.classname)) { HashMap tsImport = new HashMap<>(); + // TVG: This is used as class name in the import statements of the model file tsImport.put("classname", im); - tsImport.put("filename", toModelFilename(im)); + tsImport.put("filename", toModelFilename(removeModelSuffixIfNecessary(im))); tsImports.add(tsImport); } } @@ -437,7 +455,7 @@ public String toApiFilename(String name) { if (name.length() == 0) { return "default.service"; } - return camelize(name, true) + serviceFileSuffix; + return camelize(removeModelSuffixIfNecessary(name), true) + serviceFileSuffix; } @Override @@ -447,7 +465,8 @@ public String toApiImport(String name) { @Override public String toModelFilename(String name) { - return camelize(toModelName(name), true); + String modelName = toModelName(name); + return camelize(removeModelSuffixIfNecessary(modelName), true) + modelFileSuffix; } @Override @@ -486,7 +505,56 @@ private String getApiFilenameFromClassname(String classname) { private String getModelnameFromModelFilename(String filename) { String name = filename.substring((modelPackage() + "/").length()); - return camelize(name); + // Remove the file suffix and add the class suffix. + // This is needed because the model file suffix might not be the same as + // the model suffix. + if (modelFileSuffix.length() > 0) { + name = name.substring(0, name.length() - modelFileSuffix.length()); + } + return camelize(name) + modelSuffix; + } + + @Override + public String toModelName(String name) { + String modelName = super.toModelName(name); + if (modelSuffix.length() == 0 || modelName.endsWith(modelSuffix)) { + return modelName; + } + return modelName + modelSuffix; } + private String removeModelSuffixIfNecessary(String name) { + if (modelSuffix.length() == 0 || !name.endsWith(modelSuffix)) { + return name; + } + return name.substring(0, name.length() - modelSuffix.length()); + } + + /** + * Validates that the given string value only contains '-', '.' and alpha numeric characters. + * Throws an IllegalArgumentException, if the string contains any other characters. + * @param argument The name of the argument being validated. This is only used for displaying an error message. + * @param value The value that is being validated. + */ + private void validateFileSuffixArgument(String argument, String value) { + if (!value.matches(FILE_NAME_SUFFIX_PATTERN)) { + throw new IllegalArgumentException( + String.format("%s file suffix only allows '.', '-' and alphanumeric characters.", argument) + ); + } + } + + /** + * Validates that the given string value only contains alpha numeric characters. + * Throws an IllegalArgumentException, if the string contains any other characters. + * @param argument The name of the argument being validated. This is only used for displaying an error message. + * @param value The value that is being validated. + */ + private void validateClassSuffixArgument(String argument, String value) { + if (!value.matches(CLASS_NAME_SUFFIX_PATTERN)) { + throw new IllegalArgumentException( + String.format("%s class suffix only allows alphanumeric characters.", argument) + ); + } + } } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/TypeScriptAngularClientOptionsProvider.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/TypeScriptAngularClientOptionsProvider.java index 8bf3e65827c5..d4a1e718589a 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/TypeScriptAngularClientOptionsProvider.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/TypeScriptAngularClientOptionsProvider.java @@ -37,6 +37,8 @@ public class TypeScriptAngularClientOptionsProvider implements OptionsProvider { public static final String PREPEND_FORM_OR_BODY_PARAMETERS_VALUE = "true"; public static String SERVICE_SUFFIX = "Service"; public static String SERVICE_FILE_SUFFIX = ".service"; + public static String MODEL_SUFFIX = ""; + public static String MODEL_FILE_SUFFIX = ""; @Override public String getLanguage() { @@ -60,6 +62,8 @@ public Map createOptions() { .put(TypeScriptAngularClientCodegen.NG_VERSION, NG_VERSION) .put(TypeScriptAngularClientCodegen.SERVICE_SUFFIX, SERVICE_SUFFIX) .put(TypeScriptAngularClientCodegen.SERVICE_FILE_SUFFIX, SERVICE_FILE_SUFFIX) + .put(TypeScriptAngularClientCodegen.MODEL_SUFFIX, MODEL_SUFFIX) + .put(TypeScriptAngularClientCodegen.MODEL_FILE_SUFFIX, MODEL_FILE_SUFFIX) .put(CodegenConstants.ALLOW_UNICODE_IDENTIFIERS, ALLOW_UNICODE_IDENTIFIERS_VALUE) .put(CodegenConstants.PREPEND_FORM_OR_BODY_PARAMETERS, PREPEND_FORM_OR_BODY_PARAMETERS_VALUE) .build();