Skip to content

Commit e91cde1

Browse files
committed
Merge remote-tracking branch 'origin/master'
2 parents 8e83bee + b59957a commit e91cde1

859 files changed

Lines changed: 8936 additions & 3804 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/samples-postman.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on:
44
pull_request:
55
paths:
66
- samples/schema/postman-collection/python/**
7+
- samples/schema/postman-collection/postman.json
78
- .github/workflows/samples-postman.yaml
89
jobs:
910
build:

.github/workflows/samples-swift.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141
runs-on: ${{ matrix.os }}
4242
steps:
4343
- uses: actions/checkout@v4
44-
- uses: swift-actions/setup-swift@v1
44+
- uses: swift-actions/setup-swift@v2
4545
if: ${{ matrix.os == 'ubuntu-latest' }}
4646
with:
4747
swift-version: '5'

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1114,8 +1114,9 @@ Here is a list of template creators:
11141114
* GraphQL: @wing328 [:heart:](https://www.patreon.com/wing328)
11151115
* Ktorm: @Luiz-Monad
11161116
* MySQL: [@ybelenko](https://github.com/ybelenko)
1117+
* Postman Collection: @gcatanese
11171118
* Protocol Buffer: @wing328
1118-
* WSDL @adessoDpd
1119+
* WSDL: @adessoDpd
11191120

11201121
:heart: = Link to support the contributor directly
11211122

docs/customization.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,3 +598,10 @@ Example:
598598
```
599599
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -g java -i modules/openapi-generator/src/test/resources/3_0/petstore.yaml -o /tmp/java-okhttp/ --openapi-normalizer FILTER="operationId:addPet|getPetById"
600600
```
601+
602+
- `SET_CONTAINER_TO_NULLABLE`: When set to `array|set|map` (or just `array`) for example, it will set `nullable` in array, set and map to true.
603+
604+
Example:
605+
```
606+
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -g java -i modules/openapi-generator/src/test/resources/3_0/petstore.yaml -o /tmp/java-okhttp/ --openapi-normalizer SET_CONTAINER_TO_NULLABLE="array|map"
607+
```

docs/templating.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,7 @@ Many generators (*those extending DefaultCodegen*) come with a small set of lamb
822822
- `uppercase` - Converts all of the characters in this fragment to upper case using the rules of the `ROOT` locale.
823823
- `titlecase` - Converts text in a fragment to title case. For example `once upon a time` to `Once Upon A Time`.
824824
- `camelcase` - Converts text in a fragment to camelCase. For example `Input-text` to `inputText`.
825+
- `uncamelize` - Converts text in a fragment from camelCase or PascalCase to a string of words separated by whitespaces. For example `inputText` to `Input Text`.
825826
- `indented` - Prepends 4 spaces indention from second line of a fragment on. First line will be indented by Mustache.
826827
- `indented_8` - Prepends 8 spaces indention from second line of a fragment on. First line will be indented by Mustache.
827828
- `indented_12` - Prepends 12 spaces indention from second line of a fragment on. First line will be indented by Mustache.

modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,8 +463,9 @@ protected ImmutableMap.Builder<String, Lambda> addMustacheLambdas() {
463463
.put("snakecase", new SnakecaseLambda())
464464
.put("titlecase", new TitlecaseLambda())
465465
.put("kebabcase", new KebabCaseLambda())
466-
.put("camelcase", new CamelCaseLambda(true).generator(this))
467-
.put("pascalcase", new CamelCaseLambda(false).generator(this))
466+
.put("camelcase", new CamelCaseAndSanitizeLambda(true).generator(this))
467+
.put("pascalcase", new CamelCaseAndSanitizeLambda(false).generator(this))
468+
.put("uncamelize", new UncamelizeLambda())
468469
.put("forwardslash", new ForwardSlashLambda())
469470
.put("backslash", new BackSlashLambda())
470471
.put("doublequote", new DoubleQuoteLambda())

modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,17 @@ public class OpenAPINormalizer {
101101
final String X_INTERNAL = "x-internal";
102102
boolean removeXInternal;
103103

104-
// when set (e.g. operationId:getPetById, addPet), filter out (or remove) everything else
104+
// when set (e.g. operationId:getPetById|addPet), filter out (or remove) everything else
105105
final String FILTER = "FILTER";
106106
HashSet<String> operationIdFilters = new HashSet<>();
107107

108+
// when set (e.g. operationId:getPetById|addPet), filter out (or remove) everything else
109+
final String SET_CONTAINER_TO_NULLABLE = "SET_CONTAINER_TO_NULLABLE";
110+
HashSet<String> setContainerToNullable = new HashSet<>();
111+
boolean updateArrayToNullable;
112+
boolean updateSetToNullable;
113+
boolean updateMapToNullable;
114+
108115
// ============= end of rules =============
109116

110117
/**
@@ -199,6 +206,23 @@ public void processRules(Map<String, String> inputRules) {
199206
}
200207
}
201208
}
209+
210+
if (inputRules.get(SET_CONTAINER_TO_NULLABLE) != null) {
211+
rules.put(SET_CONTAINER_TO_NULLABLE, true);
212+
setContainerToNullable = new HashSet<>(Arrays.asList(inputRules.get(SET_CONTAINER_TO_NULLABLE).split("[|]")));
213+
if (setContainerToNullable.contains("array")) {
214+
updateArrayToNullable = true;
215+
}
216+
if (setContainerToNullable.contains("set")) {
217+
updateSetToNullable = true;
218+
}
219+
if (setContainerToNullable.contains("map")) {
220+
updateMapToNullable = true;
221+
}
222+
if (!updateArrayToNullable && !updateSetToNullable && !updateMapToNullable) {
223+
LOGGER.error("SET_CONTAINER_TO_NULLABLE rule must be in the form of `array|set|map`, e.g. `set`, `array|map`: {}", inputRules.get(SET_CONTAINER_TO_NULLABLE));
224+
}
225+
}
202226
}
203227

204228
/**
@@ -445,8 +469,10 @@ public Schema normalizeSchema(Schema schema, Set<Schema> visitedSchemas) {
445469
}
446470

447471
if (schema instanceof ArraySchema) { // array
472+
normalizeArraySchema(schema);
448473
normalizeSchema(schema.getItems(), visitedSchemas);
449474
} else if (schema.getAdditionalProperties() instanceof Schema) { // map
475+
normalizeMapSchema(schema);
450476
normalizeSchema((Schema) schema.getAdditionalProperties(), visitedSchemas);
451477
} else if (ModelUtils.isOneOf(schema)) { // oneOf
452478
return normalizeOneOf(schema, visitedSchemas);
@@ -498,6 +524,14 @@ public Schema normalizeSchema(Schema schema, Set<Schema> visitedSchemas) {
498524
return schema;
499525
}
500526

527+
private Schema normalizeArraySchema(Schema schema) {
528+
return processSetArraytoNullable(schema);
529+
}
530+
531+
private Schema normalizeMapSchema(Schema schema) {
532+
return processSetMapToNullable(schema);
533+
}
534+
501535
private Schema normalizeSimpleSchema(Schema schema, Set<Schema> visitedSchemas) {
502536
return processNormalize31Spec(schema, visitedSchemas);
503537
}
@@ -864,6 +898,60 @@ private Schema processSimplifyOneOf(Schema schema) {
864898
return schema;
865899
}
866900

901+
/**
902+
* Set nullable to true in array/set if needed.
903+
*
904+
* @param schema Schema
905+
* @return Schema
906+
*/
907+
private Schema processSetArraytoNullable(Schema schema) {
908+
if (!getRule(SET_CONTAINER_TO_NULLABLE)) {
909+
return schema;
910+
}
911+
912+
if (Boolean.TRUE.equals(schema.getUniqueItems())) { // a set
913+
if (updateSetToNullable) {
914+
if (schema.getNullable() != null || (schema.getExtensions() != null && schema.getExtensions().containsKey("x-nullable"))) {
915+
// already set, don't overwrite
916+
return schema;
917+
}
918+
schema.setNullable(true);
919+
}
920+
} else { // array
921+
if (updateArrayToNullable) {
922+
if (schema.getNullable() != null || (schema.getExtensions() != null && schema.getExtensions().containsKey("x-nullable"))) {
923+
// already set, don't overwrite
924+
return schema;
925+
}
926+
schema.setNullable(true);
927+
}
928+
}
929+
930+
return schema;
931+
}
932+
933+
/**
934+
* Set nullable to true in map if needed.
935+
*
936+
* @param schema Schema
937+
* @return Schema
938+
*/
939+
private Schema processSetMapToNullable(Schema schema) {
940+
if (!getRule(SET_CONTAINER_TO_NULLABLE)) {
941+
return schema;
942+
}
943+
944+
if (updateMapToNullable) {
945+
if (schema.getNullable() != null || (schema.getExtensions() != null && schema.getExtensions().containsKey("x-nullable"))) {
946+
// already set, don't override
947+
return schema;
948+
}
949+
schema.setNullable(true);
950+
}
951+
952+
return schema;
953+
}
954+
867955
/**
868956
* If the schema is anyOf and the sub-schemas is null, set `nullable: true` instead.
869957
* If there's only one sub-schema, simply return the sub-schema directly.
@@ -1036,6 +1124,7 @@ private Schema processNormalize31Spec(Schema schema, Set<Schema> visitedSchemas)
10361124
as.setMaxItems(schema.getMaxItems());
10371125
as.setExtensions(schema.getExtensions());
10381126
as.setXml(schema.getXml());
1127+
as.setUniqueItems(schema.getUniqueItems());
10391128
if (schema.getItems() != null) {
10401129
// `items` is also a json schema
10411130
if (StringUtils.isNotEmpty(schema.getItems().get$ref())) {

modules/openapi-generator/src/main/java/org/openapitools/codegen/examples/ExampleGenerator.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public class ExampleGenerator {
3737
private static final String MIME_TYPE_JSON = "application/json";
3838
private static final String MIME_TYPE_XML = "application/xml";
3939

40-
protected final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd", Locale.ROOT);
40+
protected final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.ROOT);
4141

4242
private static final String EXAMPLE = "example";
4343
private static final String CONTENT_TYPE = "contentType";
@@ -57,7 +57,7 @@ public ExampleGenerator(Map<String, Schema> examples, OpenAPI openAPI) {
5757
this.openAPI = openAPI;
5858
// use a fixed seed to make the "random" numbers reproducible.
5959
this.random = new Random("ExampleGenerator".hashCode());
60-
DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
60+
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
6161
}
6262

6363
public List<Map<String, String>> generateFromResponseSchema(String statusCode, Schema responseSchema, Set<String> producesInfo) {
@@ -238,7 +238,7 @@ private Object resolvePropertyToExample(String propertyName, String mediaType, S
238238
// When a property is of type Date, we want to ensure that we're returning a formatted Date.
239239
// And not returning the Date object directly.
240240
if (property.getExample() instanceof Date) {
241-
return DATE_FORMAT.format(property.getExample());
241+
return dateFormat.format(property.getExample());
242242
}
243243
return property.getExample();
244244
} else if (ModelUtils.isBooleanSchema(property)) {

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCSharpCodegen.java

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
8585
protected String enumValueSuffix = "Enum";
8686

8787
protected String sourceFolder = "src";
88-
protected String invalidNamePrefix = "var";
88+
protected static final String invalidParameterNamePrefix = "var";
89+
protected static final String invalidPropertyNamePrefix = "Var";
8990
protected CodegenConstants.ENUM_PROPERTY_NAMING_TYPE enumPropertyNaming = CodegenConstants.ENUM_PROPERTY_NAMING_TYPE.PascalCase;
9091

9192
// TODO: Add option for test folder output location. Nice to allow e.g. ./test instead of ./src.
@@ -441,7 +442,7 @@ protected ImmutableMap.Builder<String, Lambda> addMustacheLambdas() {
441442
CopyLambda copyLambda = new CopyLambda();
442443

443444
return super.addMustacheLambdas()
444-
.put("camelcase_param", new CamelCaseLambda().generator(this).escapeAsParamName(true))
445+
.put("camelcase_sanitize_param", new CamelCaseAndSanitizeLambda().generator(this).escapeAsParamName(true))
445446
.put("required", new RequiredParameterLambda())
446447
.put("optional", new OptionalParameterLambda().generator(this))
447448
.put("joinWithComma", new JoinWithCommaLambda())
@@ -461,7 +462,9 @@ protected ImmutableMap.Builder<String, Lambda> addMustacheLambdas() {
461462
.put("pasteOnce", new PasteLambda(copyLambda, true, true, true, true))
462463
.put("pasteLine", new PasteLambda(copyLambda, true, true, false, false))
463464
.put("uniqueLines", new UniqueLambda("\n", false))
464-
.put("unique", new UniqueLambda("\n", true));
465+
.put("unique", new UniqueLambda("\n", true))
466+
.put("camel_case", new CamelCaseLambda())
467+
.put("escape_reserved_word", new EscapeKeywordLambda((val) -> this.escapeKeyword(val)));
465468
}
466469

467470
@Override
@@ -664,18 +667,13 @@ protected void removePropertiesDeclaredInComposedTypes(Map<String, ModelsMap> ob
664667
}
665668

666669
private String patchPropertyName(CodegenModel model, String value) {
667-
// the casing will be wrong if we just set the name to escapeReservedWord
668-
// if we try to fix it with camelize, underscores get stripped out
669-
// so test if the name was escaped and then replace var with Var
670-
String tmpPropertyName = escapeReservedWord(model, value);
671-
if (!value.equals(tmpPropertyName) || value.startsWith(this.invalidNamePrefix)) {
672-
value = tmpPropertyName;
673-
String firstCharacter = value.substring(0, 1);
674-
value = value.substring(1);
675-
value = firstCharacter.toUpperCase(Locale.ROOT) + value;
670+
String name = escapeReservedWord(model, value);
671+
672+
if (name.startsWith(AbstractCSharpCodegen.invalidParameterNamePrefix)) {
673+
name = AbstractCSharpCodegen.invalidPropertyNamePrefix + name.substring(AbstractCSharpCodegen.invalidParameterNamePrefix.length());
676674
}
677675

678-
return value;
676+
return name;
679677
}
680678

681679
private void patchPropertyVendorExtensions(CodegenProperty property) {
@@ -700,7 +698,6 @@ protected void patchProperty(Map<String, CodegenModel> enumRefs, CodegenModel mo
700698

701699
patchPropertyVendorExtensions(property);
702700

703-
String tmpPropertyName = escapeReservedWord(model, property.name);
704701
property.name = patchPropertyName(model, property.name);
705702

706703
String[] nestedTypes = { "List", "Collection", "ICollection", "Dictionary" };
@@ -1122,7 +1119,7 @@ protected void patchVendorExtensionNullableValueType(CodegenParameter parameter)
11221119
* Returns the model related to the given parameter
11231120
*/
11241121
private CodegenModel getModelFromParameter(List<ModelMap> allModels, CodegenParameter parameter) {
1125-
return parameter.isModel
1122+
return parameter.isModel || parameter.getIsEnumOrRef()
11261123
? allModels.stream().map(m -> m.getModel()).filter(m -> m.getClassname().equals(parameter.dataType)).findFirst().orElse(null)
11271124
: null;
11281125
}
@@ -1308,23 +1305,24 @@ public String toParamName(String name) {
13081305
public String escapeReservedWord(CodegenModel model, String name) {
13091306
name = this.escapeReservedWord(name);
13101307

1311-
return name.equalsIgnoreCase(model.getClassname())
1312-
? this.invalidNamePrefix + camelize(name)
1308+
return name.equals(model.getClassname())
1309+
? AbstractCSharpCodegen.invalidParameterNamePrefix + camelize(name)
13131310
: name;
13141311
}
13151312

13161313
@Override
13171314
public String escapeReservedWord(String name) {
1318-
if (reservedWords().contains(name) ||
1319-
reservedWords().contains(name.toLowerCase(Locale.ROOT)) ||
1320-
reservedWords().contains(camelize(sanitizeName(name))) ||
1321-
isReservedWord(name) ||
1315+
if (isReservedWord(name) ||
13221316
name.matches("^\\d.*")) {
1323-
name = this.invalidNamePrefix + camelize(name);
1317+
name = AbstractCSharpCodegen.invalidParameterNamePrefix + camelize(name);
13241318
}
13251319
return name;
13261320
}
13271321

1322+
public String escapeKeyword(String value) {
1323+
return isReservedWord(value) ? "@" + value : value;
1324+
}
1325+
13281326
/**
13291327
* Return the example value of the property
13301328
*

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractFSharpCodegen.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ public void processOpts() {
313313
@Override
314314
protected ImmutableMap.Builder<String, Lambda> addMustacheLambdas() {
315315
return super.addMustacheLambdas()
316-
.put("camelcase_param", new CamelCaseLambda().generator(this).escapeAsParamName(true));
316+
.put("camelcase_param", new CamelCaseAndSanitizeLambda().generator(this).escapeAsParamName(true));
317317
}
318318

319319
@Override

0 commit comments

Comments
 (0)