|
19 | 19 |
|
20 | 20 | import io.swagger.v3.oas.models.OpenAPI;
|
21 | 21 | import io.swagger.v3.oas.models.media.ArraySchema;
|
| 22 | +import io.swagger.v3.oas.models.media.ComposedSchema; |
22 | 23 | import io.swagger.v3.oas.models.media.Schema;
|
23 | 24 | import io.swagger.v3.oas.models.parameters.Parameter;
|
24 | 25 | import org.apache.commons.lang3.StringUtils;
|
|
32 | 33 | import java.io.File;
|
33 | 34 | import java.text.SimpleDateFormat;
|
34 | 35 | import java.util.*;
|
| 36 | +import java.util.stream.Collectors; |
| 37 | + |
35 | 38 | import static org.openapitools.codegen.utils.StringUtils.camelize;
|
36 | 39 | import static org.openapitools.codegen.utils.StringUtils.underscore;
|
37 | 40 |
|
@@ -144,10 +147,12 @@ public TypeScriptClientCodegen() {
|
144 | 147 | typeMapping.put("object", "any");
|
145 | 148 | typeMapping.put("integer", "number");
|
146 | 149 | typeMapping.put("Map", "any");
|
| 150 | + typeMapping.put("map", "any"); |
147 | 151 | typeMapping.put("date", "string");
|
148 | 152 | typeMapping.put("DateTime", "Date");
|
149 | 153 | typeMapping.put("binary", "any");
|
150 | 154 | typeMapping.put("File", "any");
|
| 155 | + typeMapping.put("file", "any"); |
151 | 156 | typeMapping.put("ByteArray", "string");
|
152 | 157 | typeMapping.put("UUID", "string");
|
153 | 158 | typeMapping.put("Error", "Error");
|
@@ -373,40 +378,56 @@ public String toVarName(String name) {
|
373 | 378 | }
|
374 | 379 |
|
375 | 380 | @Override
|
376 |
| - public String toModelName(String name) { |
377 |
| - name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. |
| 381 | + public String toModelName(final String name) { |
| 382 | + String fullModelName = name; |
| 383 | + fullModelName = addPrefix(fullModelName, modelNamePrefix); |
| 384 | + fullModelName = addSuffix(fullModelName, modelNameSuffix); |
| 385 | + return toTypescriptTypeName(fullModelName, "Model"); |
| 386 | + } |
378 | 387 |
|
379 |
| - if (!StringUtils.isEmpty(modelNamePrefix)) { |
380 |
| - name = modelNamePrefix + "_" + name; |
| 388 | + protected String addPrefix(String name, String prefix) { |
| 389 | + if (!StringUtils.isEmpty(prefix)) { |
| 390 | + name = prefix + "_" + name; |
381 | 391 | }
|
| 392 | + return name; |
| 393 | + } |
382 | 394 |
|
383 |
| - if (!StringUtils.isEmpty(modelNameSuffix)) { |
384 |
| - name = name + "_" + modelNameSuffix; |
| 395 | + protected String addSuffix(String name, String suffix) { |
| 396 | + if (!StringUtils.isEmpty(suffix)) { |
| 397 | + name = name + "_" + suffix; |
385 | 398 | }
|
386 | 399 |
|
| 400 | + return name; |
| 401 | + } |
| 402 | + |
| 403 | + protected String toTypescriptTypeName(final String name, String safePrefix) { |
| 404 | + ArrayList<String> exceptions = new ArrayList<String>(Arrays.asList("\\|", " ")); |
| 405 | + String sanName = sanitizeName(name, "(?![| ])\\W", exceptions); |
| 406 | + |
| 407 | + sanName = camelize(sanName); |
| 408 | + |
387 | 409 | // model name cannot use reserved keyword, e.g. return
|
388 |
| - if (isReservedWord(name)) { |
389 |
| - String modelName = camelize("model_" + name); |
390 |
| - LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + modelName); |
| 410 | + // this is unlikely to happen, because we have just camelized the name, while reserved words are usually all lowcase |
| 411 | + if (isReservedWord(sanName)) { |
| 412 | + String modelName = safePrefix + sanName; |
| 413 | + LOGGER.warn(sanName + " (reserved word) cannot be used as model name. Renamed to " + modelName); |
391 | 414 | return modelName;
|
392 | 415 | }
|
393 | 416 |
|
394 | 417 | // model name starts with number
|
395 |
| - if (name.matches("^\\d.*")) { |
396 |
| - String modelName = camelize("model_" + name); // e.g. 200Response => Model200Response (after camelize) |
397 |
| - LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + modelName); |
| 418 | + if (sanName.matches("^\\d.*")) { |
| 419 | + String modelName = safePrefix + sanName; // e.g. 200Response => Model200Response |
| 420 | + LOGGER.warn(sanName + " (model name starts with number) cannot be used as model name. Renamed to " + modelName); |
398 | 421 | return modelName;
|
399 | 422 | }
|
400 | 423 |
|
401 |
| - if (languageSpecificPrimitives.contains(name)) { |
402 |
| - String modelName = camelize("model_" + name); |
403 |
| - LOGGER.warn(name + " (model name matches existing language type) cannot be used as a model name. Renamed to " + modelName); |
| 424 | + if (languageSpecificPrimitives.contains(sanName)) { |
| 425 | + String modelName = safePrefix + sanName; |
| 426 | + LOGGER.warn(sanName + " (model name matches existing language type) cannot be used as a model name. Renamed to " + modelName); |
404 | 427 | return modelName;
|
405 | 428 | }
|
406 | 429 |
|
407 |
| - // camelize the model name |
408 |
| - // phone_number => PhoneNumber |
409 |
| - return camelize(name); |
| 430 | + return sanName; |
410 | 431 | }
|
411 | 432 |
|
412 | 433 | @Override
|
@@ -521,7 +542,9 @@ protected boolean isReservedWord(String word) {
|
521 | 542 | public String getSchemaType(Schema p) {
|
522 | 543 | String openAPIType = super.getSchemaType(p);
|
523 | 544 | String type = null;
|
524 |
| - if (typeMapping.containsKey(openAPIType)) { |
| 545 | + if (ModelUtils.isComposedSchema(p)) { |
| 546 | + return openAPIType; |
| 547 | + } else if (typeMapping.containsKey(openAPIType)) { |
525 | 548 | type = typeMapping.get(openAPIType);
|
526 | 549 | if (languageSpecificPrimitives.contains(type))
|
527 | 550 | return type;
|
@@ -853,4 +876,55 @@ protected void addAdditionPropertiesToCodeGenModel(CodegenModel codegenModel, Sc
|
853 | 876 | codegenModel.additionalPropertiesType = getTypeDeclaration((Schema) schema.getAdditionalProperties());
|
854 | 877 | addImport(codegenModel, codegenModel.additionalPropertiesType);
|
855 | 878 | }
|
| 879 | + |
| 880 | + @Override |
| 881 | + public String toAnyOfName(List<String> names, ComposedSchema composedSchema) { |
| 882 | + List<String> types = getTypesFromSchemas(composedSchema.getAnyOf()); |
| 883 | + |
| 884 | + return String.join(" | ", types); |
| 885 | + } |
| 886 | + |
| 887 | + @Override |
| 888 | + public String toOneOfName(List<String> names, ComposedSchema composedSchema) { |
| 889 | + List<String> types = getTypesFromSchemas(composedSchema.getOneOf()); |
| 890 | + |
| 891 | + return String.join(" | ", types); |
| 892 | + } |
| 893 | + |
| 894 | + /** |
| 895 | + * Extracts the list of type names from a list of schemas. |
| 896 | + * Excludes `AnyType` if there are other valid types extracted. |
| 897 | + * |
| 898 | + * @param schemas list of schemas |
| 899 | + * @return list of types |
| 900 | + */ |
| 901 | + protected List<String> getTypesFromSchemas(List<Schema> schemas) { |
| 902 | + List<Schema> filteredSchemas = schemas.size() > 1 |
| 903 | + ? schemas.stream().filter(schema -> !"AnyType".equals(super.getSchemaType(schema))).collect(Collectors.toList()) |
| 904 | + : schemas; |
| 905 | + |
| 906 | + return filteredSchemas.stream().map(schema -> { |
| 907 | + String schemaType = getSchemaType(schema); |
| 908 | + if (ModelUtils.isArraySchema(schema)) { |
| 909 | + ArraySchema ap = (ArraySchema) schema; |
| 910 | + Schema inner = ap.getItems(); |
| 911 | + schemaType = schemaType + "<" + getSchemaType(inner) + ">"; |
| 912 | + } |
| 913 | + return schemaType; |
| 914 | + }).distinct().collect(Collectors.toList()); |
| 915 | + } |
| 916 | + |
| 917 | + @Override |
| 918 | + protected void addImport(CodegenModel m, String type) { |
| 919 | + if (type == null) { |
| 920 | + return; |
| 921 | + } |
| 922 | + |
| 923 | + String[] parts = type.split("( [|&] )|[<>]"); |
| 924 | + for (String s : parts) { |
| 925 | + if (needToImport(s)) { |
| 926 | + m.imports.add(s); |
| 927 | + } |
| 928 | + } |
| 929 | + } |
856 | 930 | }
|
0 commit comments