Merge remote-tracking branch 'origin/master' into 4.3.x

This commit is contained in:
William Cheng
2019-12-28 12:00:09 +08:00
761 changed files with 40748 additions and 6074 deletions

View File

@@ -628,6 +628,7 @@ Here are some companies/projects (alphabetical order) using OpenAPI Generator in
- [TUI InfoTec GmbH](http://www.tui-infotec.com/) - [TUI InfoTec GmbH](http://www.tui-infotec.com/)
- [unblu inc.](https://www.unblu.com/) - [unblu inc.](https://www.unblu.com/)
- [Veamly](https://www.veamly.com/) - [Veamly](https://www.veamly.com/)
- [Woleet](https://www.woleet.io/)
- [WSO2](https://wso2.com/) - [WSO2](https://wso2.com/)
- [Vouchery.io](https://vouchery.io) - [Vouchery.io](https://vouchery.io)
- [Xero](https://www.xero.com/) - [Xero](https://www.xero.com/)

View File

@@ -26,6 +26,6 @@ fi
# if you've executed sbt assembly previously it will use that instead. # if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties" export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties"
ags="$@ generate -t modules/openapi-generator/src/main/resources/asciidoc-documentation --additional-properties=specDir=modules/openapi-generator/src/main/resources/asciidoc-documentation,snippetDir=. -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g asciidoc -o samples/documentation/asciidoc" ags="generate -t modules/openapi-generator/src/main/resources/asciidoc-documentation --additional-properties=specDir=modules/openapi-generator/src/main/resources/asciidoc-documentation,snippetDir=. -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g asciidoc -o samples/documentation/asciidoc $@"
java ${JAVA_OPTS} -jar ${executable} ${ags} java ${JAVA_OPTS} -jar ${executable} ${ags}

View File

@@ -0,0 +1,34 @@
#!/bin/sh
SCRIPT="$0"
echo "# START SCRIPT: $SCRIPT"
while [ -h "$SCRIPT" ] ; do
ls=$(ls -ld "$SCRIPT")
link=$(expr "$ls" : '.*-> \(.*\)$')
if expr "$link" : '/.*' > /dev/null; then
SCRIPT="$link"
else
SCRIPT=$(dirname "$SCRIPT")/"$link"
fi
done
if [ ! -d "${APP_DIR}" ]; then
APP_DIR=$(dirname "$SCRIPT")/..
APP_DIR=$(cd "${APP_DIR}"; pwd)
fi
executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"
if [ ! -f "$executable" ]
then
mvn -B clean package
fi
# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties"
ags="generate -t modules/openapi-generator/src/main/resources/kotlin-client -i modules/openapi-generator/src/test/resources/3_0/issue-4062.yaml -g kotlin --artifact-id kotlin-uppercase-enum --additional-properties enumPropertyNaming=UPPERCASE -o samples/client/petstore/kotlin-uppercase-enum $@"
java ${JAVA_OPTS} -jar ${executable} ${ags}
#cp CI/samples.ci/client/petstore/kotlin-uppercase-enum/pom.xml samples/client/petstore/kotlin-uppercase-enum/pom.xml

View File

@@ -3,3 +3,4 @@
./bin/python-server-aiohttp-petstore.sh ./bin/python-server-aiohttp-petstore.sh
./bin/python-server-flask-petstore.sh ./bin/python-server-flask-petstore.sh
./bin/python-server-flask-petstore-python2.sh ./bin/python-server-flask-petstore-python2.sh
./bin/python-server-blueplanet-petstore.sh

View File

@@ -20,5 +20,6 @@ sidebar_label: asciidoc
|groupId|groupId in generated pom.xml| |null| |groupId|groupId in generated pom.xml| |null|
|artifactId|artifactId in generated pom.xml. This also becomes part of the generated library's filename| |null| |artifactId|artifactId in generated pom.xml. This also becomes part of the generated library's filename| |null|
|artifactVersion|artifact version in generated pom.xml. This also becomes part of the generated library's filename| |null| |artifactVersion|artifact version in generated pom.xml. This also becomes part of the generated library's filename| |null|
|snippetDir|path with includable markup snippets (e.g. test output generated by restdoc, default: .| |.| |snippetDir|path with includable markup snippets (e.g. test output generated by restdoc, default: .)| |.|
|specDir|path with includable markup spec files (e.g. handwritten additional docs, default: .| |..| |specDir|path with includable markup spec files (e.g. handwritten additional docs, default: ..)| |..|
|headerAttributes|generation of asciidoc header meta data attributes (set to false to suppress, default: true)| |true|

View File

@@ -14,6 +14,9 @@ sidebar_label: dart-dio
|pubName|Name in generated pubspec| |null| |pubName|Name in generated pubspec| |null|
|pubVersion|Version in generated pubspec| |null| |pubVersion|Version in generated pubspec| |null|
|pubDescription|Description in generated pubspec| |null| |pubDescription|Description in generated pubspec| |null|
|pubAuthor|Author name in generated pubspec| |null|
|pubAuthorEmail|Email address of the author in generated pubspec| |null|
|pubHomepage|Homepage in generated pubspec| |null|
|useEnumExtension|Allow the 'x-enum-values' extension for enums| |null| |useEnumExtension|Allow the 'x-enum-values' extension for enums| |null|
|sourceFolder|Source folder for generated code| |null| |sourceFolder|Source folder for generated code| |null|
|supportDart2|Support Dart 2.x (Dart 1.x support has been deprecated)| |true| |supportDart2|Support Dart 2.x (Dart 1.x support has been deprecated)| |true|

View File

@@ -14,6 +14,9 @@ sidebar_label: dart-jaguar
|pubName|Name in generated pubspec| |null| |pubName|Name in generated pubspec| |null|
|pubVersion|Version in generated pubspec| |null| |pubVersion|Version in generated pubspec| |null|
|pubDescription|Description in generated pubspec| |null| |pubDescription|Description in generated pubspec| |null|
|pubAuthor|Author name in generated pubspec| |null|
|pubAuthorEmail|Email address of the author in generated pubspec| |null|
|pubHomepage|Homepage in generated pubspec| |null|
|useEnumExtension|Allow the 'x-enum-values' extension for enums| |null| |useEnumExtension|Allow the 'x-enum-values' extension for enums| |null|
|sourceFolder|Source folder for generated code| |null| |sourceFolder|Source folder for generated code| |null|
|supportDart2|Support Dart 2.x (Dart 1.x support has been deprecated)| |true| |supportDart2|Support Dart 2.x (Dart 1.x support has been deprecated)| |true|

View File

@@ -14,6 +14,9 @@ sidebar_label: dart
|pubName|Name in generated pubspec| |null| |pubName|Name in generated pubspec| |null|
|pubVersion|Version in generated pubspec| |null| |pubVersion|Version in generated pubspec| |null|
|pubDescription|Description in generated pubspec| |null| |pubDescription|Description in generated pubspec| |null|
|pubAuthor|Author name in generated pubspec| |null|
|pubAuthorEmail|Email address of the author in generated pubspec| |null|
|pubHomepage|Homepage in generated pubspec| |null|
|useEnumExtension|Allow the 'x-enum-values' extension for enums| |null| |useEnumExtension|Allow the 'x-enum-values' extension for enums| |null|
|sourceFolder|Source folder for generated code| |null| |sourceFolder|Source folder for generated code| |null|
|supportDart2|Support Dart 2.x (Dart 1.x support has been deprecated)| |true| |supportDart2|Support Dart 2.x (Dart 1.x support has been deprecated)| |true|

View File

@@ -13,4 +13,5 @@ sidebar_label: go-experimental
|withXml|whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML)| |false| |withXml|whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML)| |false|
|enumClassPrefix|Prefix enum with class name| |false| |enumClassPrefix|Prefix enum with class name| |false|
|structPrefix|whether to prefix struct with the class name. e.g. DeletePetOpts => PetApiDeletePetOpts| |false| |structPrefix|whether to prefix struct with the class name. e.g. DeletePetOpts => PetApiDeletePetOpts| |false|
|withAWSV4Signature|whether to include AWS v4 signature support| |false|
|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false| |prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|

View File

@@ -13,4 +13,5 @@ sidebar_label: go
|withXml|whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML)| |false| |withXml|whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML)| |false|
|enumClassPrefix|Prefix enum with class name| |false| |enumClassPrefix|Prefix enum with class name| |false|
|structPrefix|whether to prefix struct with the class name. e.g. DeletePetOpts => PetApiDeletePetOpts| |false| |structPrefix|whether to prefix struct with the class name. e.g. DeletePetOpts => PetApiDeletePetOpts| |false|
|withAWSV4Signature|whether to include AWS v4 signature support| |false|
|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false| |prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|

View File

@@ -7,3 +7,4 @@ sidebar_label: mysql-schema
| ------ | ----------- | ------ | ------- | | ------ | ----------- | ------ | ------- |
|defaultDatabaseName|Default database name for all MySQL queries| || |defaultDatabaseName|Default database name for all MySQL queries| ||
|jsonDataTypeEnabled|Use special JSON MySQL data type for complex model properties. Requires MySQL version 5.7.8. Generates TEXT data type when disabled| |true| |jsonDataTypeEnabled|Use special JSON MySQL data type for complex model properties. Requires MySQL version 5.7.8. Generates TEXT data type when disabled| |true|
|identifierNamingConvention|Naming convention of MySQL identifiers(table names and column names). This is not related to database name which is defined by defaultDatabaseName option|<dl><dt>**original**</dt><dd>Do not transform original names</dd><dt>**snake_case**</dt><dd>Use snake_case names</dd><dl>|original|

View File

@@ -16,3 +16,4 @@ sidebar_label: python-aiohttp
|defaultController|default controller| |default_controller| |defaultController|default controller| |default_controller|
|supportPython2|support python2| |false| |supportPython2|support python2| |false|
|serverPort|TCP port to listen to in app.run| |8080| |serverPort|TCP port to listen to in app.run| |8080|
|useNose|use the nose test framework| |false|

View File

@@ -16,3 +16,4 @@ sidebar_label: python-blueplanet
|defaultController|default controller| |default_controller| |defaultController|default controller| |default_controller|
|supportPython2|support python2| |false| |supportPython2|support python2| |false|
|serverPort|TCP port to listen to in app.run| |8080| |serverPort|TCP port to listen to in app.run| |8080|
|useNose|use the nose test framework| |false|

View File

@@ -12,4 +12,5 @@ sidebar_label: python-experimental
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true| |sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true| |hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true|
|generateSourceCodeOnly|Specifies that only a library source code is to be generated.| |false| |generateSourceCodeOnly|Specifies that only a library source code is to be generated.| |false|
|useNose|use the nose test framework| |false|
|library|library template (sub-template) to use: asyncio, tornado, urllib3| |urllib3| |library|library template (sub-template) to use: asyncio, tornado, urllib3| |urllib3|

View File

@@ -16,3 +16,4 @@ sidebar_label: python-flask
|defaultController|default controller| |default_controller| |defaultController|default controller| |default_controller|
|supportPython2|support python2| |false| |supportPython2|support python2| |false|
|serverPort|TCP port to listen to in app.run| |8080| |serverPort|TCP port to listen to in app.run| |8080|
|useNose|use the nose test framework| |false|

View File

@@ -12,4 +12,5 @@ sidebar_label: python
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true| |sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true| |hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true|
|generateSourceCodeOnly|Specifies that only a library source code is to be generated.| |false| |generateSourceCodeOnly|Specifies that only a library source code is to be generated.| |false|
|useNose|use the nose test framework| |false|
|library|library template (sub-template) to use: asyncio, tornado, urllib3| |urllib3| |library|library template (sub-template) to use: asyncio, tornado, urllib3| |urllib3|

View File

@@ -69,6 +69,9 @@ public class CodegenConstants {
public static final String WITH_GO_CODEGEN_COMMENT = "withGoCodegenComment"; public static final String WITH_GO_CODEGEN_COMMENT = "withGoCodegenComment";
public static final String WITH_GO_CODEGEN_COMMENT_DESC = "whether to include Go codegen comment to disable Go Lint and collapse by default GitHub in PRs and diffs"; public static final String WITH_GO_CODEGEN_COMMENT_DESC = "whether to include Go codegen comment to disable Go Lint and collapse by default GitHub in PRs and diffs";
public static final String WITH_AWSV4_SIGNATURE_COMMENT = "withAWSV4Signature";
public static final String WITH_AWSV4_SIGNATURE_COMMENT_DESC = "whether to include AWS v4 signature support";
public static final String IS_GO_SUBMODULE = "isGoSubmodule"; public static final String IS_GO_SUBMODULE = "isGoSubmodule";
public static final String IS_GO_SUBMODULE_DESC = "whether the generated Go module is a submodule"; public static final String IS_GO_SUBMODULE_DESC = "whether the generated Go module is a submodule";

View File

@@ -1876,7 +1876,7 @@ public class DefaultCodegen implements CodegenConfig {
// parent model // parent model
final String parentName = ModelUtils.getParentName(composed, allDefinitions); final String parentName = ModelUtils.getParentName(composed, allDefinitions);
final List<String> allParents = ModelUtils.getAllParentsName(composed, allDefinitions); final List<String> allParents = ModelUtils.getAllParentsName(composed, allDefinitions, false);
final Schema parent = StringUtils.isBlank(parentName) || allDefinitions == null ? null : allDefinitions.get(parentName); final Schema parent = StringUtils.isBlank(parentName) || allDefinitions == null ? null : allDefinitions.get(parentName);
// TODO revise the logic below to set dicriminator, xml attributes // TODO revise the logic below to set dicriminator, xml attributes
@@ -2083,10 +2083,8 @@ public class DefaultCodegen implements CodegenConfig {
Map<String, Schema> allDefinitions = ModelUtils.getSchemas(this.openAPI); Map<String, Schema> allDefinitions = ModelUtils.getSchemas(this.openAPI);
allDefinitions.forEach((childName, child) -> { allDefinitions.forEach((childName, child) -> {
if (child instanceof ComposedSchema && ((ComposedSchema) child).getAllOf() != null) { if (child instanceof ComposedSchema && ((ComposedSchema) child).getAllOf() != null) {
Set<String> parentSchemas = ((ComposedSchema) child).getAllOf().stream()
.filter(s -> s.get$ref() != null) final List<String> parentSchemas = ModelUtils.getAllParentsName((ComposedSchema) child, allDefinitions, true);
.map(s -> ModelUtils.getSimpleRef(s.get$ref()))
.collect(Collectors.toSet());
if (parentSchemas.contains(schemaName)) { if (parentSchemas.contains(schemaName)) {
discriminator.getMappedModels().add(new MappedModel(childName, toModelName(childName))); discriminator.getMappedModels().add(new MappedModel(childName, toModelName(childName)));
} }

View File

@@ -26,6 +26,7 @@ import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.security.SecurityRequirement; import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme; import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server; import io.swagger.v3.oas.models.servers.Server;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.*; import org.openapitools.codegen.*;
import org.openapitools.codegen.utils.ModelUtils; import org.openapitools.codegen.utils.ModelUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -163,7 +164,7 @@ abstract public class AbstractAdaCodegen extends DefaultCodegen implements Codeg
addOption(CodegenConstants.PROJECT_NAME, "GNAT project name", addOption(CodegenConstants.PROJECT_NAME, "GNAT project name",
this.projectName); this.projectName);
modelNameSuffix = "_Type"; modelNameSuffix = "Type";
embeddedTemplateDir = templateDir = "Ada"; embeddedTemplateDir = templateDir = "Ada";
languageSpecificPrimitives = new HashSet<String>( languageSpecificPrimitives = new HashSet<String>(
@@ -242,11 +243,37 @@ abstract public class AbstractAdaCodegen extends DefaultCodegen implements Codeg
* @return capitalized model name * @return capitalized model name
*/ */
public String toModelName(final String name) { public String toModelName(final String name) {
String result = super.toModelName(name); String result = camelize(sanitizeName(name));
if (result.matches("^\\d.*") || result.startsWith("_")) {
result = "Model_" + result; if (!StringUtils.isEmpty(modelNamePrefix)) {
result = modelNamePrefix + "_" + result;
} }
return result.replaceAll("[\\.-]", "_").replaceAll("__+", "_");
// model name cannot use reserved keyword, e.g. return
if (isReservedWord(name)) {
String modelName = "Model_" + result;
LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + modelName);
return modelName;
}
// model name starts with number
if (result.matches("^\\d.*")) {
String modelName = "Model_" + result; // e.g. 200Response => Model_200Response (after camelize)
LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + modelName);
return modelName;
}
if (languageSpecificPrimitives.contains(result)) {
String modelName = "Model_" + result;
LOGGER.warn(name + " (model name matches existing language type) cannot be used as a model name. Renamed to " + modelName);
return modelName;
}
if (!StringUtils.isEmpty(modelNameSuffix)) {
result = result + "_" + modelNameSuffix;
}
return result;
} }
@Override @Override
@@ -517,7 +544,7 @@ abstract public class AbstractAdaCodegen extends DefaultCodegen implements Codeg
if (v instanceof CodegenModel) { if (v instanceof CodegenModel) {
CodegenModel m = (CodegenModel) v; CodegenModel m = (CodegenModel) v;
List<String> d = new ArrayList<String>(); List<String> d = new ArrayList<String>();
for (CodegenProperty p : m.allVars) { for (CodegenProperty p : m.vars) {
boolean isModel = false; boolean isModel = false;
CodegenProperty item = p; CodegenProperty item = p;
if (p.isContainer) { if (p.isContainer) {
@@ -531,9 +558,10 @@ abstract public class AbstractAdaCodegen extends DefaultCodegen implements Codeg
isModel = true; isModel = true;
} }
p.vendorExtensions.put("x-is-model-type", isModel); p.vendorExtensions.put("x-is-model-type", isModel);
Boolean required = p.getRequired();
// Convert optional members to use the Nullable_<T> type. // Convert optional members to use the Nullable_<T> type.
if (!p.required && nullableTypeMapping.containsKey(p.dataType)) { if (!Boolean.TRUE.equals(required) && nullableTypeMapping.containsKey(p.dataType)) {
p.dataType = nullableTypeMapping.get(p.dataType); p.dataType = nullableTypeMapping.get(p.dataType);
} }
} }

View File

@@ -477,7 +477,7 @@ public abstract class AbstractEiffelCodegen extends DefaultCodegen implements Co
// Because the child models extend the parents, the enums will be available via the parent. // Because the child models extend the parents, the enums will be available via the parent.
// Only bother with reconciliation if the parent model has enums. // Only bother with reconciliation if the parent model has enums.
if (!parentCodegenModel.hasEnums) { if (parentCodegenModel == null || !parentCodegenModel.hasEnums) {
return codegenModel; return codegenModel;
} }

View File

@@ -38,6 +38,7 @@ public abstract class AbstractGoCodegen extends DefaultCodegen implements Codege
private static final String NUMERIC_ENUM_PREFIX = "_"; private static final String NUMERIC_ENUM_PREFIX = "_";
protected boolean withGoCodegenComment = false; protected boolean withGoCodegenComment = false;
protected boolean withAWSV4Signature = false;
protected boolean withXml = false; protected boolean withXml = false;
protected boolean enumClassPrefix = false; protected boolean enumClassPrefix = false;
protected boolean structPrefix = false; protected boolean structPrefix = false;
@@ -633,6 +634,10 @@ public abstract class AbstractGoCodegen extends DefaultCodegen implements Codege
this.withGoCodegenComment = withGoCodegenComment; this.withGoCodegenComment = withGoCodegenComment;
} }
public void setWithAWSV4Signature(boolean withAWSV4Signature) {
this.withAWSV4Signature = withAWSV4Signature;
}
public void setWithXml(boolean withXml) { public void setWithXml(boolean withXml) {
this.withXml = withXml; this.withXml = withXml;
} }

View File

@@ -93,58 +93,24 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
// this includes hard reserved words defined by https://github.com/JetBrains/kotlin/blob/master/core/descriptors/src/org/jetbrains/kotlin/renderer/KeywordStringsGenerated.java // this includes hard reserved words defined by https://github.com/JetBrains/kotlin/blob/master/core/descriptors/src/org/jetbrains/kotlin/renderer/KeywordStringsGenerated.java
// as well as keywords from https://kotlinlang.org/docs/reference/keyword-reference.html // as well as keywords from https://kotlinlang.org/docs/reference/keyword-reference.html
reservedWords = new HashSet<String>(Arrays.asList( reservedWords = new HashSet<String>(Arrays.asList(
"abstract",
"annotation",
"as", "as",
"break", "break",
"case",
"catch",
"class", "class",
"companion",
"const",
"constructor",
"continue", "continue",
"crossinline",
"data",
"delegate",
"do", "do",
"else", "else",
"enum",
"external",
"false", "false",
"final",
"finally",
"for", "for",
"fun", "fun",
"if", "if",
"in", "in",
"infix",
"init",
"inline",
"inner",
"interface", "interface",
"internal",
"is", "is",
"it",
"lateinit",
"lazy",
"noinline",
"null", "null",
"object", "object",
"open",
"operator",
"out",
"override",
"package", "package",
"private",
"protected",
"public",
"reified",
"return", "return",
"sealed",
"super", "super",
"suspend",
"tailrec",
"this", "this",
"throw", "throw",
"true", "true",
@@ -153,7 +119,6 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
"typeof", "typeof",
"val", "val",
"var", "var",
"vararg",
"when", "when",
"while" "while"
)); ));
@@ -565,7 +530,7 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
modified = underscore(modified); modified = underscore(modified);
break; break;
case UPPERCASE: case UPPERCASE:
modified = modified.toUpperCase(Locale.ROOT); modified = underscore(modified).toUpperCase(Locale.ROOT);
break; break;
} }

View File

@@ -46,6 +46,7 @@ public class AsciidocDocumentationCodegen extends DefaultCodegen implements Code
public static final String SPEC_DIR = "specDir"; public static final String SPEC_DIR = "specDir";
public static final String SNIPPET_DIR = "snippetDir"; public static final String SNIPPET_DIR = "snippetDir";
public static final String HEADER_ATTRIBUTES_FLAG = "headerAttributes";
/** /**
* Lambda emitting an asciidoc "include::filename.adoc[]" if file is found in * Lambda emitting an asciidoc "include::filename.adoc[]" if file is found in
@@ -140,6 +141,7 @@ public class AsciidocDocumentationCodegen extends DefaultCodegen implements Code
protected String groupId = "org.openapitools"; protected String groupId = "org.openapitools";
protected String artifactId = "openapi-client"; protected String artifactId = "openapi-client";
protected String artifactVersion = "1.0.0"; protected String artifactVersion = "1.0.0";
protected boolean headerAttributes = true;
private IncludeMarkupLambda includeSpecMarkupLambda; private IncludeMarkupLambda includeSpecMarkupLambda;
private IncludeMarkupLambda includeSnippetMarkupLambda; private IncludeMarkupLambda includeSnippetMarkupLambda;
@@ -201,11 +203,14 @@ public class AsciidocDocumentationCodegen extends DefaultCodegen implements Code
cliOptions.add(new CliOption(CodegenConstants.ARTIFACT_VERSION, CodegenConstants.ARTIFACT_VERSION_DESC)); cliOptions.add(new CliOption(CodegenConstants.ARTIFACT_VERSION, CodegenConstants.ARTIFACT_VERSION_DESC));
cliOptions.add(new CliOption(SNIPPET_DIR, cliOptions.add(new CliOption(SNIPPET_DIR,
"path with includable markup snippets (e.g. test output generated by restdoc, default: .") "path with includable markup snippets (e.g. test output generated by restdoc, default: .)")
.defaultValue(".")); .defaultValue("."));
cliOptions.add(new CliOption(SPEC_DIR, cliOptions.add(new CliOption(SPEC_DIR,
"path with includable markup spec files (e.g. handwritten additional docs, default: .") "path with includable markup spec files (e.g. handwritten additional docs, default: ..)")
.defaultValue("..")); .defaultValue(".."));
cliOptions.add(CliOption.newBoolean(HEADER_ATTRIBUTES_FLAG,
"generation of asciidoc header meta data attributes (set to false to suppress, default: true)",
true));
additionalProperties.put("appName", "OpenAPI Sample description"); additionalProperties.put("appName", "OpenAPI Sample description");
additionalProperties.put("appDescription", "A sample OpenAPI documentation"); additionalProperties.put("appDescription", "A sample OpenAPI documentation");
@@ -236,6 +241,14 @@ public class AsciidocDocumentationCodegen extends DefaultCodegen implements Code
return input; // just return the original string return input; // just return the original string
} }
public boolean isHeaderAttributes() {
return headerAttributes;
}
public void setHeaderAttributes(boolean headerAttributes) {
this.headerAttributes = headerAttributes;
}
@Override @Override
public void processOpts() { public void processOpts() {
super.processOpts(); super.processOpts();
@@ -260,6 +273,13 @@ public class AsciidocDocumentationCodegen extends DefaultCodegen implements Code
this.linkSnippetMarkupLambda = new LinkMarkupLambda(snippetDir); this.linkSnippetMarkupLambda = new LinkMarkupLambda(snippetDir);
additionalProperties.put("snippetlink", this.linkSnippetMarkupLambda); additionalProperties.put("snippetlink", this.linkSnippetMarkupLambda);
if (additionalProperties.containsKey(HEADER_ATTRIBUTES_FLAG)) {
this.setHeaderAttributes(convertPropertyToBooleanAndWriteBack(HEADER_ATTRIBUTES_FLAG));
} else {
additionalProperties.put(HEADER_ATTRIBUTES_FLAG, headerAttributes);
}
} }
@Override @Override

View File

@@ -572,7 +572,7 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen {
} }
for (final CodegenProperty property : codegenModel.readWriteVars) { for (final CodegenProperty property : codegenModel.readWriteVars) {
if (property.defaultValue == null && property.baseName.equals(parentCodegenModel.discriminator.getPropertyName())) { if (property.defaultValue == null && parentCodegenModel.discriminator != null && property.baseName.equals(parentCodegenModel.discriminator.getPropertyName())) {
property.defaultValue = "\"" + name + "\""; property.defaultValue = "\"" + name + "\"";
} }
} }

View File

@@ -252,7 +252,7 @@ public class CSharpNetCoreClientCodegen extends AbstractCSharpCodegen {
} }
for (final CodegenProperty property : codegenModel.readWriteVars) { for (final CodegenProperty property : codegenModel.readWriteVars) {
if (property.defaultValue == null && property.baseName.equals(parentCodegenModel.discriminator.getPropertyName())) { if (property.defaultValue == null && parentCodegenModel.discriminator != null && property.baseName.equals(parentCodegenModel.discriminator.getPropertyName())) {
property.defaultValue = "\"" + name + "\""; property.defaultValue = "\"" + name + "\"";
} }
} }

View File

@@ -74,16 +74,22 @@ public class DartClientCodegen extends DefaultCodegen implements CodegenConfig {
public static final String PUB_NAME = "pubName"; public static final String PUB_NAME = "pubName";
public static final String PUB_VERSION = "pubVersion"; public static final String PUB_VERSION = "pubVersion";
public static final String PUB_DESCRIPTION = "pubDescription"; public static final String PUB_DESCRIPTION = "pubDescription";
public static final String PUB_AUTHOR = "pubAuthor";
public static final String PUB_AUTHOR_EMAIL = "pubAuthorEmail";
public static final String PUB_HOMEPAGE = "pubHomepage";
public static final String USE_ENUM_EXTENSION = "useEnumExtension"; public static final String USE_ENUM_EXTENSION = "useEnumExtension";
public static final String SUPPORT_DART2 = "supportDart2"; public static final String SUPPORT_DART2 = "supportDart2";
protected boolean browserClient = true; protected boolean browserClient = true;
protected String pubName = "openapi"; protected String pubName = "openapi";
protected String pubVersion = "1.0.0"; protected String pubVersion = "1.0.0";
protected String pubDescription = "OpenAPI API client"; protected String pubDescription = "OpenAPI API client";
protected String pubAuthor = "Author";
protected String pubAuthorEmail = "author@homepage";
protected String pubHomepage = "homepage";
protected boolean useEnumExtension = false; protected boolean useEnumExtension = false;
protected String sourceFolder = ""; protected String sourceFolder = "";
protected String apiDocPath = "docs" + File.separator; protected String apiDocPath = "doc" + File.separator;
protected String modelDocPath = "docs" + File.separator; protected String modelDocPath = "doc" + File.separator;
protected String apiTestPath = "test" + File.separator; protected String apiTestPath = "test" + File.separator;
protected String modelTestPath = "test" + File.separator; protected String modelTestPath = "test" + File.separator;
@@ -108,7 +114,9 @@ public class DartClientCodegen extends DefaultCodegen implements CodegenConfig {
List<String> reservedWordsList = new ArrayList<String>(); List<String> reservedWordsList = new ArrayList<String>();
try { try {
BufferedReader reader = new BufferedReader(new InputStreamReader(DartClientCodegen.class.getResourceAsStream("/dart/dart-keywords.txt"), Charset.forName("UTF-8"))); BufferedReader reader = new BufferedReader(new InputStreamReader(DartClientCodegen.class.getResourceAsStream("/dart/dart-keywords.txt"), Charset.forName("UTF-8")));
while(reader.ready()) { reservedWordsList.add(reader.readLine()); } while (reader.ready()) {
reservedWordsList.add(reader.readLine());
}
reader.close(); reader.close();
} catch (Exception e) { } catch (Exception e) {
LOGGER.error("Error reading dart keywords. Exception: {}", e.getMessage()); LOGGER.error("Error reading dart keywords. Exception: {}", e.getMessage());
@@ -153,6 +161,9 @@ public class DartClientCodegen extends DefaultCodegen implements CodegenConfig {
cliOptions.add(new CliOption(PUB_NAME, "Name in generated pubspec")); cliOptions.add(new CliOption(PUB_NAME, "Name in generated pubspec"));
cliOptions.add(new CliOption(PUB_VERSION, "Version in generated pubspec")); cliOptions.add(new CliOption(PUB_VERSION, "Version in generated pubspec"));
cliOptions.add(new CliOption(PUB_DESCRIPTION, "Description in generated pubspec")); cliOptions.add(new CliOption(PUB_DESCRIPTION, "Description in generated pubspec"));
cliOptions.add(new CliOption(PUB_AUTHOR, "Author name in generated pubspec"));
cliOptions.add(new CliOption(PUB_AUTHOR_EMAIL, "Email address of the author in generated pubspec"));
cliOptions.add(new CliOption(PUB_HOMEPAGE, "Homepage in generated pubspec"));
cliOptions.add(new CliOption(USE_ENUM_EXTENSION, "Allow the 'x-enum-values' extension for enums")); cliOptions.add(new CliOption(USE_ENUM_EXTENSION, "Allow the 'x-enum-values' extension for enums"));
cliOptions.add(new CliOption(CodegenConstants.SOURCE_FOLDER, "Source folder for generated code")); cliOptions.add(new CliOption(CodegenConstants.SOURCE_FOLDER, "Source folder for generated code"));
cliOptions.add(CliOption.newBoolean(SUPPORT_DART2, "Support Dart 2.x (Dart 1.x support has been deprecated)").defaultValue(Boolean.TRUE.toString())); cliOptions.add(CliOption.newBoolean(SUPPORT_DART2, "Support Dart 2.x (Dart 1.x support has been deprecated)").defaultValue(Boolean.TRUE.toString()));
@@ -214,6 +225,27 @@ public class DartClientCodegen extends DefaultCodegen implements CodegenConfig {
additionalProperties.put(PUB_DESCRIPTION, pubDescription); additionalProperties.put(PUB_DESCRIPTION, pubDescription);
} }
if (additionalProperties.containsKey(PUB_AUTHOR)) {
this.setPubAuthor((String) additionalProperties.get(PUB_AUTHOR));
} else {
//not set, use to be passed to template
additionalProperties.put(PUB_AUTHOR, pubAuthor);
}
if (additionalProperties.containsKey(PUB_AUTHOR_EMAIL)) {
this.setPubAuthorEmail((String) additionalProperties.get(PUB_AUTHOR_EMAIL));
} else {
//not set, use to be passed to template
additionalProperties.put(PUB_AUTHOR_EMAIL, pubAuthorEmail);
}
if (additionalProperties.containsKey(PUB_HOMEPAGE)) {
this.setPubHomepage((String) additionalProperties.get(PUB_HOMEPAGE));
} else {
//not set, use to be passed to template
additionalProperties.put(PUB_HOMEPAGE, pubHomepage);
}
if (additionalProperties.containsKey(USE_ENUM_EXTENSION)) { if (additionalProperties.containsKey(USE_ENUM_EXTENSION)) {
this.setUseEnumExtension(convertPropertyToBooleanAndWriteBack(USE_ENUM_EXTENSION)); this.setUseEnumExtension(convertPropertyToBooleanAndWriteBack(USE_ENUM_EXTENSION));
} else { } else {
@@ -551,6 +583,18 @@ public class DartClientCodegen extends DefaultCodegen implements CodegenConfig {
this.pubDescription = pubDescription; this.pubDescription = pubDescription;
} }
public void setPubAuthor(String pubAuthor) {
this.pubAuthor = pubAuthor;
}
public void setPubAuthorEmail(String pubAuthorEmail) {
this.pubAuthorEmail = pubAuthorEmail;
}
public void setPubHomepage(String pubHomepage) {
this.pubHomepage = pubHomepage;
}
public void setUseEnumExtension(boolean useEnumExtension) { public void setUseEnumExtension(boolean useEnumExtension) {
this.useEnumExtension = useEnumExtension; this.useEnumExtension = useEnumExtension;
} }

View File

@@ -17,6 +17,7 @@
package org.openapitools.codegen.languages; package org.openapitools.codegen.languages;
import java.util.HashMap; import java.util.HashMap;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.CliOption; import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.CodegenConstants; import org.openapitools.codegen.CodegenConstants;
@@ -121,7 +122,8 @@ public class DartDioClientCodegen extends DartClientCodegen {
return "Generates a Dart Dio client library."; return "Generates a Dart Dio client library.";
} }
@Override public void setBrowserClient(boolean browserClient) { @Override
public void setBrowserClient(boolean browserClient) {
super.browserClient = browserClient; super.browserClient = browserClient;
} }
@@ -285,37 +287,26 @@ public class DartDioClientCodegen extends DartClientCodegen {
property.isNullable = true; property.isNullable = true;
} }
if (property.isListContainer) { property.setDatatype(property.getDataType()
//Updates any List properties on a model to a BuiltList. This happens in post processing rather .replaceAll("\\bList\\b", "BuiltList")
//than type mapping as we only want this to apply to models, not every other class. .replaceAll("\\bMap\\b", "BuiltMap")
if ("List".equals(property.baseType)) { .replaceAll("\\bObject\\b", "JsonObject")
property.setDatatype( );
property.dataType.replaceAll(property.baseType, "BuiltList")); property.setBaseType(property.getBaseType()
property.setBaseType("BuiltList"); .replaceAll("\\bList\\b", "BuiltList")
model.imports.add("BuiltList"); .replaceAll("\\bMap\\b", "BuiltMap")
if ("Object".equals(property.items.baseType)) { .replaceAll("\\bObject\\b", "JsonObject")
property.setDatatype( );
property.dataType.replaceAll("Object", "JsonObject"));
property.items.setDatatype("JsonObject");
model.imports.add("JsonObject");
}
}
}
if (property.isMapContainer) {
//Updates any List properties on a model to a BuiltList. This happens in post processing rather
//than type mapping as we only want this to apply to models, not every other class.
if ("Map".equals(property.baseType)) {
property.setDatatype(property.dataType.replaceAll(property.baseType, "BuiltMap"));
property.setBaseType("BuiltMap");
model.imports.add("BuiltMap");
if ("Object".equals(property.items.baseType)) {
property.setDatatype(property.dataType.replaceAll("Object", "JsonObject"));
property.items.setDatatype("JsonObject");
model.imports.add("JsonObject");
}
}
}
if (property.dataType.contains("BuiltList")) {
model.imports.add("BuiltList");
}
if (property.dataType.contains("BuiltMap")) {
model.imports.add("BuiltMap");
}
if (property.dataType.contains("JsonObject")) {
model.imports.add("JsonObject");
}
} }
@Override @Override

View File

@@ -37,6 +37,7 @@ public class GoClientCodegen extends AbstractGoCodegen {
public static final String WITH_GO_CODEGEN_COMMENT = "withGoCodegenComment"; public static final String WITH_GO_CODEGEN_COMMENT = "withGoCodegenComment";
public static final String WITH_XML = "withXml"; public static final String WITH_XML = "withXml";
public static final String STRUCT_PREFIX = "structPrefix"; public static final String STRUCT_PREFIX = "structPrefix";
public static final String WITH_AWSV4_SIGNATURE = "withAWSV4Signature";
public GoClientCodegen() { public GoClientCodegen() {
super(); super();
@@ -58,6 +59,7 @@ public class GoClientCodegen extends AbstractGoCodegen {
cliOptions.add(CliOption.newBoolean(WITH_XML, "whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML)")); cliOptions.add(CliOption.newBoolean(WITH_XML, "whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML)"));
cliOptions.add(CliOption.newBoolean(CodegenConstants.ENUM_CLASS_PREFIX, CodegenConstants.ENUM_CLASS_PREFIX_DESC)); cliOptions.add(CliOption.newBoolean(CodegenConstants.ENUM_CLASS_PREFIX, CodegenConstants.ENUM_CLASS_PREFIX_DESC));
cliOptions.add(CliOption.newBoolean(STRUCT_PREFIX, "whether to prefix struct with the class name. e.g. DeletePetOpts => PetApiDeletePetOpts")); cliOptions.add(CliOption.newBoolean(STRUCT_PREFIX, "whether to prefix struct with the class name. e.g. DeletePetOpts => PetApiDeletePetOpts"));
cliOptions.add(CliOption.newBoolean(WITH_AWSV4_SIGNATURE, "whether to include AWS v4 signature support"));
// option to change the order of form/body parameter // option to change the order of form/body parameter
cliOptions.add(CliOption.newBoolean( cliOptions.add(CliOption.newBoolean(
@@ -109,6 +111,13 @@ public class GoClientCodegen extends AbstractGoCodegen {
} }
} }
if (additionalProperties.containsKey(WITH_AWSV4_SIGNATURE)) {
setWithAWSV4Signature(Boolean.parseBoolean(additionalProperties.get(WITH_AWSV4_SIGNATURE).toString()));
if (withAWSV4Signature) {
additionalProperties.put(WITH_AWSV4_SIGNATURE, "true");
}
}
if (additionalProperties.containsKey(WITH_XML)) { if (additionalProperties.containsKey(WITH_XML)) {
setWithXml(Boolean.parseBoolean(additionalProperties.get(WITH_XML).toString())); setWithXml(Boolean.parseBoolean(additionalProperties.get(WITH_XML).toString()));
if (withXml) { if (withXml) {

View File

@@ -24,12 +24,15 @@ import java.util.*;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static org.openapitools.codegen.utils.StringUtils.underscore;
public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig { public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(MysqlSchemaCodegen.class); private static final Logger LOGGER = LoggerFactory.getLogger(MysqlSchemaCodegen.class);
public static final String CODEGEN_VENDOR_EXTENSION_KEY = "x-mysqlSchema"; public static final String CODEGEN_VENDOR_EXTENSION_KEY = "x-mysqlSchema";
public static final String DEFAULT_DATABASE_NAME = "defaultDatabaseName"; public static final String DEFAULT_DATABASE_NAME = "defaultDatabaseName";
public static final String JSON_DATA_TYPE_ENABLED = "jsonDataTypeEnabled"; public static final String JSON_DATA_TYPE_ENABLED = "jsonDataTypeEnabled";
public static final String IDENTIFIER_NAMING_CONVENTION = "identifierNamingConvention";
public static final Integer ENUM_MAX_ELEMENTS = 65535; public static final Integer ENUM_MAX_ELEMENTS = 65535;
public static final Integer IDENTIFIER_MAX_LENGTH = 64; public static final Integer IDENTIFIER_MAX_LENGTH = 64;
@@ -53,6 +56,7 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
protected String tableNamePrefix = "tbl_", tableNameSuffix = ""; protected String tableNamePrefix = "tbl_", tableNameSuffix = "";
protected String columnNamePrefix = "col_", columnNameSuffix = ""; protected String columnNamePrefix = "col_", columnNameSuffix = "";
protected Boolean jsonDataTypeEnabled = true; protected Boolean jsonDataTypeEnabled = true;
protected String identifierNamingConvention = "original";
public MysqlSchemaCodegen() { public MysqlSchemaCodegen() {
super(); super();
@@ -158,6 +162,16 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
cliOptions.clear(); cliOptions.clear();
addOption(DEFAULT_DATABASE_NAME, "Default database name for all MySQL queries", defaultDatabaseName); addOption(DEFAULT_DATABASE_NAME, "Default database name for all MySQL queries", defaultDatabaseName);
addSwitch(JSON_DATA_TYPE_ENABLED, "Use special JSON MySQL data type for complex model properties. Requires MySQL version 5.7.8. Generates TEXT data type when disabled", jsonDataTypeEnabled); addSwitch(JSON_DATA_TYPE_ENABLED, "Use special JSON MySQL data type for complex model properties. Requires MySQL version 5.7.8. Generates TEXT data type when disabled", jsonDataTypeEnabled);
// we used to snake_case table/column names, let's add this option
CliOption identifierNamingOpt = new CliOption(IDENTIFIER_NAMING_CONVENTION,
"Naming convention of MySQL identifiers(table names and column names). This is not related to database name which is defined by " + DEFAULT_DATABASE_NAME + " option");
identifierNamingOpt.addEnum("original", "Do not transform original names")
.addEnum("snake_case", "Use snake_case names")
.setDefault("original");
cliOptions.add(identifierNamingOpt);
} }
@Override @Override
@@ -195,6 +209,10 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
additionalProperties.put(JSON_DATA_TYPE_ENABLED, getJsonDataTypeEnabled()); additionalProperties.put(JSON_DATA_TYPE_ENABLED, getJsonDataTypeEnabled());
} }
if (additionalProperties.containsKey(IDENTIFIER_NAMING_CONVENTION)) {
this.setIdentifierNamingConvention((String) additionalProperties.get(IDENTIFIER_NAMING_CONVENTION));
}
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
supportingFiles.add(new SupportingFile("mysql_schema.mustache", "", "mysql_schema.sql")); supportingFiles.add(new SupportingFile("mysql_schema.mustache", "", "mysql_schema.sql"));
} }
@@ -208,11 +226,18 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
Map<String, Object> mo = (Map<String, Object>) _mo; Map<String, Object> mo = (Map<String, Object>) _mo;
CodegenModel model = (CodegenModel) mo.get("model"); CodegenModel model = (CodegenModel) mo.get("model");
String modelName = model.getName(); String modelName = model.getName();
String tableName = this.toTableName(modelName);
String modelDescription = model.getDescription(); String modelDescription = model.getDescription();
Map<String, Object> modelVendorExtensions = model.getVendorExtensions(); Map<String, Object> modelVendorExtensions = model.getVendorExtensions();
Map<String, Object> mysqlSchema = new HashMap<String, Object>(); Map<String, Object> mysqlSchema = new HashMap<String, Object>();
Map<String, Object> tableDefinition = new HashMap<String, Object>(); Map<String, Object> tableDefinition = new HashMap<String, Object>();
if (this.getIdentifierNamingConvention().equals("snake_case") && !modelName.equals(tableName)) {
// add original name in table comment
String commentExtra = "Original model name - " + modelName + ".";
modelDescription = (modelDescription == null || modelDescription.isEmpty()) ? commentExtra : modelDescription + ". " + commentExtra;
}
if (modelVendorExtensions.containsKey(CODEGEN_VENDOR_EXTENSION_KEY)) { if (modelVendorExtensions.containsKey(CODEGEN_VENDOR_EXTENSION_KEY)) {
// user already specified schema values // user already specified schema values
LOGGER.info("Found vendor extension in '" + modelName + "' model, autogeneration skipped"); LOGGER.info("Found vendor extension in '" + modelName + "' model, autogeneration skipped");
@@ -220,7 +245,7 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
} else { } else {
modelVendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema); modelVendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema);
mysqlSchema.put("tableDefinition", tableDefinition); mysqlSchema.put("tableDefinition", tableDefinition);
tableDefinition.put("tblName", toTableName(modelName)); tableDefinition.put("tblName", tableName);
tableDefinition.put("tblComment", modelDescription); tableDefinition.put("tblComment", modelDescription);
} }
} }
@@ -271,6 +296,7 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
Map<String, Object> columnDefinition = new HashMap<String, Object>(); Map<String, Object> columnDefinition = new HashMap<String, Object>();
ArrayList columnDataTypeArguments = new ArrayList(); ArrayList columnDataTypeArguments = new ArrayList();
String baseName = property.getBaseName(); String baseName = property.getBaseName();
String colName = this.toColumnName(baseName);
String dataType = property.getDataType(); String dataType = property.getDataType();
String dataFormat = property.getDataFormat(); String dataFormat = property.getDataFormat();
String description = property.getDescription(); String description = property.getDescription();
@@ -290,9 +316,15 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
return; return;
} }
if (this.getIdentifierNamingConvention().equals("snake_case") && !baseName.equals(colName)) {
// add original name in column comment
String commentExtra = "Original param name - " + baseName + ".";
description = (description == null || description.isEmpty()) ? commentExtra : description + ". " + commentExtra;
}
vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema); vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema);
mysqlSchema.put("columnDefinition", columnDefinition); mysqlSchema.put("columnDefinition", columnDefinition);
columnDefinition.put("colName", toColumnName(baseName)); columnDefinition.put("colName", colName);
if (Boolean.TRUE.equals(isEnum)) { if (Boolean.TRUE.equals(isEnum)) {
Map<String, Object> allowableValues = property.getAllowableValues(); Map<String, Object> allowableValues = property.getAllowableValues();
@@ -352,6 +384,7 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
Map<String, Object> columnDefinition = new HashMap<String, Object>(); Map<String, Object> columnDefinition = new HashMap<String, Object>();
ArrayList columnDataTypeArguments = new ArrayList(); ArrayList columnDataTypeArguments = new ArrayList();
String baseName = property.getBaseName(); String baseName = property.getBaseName();
String colName = this.toColumnName(baseName);
String dataType = property.getDataType(); String dataType = property.getDataType();
String dataFormat = property.getDataFormat(); String dataFormat = property.getDataFormat();
String description = property.getDescription(); String description = property.getDescription();
@@ -370,9 +403,15 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
return; return;
} }
if (this.getIdentifierNamingConvention().equals("snake_case") && !baseName.equals(colName)) {
// add original name in column comment
String commentExtra = "Original param name - " + baseName + ".";
description = (description == null || description.isEmpty()) ? commentExtra : description + ". " + commentExtra;
}
vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema); vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema);
mysqlSchema.put("columnDefinition", columnDefinition); mysqlSchema.put("columnDefinition", columnDefinition);
columnDefinition.put("colName", toColumnName(baseName)); columnDefinition.put("colName", colName);
if (Boolean.TRUE.equals(isEnum)) { if (Boolean.TRUE.equals(isEnum)) {
Map<String, Object> allowableValues = property.getAllowableValues(); Map<String, Object> allowableValues = property.getAllowableValues();
@@ -431,6 +470,7 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
Map<String, Object> columnDefinition = new HashMap<String, Object>(); Map<String, Object> columnDefinition = new HashMap<String, Object>();
ArrayList columnDataTypeArguments = new ArrayList(); ArrayList columnDataTypeArguments = new ArrayList();
String baseName = property.getBaseName(); String baseName = property.getBaseName();
String colName = this.toColumnName(baseName);
String description = property.getDescription(); String description = property.getDescription();
String defaultValue = property.getDefaultValue(); String defaultValue = property.getDefaultValue();
Boolean required = property.getRequired(); Boolean required = property.getRequired();
@@ -441,9 +481,15 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
return; return;
} }
if (this.getIdentifierNamingConvention().equals("snake_case") && !baseName.equals(colName)) {
// add original name in column comment
String commentExtra = "Original param name - " + baseName + ".";
description = (description == null || description.isEmpty()) ? commentExtra : description + ". " + commentExtra;
}
vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema); vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema);
mysqlSchema.put("columnDefinition", columnDefinition); mysqlSchema.put("columnDefinition", columnDefinition);
columnDefinition.put("colName", toColumnName(baseName)); columnDefinition.put("colName", colName);
columnDefinition.put("colDataType", "TINYINT"); columnDefinition.put("colDataType", "TINYINT");
columnDefinition.put("colDataTypeArguments", columnDataTypeArguments); columnDefinition.put("colDataTypeArguments", columnDataTypeArguments);
columnDataTypeArguments.add(toCodegenMysqlDataTypeArgument(1, false)); columnDataTypeArguments.add(toCodegenMysqlDataTypeArgument(1, false));
@@ -477,6 +523,7 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
Map<String, Object> columnDefinition = new HashMap<String, Object>(); Map<String, Object> columnDefinition = new HashMap<String, Object>();
ArrayList columnDataTypeArguments = new ArrayList(); ArrayList columnDataTypeArguments = new ArrayList();
String baseName = property.getBaseName(); String baseName = property.getBaseName();
String colName = this.toColumnName(baseName);
String dataType = property.getDataType(); String dataType = property.getDataType();
String dataFormat = property.getDataFormat(); String dataFormat = property.getDataFormat();
String description = property.getDescription(); String description = property.getDescription();
@@ -492,9 +539,15 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
return; return;
} }
if (this.getIdentifierNamingConvention().equals("snake_case") && !baseName.equals(colName)) {
// add original name in column comment
String commentExtra = "Original param name - " + baseName + ".";
description = (description == null || description.isEmpty()) ? commentExtra : description + ". " + commentExtra;
}
vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema); vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema);
mysqlSchema.put("columnDefinition", columnDefinition); mysqlSchema.put("columnDefinition", columnDefinition);
columnDefinition.put("colName", toColumnName(baseName)); columnDefinition.put("colName", colName);
if (Boolean.TRUE.equals(isEnum)) { if (Boolean.TRUE.equals(isEnum)) {
Map<String, Object> allowableValues = property.getAllowableValues(); Map<String, Object> allowableValues = property.getAllowableValues();
@@ -548,6 +601,7 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
Map<String, Object> mysqlSchema = new HashMap<String, Object>(); Map<String, Object> mysqlSchema = new HashMap<String, Object>();
Map<String, Object> columnDefinition = new HashMap<String, Object>(); Map<String, Object> columnDefinition = new HashMap<String, Object>();
String baseName = property.getBaseName(); String baseName = property.getBaseName();
String colName = this.toColumnName(baseName);
String dataType = property.getDataType(); String dataType = property.getDataType();
Boolean required = property.getRequired(); Boolean required = property.getRequired();
String description = property.getDescription(); String description = property.getDescription();
@@ -559,9 +613,15 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
return; return;
} }
if (this.getIdentifierNamingConvention().equals("snake_case") && !baseName.equals(colName)) {
// add original name in column comment
String commentExtra = "Original param name - " + baseName + ".";
description = (description == null || description.isEmpty()) ? commentExtra : description + ". " + commentExtra;
}
vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema); vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema);
mysqlSchema.put("columnDefinition", columnDefinition); mysqlSchema.put("columnDefinition", columnDefinition);
columnDefinition.put("colName", toColumnName(baseName)); columnDefinition.put("colName", colName);
columnDefinition.put("colDataType", dataType); columnDefinition.put("colDataType", dataType);
if (Boolean.TRUE.equals(required)) { if (Boolean.TRUE.equals(required)) {
@@ -592,6 +652,7 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
Map<String, Object> mysqlSchema = new HashMap<String, Object>(); Map<String, Object> mysqlSchema = new HashMap<String, Object>();
Map<String, Object> columnDefinition = new HashMap<String, Object>(); Map<String, Object> columnDefinition = new HashMap<String, Object>();
String baseName = property.getBaseName(); String baseName = property.getBaseName();
String colName = this.toColumnName(baseName);
String dataType = property.getDataType(); String dataType = property.getDataType();
Boolean required = property.getRequired(); Boolean required = property.getRequired();
String description = property.getDescription(); String description = property.getDescription();
@@ -603,9 +664,15 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
return; return;
} }
if (this.getIdentifierNamingConvention().equals("snake_case") && !baseName.equals(colName)) {
// add original name in column comment
String commentExtra = "Original param name - " + baseName + ".";
description = (description == null || description.isEmpty()) ? commentExtra : description + ". " + commentExtra;
}
vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema); vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema);
mysqlSchema.put("columnDefinition", columnDefinition); mysqlSchema.put("columnDefinition", columnDefinition);
columnDefinition.put("colName", toColumnName(baseName)); columnDefinition.put("colName", colName);
columnDefinition.put("colDataType", dataType); columnDefinition.put("colDataType", dataType);
if (Boolean.FALSE.equals(getJsonDataTypeEnabled())) { if (Boolean.FALSE.equals(getJsonDataTypeEnabled())) {
columnDefinition.put("colDataType", "TEXT"); columnDefinition.put("colDataType", "TEXT");
@@ -640,6 +707,7 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
Map<String, Object> mysqlSchema = new HashMap<String, Object>(); Map<String, Object> mysqlSchema = new HashMap<String, Object>();
Map<String, Object> columnDefinition = new HashMap<String, Object>(); Map<String, Object> columnDefinition = new HashMap<String, Object>();
String baseName = property.getBaseName(); String baseName = property.getBaseName();
String colName = this.toColumnName(baseName);
Boolean required = property.getRequired(); Boolean required = property.getRequired();
String description = property.getDescription(); String description = property.getDescription();
String defaultValue = property.getDefaultValue(); String defaultValue = property.getDefaultValue();
@@ -650,9 +718,15 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
return; return;
} }
if (this.getIdentifierNamingConvention().equals("snake_case") && !baseName.equals(colName)) {
// add original name in column comment
String commentExtra = "Original param name - " + baseName + ".";
description = (description == null || description.isEmpty()) ? commentExtra : description + ". " + commentExtra;
}
vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema); vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema);
mysqlSchema.put("columnDefinition", columnDefinition); mysqlSchema.put("columnDefinition", columnDefinition);
columnDefinition.put("colName", toColumnName(baseName)); columnDefinition.put("colName", colName);
columnDefinition.put("colDataType", "TEXT"); columnDefinition.put("colDataType", "TEXT");
if (Boolean.TRUE.equals(required)) { if (Boolean.TRUE.equals(required)) {
@@ -897,6 +971,9 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
*/ */
public String toTableName(String name) { public String toTableName(String name) {
String identifier = toMysqlIdentifier(name, tableNamePrefix, tableNameSuffix); String identifier = toMysqlIdentifier(name, tableNamePrefix, tableNameSuffix);
if (identifierNamingConvention.equals("snake_case")) {
identifier = underscore(identifier);
}
if (identifier.length() > IDENTIFIER_MAX_LENGTH) { if (identifier.length() > IDENTIFIER_MAX_LENGTH) {
LOGGER.warn("Table name cannot exceed 64 chars. Name '" + name + "' will be truncated"); LOGGER.warn("Table name cannot exceed 64 chars. Name '" + name + "' will be truncated");
identifier = identifier.substring(0, IDENTIFIER_MAX_LENGTH); identifier = identifier.substring(0, IDENTIFIER_MAX_LENGTH);
@@ -913,6 +990,9 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
*/ */
public String toColumnName(String name) { public String toColumnName(String name) {
String identifier = toMysqlIdentifier(name, columnNamePrefix, columnNameSuffix); String identifier = toMysqlIdentifier(name, columnNamePrefix, columnNameSuffix);
if (identifierNamingConvention.equals("snake_case")) {
identifier = underscore(identifier);
}
if (identifier.length() > IDENTIFIER_MAX_LENGTH) { if (identifier.length() > IDENTIFIER_MAX_LENGTH) {
LOGGER.warn("Column name cannot exceed 64 chars. Name '" + name + "' will be truncated"); LOGGER.warn("Column name cannot exceed 64 chars. Name '" + name + "' will be truncated");
identifier = identifier.substring(0, IDENTIFIER_MAX_LENGTH); identifier = identifier.substring(0, IDENTIFIER_MAX_LENGTH);
@@ -1054,4 +1134,30 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
return this.jsonDataTypeEnabled; return this.jsonDataTypeEnabled;
} }
/**
* Sets identifier naming convention for table names and column names.
* This is not related to database name which is defined by defaultDatabaseName option.
*
* @param naming identifier naming convention (original|snake_case)
*/
public void setIdentifierNamingConvention(String naming) {
switch (naming) {
case "original":
case "snake_case":
this.identifierNamingConvention = naming;
break;
default:
LOGGER.warn("\"" + (String) naming + "\" is invalid \"identifierNamingConvention\" argument. Current \"" + (String) this.identifierNamingConvention + "\" used instead.");
}
}
/**
* Returns identifier naming convention for table names and column names.
*
* @return identifier naming convention
*/
public String getIdentifierNamingConvention() {
return this.identifierNamingConvention;
}
} }

View File

@@ -42,6 +42,8 @@ public class PhpSlim4ServerCodegen extends PhpSlimServerCodegen {
protected String psr7Implementation = "slim-psr7"; protected String psr7Implementation = "slim-psr7";
protected String mockDirName = "Mock"; protected String mockDirName = "Mock";
protected String mockPackage = ""; protected String mockPackage = "";
protected String utilsDirName = "Utils";
protected String utilsPackage = "";
public PhpSlim4ServerCodegen() { public PhpSlim4ServerCodegen() {
super(); super();
@@ -51,6 +53,7 @@ public class PhpSlim4ServerCodegen extends PhpSlimServerCodegen {
.build(); .build();
mockPackage = invokerPackage + "\\" + mockDirName; mockPackage = invokerPackage + "\\" + mockDirName;
utilsPackage = invokerPackage + "\\" + utilsDirName;
outputFolder = "generated-code" + File.separator + "slim4"; outputFolder = "generated-code" + File.separator + "slim4";
embeddedTemplateDir = templateDir = "php-slim4-server"; embeddedTemplateDir = templateDir = "php-slim4-server";
@@ -86,8 +89,9 @@ public class PhpSlim4ServerCodegen extends PhpSlimServerCodegen {
super.processOpts(); super.processOpts();
if (additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) { if (additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) {
// Update the invokerPackage for the default mockPackage // Update mockPackage and utilsPackage
mockPackage = invokerPackage + "\\" + mockDirName; mockPackage = invokerPackage + "\\" + mockDirName;
utilsPackage = invokerPackage + "\\" + utilsDirName;
} }
// make mock src path available in mustache template // make mock src path available in mustache template
@@ -95,6 +99,11 @@ public class PhpSlim4ServerCodegen extends PhpSlimServerCodegen {
additionalProperties.put("mockSrcPath", "./" + toSrcPath(mockPackage, srcBasePath)); additionalProperties.put("mockSrcPath", "./" + toSrcPath(mockPackage, srcBasePath));
additionalProperties.put("mockTestPath", "./" + toSrcPath(mockPackage, testBasePath)); additionalProperties.put("mockTestPath", "./" + toSrcPath(mockPackage, testBasePath));
// same for utils package
additionalProperties.put("utilsPackage", utilsPackage);
additionalProperties.put("utilsSrcPath", "./" + toSrcPath(utilsPackage, srcBasePath));
additionalProperties.put("utilsTestPath", "./" + toSrcPath(utilsPackage, testBasePath));
if (additionalProperties.containsKey(PSR7_IMPLEMENTATION)) { if (additionalProperties.containsKey(PSR7_IMPLEMENTATION)) {
this.setPsr7Implementation((String) additionalProperties.get(PSR7_IMPLEMENTATION)); this.setPsr7Implementation((String) additionalProperties.get(PSR7_IMPLEMENTATION));
} }
@@ -132,6 +141,12 @@ public class PhpSlim4ServerCodegen extends PhpSlimServerCodegen {
supportingFiles.add(new SupportingFile("openapi_data_mocker_interface.mustache", toSrcPath(mockPackage, srcBasePath), toInterfaceName("OpenApiDataMocker") + ".php")); supportingFiles.add(new SupportingFile("openapi_data_mocker_interface.mustache", toSrcPath(mockPackage, srcBasePath), toInterfaceName("OpenApiDataMocker") + ".php"));
supportingFiles.add(new SupportingFile("openapi_data_mocker.mustache", toSrcPath(mockPackage, srcBasePath), "OpenApiDataMocker.php")); supportingFiles.add(new SupportingFile("openapi_data_mocker.mustache", toSrcPath(mockPackage, srcBasePath), "OpenApiDataMocker.php"));
supportingFiles.add(new SupportingFile("openapi_data_mocker_test.mustache", toSrcPath(mockPackage, testBasePath), "OpenApiDataMockerTest.php")); supportingFiles.add(new SupportingFile("openapi_data_mocker_test.mustache", toSrcPath(mockPackage, testBasePath), "OpenApiDataMockerTest.php"));
// traits of ported utils
supportingFiles.add(new SupportingFile("string_utils_trait.mustache", toSrcPath(utilsPackage, srcBasePath), toTraitName("StringUtils") + ".php"));
supportingFiles.add(new SupportingFile("string_utils_trait_test.mustache", toSrcPath(utilsPackage, testBasePath), toTraitName("StringUtils") + "Test.php"));
supportingFiles.add(new SupportingFile("model_utils_trait.mustache", toSrcPath(utilsPackage, srcBasePath), toTraitName("ModelUtils") + ".php"));
supportingFiles.add(new SupportingFile("model_utils_trait_test.mustache", toSrcPath(utilsPackage, testBasePath), toTraitName("ModelUtils") + "Test.php"));
} }
/** /**

View File

@@ -48,6 +48,8 @@ public class PythonAbstractConnexionServerCodegen extends DefaultCodegen impleme
public static final String CONTROLLER_PACKAGE = "controllerPackage"; public static final String CONTROLLER_PACKAGE = "controllerPackage";
public static final String DEFAULT_CONTROLLER = "defaultController"; public static final String DEFAULT_CONTROLLER = "defaultController";
public static final String SUPPORT_PYTHON2 = "supportPython2"; public static final String SUPPORT_PYTHON2 = "supportPython2";
// nose is a python testing framework, we use pytest if USE_NOSE is unset
public static final String USE_NOSE = "useNose";
static final String MEDIA_TYPE = "mediaType"; static final String MEDIA_TYPE = "mediaType";
protected int serverPort = 8080; protected int serverPort = 8080;
@@ -57,6 +59,7 @@ public class PythonAbstractConnexionServerCodegen extends DefaultCodegen impleme
protected String defaultController; protected String defaultController;
protected Map<Character, String> regexModifiers; protected Map<Character, String> regexModifiers;
protected boolean fixBodyName; protected boolean fixBodyName;
protected boolean useNose = Boolean.FALSE;
public PythonAbstractConnexionServerCodegen(String templateDirectory, boolean fixBodyNameValue) { public PythonAbstractConnexionServerCodegen(String templateDirectory, boolean fixBodyNameValue) {
super(); super();
@@ -156,6 +159,8 @@ public class PythonAbstractConnexionServerCodegen extends DefaultCodegen impleme
defaultValue("false")); defaultValue("false"));
cliOptions.add(new CliOption("serverPort", "TCP port to listen to in app.run"). cliOptions.add(new CliOption("serverPort", "TCP port to listen to in app.run").
defaultValue("8080")); defaultValue("8080"));
cliOptions.add(CliOption.newBoolean(USE_NOSE, "use the nose test framework").
defaultValue(Boolean.FALSE.toString()));
} }
protected void addSupportingFiles() { protected void addSupportingFiles() {
@@ -200,6 +205,9 @@ public class PythonAbstractConnexionServerCodegen extends DefaultCodegen impleme
additionalProperties.put(SUPPORT_PYTHON2, Boolean.TRUE); additionalProperties.put(SUPPORT_PYTHON2, Boolean.TRUE);
typeMapping.put("long", "long"); typeMapping.put("long", "long");
} }
if (additionalProperties.containsKey(USE_NOSE)) {
setUseNose((String) additionalProperties.get(USE_NOSE));
}
supportingFiles.add(new SupportingFile("__main__.mustache", packagePath(), "__main__.py")); supportingFiles.add(new SupportingFile("__main__.mustache", packagePath(), "__main__.py"));
supportingFiles.add(new SupportingFile("util.mustache", packagePath(), "util.py")); supportingFiles.add(new SupportingFile("util.mustache", packagePath(), "util.py"));
supportingFiles.add(new SupportingFile("typing_utils.mustache", packagePath(), "typing_utils.py")); supportingFiles.add(new SupportingFile("typing_utils.mustache", packagePath(), "typing_utils.py"));
@@ -214,6 +222,10 @@ public class PythonAbstractConnexionServerCodegen extends DefaultCodegen impleme
controllerPackage = packageName + "." + controllerPackage; controllerPackage = packageName + "." + controllerPackage;
} }
public void setUseNose(String val) {
this.useNose = Boolean.valueOf(val);
}
private static String packageToPath(String pkg) { private static String packageToPath(String pkg) {
return pkg.replace(".", File.separator); return pkg.replace(".", File.separator);
} }

View File

@@ -44,5 +44,7 @@ public class PythonAiohttpConnexionServerCodegen extends PythonAbstractConnexion
supportingFiles.add(new SupportingFile("conftest.mustache", testPackage, "conftest.py")); supportingFiles.add(new SupportingFile("conftest.mustache", testPackage, "conftest.py"));
supportingFiles.add(new SupportingFile("__init__test.mustache", testPackage, "__init__.py")); supportingFiles.add(new SupportingFile("__init__test.mustache", testPackage, "__init__.py"));
supportingFiles.add(new SupportingFile("__init__main.mustache", packagePath(), "__init__.py")); supportingFiles.add(new SupportingFile("__init__main.mustache", packagePath(), "__init__.py"));
supportingFiles.add(new SupportingFile("tox.mustache", "", "tox.ini"));
supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
} }
} }

View File

@@ -40,6 +40,8 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
public static final String PACKAGE_URL = "packageUrl"; public static final String PACKAGE_URL = "packageUrl";
public static final String DEFAULT_LIBRARY = "urllib3"; public static final String DEFAULT_LIBRARY = "urllib3";
// nose is a python testing framework, we use pytest if USE_NOSE is unset
public static final String USE_NOSE = "useNose";
protected String packageName = "openapi_client"; protected String packageName = "openapi_client";
protected String packageVersion = "1.0.0"; protected String packageVersion = "1.0.0";
@@ -47,6 +49,7 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
protected String packageUrl; protected String packageUrl;
protected String apiDocPath = "docs/"; protected String apiDocPath = "docs/";
protected String modelDocPath = "docs/"; protected String modelDocPath = "docs/";
protected boolean useNose = Boolean.FALSE;
protected Map<Character, String> regexModifiers; protected Map<Character, String> regexModifiers;
@@ -151,6 +154,8 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
.defaultValue(Boolean.TRUE.toString())); .defaultValue(Boolean.TRUE.toString()));
cliOptions.add(new CliOption(CodegenConstants.SOURCECODEONLY_GENERATION, CodegenConstants.SOURCECODEONLY_GENERATION_DESC) cliOptions.add(new CliOption(CodegenConstants.SOURCECODEONLY_GENERATION, CodegenConstants.SOURCECODEONLY_GENERATION_DESC)
.defaultValue(Boolean.FALSE.toString())); .defaultValue(Boolean.FALSE.toString()));
cliOptions.add(CliOption.newBoolean(USE_NOSE, "use the nose test framework").
defaultValue(Boolean.FALSE.toString()));
supportedLibraries.put("urllib3", "urllib3-based client"); supportedLibraries.put("urllib3", "urllib3-based client");
supportedLibraries.put("asyncio", "Asyncio-based client (python 3.5+)"); supportedLibraries.put("asyncio", "Asyncio-based client (python 3.5+)");
@@ -216,6 +221,10 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
setPackageUrl((String) additionalProperties.get(PACKAGE_URL)); setPackageUrl((String) additionalProperties.get(PACKAGE_URL));
} }
if (additionalProperties.containsKey(USE_NOSE)) {
setUseNose((String) additionalProperties.get(USE_NOSE));
}
String readmePath = "README.md"; String readmePath = "README.md";
String readmeTemplate = "README.mustache"; String readmeTemplate = "README.mustache";
if (generateSourceCodeOnly) { if (generateSourceCodeOnly) {
@@ -228,6 +237,7 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
supportingFiles.add(new SupportingFile("tox.mustache", "", "tox.ini")); supportingFiles.add(new SupportingFile("tox.mustache", "", "tox.ini"));
supportingFiles.add(new SupportingFile("test-requirements.mustache", "", "test-requirements.txt")); supportingFiles.add(new SupportingFile("test-requirements.mustache", "", "test-requirements.txt"));
supportingFiles.add(new SupportingFile("requirements.mustache", "", "requirements.txt")); supportingFiles.add(new SupportingFile("requirements.mustache", "", "requirements.txt"));
supportingFiles.add(new SupportingFile("setup_cfg.mustache", "", "setup.cfg"));
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh")); supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore")); supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
@@ -579,6 +589,10 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
this.packageName = packageName; this.packageName = packageName;
} }
public void setUseNose(String val) {
this.useNose = Boolean.valueOf(val);
}
public void setProjectName(String projectName) { public void setProjectName(String projectName) {
this.projectName = projectName; this.projectName = projectName;
} }

View File

@@ -26,6 +26,7 @@ import io.swagger.v3.oas.models.media.FileSchema;
import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.media.XML; import io.swagger.v3.oas.models.media.XML;
import io.swagger.v3.oas.models.parameters.RequestBody; import io.swagger.v3.oas.models.parameters.RequestBody;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.servers.Server; import io.swagger.v3.oas.models.servers.Server;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.*; import org.openapitools.codegen.*;
@@ -65,6 +66,11 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
private static final String uuidType = "uuid::Uuid"; private static final String uuidType = "uuid::Uuid";
private static final String bytesType = "swagger::ByteArray"; private static final String bytesType = "swagger::ByteArray";
private static final String xmlMimeType = "application/xml";
private static final String octetMimeType = "application/octet-stream";
private static final String plainMimeType = "text/plain";
private static final String jsonMimeType = "application/json";
public RustServerCodegen() { public RustServerCodegen() {
super(); super();
@@ -485,11 +491,11 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
} }
private boolean isMimetypeXml(String mimetype) { private boolean isMimetypeXml(String mimetype) {
return mimetype.toLowerCase(Locale.ROOT).startsWith("application/xml"); return mimetype.toLowerCase(Locale.ROOT).startsWith(xmlMimeType);
} }
private boolean isMimetypePlainText(String mimetype) { private boolean isMimetypePlainText(String mimetype) {
return mimetype.toLowerCase(Locale.ROOT).startsWith("text/plain"); return mimetype.toLowerCase(Locale.ROOT).startsWith(plainMimeType);
} }
private boolean isMimetypeHtmlText(String mimetype) { private boolean isMimetypeHtmlText(String mimetype) {
@@ -505,7 +511,7 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
} }
private boolean isMimetypeOctetStream(String mimetype) { private boolean isMimetypeOctetStream(String mimetype) {
return mimetype.toLowerCase(Locale.ROOT).startsWith("application/octet-stream"); return mimetype.toLowerCase(Locale.ROOT).startsWith(octetMimeType);
} }
private boolean isMimetypePlain(String mimetype) { private boolean isMimetypePlain(String mimetype) {
@@ -563,36 +569,17 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
processParam(param, op); processParam(param, op);
} }
List<String> consumes = new ArrayList<String>(); // We keep track of the 'default' model type for this API. If there are
// *any* XML responses, then we set the default to XML, otherwise we
boolean consumesPlainText = false; // let the default be JSON. It would be odd for an API to want to use
boolean consumesXml = false; // both XML and JSON on a single operation, and if we don't know
// if "consumes" is defined (per operation or using global definition) // anything then JSON is a more modern (ergo reasonable) choice.
if (consumes != null && !consumes.isEmpty()) { boolean defaultsToXml = false;
consumes.addAll(getConsumesInfo(this.openAPI, operation));
List<Map<String, String>> c = new ArrayList<Map<String, String>>();
for (String mimeType : consumes) {
Map<String, String> mediaType = new HashMap<String, String>();
if (isMimetypeXml(mimeType)) {
additionalProperties.put("usesXml", true);
consumesXml = true;
} else if (isMimetypePlain(mimeType)) {
consumesPlainText = true;
} else if (isMimetypeWwwFormUrlEncoded(mimeType)) {
additionalProperties.put("usesUrlEncodedForm", true);
}
mediaType.put("mediaType", mimeType);
c.add(mediaType);
}
op.consumes = c;
op.hasConsumes = true;
}
List<String> produces = new ArrayList<String>(getProducesInfo(this.openAPI, operation));
// Determine the types that this operation produces. `getProducesInfo`
// simply lists all the types, and then we add the correct imports to
// the generated library.
List<String> produces = new ArrayList<String>(getProducesInfo(openAPI, operation));
boolean producesXml = false; boolean producesXml = false;
boolean producesPlainText = false; boolean producesPlainText = false;
if (produces != null && !produces.isEmpty()) { if (produces != null && !produces.isEmpty()) {
@@ -602,6 +589,7 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
if (isMimetypeXml(mimeType)) { if (isMimetypeXml(mimeType)) {
additionalProperties.put("usesXml", true); additionalProperties.put("usesXml", true);
defaultsToXml = true;
producesXml = true; producesXml = true;
} else if (isMimetypePlain(mimeType)) { } else if (isMimetypePlain(mimeType)) {
producesPlainText = true; producesPlainText = true;
@@ -621,32 +609,132 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
param.vendorExtensions.put("typeName", toModelName(param.baseName)); param.vendorExtensions.put("typeName", toModelName(param.baseName));
} }
// Set for deduplication of response IDs
Set<String> responseIds = new HashSet();
for (CodegenResponse rsp : op.responses) { for (CodegenResponse rsp : op.responses) {
// Get the original API response so we get process the schema
// directly.
ApiResponse original;
if (rsp.code == "0") {
original = operation.getResponses().get("default");
} else {
original = operation.getResponses().get(rsp.code);
}
String[] words = rsp.message.split("[^A-Za-z ]"); String[] words = rsp.message.split("[^A-Za-z ]");
// Create a unique responseID for this response.
String responseId; String responseId;
if (rsp.vendorExtensions.containsKey("x-responseId")) { if (rsp.vendorExtensions.containsKey("x-responseId")) {
// If it's been specified directly, use that.
responseId = (String) rsp.vendorExtensions.get("x-responseId"); responseId = (String) rsp.vendorExtensions.get("x-responseId");
} else if (words.length != 0) { } else if (words.length != 0) {
// If there's a description, build it from the description.
responseId = camelize(words[0].replace(" ", "_")); responseId = camelize(words[0].replace(" ", "_"));
} else { } else {
// Otherwise fall back to the http response code.
responseId = "Status" + rsp.code; responseId = "Status" + rsp.code;
} }
// Deduplicate response IDs that would otherwise contain the same
// text. We rely on the ID being unique, but since we form it from
// the raw description field we can't require that the spec writer
// provides unique descriptions.
int idTieBreaker = 2;
while (responseIds.contains(responseId)) {
String trial = String.format(Locale.ROOT, "%s_%d", responseId, idTieBreaker);
if (!responseIds.contains(trial)) {
responseId = trial;
} else {
idTieBreaker++;
}
}
responseIds.add(responseId);
rsp.vendorExtensions.put("x-responseId", responseId); rsp.vendorExtensions.put("x-responseId", responseId);
rsp.vendorExtensions.put("x-uppercaseResponseId", underscore(responseId).toUpperCase(Locale.ROOT)); rsp.vendorExtensions.put("x-uppercaseResponseId", underscore(responseId).toUpperCase(Locale.ROOT));
rsp.vendorExtensions.put("uppercase_operation_id", underscore(op.operationId).toUpperCase(Locale.ROOT)); rsp.vendorExtensions.put("uppercase_operation_id", underscore(op.operationId).toUpperCase(Locale.ROOT));
if (rsp.dataType != null) { if (rsp.dataType != null) {
rsp.vendorExtensions.put("uppercase_data_type", (rsp.dataType.replace("models::", "")).toUpperCase(Locale.ROOT)); rsp.vendorExtensions.put("uppercase_data_type", (rsp.dataType.replace("models::", "")).toUpperCase(Locale.ROOT));
// Default to producing json if nothing else is specified // Get the mimetype which is produced by this response. Note
// that although in general responses produces a set of
// different mimetypes currently we only support 1 per
// response.
String firstProduces = null;
if (original.getContent() != null) {
for (String mimetype : original.getContent().keySet()) {
firstProduces = mimetype;
break;
}
}
// The output mime type. This allows us to do sensible fallback
// to JSON/XML rather than using only the default operation
// mimetype.
String outputMime;
if (firstProduces == null) {
if (producesXml) {
outputMime = xmlMimeType;
} else if (producesPlainText) {
if (rsp.dataType.equals(bytesType)) {
outputMime = octetMimeType;
} else {
outputMime = plainMimeType;
}
} else {
outputMime = jsonMimeType;
}
} else {
// If we know exactly what mimetype this response is
// going to produce, then use that. If we have not found
// anything, then we'll fall back to the 'producesXXX'
// definitions we worked out above for the operation as a
// whole.
if (isMimetypeXml(firstProduces)) {
producesXml = true;
producesPlainText = false;
} else if (isMimetypePlain(firstProduces)) {
producesXml = false;
producesPlainText = true;
} else {
producesXml = false;
producesPlainText = false;
}
outputMime = firstProduces;
}
rsp.vendorExtensions.put("mimeType", outputMime);
// Write out the type of data we actually expect this response
// to make.
if (producesXml) { if (producesXml) {
rsp.vendorExtensions.put("producesXml", true); rsp.vendorExtensions.put("producesXml", true);
} else if (producesPlainText && rsp.dataType.equals(bytesType)) { } else if (producesPlainText) {
// Plain text means that there is not structured data in
// this response. So it'll either be a UTF-8 encoded string
// 'plainText' or some generic 'bytes'.
//
// Note that we don't yet distinguish between string/binary
// and string/bytes - that is we don't auto-detect whether
// base64 encoding should be done. They both look like
// 'producesBytes'.
if (rsp.dataType.equals(bytesType)) {
rsp.vendorExtensions.put("producesBytes", true);
} else {
rsp.vendorExtensions.put("producesPlainText", true); rsp.vendorExtensions.put("producesPlainText", true);
}
} else { } else {
rsp.vendorExtensions.put("producesJson", true); rsp.vendorExtensions.put("producesJson", true);
// If the data type is just "object", then ensure that the Rust data type // If the data type is just "object", then ensure that the
// is "serde_json::Value". This allows us to define APIs that // Rust data type is "serde_json::Value". This allows us
// can return arbitrary JSON bodies. // to define APIs that can return arbitrary JSON bodies.
if (rsp.dataType.equals("object")) { if (rsp.dataType.equals("object")) {
rsp.dataType = "serde_json::Value"; rsp.dataType = "serde_json::Value";
} }
@@ -686,7 +774,6 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
Map<String, Object> operations = (Map<String, Object>) objs.get("operations"); Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
List<CodegenOperation> operationList = (List<CodegenOperation>) operations.get("operation"); List<CodegenOperation> operationList = (List<CodegenOperation>) operations.get("operation");
for (CodegenOperation op : operationList) { for (CodegenOperation op : operationList) {
boolean consumesPlainText = false; boolean consumesPlainText = false;
boolean consumesXml = false; boolean consumesXml = false;

View File

@@ -937,7 +937,7 @@ public class ModelUtils {
if (s == null) { if (s == null) {
LOGGER.error("Failed to obtain schema from {}", parentName); LOGGER.error("Failed to obtain schema from {}", parentName);
return "UNKNOWN_PARENT_NAME"; return "UNKNOWN_PARENT_NAME";
} else if (s.getDiscriminator() != null && StringUtils.isNotEmpty(s.getDiscriminator().getPropertyName())) { } else if (hasOrInheritsDiscriminator(s, allSchemas)) {
// discriminator.propertyName is used // discriminator.propertyName is used
return parentName; return parentName;
} else { } else {
@@ -961,7 +961,7 @@ public class ModelUtils {
return null; return null;
} }
public static List<String> getAllParentsName(ComposedSchema composedSchema, Map<String, Schema> allSchemas) { public static List<String> getAllParentsName(ComposedSchema composedSchema, Map<String, Schema> allSchemas, boolean includeAncestors) {
List<Schema> interfaces = getInterfaces(composedSchema); List<Schema> interfaces = getInterfaces(composedSchema);
List<String> names = new ArrayList<String>(); List<String> names = new ArrayList<String>();
@@ -974,9 +974,12 @@ public class ModelUtils {
if (s == null) { if (s == null) {
LOGGER.error("Failed to obtain schema from {}", parentName); LOGGER.error("Failed to obtain schema from {}", parentName);
names.add("UNKNOWN_PARENT_NAME"); names.add("UNKNOWN_PARENT_NAME");
} else if (s.getDiscriminator() != null && StringUtils.isNotEmpty(s.getDiscriminator().getPropertyName())) { } else if (hasOrInheritsDiscriminator(s, allSchemas)) {
// discriminator.propertyName is used // discriminator.propertyName is used
names.add(parentName); names.add(parentName);
if (includeAncestors && s instanceof ComposedSchema) {
names.addAll(getAllParentsName((ComposedSchema) s, allSchemas, true));
}
} else { } else {
LOGGER.debug("Not a parent since discriminator.propertyName is not set {}", s.get$ref()); LOGGER.debug("Not a parent since discriminator.propertyName is not set {}", s.get$ref());
// not a parent since discriminator.propertyName is not set // not a parent since discriminator.propertyName is not set
@@ -990,6 +993,32 @@ public class ModelUtils {
return names; return names;
} }
private static boolean hasOrInheritsDiscriminator(Schema schema, Map<String, Schema> allSchemas) {
if (schema.getDiscriminator() != null && StringUtils.isNotEmpty(schema.getDiscriminator().getPropertyName())) {
return true;
}
else if (StringUtils.isNotEmpty(schema.get$ref())) {
String parentName = getSimpleRef(schema.get$ref());
Schema s = allSchemas.get(parentName);
if (s != null) {
return hasOrInheritsDiscriminator(s, allSchemas);
}
else {
LOGGER.error("Failed to obtain schema from {}", parentName);
}
}
else if (schema instanceof ComposedSchema) {
final ComposedSchema composed = (ComposedSchema) schema;
final List<Schema> interfaces = getInterfaces(composed);
for (Schema i : interfaces) {
if (hasOrInheritsDiscriminator(i, allSchemas)) {
return true;
}
}
}
return false;
}
public static boolean isNullable(Schema schema) { public static boolean isNullable(Schema schema) {
if (schema == null) { if (schema == null) {
return false; return false;

View File

@@ -6,11 +6,12 @@
-- --
-- NOTE: Auto generated by OpenAPI Generator (https://openapi-generator.tech). -- NOTE: Auto generated by OpenAPI Generator (https://openapi-generator.tech).
with "config"; with "config";
with "util"; with "utilada_sys";
with "util_http"; with "utilada_xml";
with "utilada_http";
with "security"; with "security";
with "swagger";{{#isServer}} with "swagger";{{#isServer}}
with "servlet"; with "servletada";
with "swagger_server";{{/isServer}} with "swagger_server";{{/isServer}}
project {{{projectName}}} is project {{{projectName}}} is

View File

@@ -2,17 +2,22 @@ with Ada.IO_Exceptions;
with AWS.Config.Set; with AWS.Config.Set;
with Swagger.Servers.AWS; with Swagger.Servers.AWS;
with Swagger.Servers.Applications; with Swagger.Servers.Applications;
with Util.Strings;
with Util.Log.Loggers; with Util.Log.Loggers;
with Util.Properties; with Util.Properties;
with Util.Properties.Basic;
with {{package}}.Servers; with {{package}}.Servers;
procedure {{package}}.Server is procedure {{package}}.Server is
procedure Configure (Config : in out AWS.Config.Object); procedure Configure (Config : in out AWS.Config.Object);
use Util.Properties.Basic;
CONFIG_PATH : constant String := "{{packageConfig}}.properties"; CONFIG_PATH : constant String := "{{packageConfig}}.properties";
Port : Natural := 8080;
procedure Configure (Config : in out AWS.Config.Object) is procedure Configure (Config : in out AWS.Config.Object) is
begin begin
AWS.Config.Set.Server_Port (Config, 8080); AWS.Config.Set.Server_Port (Config, Port);
AWS.Config.Set.Max_Connection (Config, 8); AWS.Config.Set.Max_Connection (Config, 8);
AWS.Config.Set.Accept_Queue_Size (Config, 512); AWS.Config.Set.Accept_Queue_Size (Config, 512);
end Configure; end Configure;
@@ -25,13 +30,15 @@ begin
Props.Load_Properties (CONFIG_PATH); Props.Load_Properties (CONFIG_PATH);
Util.Log.Loggers.Initialize (Props); Util.Log.Loggers.Initialize (Props);
Port := Integer_Property.Get (Props, "swagger.port", Port);
App.Configure (Props); App.Configure (Props);
{{package}}.Servers.Server_Impl.Register (App); {{package}}.Servers.Server_Impl.Register (App);
WS.Configure (Configure'Access); WS.Configure (Configure'Access);
WS.Register_Application ("{{basePathWithoutHost}}", App'Unchecked_Access); WS.Register_Application ("{{basePathWithoutHost}}", App'Unchecked_Access);
App.Dump_Routes (Util.Log.INFO_LEVEL); App.Dump_Routes (Util.Log.INFO_LEVEL);
Log.Info ("Connect you browser to: http://localhost:8080{{basePathWithoutHost}}/ui/index.html"); Log.Info ("Connect you browser to: http://localhost:{0}{{basePathWithoutHost}}/ui/index.html",
Util.Strings.Image (Port));
WS.Start; WS.Start;

View File

@@ -22,7 +22,7 @@
// //
{{/notes}} {{/notes}}
{{#returnType}}{{#returnTypeIsPrimitive}}{{#returnSimpleType}}{{{.}}}*{{/returnSimpleType}}{{^returnSimpleType}}{{#isListContainer}}{{{.}}}_t*{{/isListContainer}}{{#isMapContainer}}{{{.}}}{{/isMapContainer}}{{/returnSimpleType}}{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}{{{.}}}_t*{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}void{{/returnType}} {{#returnType}}{{#returnTypeIsPrimitive}}{{#returnSimpleType}}{{{.}}}*{{/returnSimpleType}}{{^returnSimpleType}}{{#isListContainer}}{{{.}}}_t*{{/isListContainer}}{{#isMapContainer}}{{{.}}}{{/isMapContainer}}{{/returnSimpleType}}{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}{{{.}}}_t*{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}void{{/returnType}}
{{{classname}}}_{{{operationId}}}(apiClient_t *apiClient{{#allParams}} ,{{#isPrimitiveType}}{{#isNumber}}{{{dataType}}}{{/isNumber}}{{#isLong}}{{{dataType}}}{{/isLong}}{{#isInteger}}{{{dataType}}}{{/isInteger}}{{#isDouble}}{{{dataType}}}{{/isDouble}}{{#isFloat}}{{{dataType}}}{{/isFloat}}{{#isBoolean}}{{dataType}}{{/isBoolean}}{{#isEnum}}{{#isString}}{{{baseName}}}_e{{/isString}}{{/isEnum}}{{^isEnum}}{{#isString}}{{{dataType}}} *{{/isString}}{{/isEnum}}{{#isByteArray}}{{{dataType}}}{{/isByteArray}}{{#isDate}}{{{dataType}}}{{/isDate}}{{#isDateTime}}{{{dataType}}}{{/isDateTime}}{{#isFile}}{{{dataType}}}{{/isFile}}{{/isPrimitiveType}}{{^isPrimitiveType}}{{#isModel}}{{#isEnum}}{{datatypeWithEnum}}_e{{/isEnum}}{{^isEnum}}{{{dataType}}}_t *{{/isEnum}}{{/isModel}}{{^isModel}}{{^isListContainer}}{{#isEnum}}{{datatypeWithEnum}}_e{{/isEnum}}{{/isListContainer}}{{/isModel}}{{#isUuid}}{{dataType}} *{{/isUuid}}{{#isEmail}}{{dataType}}{{/isEmail}}{{/isPrimitiveType}}{{#isContainer}}{{#isListContainer}}{{dataType}}_t *{{/isListContainer}}{{#isMapContainer}}{{dataType}}{{/isMapContainer}}{{/isContainer}} {{{paramName}}}{{/allParams}}) {{{classname}}}_{{{operationId}}}(apiClient_t *apiClient{{#allParams}} ,{{#isPrimitiveType}}{{#isNumber}}{{{dataType}}}{{/isNumber}}{{#isLong}}{{{dataType}}}{{/isLong}}{{#isInteger}}{{{dataType}}}{{/isInteger}}{{#isDouble}}{{{dataType}}}{{/isDouble}}{{#isFloat}}{{{dataType}}}{{/isFloat}}{{#isBoolean}}{{dataType}}{{/isBoolean}}{{#isEnum}}{{#isString}}{{{baseName}}}_e{{/isString}}{{/isEnum}}{{^isEnum}}{{#isString}}{{{dataType}}} *{{/isString}}{{/isEnum}}{{#isByteArray}}{{{dataType}}}{{/isByteArray}}{{#isDate}}{{{dataType}}}{{/isDate}}{{#isDateTime}}{{{dataType}}}{{/isDateTime}}{{#isFile}}{{{dataType}}}{{/isFile}}{{#isFreeFormObject}}{{dataType}}_t *{{/isFreeFormObject}}{{/isPrimitiveType}}{{^isPrimitiveType}}{{#isModel}}{{#isEnum}}{{datatypeWithEnum}}_e{{/isEnum}}{{^isEnum}}{{{dataType}}}_t *{{/isEnum}}{{/isModel}}{{^isModel}}{{^isListContainer}}{{#isEnum}}{{datatypeWithEnum}}_e{{/isEnum}}{{/isListContainer}}{{/isModel}}{{#isUuid}}{{dataType}} *{{/isUuid}}{{#isEmail}}{{dataType}}{{/isEmail}}{{/isPrimitiveType}}{{#isContainer}}{{#isListContainer}}{{dataType}}_t *{{/isListContainer}}{{#isMapContainer}}{{dataType}}{{/isMapContainer}}{{/isContainer}} {{{paramName}}}{{/allParams}})
{ {
list_t *localVarQueryParameters = {{#hasQueryParams}}list_create();{{/hasQueryParams}}{{^hasQueryParams}}NULL;{{/hasQueryParams}} list_t *localVarQueryParameters = {{#hasQueryParams}}list_create();{{/hasQueryParams}}{{^hasQueryParams}}NULL;{{/hasQueryParams}}
list_t *localVarHeaderParameters = {{#hasHeaderParams}}list_create();{{/hasHeaderParams}}{{^hasHeaderParams}}NULL;{{/hasHeaderParams}} list_t *localVarHeaderParameters = {{#hasHeaderParams}}list_create();{{/hasHeaderParams}}{{^hasHeaderParams}}NULL;{{/hasHeaderParams}}
@@ -39,7 +39,7 @@
{{#pathParams}} {{#pathParams}}
// Path Params // Path Params
long sizeOfPathParams_{{{paramName}}} = {{#pathParams}}{{#isLong}}sizeof({{paramName}})+3{{/isLong}}{{#isString}}strlen({{paramName}})+3{{/isString}}{{/pathParams}} + strlen("{ {{paramName}} }"); long sizeOfPathParams_{{{paramName}}} = {{#pathParams}}{{#isLong}}sizeof({{paramName}})+3{{/isLong}}{{#isString}}strlen({{paramName}})+3{{/isString}}{{#hasMore}} + {{/hasMore}}{{/pathParams}} + strlen("{ {{paramName}} }");
{{#isNumeric}} {{#isNumeric}}
if({{paramName}} == 0){ if({{paramName}} == 0){
goto end; goto end;

View File

@@ -19,7 +19,7 @@
// //
{{/notes}} {{/notes}}
{{#returnType}}{{#returnTypeIsPrimitive}}{{#returnSimpleType}}{{{.}}}*{{/returnSimpleType}}{{^returnSimpleType}}{{#isListContainer}}{{{.}}}_t*{{/isListContainer}}{{#isMapContainer}}{{{.}}}{{/isMapContainer}}{{/returnSimpleType}}{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}{{{.}}}_t*{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}void{{/returnType}} {{#returnType}}{{#returnTypeIsPrimitive}}{{#returnSimpleType}}{{{.}}}*{{/returnSimpleType}}{{^returnSimpleType}}{{#isListContainer}}{{{.}}}_t*{{/isListContainer}}{{#isMapContainer}}{{{.}}}{{/isMapContainer}}{{/returnSimpleType}}{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}{{{.}}}_t*{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}void{{/returnType}}
{{{classname}}}_{{{operationId}}}(apiClient_t *apiClient{{#allParams}} ,{{#isPrimitiveType}}{{#isNumber}}{{{dataType}}}{{/isNumber}}{{#isLong}}{{{dataType}}}{{/isLong}}{{#isInteger}}{{{dataType}}}{{/isInteger}}{{#isDouble}}{{{dataType}}}{{/isDouble}}{{#isFloat}}{{{dataType}}}{{/isFloat}}{{#isBoolean}}{{dataType}}{{/isBoolean}}{{#isEnum}}{{#isString}}{{{baseName}}}_e{{/isString}}{{/isEnum}}{{^isEnum}}{{#isString}}{{{dataType}}} *{{/isString}}{{/isEnum}}{{#isByteArray}}{{{dataType}}}{{/isByteArray}}{{#isDate}}{{{dataType}}}{{/isDate}}{{#isDateTime}}{{{dataType}}}{{/isDateTime}}{{#isFile}}{{{dataType}}}{{/isFile}}{{/isPrimitiveType}}{{^isPrimitiveType}}{{#isModel}}{{#isEnum}}{{datatypeWithEnum}}_e{{/isEnum}}{{^isEnum}}{{{dataType}}}_t *{{/isEnum}}{{/isModel}}{{^isModel}}{{^isListContainer}}{{#isEnum}}{{datatypeWithEnum}}_e{{/isEnum}}{{/isListContainer}}{{/isModel}}{{#isUuid}}{{dataType}} *{{/isUuid}}{{#isEmail}}{{dataType}}{{/isEmail}}{{/isPrimitiveType}}{{#isContainer}}{{#isListContainer}}{{dataType}}_t *{{/isListContainer}}{{#isMapContainer}}{{dataType}}{{/isMapContainer}}{{/isContainer}} {{{paramName}}}{{/allParams}}); {{{classname}}}_{{{operationId}}}(apiClient_t *apiClient{{#allParams}} ,{{#isPrimitiveType}}{{#isNumber}}{{{dataType}}}{{/isNumber}}{{#isLong}}{{{dataType}}}{{/isLong}}{{#isInteger}}{{{dataType}}}{{/isInteger}}{{#isDouble}}{{{dataType}}}{{/isDouble}}{{#isFloat}}{{{dataType}}}{{/isFloat}}{{#isBoolean}}{{dataType}}{{/isBoolean}}{{#isEnum}}{{#isString}}{{{baseName}}}_e{{/isString}}{{/isEnum}}{{^isEnum}}{{#isString}}{{{dataType}}} *{{/isString}}{{/isEnum}}{{#isByteArray}}{{{dataType}}}{{/isByteArray}}{{#isDate}}{{{dataType}}}{{/isDate}}{{#isDateTime}}{{{dataType}}}{{/isDateTime}}{{#isFile}}{{{dataType}}}{{/isFile}}{{#isFreeFormObject}}{{dataType}}_t *{{/isFreeFormObject}}{{/isPrimitiveType}}{{^isPrimitiveType}}{{#isModel}}{{#isEnum}}{{datatypeWithEnum}}_e{{/isEnum}}{{^isEnum}}{{{dataType}}}_t *{{/isEnum}}{{/isModel}}{{^isModel}}{{^isListContainer}}{{#isEnum}}{{datatypeWithEnum}}_e{{/isEnum}}{{/isListContainer}}{{/isModel}}{{#isUuid}}{{dataType}} *{{/isUuid}}{{#isEmail}}{{dataType}}{{/isEmail}}{{/isPrimitiveType}}{{#isContainer}}{{#isListContainer}}{{dataType}}_t *{{/isListContainer}}{{#isMapContainer}}{{dataType}}{{/isMapContainer}}{{/isContainer}} {{{paramName}}}{{/allParams}});
{{/operation}} {{/operation}}

View File

@@ -72,7 +72,7 @@ typedef struct {{classname}}_t {
{{datatype}}_e {{name}}; //enum model {{datatype}}_e {{name}}; //enum model
{{/isEnum}} {{/isEnum}}
{{^isEnum}} {{^isEnum}}
{{datatype}}_t *{{name}}; //model struct {{datatype}}_t *{{name}}; //model
{{/isEnum}} {{/isEnum}}
{{/isModel}} {{/isModel}}
{{#isUuid}} {{#isUuid}}

View File

@@ -75,7 +75,7 @@ public class JSON {
{{/mappedModels}} {{/mappedModels}}
classByDiscriminatorValue.put("{{classname}}".toUpperCase(Locale.ROOT), {{classname}}.class); classByDiscriminatorValue.put("{{classname}}".toUpperCase(Locale.ROOT), {{classname}}.class);
return getClassByDiscriminator(classByDiscriminatorValue, return getClassByDiscriminator(classByDiscriminatorValue,
getDiscriminatorValue(readElement, "{{{propertyName}}}")); getDiscriminatorValue(readElement, "{{{propertyBaseName}}}"));
} }
}) })
{{/discriminator}} {{/discriminator}}

View File

@@ -715,6 +715,13 @@ public class ApiClient {
} }
} }
for (Entry<String, String> entry : defaultCookieMap.entrySet()) {
String value = entry.getValue();
if (value != null) {
invocationBuilder = invocationBuilder.cookie(entry.getKey(), value);
}
}
for (Entry<String, String> entry : defaultHeaderMap.entrySet()) { for (Entry<String, String> entry : defaultHeaderMap.entrySet()) {
String key = entry.getKey(); String key = entry.getKey();
if (!headerParams.containsKey(key)) { if (!headerParams.containsKey(key)) {

View File

@@ -659,15 +659,21 @@ public class ApiClient {
} }
} }
/**
* Build cookie header. Keeps a single value per cookie (as per <a href="https://tools.ietf.org/html/rfc6265#section-5.3">
* RFC6265 section 5.3</a>).
*
* @param cookies map all cookies
* @return header string for cookies.
*/
private String buildCookieHeader(MultiValueMap<String, String> cookies) { private String buildCookieHeader(MultiValueMap<String, String> cookies) {
final StringBuilder cookieValue = new StringBuilder(); final StringBuilder cookieValue = new StringBuilder();
String delimiter = ""; String delimiter = "";
for (final Map.Entry<String, List<String>> entry : cookies.entrySet()) { for (final Map.Entry<String, List<String>> entry : cookies.entrySet()) {
for (String value : entry.getValue()) { final String value = entry.getValue().get(entry.getValue().size() - 1);
cookieValue.append(String.format("%s%s=%s", delimiter, entry.getKey(), entry.getValue())); cookieValue.append(String.format("%s%s=%s", delimiter, entry.getKey(), value));
delimiter = "; "; delimiter = "; ";
} }
}
return cookieValue.toString(); return cookieValue.toString();
} }

View File

@@ -1,4 +1,5 @@
= {{{appName}}} = {{{appName}}}
{{#headerAttributes}}
{{infoEmail}} {{infoEmail}}
{{#version}}{{{version}}}{{/version}} {{#version}}{{{version}}}{{/version}}
:toc: left :toc: left
@@ -8,9 +9,10 @@
:keywords: openapi, rest, {{appName}} :keywords: openapi, rest, {{appName}}
:specDir: {{specDir}} :specDir: {{specDir}}
:snippetDir: {{snippetDir}} :snippetDir: {{snippetDir}}
:generator-template: v1 2019-11-19 :generator-template: v1 2019-12-20
:info-url: {{infoUrl}} :info-url: {{infoUrl}}
:app-name: {{appName}} :app-name: {{appName}}
{{/headerAttributes}}
[abstract] [abstract]
.Abstract .Abstract

View File

@@ -10,8 +10,6 @@ abstract class {{classname}} implements Built<{{classname}}, {{classname}}Builde
{{#isNullable}} {{#isNullable}}
@nullable @nullable
{{/isNullable}} {{/isNullable}}
{{#description}}/* {{{description}}} */{{/description}}
@BuiltValueField(wireName: '{{baseName}}') @BuiltValueField(wireName: '{{baseName}}')
{{{dataType}}} get {{name}}; {{{dataType}}} get {{name}};
{{#allowableValues}} {{#allowableValues}}

View File

@@ -1,6 +1,9 @@
name: {{pubName}} name: {{pubName}}
version: {{pubVersion}} version: {{pubVersion}}
description: {{pubDescription}} description: {{pubDescription}}
authors:
- {{pubAuthor}} <{{pubAuthorEmail}}>
homepage: {{pubHomepage}}
environment: environment:
sdk: '>=2.0.0 <3.0.0' sdk: '>=2.0.0 <3.0.0'
dependencies: dependencies:

View File

@@ -24,6 +24,9 @@ Install the following dependencies:
```shell ```shell
go get github.com/stretchr/testify/assert go get github.com/stretchr/testify/assert
go get golang.org/x/oauth2 go get golang.org/x/oauth2
{{#withAWSV4Signature}}
go get github.com/aws/aws-sdk-go/aws
{{/withAWSV4Signature}}
go get golang.org/x/net/context go get golang.org/x/net/context
go get github.com/antihax/optional go get github.com/antihax/optional
``` ```
@@ -113,6 +116,18 @@ r, err := client.Service.Operation(auth, args)
{{/isOAuth}} {{/isOAuth}}
{{/authMethods}} {{/authMethods}}
{{#withAWSV4Signature}}
Example
```golang
auth := context.WithValue(context.Background(), sw.ContextAWSv4, sw.AWSv4{
AccessKey: "ACCESSKEYSTRING",
SecretKey: "SECRETKEYSTRING",
})
r, err := client.Service.Operation(auth, args)
```
{{/withAWSV4Signature}}
## Author ## Author
{{#apiInfo}}{{#apis}}{{^hasMore}}{{infoEmail}} {{#apiInfo}}{{#apis}}{{^hasMore}}{{infoEmail}}

View File

@@ -24,6 +24,10 @@ import (
"unicode/utf8" "unicode/utf8"
"golang.org/x/oauth2" "golang.org/x/oauth2"
{{#withAWSV4Signature}}
awsv4 "github.com/aws/aws-sdk-go/aws/signer/v4"
awscredentials "github.com/aws/aws-sdk-go/aws/credentials"
{{/withAWSV4Signature}}
) )
var ( var (
@@ -352,6 +356,25 @@ func (c *APIClient) prepareRequest(
if auth, ok := ctx.Value(ContextAccessToken).(string); ok { if auth, ok := ctx.Value(ContextAccessToken).(string); ok {
localVarRequest.Header.Add("Authorization", "Bearer "+auth) localVarRequest.Header.Add("Authorization", "Bearer "+auth)
} }
{{#withAWSV4Signature}}
// AWS Signature v4 Authentication
if auth, ok := ctx.Value(ContextAWSv4).(AWSv4); ok {
creds := awscredentials.NewStaticCredentials(auth.AccessKey, auth.SecretKey, "")
signer := awsv4.NewSigner(creds)
var reader *strings.Reader
if body == nil {
reader = strings.NewReader("")
} else {
reader = strings.NewReader(body.String())
}
timestamp := time.Now()
_, err := signer.Sign(localVarRequest, reader, "oapi", "eu-west-2", timestamp)
if err != nil {
return nil, err
}
}
{{/withAWSV4Signature}}
} }
for header, value := range c.cfg.DefaultHeader { for header, value := range c.cfg.DefaultHeader {

View File

@@ -29,6 +29,11 @@ var (
// ContextAPIKey takes an APIKey as authentication for the request // ContextAPIKey takes an APIKey as authentication for the request
ContextAPIKey = contextKey("apikey") ContextAPIKey = contextKey("apikey")
{{#withAWSV4Signature}}
// ContextAWSv4 takes an Access Key and a Secret Key for signing AWS Signature v4.
ContextAWSv4 = contextKey("awsv4")
{{/withAWSV4Signature}}
) )
// BasicAuth provides basic http authentication to a request passed via context using ContextBasicAuth // BasicAuth provides basic http authentication to a request passed via context using ContextBasicAuth
@@ -43,6 +48,15 @@ type APIKey struct {
Prefix string Prefix string
} }
{{#withAWSV4Signature}}
// AWSv4 provides AWS Signature to a request passed via context using ContextAWSv4
// https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html
type AWSv4 struct {
AccessKey string
SecretKey string
}
{{/withAWSV4Signature}}
// ServerVariable stores the information about a server variable // ServerVariable stores the information about a server variable
type ServerVariable struct { type ServerVariable struct {
Description string Description string

View File

@@ -3,4 +3,5 @@ module {{gitHost}}/{{gitUserId}}/{{gitRepoId}}{{#isGoSubmodule}}/{{packageName}}
require ( require (
github.com/antihax/optional v1.0.0 github.com/antihax/optional v1.0.0
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
{{#withAWSV4Signature}}github.com/aws/aws-sdk-go v1.26.3{{/withAWSV4Signature}}
) )

View File

@@ -1,6 +1,8 @@
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/aws/aws-sdk-go v1.26.3 h1:szQdfJcUBAhQT0zZEx4sxoDuWb7iScoucxCiVxDmaBk=
github.com/aws/aws-sdk-go v1.26.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=

View File

@@ -5,7 +5,7 @@ composer.phar
# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control # Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
# composer.lock composer.lock
# phplint tool creates cache file which is not necessary in a codebase # phplint tool creates cache file which is not necessary in a codebase
/.phplint-cache /.phplint-cache

View File

@@ -43,11 +43,13 @@
"test": [ "test": [
"@test-apis", "@test-apis",
"@test-models", "@test-models",
"@test-mock" "@test-mock",
"@test-utils"
], ],
"test-apis": "phpunit --testsuite Apis", "test-apis": "phpunit --testsuite Apis",
"test-models": "phpunit --testsuite Models", "test-models": "phpunit --testsuite Models",
"test-mock": "phpunit --testsuite Mock", "test-mock": "phpunit --testsuite Mock",
"test-utils": "phpunit --testsuite Utils",
"phpcs": "phpcs", "phpcs": "phpcs",
"phplint": "phplint ./ --exclude=vendor" "phplint": "phplint ./ --exclude=vendor"
} }

View File

@@ -0,0 +1,132 @@
<?php
/**
* {{traitNamePrefix}}ModelUtils{{traitNameSuffix}}
*
* PHP version 7.1
*
* @package {{invokerPackage}}
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
*/
/**{{#apiInfo}}{{#appName}}
* {{{appName}}}
*
{{/appName}}
{{#appDescription}}
* {{{appDescription}}}
{{/appDescription}}
{{#version}}
* The version of the OpenAPI document: {{{version}}}
{{/version}}
{{#infoEmail}}
* Contact: {{{infoEmail}}}
{{/infoEmail}}
* Generated by: https://github.com/openapitools/openapi-generator.git
*/
/**
* NOTE: This class is auto generated by the openapi generator program.
* https://github.com/openapitools/openapi-generator
* Do not edit the class manually.
*/
namespace {{utilsPackage}};
use {{utilsPackage}}\{{traitNamePrefix}}StringUtils{{traitNameSuffix}};
/**
* {{traitNamePrefix}}ModelUtils{{traitNameSuffix}} Class Doc Comment
* This class duplicates functionality of ModelUtils.java and AbstractPhpCodegen.java classes.
*
* @package {{utilsPackage}}
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
*/
trait {{traitNamePrefix}}ModelUtils{{traitNameSuffix}}
{
use {{traitNamePrefix}}StringUtils{{traitNameSuffix}};
/**
* Parses model class name from provided ref.
* @link https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#reference-object
* This method doesn't check that class exists and autoloaded.
* This is recreated method of @link modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java class.
*
* @param string $ref Reference, eg. #/components/schemas/Pet
*
* @return string|null classname or null on fail
*/
public static function getSimpleRef($ref)
{
$model = null;
if (stripos($ref, '#/components/') === 0) {
// starts with #/components/
$model = substr($ref, strrpos($ref, '/') + 1);
} elseif (stripos($ref, '#/definitions/') === 0) {
// starts with #/definitions/
$model = substr($ref, strrpos($ref, '/') + 1);
}
return $model;
}
/**
* Output the proper model name (capitalized).
* In case the name belongs to the TypeSystem it won't be renamed.
* This is recreated method of @link modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPhpCodegen.java class.
*
* @param string $name the name of the model
* @param string|null $modelNamePrefix modelNamePrefix generator option
* @param string|null $modelNameSuffix modelNameSuffix generator option
*
* @return string capitalized model name
*/
public static function toModelName(
$name,
$modelNamePrefix = {{#modelNamePrefix}}'{{modelNamePrefix}}'{{/modelNamePrefix}}{{^modelNamePrefix}}null{{/modelNamePrefix}},
$modelNameSuffix = {{#modelNameSuffix}}'{{modelNameSuffix}}'{{/modelNameSuffix}}{{^modelNameSuffix}}null{{/modelNameSuffix}}
) {
if (is_string($name) === false || empty($name)) {
return null;
}
// remove [
$name = str_replace(']', '', $name);
// Note: backslash ("\\") is allowed for e.g. "\\DateTime"
$name = preg_replace('/[^\w\\\\]+/', '_', $name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
// remove underscores from start and end
$name = trim($name, '_');
// remove dollar sign
$name = str_replace('$', '', $name);
// model name cannot use reserved keyword
if (self::isReservedWord($name)) {
$name = 'model_' . $name; // e.g. return => ModelReturn (after camelize)
}
// model name starts with number
if (preg_match('/^\d.*/', $name) === 1) {
$name = 'model_' . $name; // e.g. 200Response => Model200Response (after camelize)
}
// add prefix and/or suffic only if name does not start wth \ (e.g. \DateTime)
if (preg_match('/^\\\\.*/', $name) !== 1) {
if (is_string($modelNamePrefix) && !empty($modelNamePrefix)) {
$name = $modelNamePrefix . '_' . $name;
}
if (is_string($modelNameSuffix) && !empty($modelNameSuffix)) {
$name = $name . '_' . $modelNameSuffix;
}
}
// camelize the model name
// phone_number => PhoneNumber
return self::camelize($name);
}
}
{{/apiInfo}}

View File

@@ -0,0 +1,111 @@
<?php
/**
* {{traitNamePrefix}}ModelUtils{{traitNameSuffix}}Test
*
* PHP version 7.1
*
* @package {{invokerPackage}}
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
*/
/**{{#apiInfo}}{{#appName}}
* {{{appName}}}
*
{{/appName}}
{{#appDescription}}
* {{{appDescription}}}
{{/appDescription}}
{{#version}}
* The version of the OpenAPI document: {{{version}}}
{{/version}}
{{#infoEmail}}
* Contact: {{{infoEmail}}}
{{/infoEmail}}
* Generated by: https://github.com/openapitools/openapi-generator.git
*/
/**
* NOTE: This class is auto generated by the openapi generator program.
* https://github.com/openapitools/openapi-generator
* Do not edit the class manually.
*/
namespace {{utilsPackage}};
use {{utilsPackage}}\{{traitNamePrefix}}ModelUtils{{traitNameSuffix}} as ModelUtils;
use PHPUnit\Framework\TestCase;
/**
* {{traitNamePrefix}}ModelUtils{{traitNameSuffix}}Test Class Doc Comment
*
* @package {{utilsPackage}}
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
* @coversDefaultClass \{{utilsPackage}}\{{traitNamePrefix}}ModelUtils{{traitNameSuffix}}
*/
class {{traitNamePrefix}}ModelUtils{{traitNameSuffix}}Test extends TestCase
{
/**
* @covers ::getSimpleRef
* @dataProvider provideRefs
*/
public function testGetSimpleRef($ref, $expectedRef)
{
$this->assertSame($expectedRef, ModelUtils::getSimpleRef($ref));
}
public function provideRefs()
{
return [
'Reference Object OAS 3.0' => [
'#/components/schemas/Pet', 'Pet',
],
'Reference Object Swagger 2.0' => [
'#/definitions/Pet', 'Pet',
],
'Underscored classname' => [
'#/components/schemas/_foobar_Objects', '_foobar_Objects',
],
'Relative Documents With Embedded Schema' => [
'definitions.json#/Pet', null,
],
'null as argument' => [
null, null,
],
'number as argument' => [
156, null,
],
];
}
/**
* @covers ::toModelName
* @dataProvider provideModelNames
*/
public function testToModelName($name, $prefix, $suffix, $expectedModel)
{
$this->assertSame($expectedModel, ModelUtils::toModelName($name, $prefix, $suffix));
}
public function provideModelNames()
{
return [
// fixtures from modules/openapi-generator/src/test/java/org/openapitools/codegen/utils/StringUtilsTest.java
['abcd', null, null, 'Abcd'],
['some-value', null, null, 'SomeValue'],
['some_value', null, null, 'SomeValue'],
['$type', null, null, 'Type'],
['123', null, null, 'Model123'],
['$123', null, null, 'Model123'],
['return', null, null, 'ModelReturn'],
['200Response', null, null, 'Model200Response'],
['abcd', 'SuperModel', null, 'SuperModelAbcd'],
['abcd', null, 'WithEnd', 'AbcdWithEnd'],
['abcd', 'WithStart', 'AndEnd', 'WithStartAbcdAndEnd'],
['_foobar_Objects', null, null, 'FoobarObjects'],
[null, null, null, null],
];
}
}
{{/apiInfo}}

View File

@@ -34,6 +34,7 @@
namespace {{mockPackage}}; namespace {{mockPackage}};
use {{mockPackage}}\{{interfaceNamePrefix}}OpenApiDataMocker{{interfaceNameSuffix}} as IMocker; use {{mockPackage}}\{{interfaceNamePrefix}}OpenApiDataMocker{{interfaceNameSuffix}} as IMocker;
use StdClass;
use InvalidArgumentException; use InvalidArgumentException;
/** /**
@@ -82,6 +83,13 @@ final class OpenApiDataMocker implements IMocker
$maxItems = $options['maxItems'] ?? null; $maxItems = $options['maxItems'] ?? null;
$uniqueItems = $options['uniqueItems'] ?? false; $uniqueItems = $options['uniqueItems'] ?? false;
return $this->mockArray($items, $minItems, $maxItems, $uniqueItems); return $this->mockArray($items, $minItems, $maxItems, $uniqueItems);
case IMocker::DATA_TYPE_OBJECT:
$properties = $options['properties'] ?? null;
$minProperties = $options['minProperties'] ?? 0;
$maxProperties = $options['maxProperties'] ?? null;
$additionalProperties = $options['additionalProperties'] ?? null;
$required = $options['required'] ?? null;
return $this->mockObject($properties, $minProperties, $maxProperties, $additionalProperties, $required);
default: default:
throw new InvalidArgumentException('"dataType" must be one of ' . implode(', ', [ throw new InvalidArgumentException('"dataType" must be one of ' . implode(', ', [
IMocker::DATA_TYPE_INTEGER, IMocker::DATA_TYPE_INTEGER,
@@ -89,6 +97,7 @@ final class OpenApiDataMocker implements IMocker
IMocker::DATA_TYPE_STRING, IMocker::DATA_TYPE_STRING,
IMocker::DATA_TYPE_BOOLEAN, IMocker::DATA_TYPE_BOOLEAN,
IMocker::DATA_TYPE_ARRAY, IMocker::DATA_TYPE_ARRAY,
IMocker::DATA_TYPE_OBJECT,
])); ]));
} }
} }
@@ -220,7 +229,7 @@ final class OpenApiDataMocker implements IMocker
* Shortcut to mock array type * Shortcut to mock array type
* Equivalent to mockData(DATA_TYPE_ARRAY); * Equivalent to mockData(DATA_TYPE_ARRAY);
* *
* @param array $items Array of described items * @param object|array $items Object or assoc array of described items
* @param int|null $minItems (optional) An array instance is valid against "minItems" if its size is greater than, or equal to, the value of this keyword. * @param int|null $minItems (optional) An array instance is valid against "minItems" if its size is greater than, or equal to, the value of this keyword.
* @param int|null $maxItems (optional) An array instance is valid against "maxItems" if its size is less than, or equal to, the value of this keyword * @param int|null $maxItems (optional) An array instance is valid against "maxItems" if its size is less than, or equal to, the value of this keyword
* @param bool|null $uniqueItems (optional) If it has boolean value true, the instance validates successfully if all of its elements are unique * @param bool|null $uniqueItems (optional) If it has boolean value true, the instance validates successfully if all of its elements are unique
@@ -239,8 +248,12 @@ final class OpenApiDataMocker implements IMocker
$minSize = 0; $minSize = 0;
$maxSize = \PHP_INT_MAX; $maxSize = \PHP_INT_MAX;
if (is_array($items) === false || array_key_exists('type', $items) === false) { if (
throw new InvalidArgumentException('"items" must be assoc array with "type" key'); (is_array($items) === false && is_object($items) === false)
|| (is_array($items) && array_key_exists('type', $items) === false)
|| (is_object($items) && isset($items->type) === false)
) {
new InvalidArgumentException('"items" must be object or assoc array with "type" key');
} }
if ($minItems !== null) { if ($minItems !== null) {
@@ -260,9 +273,9 @@ final class OpenApiDataMocker implements IMocker
$maxSize = $maxItems; $maxSize = $maxItems;
} }
$dataType = $items['type'];
$dataFormat = $items['format'] ?? null;
$options = $this->extractSchemaProperties($items); $options = $this->extractSchemaProperties($items);
$dataType = $options['type'];
$dataFormat = $options['format'] ?? null;
// always genarate smallest possible array to avoid huge JSON responses // always genarate smallest possible array to avoid huge JSON responses
$arrSize = ($maxSize < 1) ? $maxSize : max($minSize, 1); $arrSize = ($maxSize < 1) ? $maxSize : max($minSize, 1);
@@ -273,17 +286,104 @@ final class OpenApiDataMocker implements IMocker
} }
/** /**
* @internal Extract OAS properties from array or object. * Shortcut to mock object type.
* Equivalent to mockData(DATA_TYPE_OBJECT);
* *
* @param array $arr Processed array * @param object|array $properties Object or array of described properties
* @param int|null $minProperties (optional) An object instance is valid against "minProperties" if its number of properties is greater than, or equal to, the value of this keyword.
* @param int|null $maxProperties (optional) An object instance is valid against "maxProperties" if its number of properties is less than, or equal to, the value of this keyword.
* @param bool|object|array|null $additionalProperties (optional) If "additionalProperties" is true, validation always succeeds.
* If "additionalProperties" is false, validation succeeds only if the instance is an object and all properties on the instance were covered by "properties" and/or "patternProperties".
* If "additionalProperties" is an object, validate the value as a schema to all of the properties that weren't validated by "properties" nor "patternProperties".
* @param array|null $required (optional) This array MUST have at least one element. Elements of this array must be strings, and MUST be unique.
* An object instance is valid if its property set contains all elements in this array value.
*
* @throws \InvalidArgumentException when invalid arguments passed
*
* @return object
*/
public function mockObject(
$properties,
$minProperties = 0,
$maxProperties = null,
$additionalProperties = null,
$required = null
) {
$obj = new StdClass();
if (is_object($properties) === false && is_array($properties) === false) {
throw new InvalidArgumentException('The value of "properties" must be an array or object');
}
foreach ($properties as $propName => $propValue) {
if (is_object($propValue) === false && is_array($propValue) === false) {
throw new InvalidArgumentException('Each value of "properties" must be an array or object');
}
}
if ($minProperties !== null) {
if (is_integer($minProperties) === false || $minProperties < 0) {
throw new InvalidArgumentException('"minProperties" must be an integer. This integer must be greater than, or equal to, 0');
}
}
if ($maxProperties !== null) {
if (is_integer($maxProperties) === false || $maxProperties < 0) {
throw new InvalidArgumentException('"maxProperties" must be an integer. This integer must be greater than, or equal to, 0.');
}
if ($maxProperties < $minProperties) {
throw new InvalidArgumentException('"maxProperties" value cannot be less than "minProperties"');
}
}
if ($additionalProperties !== null) {
if (is_bool($additionalProperties) === false && is_object($additionalProperties) === false && is_array($additionalProperties) === false) {
throw new InvalidArgumentException('The value of "additionalProperties" must be a boolean or object or array.');
}
}
if ($required !== null) {
if (
is_array($required) === false
|| count($required) > count(array_unique($required))
) {
throw new InvalidArgumentException('The value of "required" must be an array. Elements of this array must be unique.');
}
foreach ($required as $requiredPropName) {
if (is_string($requiredPropName) === false) {
throw new InvalidArgumentException('Elements of "required" array must be strings');
}
}
}
foreach ($properties as $propName => $propValue) {
$options = $this->extractSchemaProperties($propValue);
$dataType = $options['type'];
$dataFormat = $options['dataFormat'] ?? null;
$obj->$propName = $this->mock($dataType, $dataFormat, $options);
}
return $obj;
}
/**
* @internal Extract OAS properties from array or object.
* @codeCoverageIgnore
*
* @param array|object $val Processed array or object
* *
* @return array * @return array
*/ */
private function extractSchemaProperties($arr) private function extractSchemaProperties($val)
{ {
$props = []; $props = [
'type' => null,
'format' => null,
];
foreach ( foreach (
[ [
'type',
'format',
'minimum', 'minimum',
'maximum', 'maximum',
'exclusiveMinimum', 'exclusiveMinimum',
@@ -304,8 +404,10 @@ final class OpenApiDataMocker implements IMocker
'example', 'example',
] as $propName ] as $propName
) { ) {
if (array_key_exists($propName, $arr)) { if (is_array($val) && array_key_exists($propName, $val)) {
$props[$propName] = $arr[$propName]; $props[$propName] = $val[$propName];
} elseif (is_object($val) && isset($val->$propName)) {
$props[$propName] = $val->$propName;
} }
} }
return $props; return $props;
@@ -313,6 +415,7 @@ final class OpenApiDataMocker implements IMocker
/** /**
* @internal * @internal
* @codeCoverageIgnore
* *
* @return float|int * @return float|int
*/ */

View File

@@ -63,6 +63,9 @@ interface {{interfaceNamePrefix}}OpenApiDataMocker{{interfaceNameSuffix}}
/** @var string DATA_TYPE_ARRAY */ /** @var string DATA_TYPE_ARRAY */
public const DATA_TYPE_ARRAY = 'array'; public const DATA_TYPE_ARRAY = 'array';
/** @var string DATA_TYPE_OBJECT */
public const DATA_TYPE_OBJECT = 'object';
/** @var string DATA_FORMAT_INT32 Signed 32 bits */ /** @var string DATA_FORMAT_INT32 Signed 32 bits */
public const DATA_FORMAT_INT32 = 'int32'; public const DATA_FORMAT_INT32 = 'int32';
@@ -194,7 +197,7 @@ interface {{interfaceNamePrefix}}OpenApiDataMocker{{interfaceNameSuffix}}
* Shortcut to mock array type * Shortcut to mock array type
* Equivalent to mockData(DATA_TYPE_ARRAY); * Equivalent to mockData(DATA_TYPE_ARRAY);
* *
* @param array $items Array of described items * @param object|array $items Object or assoc array of described items
* @param int|null $minItems (optional) An array instance is valid against "minItems" if its size is greater than, or equal to, the value of this keyword. * @param int|null $minItems (optional) An array instance is valid against "minItems" if its size is greater than, or equal to, the value of this keyword.
* @param int|null $maxItems (optional) An array instance is valid against "maxItems" if its size is less than, or equal to, the value of this keyword * @param int|null $maxItems (optional) An array instance is valid against "maxItems" if its size is less than, or equal to, the value of this keyword
* @param bool|null $uniqueItems (optional) If it has boolean value true, the instance validates successfully if all of its elements are unique * @param bool|null $uniqueItems (optional) If it has boolean value true, the instance validates successfully if all of its elements are unique
@@ -209,5 +212,30 @@ interface {{interfaceNamePrefix}}OpenApiDataMocker{{interfaceNameSuffix}}
$maxItems = null, $maxItems = null,
$uniqueItems = false $uniqueItems = false
); );
/**
* Shortcut to mock object type.
* Equivalent to mockData(DATA_TYPE_OBJECT);
*
* @param object|array $properties Object or array of described properties
* @param int|null $minProperties (optional) An object instance is valid against "minProperties" if its number of properties is greater than, or equal to, the value of this keyword.
* @param int|null $maxProperties (optional) An object instance is valid against "maxProperties" if its number of properties is less than, or equal to, the value of this keyword.
* @param bool|object|array|null $additionalProperties (optional) If "additionalProperties" is true, validation always succeeds.
* If "additionalProperties" is false, validation succeeds only if the instance is an object and all properties on the instance were covered by "properties" and/or "patternProperties".
* If "additionalProperties" is an object, validate the value as a schema to all of the properties that weren't validated by "properties" nor "patternProperties".
* @param array|null $required (optional) This array MUST have at least one element. Elements of this array must be strings, and MUST be unique.
* An object instance is valid if its property set contains all elements in this array value.
*
* @throws \InvalidArgumentException when invalid arguments passed
*
* @return object
*/
public function mockObject(
$properties,
$minProperties = 0,
$maxProperties = null,
$additionalProperties = null,
$required = null
);
} }
{{/apiInfo}} {{/apiInfo}}

View File

@@ -37,6 +37,7 @@ use {{mockPackage}}\OpenApiDataMocker;
use {{mockPackage}}\{{interfaceNamePrefix}}OpenApiDataMocker{{interfaceNameSuffix}} as IMocker; use {{mockPackage}}\{{interfaceNamePrefix}}OpenApiDataMocker{{interfaceNameSuffix}} as IMocker;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Constraint\IsType; use PHPUnit\Framework\Constraint\IsType;
use StdClass;
/** /**
* OpenApiDataMockerTest Class Doc Comment * OpenApiDataMockerTest Class Doc Comment
@@ -55,7 +56,8 @@ class OpenApiDataMockerTest extends TestCase
public function testMockCorrectArguments($dataType, $dataFormat, $options, $expectedType) public function testMockCorrectArguments($dataType, $dataFormat, $options, $expectedType)
{ {
$mocker = new OpenApiDataMocker(); $mocker = new OpenApiDataMocker();
$this->assertInternalType($expectedType, $mocker->mock($dataType)); $data = $mocker->mock($dataType, $dataFormat, $options);
$this->assertInternalType($expectedType, $data);
} }
public function provideMockCorrectArguments() public function provideMockCorrectArguments()
@@ -65,6 +67,39 @@ class OpenApiDataMockerTest extends TestCase
[IMocker::DATA_TYPE_NUMBER, null, null, IsType::TYPE_FLOAT], [IMocker::DATA_TYPE_NUMBER, null, null, IsType::TYPE_FLOAT],
[IMocker::DATA_TYPE_STRING, null, null, IsType::TYPE_STRING], [IMocker::DATA_TYPE_STRING, null, null, IsType::TYPE_STRING],
[IMocker::DATA_TYPE_BOOLEAN, null, null, IsType::TYPE_BOOL], [IMocker::DATA_TYPE_BOOLEAN, null, null, IsType::TYPE_BOOL],
[IMocker::DATA_TYPE_ARRAY, null, [
'items' => [
'type' => IMocker::DATA_TYPE_INTEGER,
],
], IsType::TYPE_ARRAY],
[IMocker::DATA_TYPE_OBJECT, null, [
'properties' => [
'username' => [
'type' => IMocker::DATA_TYPE_INTEGER,
],
],
], IsType::TYPE_OBJECT],
];
}
/**
* @covers ::mock
* @dataProvider provideMockInvalidArguments
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage "dataType" must be one of integer, number, string, boolean, array, object
*/
public function testMockInvalidArguments($dataType, $dataFormat, $options)
{
$mocker = new OpenApiDataMocker();
$data = $mocker->mock($dataType, $dataFormat, $options);
}
public function provideMockInvalidArguments()
{
return [
['foobar', null, null],
[3.14, null, null],
[null, null, null],
]; ];
} }
@@ -440,6 +475,8 @@ class OpenApiDataMockerTest extends TestCase
$this->assertContainsOnly($expectedItemsType, $arr, true); $this->assertContainsOnly($expectedItemsType, $arr, true);
} }
if (is_array($items)) {
$dataType = $items['type'];
$dataFormat = $items['dataFormat'] ?? null; $dataFormat = $items['dataFormat'] ?? null;
// items field numeric properties // items field numeric properties
@@ -459,9 +496,33 @@ class OpenApiDataMockerTest extends TestCase
$subMinItems = $items['minItems'] ?? null; $subMinItems = $items['minItems'] ?? null;
$subMaxItems = $items['maxItems'] ?? null; $subMaxItems = $items['maxItems'] ?? null;
$subUniqueItems = $items['uniqueItems'] ?? null; $subUniqueItems = $items['uniqueItems'] ?? null;
} else {
// is object
$dataType = $items->type;
$dataFormat = $items->dataFormat ?? null;
// items field numeric properties
$minimum = $items->minimum ?? null;
$maximum = $items->maximum ?? null;
$exclusiveMinimum = $items->exclusiveMinimum ?? null;
$exclusiveMaximum = $items->exclusiveMaximum ?? null;
// items field string properties
$minLength = $items->minLength ?? null;
$maxLength = $items->maxLength ?? null;
$enum = $items->enum ?? null;
$pattern = $items->pattern ?? null;
// items field array properties
$subItems = $items->items ?? null;
$subMinItems = $items->minItems ?? null;
$subMaxItems = $items->maxItems ?? null;
$subUniqueItems = $items->uniqueItems ?? null;
}
foreach ($arr as $item) { foreach ($arr as $item) {
switch ($items['type']) { switch ($dataType) {
case IMocker::DATA_TYPE_INTEGER: case IMocker::DATA_TYPE_INTEGER:
$this->internalAssertNumber($item, $minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum); $this->internalAssertNumber($item, $minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum);
break; break;
@@ -486,13 +547,15 @@ class OpenApiDataMockerTest extends TestCase
$intItems = ['type' => IMocker::DATA_TYPE_INTEGER, 'minimum' => 5, 'maximum' => 10]; $intItems = ['type' => IMocker::DATA_TYPE_INTEGER, 'minimum' => 5, 'maximum' => 10];
$floatItems = ['type' => IMocker::DATA_TYPE_NUMBER, 'minimum' => -32.4, 'maximum' => 88.6, 'exclusiveMinimum' => true, 'exclusiveMaximum' => true]; $floatItems = ['type' => IMocker::DATA_TYPE_NUMBER, 'minimum' => -32.4, 'maximum' => 88.6, 'exclusiveMinimum' => true, 'exclusiveMaximum' => true];
$strItems = ['type' => IMocker::DATA_TYPE_STRING, 'minLength' => 20, 'maxLength' => 50]; $strItems = ['type' => IMocker::DATA_TYPE_STRING, 'minLength' => 20, 'maxLength' => 50];
$boolItems = ['type' => IMocker::DATA_TYPE_BOOLEAN]; $boolItems = (object) ['type' => IMocker::DATA_TYPE_BOOLEAN];
$arrayItems = ['type' => IMocker::DATA_TYPE_ARRAY, 'items' => ['type' => IMocker::DATA_TYPE_STRING, 'minItems' => 3, 'maxItems' => 10]]; $arrayItems = (object) ['type' => IMocker::DATA_TYPE_ARRAY, 'items' => ['type' => IMocker::DATA_TYPE_STRING, 'minItems' => 3, 'maxItems' => 10]];
$objectItems = (object) ['type' => IMocker::DATA_TYPE_OBJECT, 'properties' => (object)['username' => ['type' => IMocker::DATA_TYPE_STRING]]];
$expectedInt = IsType::TYPE_INT; $expectedInt = IsType::TYPE_INT;
$expectedFloat = IsType::TYPE_FLOAT; $expectedFloat = IsType::TYPE_FLOAT;
$expectedStr = IsType::TYPE_STRING; $expectedStr = IsType::TYPE_STRING;
$expectedBool = IsType::TYPE_BOOL; $expectedBool = IsType::TYPE_BOOL;
$expectedArray = IsType::TYPE_ARRAY; $expectedArray = IsType::TYPE_ARRAY;
$expectedObject = IsType::TYPE_OBJECT;
return [ return [
'empty array' => [ 'empty array' => [
@@ -531,6 +594,9 @@ class OpenApiDataMockerTest extends TestCase
'array of one array of strings' => [ 'array of one array of strings' => [
$arrayItems, null, null, false, $expectedArray, 1, $arrayItems, null, null, false, $expectedArray, 1,
], ],
'array of one object' => [
$objectItems, null, null, false, $expectedObject, 1
],
]; ];
} }
@@ -583,5 +649,125 @@ class OpenApiDataMockerTest extends TestCase
], ],
]; ];
} }
/**
* @dataProvider provideMockObjectCorrectArguments
* @covers ::mockObject
*/
public function testMockObjectWithCorrectArguments(
$properties,
$minProperties,
$maxProperties,
$additionalProperties,
$required,
$expectedKeys
) {
$mocker = new OpenApiDataMocker();
$obj = $mocker->mockObject(
$properties,
$minProperties,
$maxProperties,
$additionalProperties,
$required
);
$this->assertInternalType(IsType::TYPE_OBJECT, $obj);
$this->assertSame($expectedKeys, array_keys(get_object_vars($obj)));
}
public function provideMockObjectCorrectArguments()
{
$additionProps = [
'extra' => [
'type' => IMocker::DATA_TYPE_STRING,
],
];
return [
'empty object' => [
[], 1, 10, true, null, [],
],
'empty object from StdClass' => [
new StdClass(), 1, 5, false, null, [],
],
'object with username property' => [
[
'username' => [
'type' => IMocker::DATA_TYPE_STRING,
],
], 0, 5, $additionProps, null, ['username'],
],
'object with foobar property' => [
(object) [
'foobar' => [
'type' => IMocker::DATA_TYPE_INTEGER,
],
], 1, 1, (object) $additionProps, null, ['foobar'],
],
];
}
/**
* @dataProvider provideMockObjectInvalidArguments
* @expectedException \InvalidArgumentException
* @covers ::mockObject
*/
public function testMockObjectWithInvalidArguments(
$properties,
$minProperties,
$maxProperties,
$additionalProperties,
$required
) {
$mocker = new OpenApiDataMocker();
$obj = $mocker->mockObject($properties, $minProperties, $maxProperties, $additionalProperties, $required);
}
public function provideMockObjectInvalidArguments()
{
return [
'properties cannot be null' => [
null, 0, 10, false, null,
],
'properties cannot be a string' => [
'foobar', 0, 10, false, null,
],
'minProperties is not integer' => [
[], 3.12, null, false, null,
],
'minProperties is negative' => [
[], -10, null, false, null,
],
'minProperties is not number' => [
[], '1', null, false, null,
],
'maxProperties is not integer' => [
[], null, 3.12, false, null,
],
'maxProperties is negative' => [
[], null, -10, false, null,
],
'maxProperties is not number' => [
[], null, 'foobaz', false, null,
],
'maxProperties less than minProperties' => [
[], 5, 2, false, null,
],
'additionalProperties is not object|array|boolean' => [
[], null, null, 'foobar', null,
],
'required is object, not array' => [
[], null, null, null, new StdClass(),
],
'required is not array' => [
[], null, null, null, 'foobar',
],
'required array with duplicates' => [
[], null, null, null, ['username', 'username'],
],
'required array of non-strings' => [
[], null, null, null, [1, 2, 3],
],
];
}
} }
{{/apiInfo}} {{/apiInfo}}

View File

@@ -20,12 +20,16 @@
<testsuite name="Mock"> <testsuite name="Mock">
<directory>{{mockTestPath}}</directory> <directory>{{mockTestPath}}</directory>
</testsuite> </testsuite>
<testsuite name="Utils">
<directory>{{utilsTestPath}}</directory>
</testsuite>
</testsuites> </testsuites>
<filter> <filter>
<whitelist processUncoveredFilesFromWhitelist="true"> <whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">{{apiSrcPath}}</directory> <directory suffix=".php">{{apiSrcPath}}</directory>
<directory suffix=".php">{{modelSrcPath}}</directory> <directory suffix=".php">{{modelSrcPath}}</directory>
<directory suffix=".php">{{mockSrcPath}}</directory> <directory suffix=".php">{{mockSrcPath}}</directory>
<directory suffix=".php">{{utilsSrcPath}}</directory>
</whitelist> </whitelist>
</filter> </filter>
<php> <php>

View File

@@ -0,0 +1,141 @@
<?php
/**
* {{traitNamePrefix}}StringUtils{{traitNameSuffix}}
*
* PHP version 7.1
*
* @package {{invokerPackage}}
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
*/
/**{{#apiInfo}}{{#appName}}
* {{{appName}}}
*
{{/appName}}
{{#appDescription}}
* {{{appDescription}}}
{{/appDescription}}
{{#version}}
* The version of the OpenAPI document: {{{version}}}
{{/version}}
{{#infoEmail}}
* Contact: {{{infoEmail}}}
{{/infoEmail}}
* Generated by: https://github.com/openapitools/openapi-generator.git
*/
/**
* NOTE: This class is auto generated by the openapi generator program.
* https://github.com/openapitools/openapi-generator
* Do not edit the class manually.
*/
namespace {{utilsPackage}};
/**
* {{traitNamePrefix}}StringUtils{{traitNameSuffix}} Class Doc Comment
* This class duplicates functionality of StringUtils.java and AbstractPhpCodegen.java classes.
*
* @package {{utilsPackage}}
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
*/
trait {{traitNamePrefix}}StringUtils{{traitNameSuffix}}
{
/**
* Camelize name (parameter, property, method, etc)
* This is recreated method of @link modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/StringUtils.java class.
*
* @param string $word string to be camelize
* @param bool $lowercaseFirstLetter lower case for first letter if set to true
*
* @return string camelized string
*/
public static function camelize($word, $lowercaseFirstLetter = false)
{
// Replace all slashes with dots (package separator)
$p = '/\/(.?)/';
$word = preg_replace($p, '.$1', $word);
// case out dots
$parts = explode('.', $word);
$str = '';
foreach ($parts as $z) {
if (strlen($z) > 0) {
$str .= strtoupper(substr($z, 0, 1)) . substr($z, 1);
}
}
$word = $str;
// Uppercase the class name.
$p = '/(\.?)(\w)([^\.]*)$/';
$word = preg_replace_callback($p, function ($matches) {
$rep = $matches[1] . strtoupper($matches[2]) . $matches[3];
$rep = preg_replace('/\$/', '\\\$', $rep);
return $rep;
}, $word);
// Remove all underscores (underscore_case to camelCase)
$p = '/(_)(.)/';
while (preg_match($p, $word, $matches) === 1) {
$original = $matches[2][0];
$upperCase = strtoupper($original);
if ($original === $upperCase) {
$word = preg_replace($p, '$2', $word);
} else {
$word = preg_replace($p, $upperCase, $word);
}
}
// Remove all hyphens (hyphen-case to camelCase)
$p = '/(-)(.)/';
while (preg_match($p, $word, $matches) === 1) {
$upperCase = strtoupper($matches[2][0]);
$word = preg_replace($p, $upperCase, $word);
}
if ($lowercaseFirstLetter === true && strlen($word) > 0) {
$i = 0;
$charAt = substr($word, $i, 1);
while (
$i + 1 < strlen($word)
&& !(
($charAt >= 'a' && $charAt <= 'z')
|| ($charAt >= 'A' && $charAt <= 'Z')
)
) {
$i++;
$charAt = substr($word, $i, 1);
}
$i++;
$word = strtolower(substr($word, 0, $i)) . substr($word, $i);
}
// remove all underscore
$word = str_replace('_', '', $word);
return $word;
}
/**
* Checks whether string is reserved php keyword.
* This is recreated method of @link modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPhpCodegen.java class.
*
* @param string $word Checked string
*
* @return bool
*/
public static function isReservedWord($word)
{
if (is_string($word) === false) {
return false;
}
// __halt_compiler is ommited because class names with underscores not allowed anyway
return in_array(
strtolower($word),
['abstract', 'and', 'array', 'as', 'break', 'callable', 'case', 'catch', 'class', 'clone', 'const', 'continue', 'declare', 'default', 'die', 'do', 'echo', 'else', 'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile', 'eval', 'exit', 'extends', 'final', 'for', 'foreach', 'function', 'global', 'goto', 'if', 'implements', 'include', 'include_once', 'instanceof', 'insteadof', 'interface', 'isset', 'list', 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public', 'require', 'require_once', 'return', 'static', 'switch', 'throw', 'trait', 'try', 'unset', 'use', 'var', 'while', 'xor']
);
}
}
{{/apiInfo}}

View File

@@ -0,0 +1,108 @@
<?php
/**
* {{traitNamePrefix}}StringUtils{{traitNameSuffix}}Test
*
* PHP version 7.1
*
* @package {{invokerPackage}}
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
*/
/**{{#apiInfo}}{{#appName}}
* {{{appName}}}
*
{{/appName}}
{{#appDescription}}
* {{{appDescription}}}
{{/appDescription}}
{{#version}}
* The version of the OpenAPI document: {{{version}}}
{{/version}}
{{#infoEmail}}
* Contact: {{{infoEmail}}}
{{/infoEmail}}
* Generated by: https://github.com/openapitools/openapi-generator.git
*/
/**
* NOTE: This class is auto generated by the openapi generator program.
* https://github.com/openapitools/openapi-generator
* Do not edit the class manually.
*/
namespace {{utilsPackage}};
use {{utilsPackage}}\{{traitNamePrefix}}StringUtils{{traitNameSuffix}} as StringUtils;
use PHPUnit\Framework\TestCase;
/**
* {{traitNamePrefix}}StringUtils{{traitNameSuffix}}Test Class Doc Comment
*
* @package {{utilsPackage}}
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
* @coversDefaultClass \{{utilsPackage}}\{{traitNamePrefix}}StringUtils{{traitNameSuffix}}
*/
class {{traitNamePrefix}}StringUtils{{traitNameSuffix}}Test extends TestCase
{
/**
* @covers ::camelize
* @dataProvider provideWordsForCamelizeTest
*/
public function testCamelize($word, $lowercaseFirstLetter, $expectedWord)
{
$this->assertSame($expectedWord, StringUtils::camelize($word, $lowercaseFirstLetter));
}
public function provideWordsForCamelizeTest()
{
return [
// fixtures from modules/openapi-generator/src/test/java/org/openapitools/codegen/utils/StringUtilsTest.java
['openApiServer/model/pet', null, 'OpenApiServerModelPet'],
['abcd', null, 'Abcd'],
['some-value', null, 'SomeValue'],
['some-Value', null, 'SomeValue'],
['some_value', null, 'SomeValue'],
['some_Value', null, 'SomeValue'],
['$type', null, '$Type'],
['abcd', true, 'abcd'],
['some-value', true, 'someValue'],
['some_value', true, 'someValue'],
['Abcd', true, 'abcd'],
['$type', true, '$type'],
['123', true, '123'],
['$123', true, '$123'],
];
}
/**
* @covers ::isReservedWord
* @dataProvider provideWordsForIsReservedTest
*/
public function testisReservedWord($word, $expected)
{
$this->assertSame($expected, StringUtils::isReservedWord($word));
}
public function provideWordsForIsReservedTest()
{
return [
['return', true],
['switch', true],
['class', true],
['interface', true],
['ABSTRACT', true],
['Trait', true],
['final', true],
['foobar', false],
['DateTime', false],
['Pet', false],
[123, false],
[null, false],
];
}
}
{{/apiInfo}}

View File

@@ -0,0 +1,66 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
venv/
.venv/
.python-version
.pytest_cache
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
#Ipython Notebook
.ipynb_checkpoints

View File

@@ -1,6 +1,13 @@
{{#useNose}}
coverage>=4.0.3 coverage>=4.0.3
pytest>=1.3.7 nose>=1.3.7
pluggy>=0.3.1 pluggy>=0.3.1
py>=1.4.31 py>=1.4.31
randomize>=0.13 randomize>=0.13
{{/useNose}}
{{^useNose}}
pytest~=4.6.7 # needed for python 2.7+3.4
pytest-cov>=2.8.1
pytest-randomly==1.2.3 # needed for python 2.7+3.4
pytest-aiohttp>=0.3.0 pytest-aiohttp>=0.3.0
{{/useNose}}

View File

@@ -0,0 +1,10 @@
[tox]
envlist = py3
skipsdist=True
[testenv]
deps=-r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
commands=
{{^useNose}}pytest --cov={{{packageName}}}{{/useNose}}{{#useNose}}nosetests{{/useNose}}

View File

@@ -46,6 +46,7 @@ coverage.xml
.hypothesis/ .hypothesis/
venv/ venv/
.python-version .python-version
.pytest_cache
# Translations # Translations
*.mo *.mo

View File

@@ -1,6 +1,13 @@
flask_testing==0.6.1 {{#useNose}}
coverage>=4.0.3 coverage>=4.0.3
nose>=1.3.7 nose>=1.3.7
pluggy>=0.3.1 pluggy>=0.3.1
py>=1.4.31 py>=1.4.31
randomize>=0.13 randomize>=0.13
{{/useNose}}
{{^useNose}}
pytest~=4.6.7 # needed for python 2.7+3.4
pytest-cov>=2.8.1
pytest-randomly==1.2.3 # needed for python 2.7+3.4
{{/useNose}}
flask_testing==0.6.1

View File

@@ -6,5 +6,4 @@ deps=-r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt -r{toxinidir}/test-requirements.txt
commands= commands=
nosetests \ {{^useNose}}pytest --cov={{{packageName}}}{{/useNose}}{{#useNose}}nosetests{{/useNose}}
[]

View File

@@ -45,7 +45,9 @@ coverage.xml
*,cover *,cover
.hypothesis/ .hypothesis/
venv/ venv/
.venv/
.python-version .python-version
.pytest_cache
# Translations # Translations
*.mo *.mo

View File

@@ -1,4 +1,7 @@
connexion >= 2.0.2 connexion >= 2.5.0; python_version>="3.6"
connexion >= 2.3.0; python_version=="3.5"
connexion >= 2.3.0; python_version=="3.4"
connexion == 2.4.0; python_version<="2.7"
swagger-ui-bundle >= 0.0.2 swagger-ui-bundle >= 0.0.2
python_dateutil >= 2.6.0 python_dateutil >= 2.6.0
{{#supportPython2}} {{#supportPython2}}

View File

@@ -1,6 +1,13 @@
flask_testing==0.6.1 {{#useNose}}
coverage>=4.0.3 coverage>=4.0.3
nose>=1.3.7 nose>=1.3.7
pluggy>=0.3.1 pluggy>=0.3.1
py>=1.4.31 py>=1.4.31
randomize>=0.13 randomize>=0.13
{{/useNose}}
{{^useNose}}
pytest~=4.6.7 # needed for python 2.7+3.4
pytest-cov>=2.8.1
pytest-randomly==1.2.3 # needed for python 2.7+3.4
{{/useNose}}
flask_testing==0.6.1

View File

@@ -6,5 +6,4 @@ deps=-r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt -r{toxinidir}/test-requirements.txt
commands= commands=
nosetests \ {{^useNose}}pytest --cov={{{packageName}}}{{/useNose}}{{#useNose}}nosetests{{/useNose}}
[]

View File

@@ -45,7 +45,9 @@ coverage.xml
*,cover *,cover
.hypothesis/ .hypothesis/
venv/ venv/
.venv/
.python-version .python-version
.pytest_cache
# Translations # Translations
*.mo *.mo

View File

@@ -1,13 +1,13 @@
{{^asyncio}} {{#useNose}}
coverage>=4.0.3 coverage>=4.0.3
nose>=1.3.7 nose>=1.3.7
{{/asyncio}}
{{#asyncio}}
pytest>=3.6.0
pytest-cov>=2.6.1
{{/asyncio}}
pluggy>=0.3.1 pluggy>=0.3.1
py>=1.4.31 py>=1.4.31
randomize>=0.13 randomize>=0.13
{{/useNose}}
{{^useNose}}
pytest~=4.6.7 # needed for python 2.7+3.4
pytest-cov>=2.8.1
pytest-randomly==1.2.3 # needed for python 2.7+3.4
{{/useNose}}
mock; python_version<="2.7" mock; python_version<="2.7"

View File

@@ -0,0 +1,13 @@
{{#useNose}}
[nosetests]
logging-clear-handlers=true
verbosity=2
randomize=true
exe=true
with-coverage=true
cover-package=petstore_api
cover-erase=true
{{/useNose}}
[flake8]
max-line-length=99

View File

@@ -1,11 +1,12 @@
{{^asyncio}} {{#useNose}}
coverage>=4.0.3 coverage>=4.0.3
nose>=1.3.7 nose>=1.3.7
{{/asyncio}}
{{#asyncio}}
pytest>=3.6.0
pytest-cov>=2.6.1
{{/asyncio}}
pluggy>=0.3.1 pluggy>=0.3.1
py>=1.4.31 py>=1.4.31
randomize>=0.13 randomize>=0.13
{{/useNose}}
{{^useNose}}
pytest~=4.6.7 # needed for python 2.7+3.4
pytest-cov>=2.8.1
pytest-randomly==1.2.3 # needed for python 2.7+3.4
{{/useNose}}

View File

@@ -11,10 +11,4 @@ deps=-r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt -r{toxinidir}/test-requirements.txt
commands= commands=
{{^asyncio}} {{^useNose}}pytest --cov={{{packageName}}}{{/useNose}}{{#useNose}}nosetests{{/useNose}}
nosetests \
[]
{{/asyncio}}
{{#asyncio}}
pytest -v --cov {{{packageName}}}
{{/asyncio}}

View File

@@ -18,7 +18,7 @@ conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }
futures = "0.1" futures = "0.1"
swagger = "2" swagger = "2"
lazy_static = "0.2" lazy_static = "1.4"
log = "0.3.0" log = "0.3.0"
mime = "0.2.6" mime = "0.2.6"
multipart = "0.13.3" multipart = "0.13.3"

View File

@@ -86,7 +86,7 @@ fn into_base_path(input: &str, correct_scheme: Option<&'static str>) -> Result<S
/// A client that implements the API by making HTTP calls out to a server. /// A client that implements the API by making HTTP calls out to a server.
pub struct Client<F> where pub struct Client<F> where
F: Future<Item=hyper::Response, Error=hyper::Error> + 'static { F: Future<Item=hyper::Response, Error=hyper::Error> + 'static {
client_service: Arc<Box<hyper::client::Service<Request=hyper::Request<hyper::Body>, Response=hyper::Response, Error=hyper::Error, Future=F>>>, client_service: Arc<Box<dyn hyper::client::Service<Request=hyper::Request<hyper::Body>, Response=hyper::Response, Error=hyper::Error, Future=F>>>,
base_path: String, base_path: String,
} }
@@ -197,7 +197,7 @@ impl Client<hyper::client::FutureResponse> {
handle: Handle, handle: Handle,
base_path: &str, base_path: &str,
protocol: Option<&'static str>, protocol: Option<&'static str>,
connector_fn: Box<Fn(&Handle) -> C + Send + Sync>, connector_fn: Box<dyn Fn(&Handle) -> C + Send + Sync>,
) -> Result<Client<hyper::client::FutureResponse>, ClientInitError> ) -> Result<Client<hyper::client::FutureResponse>, ClientInitError>
where where
C: hyper::client::Connect + hyper::client::Service, C: hyper::client::Connect + hyper::client::Service,
@@ -224,7 +224,7 @@ impl Client<hyper::client::FutureResponse> {
/// should be mentioned here. /// should be mentioned here.
#[deprecated(note="Use try_new_with_client_service instead")] #[deprecated(note="Use try_new_with_client_service instead")]
pub fn try_new_with_hyper_client( pub fn try_new_with_hyper_client(
hyper_client: Arc<Box<hyper::client::Service<Request=hyper::Request<hyper::Body>, Response=hyper::Response, Error=hyper::Error, Future=hyper::client::FutureResponse>>>, hyper_client: Arc<Box<dyn hyper::client::Service<Request=hyper::Request<hyper::Body>, Response=hyper::Response, Error=hyper::Error, Future=hyper::client::FutureResponse>>>,
handle: Handle, handle: Handle,
base_path: &str base_path: &str
) -> Result<Client<hyper::client::FutureResponse>, ClientInitError> ) -> Result<Client<hyper::client::FutureResponse>, ClientInitError>
@@ -242,7 +242,7 @@ impl<F> Client<F> where
/// Constructor for creating a `Client` by passing in a pre-made `hyper` client Service. /// Constructor for creating a `Client` by passing in a pre-made `hyper` client Service.
/// ///
/// This allows adding custom wrappers around the underlying transport, for example for logging. /// This allows adding custom wrappers around the underlying transport, for example for logging.
pub fn try_new_with_client_service(client_service: Arc<Box<hyper::client::Service<Request=hyper::Request<hyper::Body>, Response=hyper::Response, Error=hyper::Error, Future=F>>>, pub fn try_new_with_client_service(client_service: Arc<Box<dyn hyper::client::Service<Request=hyper::Request<hyper::Body>, Response=hyper::Response, Error=hyper::Error, Future=F>>>,
handle: Handle, handle: Handle,
base_path: &str) base_path: &str)
-> Result<Client<F>, ClientInitError> -> Result<Client<F>, ClientInitError>
@@ -258,7 +258,7 @@ impl<F, C> Api<C> for Client<F> where
F: Future<Item=hyper::Response, Error=hyper::Error> + 'static, F: Future<Item=hyper::Response, Error=hyper::Error> + 'static,
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<AuthData>>{{/hasAuthMethods}}{ C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<AuthData>>{{/hasAuthMethods}}{
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}} {{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(&self{{#allParams}}, param_{{{paramName}}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}, context: &C) -> Box<Future<Item={{{operationId}}}Response, Error=ApiError>> { fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(&self{{#allParams}}, param_{{{paramName}}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}, context: &C) -> Box<dyn Future<Item={{{operationId}}}Response, Error=ApiError>> {
let mut uri = format!( let mut uri = format!(
"{}{{{basePathWithoutHost}}}{{path}}", "{}{{{basePathWithoutHost}}}{{path}}",
self.base_path{{#pathParams}}, {{{baseName}}}=utf8_percent_encode(&param_{{{paramName}}}.to_string(), ID_ENCODE_SET){{/pathParams}} self.base_path{{#pathParams}}, {{{baseName}}}=utf8_percent_encode(&param_{{{paramName}}}.to_string(), ID_ENCODE_SET){{/pathParams}}
@@ -269,7 +269,7 @@ impl<F, C> Api<C> for Client<F> where
{{^required}} if let Some({{{paramName}}}) = param_{{{paramName}}} { {{^required}} if let Some({{{paramName}}}) = param_{{{paramName}}} {
query_string.append_pair("{{{baseName}}}", &{{{paramName}}}{{#isListContainer}}.join(","){{/isListContainer}}{{^isListContainer}}.to_string(){{/isListContainer}}); query_string.append_pair("{{{baseName}}}", &{{{paramName}}}{{#isListContainer}}.join(","){{/isListContainer}}{{^isListContainer}}.to_string(){{/isListContainer}});
}{{/required}}{{/queryParams}} }{{/required}}{{/queryParams}}
{{#authMethods}}{{#isApiKey}}{{#isKeyInQuery}} if let Some(auth_data) = (context as &Has<Option<AuthData>>).get().as_ref() { {{#authMethods}}{{#isApiKey}}{{#isKeyInQuery}} if let Some(auth_data) = (context as &dyn Has<Option<AuthData>>).get().as_ref() {
if let AuthData::ApiKey(ref api_key) = *auth_data { if let AuthData::ApiKey(ref api_key) = *auth_data {
query_string.append_pair("{{keyParamName}}", api_key); query_string.append_pair("{{keyParamName}}", api_key);
} }
@@ -416,10 +416,10 @@ impl<F, C> Api<C> for Client<F> where
{{/consumesMultipart}} {{/consumesMultipart}}
{{/vendorExtensions}} {{/vendorExtensions}}
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone())); request.headers_mut().set(XSpanId((context as &dyn Has<XSpanIdString>).get().0.clone()));
{{#vendorExtensions.hasHeaderAuthMethods}} {{#vendorExtensions.hasHeaderAuthMethods}}
(context as &Has<Option<AuthData>>).get().as_ref().map(|auth_data| { (context as &dyn Has<Option<AuthData>>).get().as_ref().map(|auth_data| {
// Currently only authentication with Basic, API Key, and Bearer are supported // Currently only authentication with Basic, API Key, and Bearer are supported
match auth_data { match auth_data {
{{#authMethods}} {{#authMethods}}
@@ -480,7 +480,7 @@ impl<F, C> Api<C> for Client<F> where
{{#headers}} header! { (Response{{{nameInCamelCase}}}, "{{{baseName}}}") => [{{{datatype}}}] } {{#headers}} header! { (Response{{{nameInCamelCase}}}, "{{{baseName}}}") => [{{{datatype}}}] }
let response_{{{name}}} = match response.headers().get::<Response{{{nameInCamelCase}}}>() { let response_{{{name}}} = match response.headers().get::<Response{{{nameInCamelCase}}}>() {
Some(response_{{{name}}}) => response_{{{name}}}.0.clone(), Some(response_{{{name}}}) => response_{{{name}}}.0.clone(),
None => return Box::new(future::err(ApiError(String::from("Required response header {{{baseName}}} for response {{{code}}} was not found.")))) as Box<Future<Item=_, Error=_>>, None => return Box::new(future::err(ApiError(String::from("Required response header {{{baseName}}} for response {{{code}}} was not found.")))) as Box<dyn Future<Item=_, Error=_>>,
}; };
{{/headers}} {{/headers}}
let body = response.body(); let body = response.body();
@@ -491,23 +491,29 @@ impl<F, C> Api<C> for Client<F> where
.map_err(|e| ApiError(format!("Failed to read response: {}", e))) .map_err(|e| ApiError(format!("Failed to read response: {}", e)))
.and_then(|body| .and_then(|body|
{{#vendorExtensions}} {{#vendorExtensions}}
{{#producesPlainText}} {{#producesBytes}}
Ok(swagger::ByteArray(body.to_vec())) Ok(swagger::ByteArray(body.to_vec()))
{{/producesPlainText}}{{^producesPlainText}} {{/producesBytes}}
{{^producesBytes}}
str::from_utf8(&body) str::from_utf8(&body)
.map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e))) .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))
.and_then(|body| .and_then(|body|
{{#producesXml}} {{#producesXml}}
// ToDo: this will move to swagger-rs and become a standard From conversion trait // ToDo: this will move to swagger-rs and become a standard From conversion trait
// once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream // once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream
serde_xml_rs::from_str::<{{{dataType}}}>(body) serde_xml_rs::from_str::<{{{dataType}}}>(body)
.map_err(|e| ApiError(format!("Response body did not match the schema: {}", e))) .map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))
{{/producesXml}}{{#producesJson}} {{/producesXml}}
{{#producesJson}}
serde_json::from_str::<{{{dataType}}}>(body) serde_json::from_str::<{{{dataType}}}>(body)
.map_err(|e| e.into()) .map_err(|e| e.into())
{{/producesJson}} {{/producesJson}}
{{#producesPlainText}}
Ok(body.to_string())
{{/producesPlainText}}
) )
{{/producesPlainText}}{{/vendorExtensions}} {{/producesBytes}}
{{/vendorExtensions}}
) )
.map(move |body| { .map(move |body| {
{{{operationId}}}Response::{{#vendorExtensions}}{{x-responseId}}{{/vendorExtensions}}{{^headers}}(body){{/headers}}{{#headers}}{{#-first}}{ body: body, {{/-first}}{{{name}}}: response_{{{name}}}{{^-last}}, {{/-last}}{{#-last}} }{{/-last}}{{/headers}} {{{operationId}}}Response::{{#vendorExtensions}}{{x-responseId}}{{/vendorExtensions}}{{^headers}}(body){{/headers}}{{#headers}}{{#-first}}{ body: body, {{/-first}}{{{name}}}: response_{{{name}}}{{^-last}}, {{/-last}}{{#-last}} }{{/-last}}{{/headers}}
@@ -526,7 +532,7 @@ impl<F, C> Api<C> for Client<F> where
{{/headers}} {{/headers}}
) )
{{/dataType}} {{/dataType}}
) as Box<Future<Item=_, Error=_>> ) as Box<dyn Future<Item=_, Error=_>>
}, },
{{/responses}} {{/responses}}
code => { code => {
@@ -546,7 +552,7 @@ impl<F, C> Api<C> for Client<F> where
Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), Err(e) => Cow::from(format!("<Failed to read body: {}>", e)),
}))) })))
) )
) as Box<Future<Item=_, Error=_>> ) as Box<dyn Future<Item=_, Error=_>>
} }
} }
})) }))
@@ -577,7 +583,7 @@ impl From<openssl::error::ErrorStack> for ClientInitError {
impl fmt::Display for ClientInitError { impl fmt::Display for ClientInitError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(self as &fmt::Debug).fmt(f) (self as &dyn fmt::Debug).fmt(f)
} }
} }

View File

@@ -72,7 +72,7 @@ fn main() {
{{#vendorExtensions}}{{#noClientExample}}// Disabled because there's no example. {{#vendorExtensions}}{{#noClientExample}}// Disabled because there's no example.
// {{/noClientExample}}Some("{{{operationId}}}") => { // {{/noClientExample}}Some("{{{operationId}}}") => {
{{#noClientExample}}// {{/noClientExample}} let result = core.run(client.{{{operation_id}}}{{/vendorExtensions}}({{#allParams}}{{^-first}}, {{/-first}}{{#vendorExtensions}}{{{example}}}{{/vendorExtensions}}{{/allParams}})); {{#noClientExample}}// {{/noClientExample}} let result = core.run(client.{{{operation_id}}}{{/vendorExtensions}}({{#allParams}}{{^-first}}, {{/-first}}{{#vendorExtensions}}{{{example}}}{{/vendorExtensions}}{{/allParams}}));
{{#vendorExtensions}}{{#noClientExample}}// {{/noClientExample}}{{/vendorExtensions}} println!("{:?} (X-Span-ID: {:?})", result, (client.context() as &Has<XSpanIdString>).get().clone()); {{#vendorExtensions}}{{#noClientExample}}// {{/noClientExample}}{{/vendorExtensions}} println!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has<XSpanIdString>).get().clone());
{{#vendorExtensions}}{{#noClientExample}}// {{/noClientExample}}{{/vendorExtensions}} }, {{#vendorExtensions}}{{#noClientExample}}// {{/noClientExample}}{{/vendorExtensions}} },
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} {{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
_ => { _ => {

View File

@@ -31,7 +31,7 @@ impl<C> Server<C> {
impl<C> Api<C> for Server<C> where C: Has<XSpanIdString>{ impl<C> Api<C> for Server<C> where C: Has<XSpanIdString>{
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}} {{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
{{#summary}} /// {{{summary}}}{{/summary}} {{#summary}} /// {{{summary}}}{{/summary}}
fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(&self{{#allParams}}, {{{paramName}}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}, context: &C) -> Box<Future<Item={{{operationId}}}Response, Error=ApiError>> { fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(&self{{#allParams}}, {{{paramName}}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}, context: &C) -> Box<dyn Future<Item={{{operationId}}}Response, Error=ApiError>> {
let context = context.clone(); let context = context.clone();
println!("{{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}({{#allParams}}{{#vendorExtensions}}{{{formatString}}}{{/vendorExtensions}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) - X-Span-ID: {:?}"{{#allParams}}, {{{paramName}}}{{/allParams}}, context.get().0.clone());{{#allParams}}{{/allParams}} println!("{{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}({{#allParams}}{{#vendorExtensions}}{{{formatString}}}{{/vendorExtensions}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) - X-Span-ID: {:?}"{{#allParams}}, {{{paramName}}}{{/allParams}}, context.get().0.clone());{{#allParams}}{{/allParams}}
Box::new(futures::failed("Generic failure".into())) Box::new(futures::failed("Generic failure".into()))

View File

@@ -92,7 +92,7 @@ pub enum {{{operationId}}}Response {
pub trait Api<C> { pub trait Api<C> {
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}} {{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
{{#summary}} /// {{{summary}}}{{/summary}} {{#summary}} /// {{{summary}}}{{/summary}}
fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(&self{{#allParams}}, {{{paramName}}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}, context: &C) -> Box<Future<Item={{{operationId}}}Response, Error=ApiError>>; fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(&self{{#allParams}}, {{{paramName}}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}, context: &C) -> Box<dyn Future<Item={{{operationId}}}Response, Error=ApiError>>;
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} {{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
} }
@@ -100,7 +100,7 @@ pub trait Api<C> {
pub trait ApiNoContext { pub trait ApiNoContext {
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}} {{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
{{#summary}} /// {{{summary}}}{{/summary}} {{#summary}} /// {{{summary}}}{{/summary}}
fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(&self{{#allParams}}, {{{paramName}}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}) -> Box<Future<Item={{{operationId}}}Response, Error=ApiError>>; fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(&self{{#allParams}}, {{{paramName}}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}) -> Box<dyn Future<Item={{{operationId}}}Response, Error=ApiError>>;
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} {{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
} }
@@ -119,7 +119,7 @@ impl<'a, T: Api<C> + Sized, C> ContextWrapperExt<'a, C> for T {
impl<'a, T: Api<C>, C> ApiNoContext for ContextWrapper<'a, T, C> { impl<'a, T: Api<C>, C> ApiNoContext for ContextWrapper<'a, T, C> {
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}} {{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
{{#summary}} /// {{{summary}}}{{/summary}} {{#summary}} /// {{{summary}}}{{/summary}}
fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(&self{{#allParams}}, {{{paramName}}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}) -> Box<Future<Item={{{operationId}}}Response, Error=ApiError>> { fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(&self{{#allParams}}, {{{paramName}}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}) -> Box<dyn Future<Item={{{operationId}}}Response, Error=ApiError>> {
self.api().{{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}({{#allParams}}{{{paramName}}}, {{/allParams}}&self.context()) self.api().{{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}({{#allParams}}{{{paramName}}}, {{/allParams}}&self.context())
} }
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} {{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}

View File

@@ -7,7 +7,7 @@ pub mod responses {
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}{{#responses}}{{#produces}}{{#-first}}{{#dataType}} {{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}{{#responses}}{{#produces}}{{#-first}}{{#dataType}}
lazy_static! { lazy_static! {
/// Create Mime objects for the response content types for {{{operationId}}} /// Create Mime objects for the response content types for {{{operationId}}}
pub static ref {{#vendorExtensions}}{{{uppercase_operation_id}}}_{{x-uppercaseResponseId}}{{/vendorExtensions}}: Mime = "{{{mediaType}}}".parse().unwrap(); pub static ref {{#vendorExtensions}}{{{uppercase_operation_id}}}_{{x-uppercaseResponseId}}: Mime = "{{{mimeType}}}".parse().unwrap();{{/vendorExtensions}}
} }
{{/dataType}}{{/-first}}{{/produces}}{{/responses}}{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} {{/dataType}}{{/-first}}{{/produces}}{{/responses}}{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
} }

View File

@@ -128,7 +128,7 @@ where
type Request = (Request, C); type Request = (Request, C);
type Response = Response; type Response = Response;
type Error = Error; type Error = Error;
type Future = Box<Future<Item=Response, Error=Error>>; type Future = Box<dyn Future<Item=Response, Error=Error>>;
fn call(&self, (req, mut context): Self::Request) -> Self::Future { fn call(&self, (req, mut context): Self::Request) -> Self::Future {
let api_impl = self.api_impl.clone(); let api_impl = self.api_impl.clone();
@@ -143,7 +143,7 @@ where
&hyper::Method::{{vendorExtensions.HttpMethod}} if path.matched(paths::ID_{{vendorExtensions.PATH_ID}}) => { &hyper::Method::{{vendorExtensions.HttpMethod}} if path.matched(paths::ID_{{vendorExtensions.PATH_ID}}) => {
{{#hasAuthMethods}} {{#hasAuthMethods}}
{ {
let authorization = match (&context as &Has<Option<Authorization>>).get() { let authorization = match (&context as &dyn Has<Option<Authorization>>).get() {
&Some(ref authorization) => authorization, &Some(ref authorization) => authorization,
&None => return Box::new(future::ok(Response::new() &None => return Box::new(future::ok(Response::new()
.with_status(StatusCode::Forbidden) .with_status(StatusCode::Forbidden)
@@ -257,7 +257,7 @@ where
// values, rather than causing a 400 response). Produce warning header and logs for // values, rather than causing a 400 response). Produce warning header and logs for
// any unused fields. // any unused fields.
Box::new(body.concat2() Box::new(body.concat2()
.then(move |result| -> Box<Future<Item=Response, Error=Error>> { .then(move |result| -> Box<dyn Future<Item=Response, Error=Error>> {
match result { match result {
Ok(body) => { Ok(body) => {
{{#vendorExtensions}} {{#vendorExtensions}}
@@ -313,7 +313,7 @@ where
// values, rather than causing a 400 response). Produce warning header and logs for // values, rather than causing a 400 response). Produce warning header and logs for
// any unused fields. // any unused fields.
Box::new(body.concat2() Box::new(body.concat2()
.then(move |result| -> Box<Future<Item=Response, Error=Error>> { .then(move |result| -> Box<dyn Future<Item=Response, Error=Error>> {
match result { match result {
Ok(body) => { Ok(body) => {
// Read Form Parameters from body // Read Form Parameters from body
@@ -404,7 +404,7 @@ where
Box::new(api_impl.{{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}({{#allParams}}param_{{{paramName}}}{{#isListContainer}}.as_ref(){{/isListContainer}}, {{/allParams}}&context) Box::new(api_impl.{{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}({{#allParams}}param_{{{paramName}}}{{#isListContainer}}.as_ref(){{/isListContainer}}, {{/allParams}}&context)
.then(move |result| { .then(move |result| {
let mut response = Response::new(); let mut response = Response::new();
response.headers_mut().set(XSpanId((&context as &Has<XSpanIdString>).get().0.to_string())); response.headers_mut().set(XSpanId((&context as &dyn Has<XSpanIdString>).get().0.to_string()));
{{#bodyParams}}{{#vendorExtensions}}{{^consumesPlainText}} {{#bodyParams}}{{#vendorExtensions}}{{^consumesPlainText}}
if !unused_elements.is_empty() { if !unused_elements.is_empty() {
response.headers_mut().set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); response.headers_mut().set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements)));
@@ -444,18 +444,28 @@ where
response.headers_mut().set(ContentType(mimetypes::responses::{{#vendorExtensions}}{{{uppercase_operation_id}}}_{{x-uppercaseResponseId}}{{/vendorExtensions}}.clone())); response.headers_mut().set(ContentType(mimetypes::responses::{{#vendorExtensions}}{{{uppercase_operation_id}}}_{{x-uppercaseResponseId}}{{/vendorExtensions}}.clone()));
{{/dataType}}{{/-first}}{{/produces}} {{/dataType}}{{/-first}}{{/produces}}
{{#dataType}} {{#dataType}}
{{#vendorExtensions}}{{#producesXml}}{{^has_namespace}} {{#vendorExtensions}}
{{#producesXml}}
{{^has_namespace}}
let body = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); let body = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize");
{{/has_namespace}}{{#has_namespace}} {{/has_namespace}}
{{#has_namespace}}
let mut namespaces = BTreeMap::new(); let mut namespaces = BTreeMap::new();
// An empty string is used to indicate a global namespace in xmltree. // An empty string is used to indicate a global namespace in xmltree.
namespaces.insert("".to_string(), {{{dataType}}}::NAMESPACE.to_string()); namespaces.insert("".to_string(), {{{dataType}}}::NAMESPACE.to_string());
let body = serde_xml_rs::to_string_with_namespaces(&body, namespaces).expect("impossible to fail to serialize"); let body = serde_xml_rs::to_string_with_namespaces(&body, namespaces).expect("impossible to fail to serialize");
{{/has_namespace}}{{/producesXml}}{{#producesJson}} {{/has_namespace}}
{{/producesXml}}
{{#producesJson}}
let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); let body = serde_json::to_string(&body).expect("impossible to fail to serialize");
{{/producesJson}}{{#producesPlainText}} {{/producesJson}}
{{#producesBytes}}
let body = body.0; let body = body.0;
{{/producesPlainText}}{{/vendorExtensions}} {{/producesBytes}}
{{#producesPlainText}}
let body = body;
{{/producesPlainText}}
{{/vendorExtensions}}
response.set_body(body); response.set_body(body);
{{/dataType}} {{/dataType}}
}, },
@@ -476,7 +486,7 @@ where
{{^consumesMultipart}} {{^consumesMultipart}}
{{^bodyParams}} {{^bodyParams}}
}} }}
}) as Box<Future<Item=Response, Error=Error>> }) as Box<dyn Future<Item=Response, Error=Error>>
{{/bodyParams}} {{/bodyParams}}
{{/consumesMultipart}} {{/consumesMultipart}}
{{/vendorExtensions}} {{/vendorExtensions}}
@@ -486,13 +496,13 @@ where
Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter {{{baseName}}}: {}", e)))), Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter {{{baseName}}}: {}", e)))),
} }
}) })
) as Box<Future<Item=Response, Error=Error>> ) as Box<dyn Future<Item=Response, Error=Error>>
{{/-first}} {{/-first}}
{{/bodyParams}} {{/bodyParams}}
{{#vendorExtensions}} {{#vendorExtensions}}
{{#consumesMultipart}} {{#consumesMultipart}}
{{^bodyParams}} {{^bodyParams}}
as Box<Future<Item=Response, Error=Error>> as Box<dyn Future<Item=Response, Error=Error>>
}, },
Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read multipart body")))), Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read multipart body")))),
} }
@@ -503,7 +513,7 @@ where
{{/vendorExtensions}} {{/vendorExtensions}}
}, },
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} {{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
_ => Box::new(future::ok(Response::new().with_status(StatusCode::NotFound))) as Box<Future<Item=Response, Error=Error>>, _ => Box::new(future::ok(Response::new().with_status(StatusCode::NotFound))) as Box<dyn Future<Item=Response, Error=Error>>,
} }
} }
} }

View File

@@ -488,6 +488,7 @@ public class DefaultCodegenTest {
test.setPropertyBaseName("className"); test.setPropertyBaseName("className");
test.getMappedModels().add(new CodegenDiscriminator.MappedModel("Dog", "Dog")); test.getMappedModels().add(new CodegenDiscriminator.MappedModel("Dog", "Dog"));
test.getMappedModels().add(new CodegenDiscriminator.MappedModel("Cat", "Cat")); test.getMappedModels().add(new CodegenDiscriminator.MappedModel("Cat", "Cat"));
test.getMappedModels().add(new CodegenDiscriminator.MappedModel("BigCat", "BigCat"));
Assert.assertEquals(discriminator, test); Assert.assertEquals(discriminator, test);
} }

View File

@@ -22,7 +22,7 @@ import org.testng.annotations.Test;
import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.OpenAPI;
/** check against ping.yaml spec. */ /** unit test asciidoc markup generation against ping.yaml openapi spec. */
public class AsciidocGeneratorTest { public class AsciidocGeneratorTest {
private static final Logger LOGGER = LoggerFactory.getLogger(AsciidocGeneratorTest.class); private static final Logger LOGGER = LoggerFactory.getLogger(AsciidocGeneratorTest.class);
@@ -114,4 +114,40 @@ public class AsciidocGeneratorTest {
} }
@Test
public void testHeaderAttributesFlagRemovesAttributesFromMarkupHeaderSection() throws Exception {
File output = Files.createTempDirectory("test").toFile();
LOGGER.info("test: generating sample markup " + output.getAbsolutePath());
Map<String, Object> props = new TreeMap<String, Object>();
props.put("specDir", "spec");
final CodegenConfigurator configurator = new CodegenConfigurator()
.setGeneratorName("asciidoc")
.setInputSpec("src/test/resources/3_0/ping.yaml")
.setOutputDir(output.getAbsolutePath())
.addAdditionalProperty(AsciidocDocumentationCodegen.HEADER_ATTRIBUTES_FLAG, "false") // option avoids generation of attributes
.addAdditionalProperty(AsciidocDocumentationCodegen.SPEC_DIR, "SPEC-DIR")
.addAdditionalProperty(AsciidocDocumentationCodegen.SNIPPET_DIR, "MY/SNIPPET/DIR");
DefaultGenerator generator = new DefaultGenerator();
boolean markupFileGenerated = false;
List<File> files = generator.opts(configurator.toClientOptInput()).generate();
for (File file : files) {
if (file.getName().equals("index.adoc")) {
markupFileGenerated = true;
String markupContent = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
Assert.assertFalse(markupContent.contains(":specDir: SPEC-DIR"),
"not expected :specDir: in: " + markupContent.substring(0, 250));
Assert.assertFalse(markupContent.contains(":snippetDir: MY/SNIPPET/DIR"),
"not expected :snippetDir: in: " + markupContent.substring(0, 250));
Assert.assertFalse(markupContent.contains(":toc:"),
"not expected :toc: in: " + markupContent.substring(0, 250)); // typical attributes not found in markup.
}
}
Assert.assertTrue(markupFileGenerated, "index.adoc is not generated!");
}
} }

View File

@@ -52,6 +52,12 @@ public class DartClientOptionsTest extends AbstractOptionsTest {
times = 1; times = 1;
clientCodegen.setPubDescription(DartClientOptionsProvider.PUB_DESCRIPTION_VALUE); clientCodegen.setPubDescription(DartClientOptionsProvider.PUB_DESCRIPTION_VALUE);
times = 1; times = 1;
clientCodegen.setPubAuthor(DartClientOptionsProvider.PUB_AUTHOR_VALUE);
times = 1;
clientCodegen.setPubAuthorEmail(DartClientOptionsProvider.PUB_AUTHOR_EMAIL_VALUE);
times = 1;
clientCodegen.setPubHomepage(DartClientOptionsProvider.PUB_HOMEPAGE_VALUE);
times = 1;
clientCodegen.setSourceFolder(DartClientOptionsProvider.SOURCE_FOLDER_VALUE); clientCodegen.setSourceFolder(DartClientOptionsProvider.SOURCE_FOLDER_VALUE);
times = 1; times = 1;
clientCodegen.setUseEnumExtension(Boolean.valueOf(DartClientOptionsProvider.USE_ENUM_EXTENSION)); clientCodegen.setUseEnumExtension(Boolean.valueOf(DartClientOptionsProvider.USE_ENUM_EXTENSION));

View File

@@ -21,10 +21,8 @@ import mockit.Expectations;
import mockit.Tested; import mockit.Tested;
import org.openapitools.codegen.AbstractOptionsTest; import org.openapitools.codegen.AbstractOptionsTest;
import org.openapitools.codegen.CodegenConfig; import org.openapitools.codegen.CodegenConfig;
import org.openapitools.codegen.languages.DartClientCodegen;
import org.openapitools.codegen.languages.DartDioClientCodegen; import org.openapitools.codegen.languages.DartDioClientCodegen;
import org.openapitools.codegen.options.DartDioClientOptionsProvider; import org.openapitools.codegen.options.DartDioClientOptionsProvider;
import org.openapitools.codegen.options.DartDioClientOptionsProvider;
public class DartDioClientOptionsTest extends AbstractOptionsTest { public class DartDioClientOptionsTest extends AbstractOptionsTest {
@@ -54,6 +52,12 @@ public class DartDioClientOptionsTest extends AbstractOptionsTest {
times = 1; times = 1;
clientCodegen.setPubDescription(DartDioClientOptionsProvider.PUB_DESCRIPTION_VALUE); clientCodegen.setPubDescription(DartDioClientOptionsProvider.PUB_DESCRIPTION_VALUE);
times = 1; times = 1;
//clientCodegen.setPubAuthor(DartDioClientOptionsProvider.PUB_AUTHOR_VALUE);
//times = 1;
//clientCodegen.setPubAuthorEmail(DartDioClientOptionsProvider.PUB_AUTHOR_EMAIL_VALUE);
//times = 1;
//clientCodegen.setPubHomepage(DartDioClientOptionsProvider.PUB_HOMEPAGE_VALUE);
//times = 1;
clientCodegen.setSourceFolder(DartDioClientOptionsProvider.SOURCE_FOLDER_VALUE); clientCodegen.setSourceFolder(DartDioClientOptionsProvider.SOURCE_FOLDER_VALUE);
times = 1; times = 1;
clientCodegen.setUseEnumExtension(Boolean.valueOf(DartDioClientOptionsProvider.USE_ENUM_EXTENSION)); clientCodegen.setUseEnumExtension(Boolean.valueOf(DartDioClientOptionsProvider.USE_ENUM_EXTENSION));

View File

@@ -58,6 +58,8 @@ public class GoClientOptionsTest extends AbstractOptionsTest {
times = 1; times = 1;
clientCodegen.setStructPrefix(Boolean.valueOf(GoClientOptionsProvider.STRUCT_PREFIX_VALUE)); clientCodegen.setStructPrefix(Boolean.valueOf(GoClientOptionsProvider.STRUCT_PREFIX_VALUE));
times = 1; times = 1;
clientCodegen.setWithAWSV4Signature(Boolean.valueOf(GoClientOptionsProvider.WITH_AWSV4_SIGNATURE));
times = 1;
}}; }};
} }
} }

View File

@@ -45,6 +45,7 @@ public abstract class JavaJaxrsBaseTest {
String jsonSubType = "@JsonSubTypes({\n" + String jsonSubType = "@JsonSubTypes({\n" +
" @JsonSubTypes.Type(value = Dog.class, name = \"Dog\"),\n" + " @JsonSubTypes.Type(value = Dog.class, name = \"Dog\"),\n" +
" @JsonSubTypes.Type(value = Cat.class, name = \"Cat\"),\n" + " @JsonSubTypes.Type(value = Cat.class, name = \"Cat\"),\n" +
" @JsonSubTypes.Type(value = BigDog.class, name = \"BigDog\"),\n" +
"})"; "})";
assertFileContains(generator, outputPath + "/src/gen/java/org/openapitools/model/Animal.java", jsonTypeInfo, jsonSubType); assertFileContains(generator, outputPath + "/src/gen/java/org/openapitools/model/Animal.java", jsonTypeInfo, jsonSubType);
} }

View File

@@ -274,4 +274,24 @@ public class MysqlSchemaCodegenTest {
Assert.assertFalse(codegen.getJsonDataTypeEnabled()); Assert.assertFalse(codegen.getJsonDataTypeEnabled());
} }
@Test
public void testSetIdentifierNamingConvention() {
final MysqlSchemaCodegen codegen = new MysqlSchemaCodegen();
Assert.assertSame("original", codegen.getIdentifierNamingConvention());
codegen.setIdentifierNamingConvention("invalidValue");
Assert.assertSame("original", codegen.getIdentifierNamingConvention());
codegen.setIdentifierNamingConvention("snake_case");
Assert.assertSame("snake_case", codegen.getIdentifierNamingConvention());
codegen.setIdentifierNamingConvention("anotherInvalid");
Assert.assertSame("snake_case", codegen.getIdentifierNamingConvention());
}
@Test
public void testGetIdentifierNamingConvention() {
final MysqlSchemaCodegen codegen = new MysqlSchemaCodegen();
Assert.assertSame("original", codegen.getIdentifierNamingConvention());
codegen.setIdentifierNamingConvention("snake_case");
Assert.assertSame("snake_case", codegen.getIdentifierNamingConvention());
}
} }

View File

@@ -45,6 +45,8 @@ public class MysqlSchemaOptionsTest extends AbstractOptionsTest {
times = 1; times = 1;
clientCodegen.setJsonDataTypeEnabled(Boolean.valueOf(MysqlSchemaOptionsProvider.JSON_DATA_TYPE_ENABLED_VALUE)); clientCodegen.setJsonDataTypeEnabled(Boolean.valueOf(MysqlSchemaOptionsProvider.JSON_DATA_TYPE_ENABLED_VALUE));
times = 1; times = 1;
clientCodegen.setIdentifierNamingConvention(MysqlSchemaOptionsProvider.IDENTIFIER_NAMING_CONVENTION_VALUE);
times = 1;
}}; }};
} }
} }

View File

@@ -28,9 +28,12 @@ public class DartClientOptionsProvider implements OptionsProvider {
public static final String SORT_MODEL_PROPERTIES_VALUE = "false"; public static final String SORT_MODEL_PROPERTIES_VALUE = "false";
public static final String ENSURE_UNIQUE_PARAMS_VALUE = "true"; public static final String ENSURE_UNIQUE_PARAMS_VALUE = "true";
public static final String BROWSER_CLIENT_VALUE = "true"; public static final String BROWSER_CLIENT_VALUE = "true";
public static final String PUB_NAME_VALUE = "swagger"; public static final String PUB_NAME_VALUE = "openapi";
public static final String PUB_VERSION_VALUE = "1.0.0-SNAPSHOT"; public static final String PUB_VERSION_VALUE = "1.0.0-SNAPSHOT";
public static final String PUB_DESCRIPTION_VALUE = "Swagger API client dart"; public static final String PUB_DESCRIPTION_VALUE = "OpenAPI API client dart";
public static final String PUB_AUTHOR_VALUE = "Author";
public static final String PUB_AUTHOR_EMAIL_VALUE = "author@homepage";
public static final String PUB_HOMEPAGE_VALUE = "Homepage";
public static final String SOURCE_FOLDER_VALUE = "src"; public static final String SOURCE_FOLDER_VALUE = "src";
public static final String USE_ENUM_EXTENSION = "true"; public static final String USE_ENUM_EXTENSION = "true";
public static final String ALLOW_UNICODE_IDENTIFIERS_VALUE = "false"; public static final String ALLOW_UNICODE_IDENTIFIERS_VALUE = "false";
@@ -51,6 +54,9 @@ public class DartClientOptionsProvider implements OptionsProvider {
.put(DartClientCodegen.PUB_NAME, PUB_NAME_VALUE) .put(DartClientCodegen.PUB_NAME, PUB_NAME_VALUE)
.put(DartClientCodegen.PUB_VERSION, PUB_VERSION_VALUE) .put(DartClientCodegen.PUB_VERSION, PUB_VERSION_VALUE)
.put(DartClientCodegen.PUB_DESCRIPTION, PUB_DESCRIPTION_VALUE) .put(DartClientCodegen.PUB_DESCRIPTION, PUB_DESCRIPTION_VALUE)
.put(DartClientCodegen.PUB_AUTHOR, PUB_AUTHOR_VALUE)
.put(DartClientCodegen.PUB_AUTHOR_EMAIL, PUB_AUTHOR_EMAIL_VALUE)
.put(DartClientCodegen.PUB_HOMEPAGE, PUB_HOMEPAGE_VALUE)
.put(CodegenConstants.SOURCE_FOLDER, SOURCE_FOLDER_VALUE) .put(CodegenConstants.SOURCE_FOLDER, SOURCE_FOLDER_VALUE)
.put(DartClientCodegen.USE_ENUM_EXTENSION, USE_ENUM_EXTENSION) .put(DartClientCodegen.USE_ENUM_EXTENSION, USE_ENUM_EXTENSION)
.put(CodegenConstants.ALLOW_UNICODE_IDENTIFIERS, ALLOW_UNICODE_IDENTIFIERS_VALUE) .put(CodegenConstants.ALLOW_UNICODE_IDENTIFIERS, ALLOW_UNICODE_IDENTIFIERS_VALUE)

View File

@@ -18,29 +18,33 @@
package org.openapitools.codegen.options; package org.openapitools.codegen.options;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import java.util.Map; import java.util.Map;
import org.openapitools.codegen.CodegenConstants; import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.languages.DartDioClientCodegen; import org.openapitools.codegen.languages.DartDioClientCodegen;
import org.openapitools.codegen.languages.DartDioClientCodegen;
public class DartDioClientOptionsProvider implements OptionsProvider { public class DartDioClientOptionsProvider implements OptionsProvider {
public static final String SORT_PARAMS_VALUE = "true"; public static final String SORT_PARAMS_VALUE = "true";
public static final String SORT_MODEL_PROPERTIES_VALUE = "false"; public static final String SORT_MODEL_PROPERTIES_VALUE = "false";
public static final String ENSURE_UNIQUE_PARAMS_VALUE = "true"; public static final String ENSURE_UNIQUE_PARAMS_VALUE = "true";
public static final String BROWSER_CLIENT_VALUE = "true"; public static final String BROWSER_CLIENT_VALUE = "true";
public static final String PUB_NAME_VALUE = "swagger"; public static final String PUB_NAME_VALUE = "openapi";
public static final String PUB_VERSION_VALUE = "1.0.0-SNAPSHOT"; public static final String PUB_VERSION_VALUE = "1.0.0-SNAPSHOT";
public static final String PUB_DESCRIPTION_VALUE = "Swagger API client dart"; public static final String PUB_DESCRIPTION_VALUE = "OpenAPI API client dart";
public static final String SOURCE_FOLDER_VALUE = "src"; public static final String SOURCE_FOLDER_VALUE = "src";
public static final String USE_ENUM_EXTENSION = "true"; public static final String USE_ENUM_EXTENSION = "true";
public static final String ALLOW_UNICODE_IDENTIFIERS_VALUE = "false"; public static final String ALLOW_UNICODE_IDENTIFIERS_VALUE = "false";
public static final String PREPEND_FORM_OR_BODY_PARAMETERS_VALUE = "true"; public static final String PREPEND_FORM_OR_BODY_PARAMETERS_VALUE = "true";
public static final String DATE_LIBRARY = "core"; public static final String DATE_LIBRARY = "core";
public static final String NULLABLE_FIELDS = "true"; public static final String NULLABLE_FIELDS = "true";
public static final String PUB_AUTHOR_VALUE = "Author";
public static final String PUB_AUTHOR_EMAIL_VALUE = "author@homepage";
public static final String PUB_HOMEPAGE_VALUE = "Homepage";
@Override @Override
public String getLanguage() { public String getLanguage() {
return "dart"; return "dart-dio";
} }
@Override @Override
@@ -53,6 +57,9 @@ public class DartDioClientOptionsProvider implements OptionsProvider {
.put(DartDioClientCodegen.PUB_NAME, PUB_NAME_VALUE) .put(DartDioClientCodegen.PUB_NAME, PUB_NAME_VALUE)
.put(DartDioClientCodegen.PUB_VERSION, PUB_VERSION_VALUE) .put(DartDioClientCodegen.PUB_VERSION, PUB_VERSION_VALUE)
.put(DartDioClientCodegen.PUB_DESCRIPTION, PUB_DESCRIPTION_VALUE) .put(DartDioClientCodegen.PUB_DESCRIPTION, PUB_DESCRIPTION_VALUE)
.put(DartDioClientCodegen.PUB_AUTHOR, PUB_AUTHOR_VALUE)
.put(DartDioClientCodegen.PUB_AUTHOR_EMAIL, PUB_AUTHOR_EMAIL_VALUE)
.put(DartDioClientCodegen.PUB_HOMEPAGE, PUB_HOMEPAGE_VALUE)
.put(CodegenConstants.SOURCE_FOLDER, SOURCE_FOLDER_VALUE) .put(CodegenConstants.SOURCE_FOLDER, SOURCE_FOLDER_VALUE)
.put(DartDioClientCodegen.USE_ENUM_EXTENSION, USE_ENUM_EXTENSION) .put(DartDioClientCodegen.USE_ENUM_EXTENSION, USE_ENUM_EXTENSION)
.put(CodegenConstants.ALLOW_UNICODE_IDENTIFIERS, ALLOW_UNICODE_IDENTIFIERS_VALUE) .put(CodegenConstants.ALLOW_UNICODE_IDENTIFIERS, ALLOW_UNICODE_IDENTIFIERS_VALUE)
@@ -60,7 +67,6 @@ public class DartDioClientOptionsProvider implements OptionsProvider {
.put(DartDioClientCodegen.SUPPORT_DART2, "false") .put(DartDioClientCodegen.SUPPORT_DART2, "false")
.put(DartDioClientCodegen.DATE_LIBRARY, DATE_LIBRARY) .put(DartDioClientCodegen.DATE_LIBRARY, DATE_LIBRARY)
.put(DartDioClientCodegen.NULLABLE_FIELDS, NULLABLE_FIELDS) .put(DartDioClientCodegen.NULLABLE_FIELDS, NULLABLE_FIELDS)
.build(); .build();
} }

View File

@@ -32,6 +32,7 @@ public class GoClientOptionsProvider implements OptionsProvider {
public static final Boolean PREPEND_FORM_OR_BODY_PARAMETERS_VALUE = true; public static final Boolean PREPEND_FORM_OR_BODY_PARAMETERS_VALUE = true;
public static final boolean IS_GO_SUBMODULE_VALUE = true; public static final boolean IS_GO_SUBMODULE_VALUE = true;
public static final boolean STRUCT_PREFIX_VALUE = true; public static final boolean STRUCT_PREFIX_VALUE = true;
public static final boolean WITH_AWSV4_SIGNATURE = true;
@Override @Override
public String getLanguage() { public String getLanguage() {
@@ -50,6 +51,7 @@ public class GoClientOptionsProvider implements OptionsProvider {
.put(CodegenConstants.ENUM_CLASS_PREFIX, "true") .put(CodegenConstants.ENUM_CLASS_PREFIX, "true")
.put(CodegenConstants.PREPEND_FORM_OR_BODY_PARAMETERS, "true") .put(CodegenConstants.PREPEND_FORM_OR_BODY_PARAMETERS, "true")
.put(CodegenConstants.IS_GO_SUBMODULE, "true") .put(CodegenConstants.IS_GO_SUBMODULE, "true")
.put(CodegenConstants.WITH_AWSV4_SIGNATURE_COMMENT, "true")
.put("structPrefix", "true") .put("structPrefix", "true")
.build(); .build();
} }

View File

@@ -24,6 +24,7 @@ import java.util.Map;
public class MysqlSchemaOptionsProvider implements OptionsProvider { public class MysqlSchemaOptionsProvider implements OptionsProvider {
public static final String DEFAULT_DATABASE_NAME_VALUE = "database_name"; public static final String DEFAULT_DATABASE_NAME_VALUE = "database_name";
public static final String JSON_DATA_TYPE_ENABLED_VALUE = "false"; public static final String JSON_DATA_TYPE_ENABLED_VALUE = "false";
public static final String IDENTIFIER_NAMING_CONVENTION_VALUE = "snake_case";
@Override @Override
public String getLanguage() { public String getLanguage() {
@@ -35,6 +36,7 @@ public class MysqlSchemaOptionsProvider implements OptionsProvider {
ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<String, String>(); ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<String, String>();
return builder.put(MysqlSchemaCodegen.DEFAULT_DATABASE_NAME, DEFAULT_DATABASE_NAME_VALUE) return builder.put(MysqlSchemaCodegen.DEFAULT_DATABASE_NAME, DEFAULT_DATABASE_NAME_VALUE)
.put(MysqlSchemaCodegen.JSON_DATA_TYPE_ENABLED, JSON_DATA_TYPE_ENABLED_VALUE) .put(MysqlSchemaCodegen.JSON_DATA_TYPE_ENABLED, JSON_DATA_TYPE_ENABLED_VALUE)
.put(MysqlSchemaCodegen.IDENTIFIER_NAMING_CONVENTION, IDENTIFIER_NAMING_CONVENTION_VALUE)
.build(); .build();
} }

View File

@@ -28,6 +28,7 @@ public class PythonClientOptionsProvider implements OptionsProvider {
public static final String PROJECT_NAME_VALUE = "swagger-client-python"; public static final String PROJECT_NAME_VALUE = "swagger-client-python";
public static final String PACKAGE_VERSION_VALUE = "1.0.0-SNAPSHOT"; public static final String PACKAGE_VERSION_VALUE = "1.0.0-SNAPSHOT";
public static final String PACKAGE_URL_VALUE = ""; public static final String PACKAGE_URL_VALUE = "";
public static final String USE_NOSE_VALUE = "false";
@Override @Override
public String getLanguage() { public String getLanguage() {
@@ -45,6 +46,7 @@ public class PythonClientOptionsProvider implements OptionsProvider {
.put(CodegenConstants.HIDE_GENERATION_TIMESTAMP, "true") .put(CodegenConstants.HIDE_GENERATION_TIMESTAMP, "true")
.put(CodegenConstants.SOURCECODEONLY_GENERATION, "false") .put(CodegenConstants.SOURCECODEONLY_GENERATION, "false")
.put(CodegenConstants.LIBRARY, "urllib3") .put(CodegenConstants.LIBRARY, "urllib3")
.put(PythonClientCodegen.USE_NOSE, USE_NOSE_VALUE)
.build(); .build();
} }

View File

@@ -56,6 +56,9 @@ public class PythonClientOptionsTest extends AbstractOptionsTest {
clientCodegen.setPackageUrl(PythonClientOptionsProvider.PACKAGE_URL_VALUE); clientCodegen.setPackageUrl(PythonClientOptionsProvider.PACKAGE_URL_VALUE);
times = 1; times = 1;
clientCodegen.setUseNose(PythonClientOptionsProvider.USE_NOSE_VALUE);
times = 1;
clientCodegen.packagePath(); clientCodegen.packagePath();
result = PythonClientOptionsProvider.PACKAGE_NAME_VALUE.replace('.', File.separatorChar); result = PythonClientOptionsProvider.PACKAGE_NAME_VALUE.replace('.', File.separatorChar);
minTimes = 1; minTimes = 1;

View File

@@ -1330,6 +1330,14 @@ definitions:
properties: properties:
declawed: declawed:
type: boolean type: boolean
BigCat:
allOf:
- $ref: '#/definitions/Cat'
- type: object
properties:
kind:
type: string
enum: [lions, tigers, leopards, jaguars]
Animal: Animal:
type: object type: object
discriminator: className discriminator: className

View File

@@ -0,0 +1,33 @@
openapi: 3.0.0
servers:
- url: 'http://petstore.swagger.io/v2'
info:
description: Test for issue 4062
version: 1.0.0
title: OpenAPI Petstore
license:
name: Apache-2.0
url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
paths:
/enum:
get:
tags:
- enum
summary: Get enums
description: ''
operationId: getEnum
responses:
'200':
description: success
content:
application/json:
schema:
$ref: '#/components/schemas/PetEnum'
components:
schemas:
PetEnum:
type: string
description: An enum with complex-ish naming
enum:
- myFirstValue
- MY_SECOND_VALUE

View File

@@ -45,6 +45,56 @@ paths:
description: 'OK' description: 'OK'
'400': '400':
description: Bad Request description: Bad Request
/multiget:
get:
summary: Get some stuff.
responses:
200:
description: JSON rsp
content:
application/json:
schema:
$ref: "#/components/schemas/anotherXmlObject"
201:
description: XML rsp
content:
application/xml:
schema:
type: object
properties:
foo:
type: string
202:
description: octet rsp
content:
application/octet-stream:
schema:
type: string
format: binary
203:
description: string rsp
content:
text/plain:
schema:
type: string
204:
description: Duplicate Response long text. One.
content:
application/json:
schema:
$ref: "#/components/schemas/anotherXmlObject"
205:
description: Duplicate Response long text. Two.
content:
application/json:
schema:
$ref: "#/components/schemas/anotherXmlObject"
206:
description: Duplicate Response long text. Three.
content:
application/json:
schema:
$ref: "#/components/schemas/anotherXmlObject"
/xml_other: /xml_other:
post: post:
requestBody: requestBody:

Some files were not shown because too many files have changed in this diff Show More