diff --git a/.gitignore b/.gitignore index 645eee18798..208ea3e43a7 100644 --- a/.gitignore +++ b/.gitignore @@ -63,6 +63,7 @@ samples/client/petstore/java/hello.txt samples/client/petstore/java/okhttp-gson/hello.txt samples/client/petstore/java/jersey1/hello.txt samples/client/petstore/java/jersey2-java8/hello.txt +samples/client/petstore/java/jersey2/hello.txt samples/client/petstore/android/default/hello.txt samples/client/petstore/android/volley/.gradle/ samples/client/petstore/android/volley/build/ @@ -159,4 +160,3 @@ samples/client/petstore/typescript-node/npm/npm-debug.log # aspnetcore samples/server/petstore/aspnetcore/.vs/ - diff --git a/README.md b/README.md index c45194e0fff..2937f082953 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ This is the swagger codegen project, which allows generation of API client libraries (SDK generation), server stubs and documentation automatically given an [OpenAPI Spec](https://github.com/OAI/OpenAPI-Specification). Currently, the following languages/frameworks are supported: - **API clients**: **ActionScript**, **Apex**, **Bash**, **C#** (.net 2.0, 4.0 or later), **C++** (cpprest, Qt5, Tizen), **Clojure**, **Dart**, **Elixir**, **Go**, **Groovy**, **Haskell**, **Java** (Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign), **Kotlin**, **Node.js** (ES5, ES6, AngularJS with Google Closure Compiler annotations) **Objective-C**, **Perl**, **PHP**, **Python**, **Ruby**, **Scala**, **Swift** (2.x, 3.x), **Typescript** (Angular1.x, Angular2.x, Fetch, jQuery, Node) -- **Server stubs**: **C#** (ASP.NET Core, NancyFx), **C++** (Restbed), **Erlang**, **Go**, **Haskell**, **Java** (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, RestEasy, Play Framework), **PHP** (Lumen, Slim, Silex, [Zend Expressive](https://github.com/zendframework/zend-expressive)), **Python** (Flask), **NodeJS**, **Ruby** (Sinatra, Rails5), **Scala** ([Finch](https://github.com/finagle/finch), Scalatra) +- **Server stubs**: **C#** (ASP.NET Core, NancyFx), **C++** (Pistache, Restbed), **Erlang**, **Go**, **Haskell**, **Java** (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, RestEasy, Play Framework), **PHP** (Lumen, Slim, Silex, [Zend Expressive](https://github.com/zendframework/zend-expressive)), **Python** (Flask), **NodeJS**, **Ruby** (Sinatra, Rails5), **Scala** ([Finch](https://github.com/finagle/finch), Scalatra) - **API documentation generators**: **HTML**, **Confluence Wiki** - **Others**: **JMeter** @@ -932,6 +932,7 @@ Here is a list of template creators: * Server Stubs * C# ASP.NET5: @jimschubert * C# NancyFX: @mstefaniuk + * C++ Pistache: @sebymiano * C++ Restbed: @stkrwork * Erlang Server: @galaxie * Go Server: @guohuang diff --git a/bin/pistache-server-petstore.sh b/bin/pistache-server-petstore.sh new file mode 100755 index 00000000000..4a2667a5f81 --- /dev/null +++ b/bin/pistache-server-petstore.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +SCRIPT="$0" + +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/swagger-codegen-cli/target/swagger-codegen-cli.jar" + +if [ ! -f "$executable" ] +then + mvn clean package +fi + +# if you've executed sbt assembly previously it will use that instead. +export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties" +ags="$@ generate -l pistache-server -i modules/swagger-codegen/src/test/resources/2_0/petstore.yaml -o samples/server/petstore/pistache-server" + +java $JAVA_OPTS -jar $executable $ags diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenConstants.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenConstants.java index d9bf80c1b62..4dea75e8208 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenConstants.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenConstants.java @@ -96,6 +96,7 @@ public class CodegenConstants { public static final String ENSURE_UNIQUE_PARAMS = "ensureUniqueParams"; public static final String ENSURE_UNIQUE_PARAMS_DESC = "Whether to ensure parameter names are unique in an operation (rename parameters that are not)."; + public static final String PROJECT_NAME = "projectName"; public static final String PACKAGE_NAME = "packageName"; public static final String PACKAGE_VERSION = "packageVersion"; diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenOperation.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenOperation.java index e5d7db8170f..90a88df5fa7 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenOperation.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenOperation.java @@ -118,7 +118,7 @@ public class CodegenOperation { * @return true if act as Restful show method, false otherwise */ public boolean isRestfulShow() { - return "GET".equals(httpMethod) && isMemberPath(); + return "GET".equalsIgnoreCase(httpMethod) && isMemberPath(); } /** @@ -127,7 +127,7 @@ public class CodegenOperation { * @return true if act as Restful create method, false otherwise */ public boolean isRestfulCreate() { - return "POST".equals(httpMethod) && "".equals(pathWithoutBaseName()); + return "POST".equalsIgnoreCase(httpMethod) && "".equals(pathWithoutBaseName()); } /** @@ -136,7 +136,7 @@ public class CodegenOperation { * @return true if act as Restful update method, false otherwise */ public boolean isRestfulUpdate() { - return Arrays.asList("PUT", "PATCH").contains(httpMethod) && isMemberPath(); + return Arrays.asList("PUT", "PATCH").contains(httpMethod.toUpperCase()) && isMemberPath(); } /** @@ -145,7 +145,7 @@ public class CodegenOperation { * @return true if act as Restful destroy method, false otherwise */ public boolean isRestfulDestroy() { - return "DELETE".equals(httpMethod) && isMemberPath(); + return "DELETE".equalsIgnoreCase(httpMethod) && isMemberPath(); } /** @@ -173,7 +173,6 @@ public class CodegenOperation { */ private boolean isMemberPath() { if (pathParams.size() != 1) return false; - String id = pathParams.get(0).baseName; return ("/{" + id + "}").equals(pathWithoutBaseName()); } diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/FlaskConnexionCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/FlaskConnexionCodegen.java index c4f9eba2f66..cf4b7a5b5c8 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/FlaskConnexionCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/FlaskConnexionCodegen.java @@ -141,6 +141,8 @@ public class FlaskConnexionCodegen extends DefaultCodegen implements CodegenConf defaultValue("default_controller")); cliOptions.add(new CliOption(SUPPORT_PYTHON2, "support python2"). defaultValue("false")); + cliOptions.add(new CliOption("serverPort", "TCP port to listen to in app.run"). + defaultValue("8080")); } @Override diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClosureAngularClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClosureAngularClientCodegen.java index 779f51d178b..24f6d22112b 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClosureAngularClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClosureAngularClientCodegen.java @@ -3,6 +3,7 @@ package io.swagger.codegen.languages; import io.swagger.codegen.CodegenModel; import io.swagger.codegen.*; import io.swagger.models.properties.*; +import io.swagger.models.Swagger; import java.util.TreeSet; import java.util.*; @@ -11,8 +12,14 @@ import java.io.File; import org.apache.commons.lang3.StringUtils; public class JavascriptClosureAngularClientCodegen extends DefaultCodegen implements CodegenConfig { + + public static final String USE_ES6 = "useEs6"; + + protected boolean useEs6; + public JavascriptClosureAngularClientCodegen() { super(); + outputFolder = "generated-code/javascript-closure-angular"; supportsInheritance = false; setReservedWordsLowerCase(Arrays.asList("abstract", @@ -64,15 +71,11 @@ public class JavascriptClosureAngularClientCodegen extends DefaultCodegen implem typeMapping.put("binary", "string"); - outputFolder = "generated-code/javascript-closure-angular"; - modelTemplateFiles.put("model.mustache", ".js"); - apiTemplateFiles.put("api.mustache", ".js"); - embeddedTemplateDir = templateDir = "Javascript-Closure-Angular"; - apiPackage = "API.Client"; - modelPackage = "API.Client"; - cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, "hides the timestamp when files were generated") .defaultValue(Boolean.TRUE.toString())); + cliOptions.add(new CliOption(USE_ES6, + "use ES6 templates") + .defaultValue(Boolean.FALSE.toString())); } @Override @@ -83,6 +86,28 @@ public class JavascriptClosureAngularClientCodegen extends DefaultCodegen implem if (!additionalProperties.containsKey(CodegenConstants.HIDE_GENERATION_TIMESTAMP)) { additionalProperties.put(CodegenConstants.HIDE_GENERATION_TIMESTAMP, Boolean.TRUE.toString()); } + + if (additionalProperties.containsKey(USE_ES6)) { + setUseEs6(convertPropertyToBooleanAndWriteBack(USE_ES6)); + } + } + + @Override + public void preprocessSwagger(Swagger swagger) { + super.preprocessSwagger(swagger); + + if (useEs6) { + embeddedTemplateDir = templateDir = "Javascript-Closure-Angular/es6"; + apiPackage = "resources"; + apiTemplateFiles.put("api.mustache", ".js"); + supportingFiles.add(new SupportingFile("module.mustache", "", "module.js")); + } else { + modelTemplateFiles.put("model.mustache", ".js"); + apiTemplateFiles.put("api.mustache", ".js"); + embeddedTemplateDir = templateDir = "Javascript-Closure-Angular"; + apiPackage = "API.Client"; + modelPackage = "API.Client"; + } } @Override @@ -102,7 +127,7 @@ public class JavascriptClosureAngularClientCodegen extends DefaultCodegen implem } @Override - public String escapeReservedWord(String name) { + public String escapeReservedWord(String name) { if(this.reservedWordsMappings().containsKey(name)) { return this.reservedWordsMappings().get(name); } @@ -121,7 +146,7 @@ public class JavascriptClosureAngularClientCodegen extends DefaultCodegen implem @Override public String toVarName(String name) { // sanitize name - name = sanitizeName(name); + name = sanitizeName(name); // replace - with _ e.g. created-at => created_at name = name.replaceAll("-", "_"); @@ -273,4 +298,7 @@ public class JavascriptClosureAngularClientCodegen extends DefaultCodegen implem return input.replace("*/", "*_/").replace("/*", "/_*"); } + public void setUseEs6(boolean useEs6) { + this.useEs6 = useEs6; + } } diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PistacheServerCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PistacheServerCodegen.java new file mode 100644 index 00000000000..a56ef44710a --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PistacheServerCodegen.java @@ -0,0 +1,409 @@ +package io.swagger.codegen.languages; + + +import io.swagger.codegen.*; +import io.swagger.models.Model; +import io.swagger.models.Operation; +import io.swagger.models.Response; +import io.swagger.models.Swagger; +import io.swagger.models.properties.*; + +import javax.validation.constraints.Null; +import java.io.File; +import java.util.*; + +public class PistacheServerCodegen extends DefaultCodegen implements CodegenConfig { + protected String implFolder = "impl"; + + @Override + public CodegenType getTag() { + return CodegenType.SERVER; + } + + @Override + public String getName() { + return "pistache-server"; + } + + @Override + public String getHelp() { + return "Generates a C++ API server (based on Pistache)"; + } + + public PistacheServerCodegen() { + super(); + + apiPackage = "io.swagger.server.api"; + modelPackage = "io.swagger.server.model"; + + modelTemplateFiles.put("model-header.mustache", ".h"); + modelTemplateFiles.put("model-source.mustache", ".cpp"); + + apiTemplateFiles.put("api-header.mustache", ".h"); + apiTemplateFiles.put("api-source.mustache", ".cpp"); + apiTemplateFiles.put("api-impl-header.mustache", ".h"); + apiTemplateFiles.put("api-impl-source.mustache", ".cpp"); + apiTemplateFiles.put("main-api-server.mustache", ".cpp"); + + embeddedTemplateDir = templateDir = "pistache-server"; + + cliOptions.clear(); + + reservedWords = new HashSet<>(); + + supportingFiles.add(new SupportingFile("modelbase-header.mustache", "model", "ModelBase.h")); + supportingFiles.add(new SupportingFile("modelbase-source.mustache", "model", "ModelBase.cpp")); + supportingFiles.add(new SupportingFile("cmake.mustache", "", "CMakeLists.txt")); + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + + languageSpecificPrimitives = new HashSet( + Arrays.asList("int", "char", "bool", "long", "float", "double", "int32_t", "int64_t")); + + typeMapping = new HashMap(); + typeMapping.put("date", "std::string"); + typeMapping.put("DateTime", "std::string"); + typeMapping.put("string", "std::string"); + typeMapping.put("integer", "int32_t"); + typeMapping.put("long", "int64_t"); + typeMapping.put("boolean", "bool"); + typeMapping.put("array", "std::vector"); + typeMapping.put("map", "std::map"); + typeMapping.put("file", "std::string"); + typeMapping.put("object", "Object"); + typeMapping.put("binary", "std::string"); + typeMapping.put("number", "double"); + typeMapping.put("UUID", "std::string"); + + super.importMapping = new HashMap(); + importMapping.put("std::vector", "#include "); + importMapping.put("std::map", "#include "); + importMapping.put("std::string", "#include "); + importMapping.put("Object", "#include \"Object.h\""); + } + + @Override + public void processOpts() { + super.processOpts(); + + additionalProperties.put("modelNamespaceDeclarations", modelPackage.split("\\.")); + additionalProperties.put("modelNamespace", modelPackage.replaceAll("\\.", "::")); + additionalProperties.put("apiNamespaceDeclarations", apiPackage.split("\\.")); + additionalProperties.put("apiNamespace", apiPackage.replaceAll("\\.", "::")); + } + + /** + * Escapes a reserved word as defined in the `reservedWords` array. Handle + * escaping those terms here. This logic is only called if a variable + * matches the reseved words + * + * @return the escaped term + */ + @Override + public String escapeReservedWord(String name) { + return "_" + name; // add an underscore to the name + } + + @Override + public String toModelImport(String name) { + if (importMapping.containsKey(name)) { + return importMapping.get(name); + } else { + return "#include \"" + name + ".h\""; + } + } + + @Override + public CodegenModel fromModel(String name, Model model, Map allDefinitions) { + CodegenModel codegenModel = super.fromModel(name, model, allDefinitions); + + Set oldImports = codegenModel.imports; + codegenModel.imports = new HashSet<>(); + for (String imp : oldImports) { + String newImp = toModelImport(imp); + if (!newImp.isEmpty()) { + codegenModel.imports.add(newImp); + } + } + + return codegenModel; + } + + @Override + public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, + Map definitions, Swagger swagger) { + CodegenOperation op = super.fromOperation(path, httpMethod, operation, definitions, swagger); + + if (operation.getResponses() != null && !operation.getResponses().isEmpty()) { + Response methodResponse = findMethodResponse(operation.getResponses()); + + if (methodResponse != null) { + if (methodResponse.getSchema() != null) { + CodegenProperty cm = fromProperty("response", methodResponse.getSchema()); + op.vendorExtensions.put("x-codegen-response", cm); + if(cm.datatype == "HttpContent") { + op.vendorExtensions.put("x-codegen-response-ishttpcontent", true); + } + } + } + } + + String pathForPistache = path.replaceAll("\\{(.*?)}", ":$1"); + op.vendorExtensions.put("x-codegen-pistache-path", pathForPistache); + + return op; + } + + @SuppressWarnings("unchecked") + @Override + public Map postProcessOperations(Map objs) { + Map operations = (Map) objs.get("operations"); + String classname = (String) operations.get("classname"); + operations.put("classnameSnakeUpperCase", DefaultCodegen.underscore(classname).toUpperCase()); + operations.put("classnameSnakeLowerCase", DefaultCodegen.underscore(classname).toLowerCase()); + + List operationList = (List) operations.get("operation"); + for (CodegenOperation op : operationList) { + boolean consumeJson = false; + boolean isParsingSupported = true; + if (op.bodyParam != null) { + if (op.bodyParam.vendorExtensions == null) { + op.bodyParam.vendorExtensions = new HashMap<>(); + } + + op.bodyParam.vendorExtensions.put("x-codegen-pistache-isStringOrDate", op.bodyParam.isString || op.bodyParam.isDate); + } + if(op.consumes != null) { + for (Map consume : op.consumes) { + if (consume.get("mediaType") != null && consume.get("mediaType").equals("application/json")) { + consumeJson = true; + } + } + } + + op.httpMethod = op.httpMethod.substring(0, 1).toUpperCase() + op.httpMethod.substring(1).toLowerCase(); + + for(CodegenParameter param : op.allParams){ + if (param.isFormParam) isParsingSupported=false; + if (param.isFile) isParsingSupported=false; + if (param.isCookieParam) isParsingSupported=false; + + //TODO: This changes the info about the real type but it is needed to parse the header params + if (param.isHeaderParam) { + param.dataType = "Optional"; + param.baseType = "Optional"; + } else if(param.isQueryParam){ + if(param.isPrimitiveType) { + param.dataType = "Optional<" + param.dataType + ">"; + } else { + param.dataType = "Optional<" + param.baseType + ">"; + param.baseType = "Optional<" + param.baseType + ">"; + } + } + } + + if (op.vendorExtensions == null) { + op.vendorExtensions = new HashMap<>(); + } + op.vendorExtensions.put("x-codegen-pistache-consumesJson", consumeJson); + op.vendorExtensions.put("x-codegen-pistache-isParsingSupported", isParsingSupported); + } + + return objs; + } + + @Override + public String toModelFilename(String name) { + return initialCaps(name); + } + + @Override + public String apiFilename(String templateName, String tag) { + String result = super.apiFilename(templateName, tag); + + if ( templateName.endsWith("impl-header.mustache") ) { + int ix = result.lastIndexOf('/'); + result = result.substring(0, ix) + result.substring(ix, result.length() - 2) + "Impl.h"; + result = result.replace(apiFileFolder(), implFileFolder()); + } else if ( templateName.endsWith("impl-source.mustache") ) { + int ix = result.lastIndexOf('/'); + result = result.substring(0, ix) + result.substring(ix, result.length() - 4) + "Impl.cpp"; + result = result.replace(apiFileFolder(), implFileFolder()); + } else if ( templateName.endsWith("api-server.mustache") ) { + int ix = result.lastIndexOf('/'); + result = result.substring(0, ix) + result.substring(ix, result.length() - 4) + "MainServer.cpp"; + result = result.replace(apiFileFolder(), outputFolder); + } + return result; + } + + @Override + public String toApiFilename(String name) { + return initialCaps(name) + "Api"; + } + + /** + * Optional - type declaration. This is a String which is used by the + * templates to instantiate your types. There is typically special handling + * for different property types + * + * @return a string value used as the `dataType` field for model templates, + * `returnType` for api templates + */ + @Override + public String getTypeDeclaration(Property p) { + String swaggerType = getSwaggerType(p); + + if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + Property inner = ap.getItems(); + return getSwaggerType(p) + "<" + getTypeDeclaration(inner) + ">"; + } + if (p instanceof MapProperty) { + MapProperty mp = (MapProperty) p; + Property inner = mp.getAdditionalProperties(); + return getSwaggerType(p) + ""; + } + if (p instanceof StringProperty || p instanceof DateProperty + || p instanceof DateTimeProperty || p instanceof FileProperty + || languageSpecificPrimitives.contains(swaggerType)) { + return toModelName(swaggerType); + } + + return "std::shared_ptr<" + swaggerType + ">"; + } + + @Override + public String toDefaultValue(Property p) { + if (p instanceof StringProperty) { + return "\"\""; + } else if (p instanceof BooleanProperty) { + return "false"; + } else if (p instanceof DateProperty) { + return "\"\""; + } else if (p instanceof DateTimeProperty) { + return "\"\""; + } else if (p instanceof DoubleProperty) { + return "0.0"; + } else if (p instanceof FloatProperty) { + return "0.0f"; + } else if (p instanceof IntegerProperty || p instanceof BaseIntegerProperty) { + return "0"; + } else if (p instanceof LongProperty) { + return "0L"; + } else if (p instanceof DecimalProperty) { + return "0.0"; + } else if (p instanceof MapProperty) { + MapProperty ap = (MapProperty) p; + String inner = getSwaggerType(ap.getAdditionalProperties()); + return "std::map()"; + } else if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + String inner = getSwaggerType(ap.getItems()); + if (!languageSpecificPrimitives.contains(inner)) { + inner = "std::shared_ptr<" + inner + ">"; + } + return "std::vector<" + inner + ">()"; + } else if (p instanceof RefProperty) { + RefProperty rp = (RefProperty) p; + return "new " + toModelName(rp.getSimpleRef()) + "()"; + } + return "nullptr"; + } + + @Override + public void postProcessParameter(CodegenParameter parameter) { + super.postProcessParameter(parameter); + + boolean isPrimitiveType = parameter.isPrimitiveType == Boolean.TRUE; + boolean isListContainer = parameter.isListContainer == Boolean.TRUE; + boolean isString = parameter.isString == Boolean.TRUE; + + if (!isPrimitiveType && !isListContainer && !isString && !parameter.dataType.startsWith("std::shared_ptr")) { + parameter.dataType = "std::shared_ptr<" + parameter.dataType + ">"; + } + } + + /** + * Location to write model files. You can use the modelPackage() as defined + * when the class is instantiated + */ + public String modelFileFolder() { + return (outputFolder + "/model").replace("/", File.separator); + } + + /** + * Location to write api files. You can use the apiPackage() as defined when + * the class is instantiated + */ + @Override + public String apiFileFolder() { + return (outputFolder + "/api").replace("/", File.separator); + } + + private String implFileFolder() { + return (outputFolder + "/" + implFolder).replace("/", File.separator); + } + + /** + * Optional - swagger type conversion. This is used to map swagger types in + * a `Property` into either language specific types via `typeMapping` or + * into complex models if there is not a mapping. + * + * @return a string value of the type or complex model for this property + * @see io.swagger.models.properties.Property + */ + @Override + public String getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if (typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if (languageSpecificPrimitives.contains(type)) + return toModelName(type); + } else + type = swaggerType; + return toModelName(type); + } + + @Override + public String toModelName(String type) { + if (typeMapping.keySet().contains(type) || typeMapping.values().contains(type) + || importMapping.values().contains(type) || defaultIncludes.contains(type) + || languageSpecificPrimitives.contains(type)) { + return type; + } else { + return Character.toUpperCase(type.charAt(0)) + type.substring(1); + } + } + + @Override + public String toVarName(String name) { + if (typeMapping.keySet().contains(name) || typeMapping.values().contains(name) + || importMapping.values().contains(name) || defaultIncludes.contains(name) + || languageSpecificPrimitives.contains(name)) { + return name; + } + + if (name.length() > 1) { + return Character.toUpperCase(name.charAt(0)) + name.substring(1); + } + + return name; + } + + @Override + public String toApiName(String type) { + return Character.toUpperCase(type.charAt(0)) + type.substring(1) + "Api"; + } + + @Override + public String escapeQuotationMark(String input) { + // remove " to avoid code injection + return input.replace("\"", ""); + } + + @Override + public String escapeUnsafeCharacters(String input) { + return input.replace("*/", "*_/").replace("/*", "/_*"); + } +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PythonClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PythonClientCodegen.java index 641534690e7..ca0f59ec76b 100755 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PythonClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PythonClientCodegen.java @@ -24,8 +24,9 @@ import org.apache.commons.lang3.StringUtils; public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig { public static final String PACKAGE_URL = "packageUrl"; - protected String packageName; + protected String packageName; // e.g. petstore_api protected String packageVersion; + protected String projectName; // for setup.py, e.g. petstore-api protected String packageUrl; protected String apiDocPath = "docs/"; protected String modelDocPath = "docs/"; @@ -114,6 +115,7 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig cliOptions.clear(); cliOptions.add(new CliOption(CodegenConstants.PACKAGE_NAME, "python package name (convention: snake_case).") .defaultValue("swagger_client")); + cliOptions.add(new CliOption(CodegenConstants.PROJECT_NAME, "python project name in setup.py (e.g. petstore-api).")); cliOptions.add(new CliOption(CodegenConstants.PACKAGE_VERSION, "python package version.") .defaultValue("1.0.0")); cliOptions.add(new CliOption(PACKAGE_URL, "python package URL.")); @@ -139,6 +141,15 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig setPackageName("swagger_client"); } + if (additionalProperties.containsKey(CodegenConstants.PROJECT_NAME)) { + setProjectName((String) additionalProperties.get(CodegenConstants.PROJECT_NAME)); + } + else { + // default: set project based on package name + // e.g. petstore_api (package name) => petstore-api (project name) + setProjectName(packageName.replaceAll("_", "-")); + } + if (additionalProperties.containsKey(CodegenConstants.PACKAGE_VERSION)) { setPackageVersion((String) additionalProperties.get(CodegenConstants.PACKAGE_VERSION)); } @@ -154,6 +165,7 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig Boolean.valueOf(additionalProperties().get(CodegenConstants.HIDE_GENERATION_TIMESTAMP).toString())); } + additionalProperties.put(CodegenConstants.PROJECT_NAME, projectName); additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName); additionalProperties.put(CodegenConstants.PACKAGE_VERSION, packageVersion); @@ -201,7 +213,7 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig // process enum in models return postProcessModelsEnum(objs); } - + @Override public void postProcessParameter(CodegenParameter parameter){ postProcessPattern(parameter.pattern, parameter.vendorExtensions); @@ -493,6 +505,10 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig this.packageName = packageName; } + public void setProjectName(String projectName) { + this.projectName= projectName; + } + public void setPackageVersion(String packageVersion) { this.packageVersion = packageVersion; } diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/RestbedCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/RestbedCodegen.java index 639b0d9f5a5..730d6e075b6 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/RestbedCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/RestbedCodegen.java @@ -1,5 +1,6 @@ package io.swagger.codegen.languages; +import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -181,7 +182,7 @@ public class RestbedCodegen extends DefaultCodegen implements CodegenConfig { * when the class is instantiated */ public String modelFileFolder() { - return outputFolder + "/model"; + return (outputFolder + "/model").replace("/", File.separator); } /** @@ -190,7 +191,7 @@ public class RestbedCodegen extends DefaultCodegen implements CodegenConfig { */ @Override public String apiFileFolder() { - return outputFolder + "/api"; + return (outputFolder + "/api").replace("/", File.separator); } @Override diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/StaticHtml2Generator.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/StaticHtml2Generator.java index 4ee92bd3246..daf7f96e3e9 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/StaticHtml2Generator.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/StaticHtml2Generator.java @@ -1,14 +1,7 @@ package io.swagger.codegen.languages; -import io.swagger.codegen.CliOption; -import io.swagger.codegen.CodegenConfig; -import io.swagger.codegen.CodegenConstants; -import io.swagger.codegen.CodegenOperation; -import io.swagger.codegen.CodegenParameter; -import io.swagger.codegen.CodegenResponse; -import io.swagger.codegen.CodegenType; -import io.swagger.codegen.DefaultCodegen; -import io.swagger.codegen.SupportingFile; +import com.samskivert.mustache.Mustache; +import io.swagger.codegen.*; import io.swagger.models.Info; import org.yaml.snakeyaml.error.Mark; import io.swagger.codegen.utils.Markdown; @@ -129,6 +122,7 @@ public class StaticHtml2Generator extends DefaultCodegen implements CodegenConfi response.code = "default"; } } + op.formParams = postProcessParameterEnum(op.formParams); } return objs; } @@ -215,6 +209,30 @@ public class StaticHtml2Generator extends DefaultCodegen implements CodegenConfi } } + /** + * Format to HTML the enums contained in every operations + * + * @param parameterList The whole parameters contained in one operation + * @return String | Html formated enum + */ + public List postProcessParameterEnum(List parameterList) { + String enumFormatted = ""; + for(CodegenParameter parameter : parameterList) { + if (parameter.isEnum) { + for (int i = 0; i < parameter._enum.size(); i++) { + String spacer = (i == (parameter._enum.size() - 1)) ? " " : ", "; + + if (parameter._enum.get(i) != null) + enumFormatted += "`" + parameter._enum.get(i) + "`" + spacer; + } + Markdown markInstance = new Markdown(); + if (!enumFormatted.isEmpty()) + parameter.vendorExtensions.put("x-eumFormatted", markInstance.toHtml(enumFormatted)); + } + } + return parameterList; + } + private String sanitizePath(String p) { //prefer replace a ', instead of a fuLL URL encode for readability return p.replaceAll("'", "%27"); diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/ApiClient.mustache index b8a5f95d9d1..986354e768b 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/ApiClient.mustache @@ -682,48 +682,56 @@ public class ApiClient { Entity entity = serialize(body, formParams, contentType); - Response response; + Response response = null; - if ("GET".equals(method)) { - response = invocationBuilder.get(); - } else if ("POST".equals(method)) { - response = invocationBuilder.post(entity); - } else if ("PUT".equals(method)) { - response = invocationBuilder.put(entity); - } else if ("DELETE".equals(method)) { - response = invocationBuilder.delete(); - } else if ("PATCH".equals(method)) { - response = invocationBuilder.header("X-HTTP-Method-Override", "PATCH").post(entity); - } else { - throw new ApiException(500, "unknown method type " + method); - } - - statusCode = response.getStatusInfo().getStatusCode(); - responseHeaders = buildResponseHeaders(response); - - if (response.getStatus() == Status.NO_CONTENT.getStatusCode()) { - return null; - } else if (response.getStatusInfo().getFamily() == Status.Family.SUCCESSFUL) { - if (returnType == null) - return null; - else - return deserialize(response, returnType); - } else { - String message = "error"; - String respBody = null; - if (response.hasEntity()) { - try { - respBody = String.valueOf(response.readEntity(String.class)); - message = respBody; - } catch (RuntimeException e) { - // e.printStackTrace(); - } + try { + if ("GET".equals(method)) { + response = invocationBuilder.get(); + } else if ("POST".equals(method)) { + response = invocationBuilder.post(entity); + } else if ("PUT".equals(method)) { + response = invocationBuilder.put(entity); + } else if ("DELETE".equals(method)) { + response = invocationBuilder.delete(); + } else if ("PATCH".equals(method)) { + response = invocationBuilder.header("X-HTTP-Method-Override", "PATCH").post(entity); + } else { + throw new ApiException(500, "unknown method type " + method); + } + + statusCode = response.getStatusInfo().getStatusCode(); + responseHeaders = buildResponseHeaders(response); + + if (response.getStatus() == Status.NO_CONTENT.getStatusCode()) { + return null; + } else if (response.getStatusInfo().getFamily() == Status.Family.SUCCESSFUL) { + if (returnType == null) + return null; + else + return deserialize(response, returnType); + } else { + String message = "error"; + String respBody = null; + if (response.hasEntity()) { + try { + respBody = String.valueOf(response.readEntity(String.class)); + message = respBody; + } catch (RuntimeException e) { + // e.printStackTrace(); + } + } + throw new ApiException( + response.getStatus(), + message, + buildResponseHeaders(response), + respBody); + } + } finally { + try { + response.close(); + } catch (Exception e) { + // it's not critical, since the response object is local in method invokeAPI; that's fine, just continue } - throw new ApiException( - response.getStatus(), - message, - buildResponseHeaders(response), - respBody); } } diff --git a/modules/swagger-codegen/src/main/resources/JavaSpring/api.mustache b/modules/swagger-codegen/src/main/resources/JavaSpring/api.mustache index 2f112dcdaad..94de93b8646 100644 --- a/modules/swagger-codegen/src/main/resources/JavaSpring/api.mustache +++ b/modules/swagger-codegen/src/main/resources/JavaSpring/api.mustache @@ -1,3 +1,8 @@ +/** + * NOTE: This class is auto generated by the swagger code generator program ({{{generatorVersion}}}). + * https://github.com/swagger-api/swagger-codegen + * Do not edit the class manually. + */ package {{package}}; {{#imports}}import {{import}}; diff --git a/modules/swagger-codegen/src/main/resources/Javascript-Closure-Angular/es6/api.mustache b/modules/swagger-codegen/src/main/resources/Javascript-Closure-Angular/es6/api.mustache new file mode 100644 index 00000000000..ffb87706783 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript-Closure-Angular/es6/api.mustache @@ -0,0 +1,64 @@ +/** + * @fileoverview AUTOMATICALLY GENERATED service for {{package}}.{{classname}}. + * Do not edit this file by hand or your changes will be lost next time it is + * generated.{{#appDescription}} + * + * {{ appDescription }}{{/appDescription}}{{#version}} + * Version: {{version}}{{/version}}{{#appContact}} + * Contact: {{appContact}}{{/appContact}} +{{^hideGenerationTimestamp}} + * Generated at: {{generatedDate}} +{{/hideGenerationTimestamp}} + * Generated by: {{generatorClass}} + */{{#licenseInfo}} +/** + * @license {{licenseInfo}}{{#licenseUrl}} + * {{licenseUrl}}{{/licenseUrl}} + */ +{{/licenseInfo}} + +{{#operations}} + +export default class {{classname}} { + + /** + {{#description}} + * {{&description}} + {{/description}} + * @constructor + * @param {!angular.$resource} $resource + * @ngInject + */ + constructor($resource) { + this.basePath = '{{basePath}}'; + + return $resource(null, {}, { + {{#operation}} + '{{operationId}}': this.{{operationId}}(), + {{/operation}} + }); + } + +{{#operation}} + + /** + * {{summary}} + * {{notes}} {{#pathParams}} + * @param {object} { {{paramName}} : !{{{dataType}}}{{^required}}={{/required}} } path parameters required by resource {{/pathParams}}{{#bodyParams}} + * @param {object} { {{paramName}} : !{{{dataType}}}{{^required}}={{/required}} } postData required by resource {{/bodyParams}} + * @param {function} Success Callback + * @param {function} Error Callback + * @return {object} + */ + {{operationId}}() { + return { + method: '{{httpMethod}}', + url: this.basePath + '{{path}}' + {{#pathParams}} + .replace('{' + '{{baseName}}' + '}', ':{{paramName}}') + {{/pathParams}} + } + } +{{/operation}} +} +{{/operations}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/Javascript-Closure-Angular/es6/module.mustache b/modules/swagger-codegen/src/main/resources/Javascript-Closure-Angular/es6/module.mustache new file mode 100644 index 00000000000..e142e74c187 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript-Closure-Angular/es6/module.mustache @@ -0,0 +1,18 @@ +{{#apiInfo}} +{{#apis}} +{{#operations}} +import {{classname}} from './resources/{{classname}}'; +{{/operations}} +{{/apis}} + +let moduleName = '{{appName}}'.toLowerCase().replace(/\s/g, '.'); + +export default angular + .module(moduleName, []) + {{#apis}} + {{#operations}} + .service('{{classname}}', {{classname}}) + {{/operations}} + {{/apis}}; + +{{/apiInfo}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig b/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig index 5f55c67e100..d14bc660c0e 100644 --- a/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig +++ b/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig @@ -41,6 +41,7 @@ io.swagger.codegen.languages.NodeJSServerCodegen io.swagger.codegen.languages.ObjcClientCodegen io.swagger.codegen.languages.PerlClientCodegen io.swagger.codegen.languages.PhpClientCodegen +io.swagger.codegen.languages.PistacheServerCodegen io.swagger.codegen.languages.PythonClientCodegen io.swagger.codegen.languages.Qt5CPPGenerator io.swagger.codegen.languages.Rails5ServerCodegen diff --git a/modules/swagger-codegen/src/main/resources/htmlDocs2/index.mustache b/modules/swagger-codegen/src/main/resources/htmlDocs2/index.mustache index 53946c40214..c50e1ab7b17 100644 --- a/modules/swagger-codegen/src/main/resources/htmlDocs2/index.mustache +++ b/modules/swagger-codegen/src/main/resources/htmlDocs2/index.mustache @@ -59,11 +59,6 @@ }); } - - // load google web fonts - loadGoogleFontCss(); - - // Bootstrap Scrollspy $(this).scrollspy({ target: '#scrollingNav', offset: 18 }); @@ -105,21 +100,6 @@ //Convert elements with "marked" class to markdown processMarked(); - - /** - * Load google fonts. - */ - function loadGoogleFontCss() { - WebFont.load({ - active: function() { - // Update scrollspy - $(window).scrollspy('refresh') - }, - google: { - families: ['Source Code Pro', 'Source Sans Pro:n4,n6,n7'] - } - }); - } });