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

This commit is contained in:
William Cheng 2021-01-08 21:06:47 +08:00
commit 18bec1da28
954 changed files with 41988 additions and 4607 deletions

View File

@ -7,5 +7,5 @@
- [ ] Pull Request title clearly describes the work in the pull request and Pull Request description provides details about how to validate the work. Missing information here may result in delayed response from the community.
- [ ] If contributing template-only or documentation-only changes which will change sample output, [build the project](https://github.com/OpenAPITools/openapi-generator#14---build-projects) beforehand.
- [ ] Run the shell script `./bin/generate-samples.sh`to update all Petstore samples related to your fix. This is important, as CI jobs will verify _all_ generator outputs of your HEAD commit as it would merge with master. These must match the expectations made by your contribution. You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example `./bin/generate-samples.sh bin/configs/java*`. For Windows users, please run the script in [Git BASH](https://gitforwindows.org/).
- [ ] File the PR against the [correct branch](https://github.com/OpenAPITools/openapi-generator/wiki/Git-Branches): `master`
- [ ] File the PR against the [correct branch](https://github.com/OpenAPITools/openapi-generator/wiki/Git-Branches): `master`, `5.1.x`, `6.0.x`
- [ ] Copy the [technical committee](https://github.com/openapitools/openapi-generator/#62---openapi-generator-technical-committee) to review the pull request if your PR is targeting a particular programming language.

3
.gitignore vendored
View File

@ -258,3 +258,6 @@ samples/client/petstore/c/*.so
# Ruby
samples/openapi3/client/petstore/ruby/Gemfile.lock
samples/openapi3/client/petstore/ruby-faraday/Gemfile.lock
# Crystal
samples/client/petstore/crystal/lib

117
.mvn/wrapper/MavenWrapperDownloader.java vendored Normal file
View File

@ -0,0 +1,117 @@
/*
* Copyright 2007-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
* use instead of the default one.
*/
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
".mvn/wrapper/maven-wrapper.properties";
/**
* Path where the maven-wrapper.jar will be saved to.
*/
private static final String MAVEN_WRAPPER_JAR_PATH =
".mvn/wrapper/maven-wrapper.jar";
/**
* Name of the property which should be used to override the default download url for the wrapper.
*/
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
public static void main(String args[]) {
System.out.println("- Downloader started");
File baseDirectory = new File(args[0]);
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
// If the maven-wrapper.properties exists, read it and check if it contains a custom
// wrapperUrl parameter.
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
String url = DEFAULT_DOWNLOAD_URL;
if(mavenWrapperPropertyFile.exists()) {
FileInputStream mavenWrapperPropertyFileInputStream = null;
try {
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
Properties mavenWrapperProperties = new Properties();
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
} catch (IOException e) {
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
} finally {
try {
if(mavenWrapperPropertyFileInputStream != null) {
mavenWrapperPropertyFileInputStream.close();
}
} catch (IOException e) {
// Ignore ...
}
}
}
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
try {
downloadFileFromURL(url, outputFile);
System.out.println("Done");
System.exit(0);
} catch (Throwable e) {
System.out.println("- Error downloading");
e.printStackTrace();
System.exit(1);
}
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destination);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
}
}

Binary file not shown.

View File

@ -1 +1,2 @@
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.3/apache-maven-3.3.3-bin.zip
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

View File

@ -62,6 +62,17 @@ addons:
- petstore.swagger.io
before_install:
# to run petstore server locally via docker
- echo "$DOCKER_HUB_PASSWORD" | docker login --username=$DOCKER_HUB_USERNAME --password-stdin || true
- docker pull swaggerapi/petstore
- docker run -d -e SWAGGER_HOST=http://petstore.swagger.io -e SWAGGER_BASE_PATH=/v2 -p 80:8080 swaggerapi/petstore
- docker ps -a
# install crystal
- curl -sSL https://dist.crystal-lang.org/apt/setup.sh | sudo bash
- curl -sL "https://keybase.io/crystal/pgp_keys.asc" | sudo apt-key add -
- echo "deb https://dist.crystal-lang.org/apt crystal main" | sudo tee /etc/apt/sources.list.d/crystal.list
- sudo apt-get update
- sudo apt install crystal
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.22.0
- export PATH="$HOME/.yarn/bin:$PATH"
# install rust
@ -75,10 +86,6 @@ before_install:
- npm config set registry http://registry.npmjs.org/
# set python 3.6.3 as default
- source ~/virtualenv/python3.6/bin/activate
# to run petstore server locally via docker
- docker pull swaggerapi/petstore
- docker run -d -e SWAGGER_HOST=http://petstore.swagger.io -e SWAGGER_BASE_PATH=/v2 -p 80:8080 swaggerapi/petstore
- docker ps -a
# -- skip bash test to shorten build time
# Add bats test framework and cURL for Bash script integration tests
#- sudo add-apt-repository ppa:duggan/bats --yes
@ -124,7 +131,7 @@ before_install:
fi;
- pushd .; cd website; yarn install; popd
# install Deno
- sh -s v1.1.2 < ./CI/deno_install.sh
- sh -s v1.6.2 < ./CI/deno_install.sh
- export PATH="$HOME/.deno/bin:$PATH"
install:

View File

@ -41,13 +41,14 @@ elif [ "$NODE_INDEX" = "2" ]; then
curl -sSL https://get.haskellstack.org/ | sh
stack upgrade
stack --version
# install r
# prepare r
sudo sh -c 'echo "deb http://cran.rstudio.com/bin/linux/ubuntu trusty/" >> /etc/apt/sources.list'
gpg --keyserver keyserver.ubuntu.com --recv-key E084DAB9
gpg -a --export E084DAB9 | sudo apt-key add -
sudo apt-get update
sudo apt-get -y install r-base
R --version
# install curl
sudo apt-get -y build-dep libcurl4-gnutls-dev
sudo apt-get -y install libcurl4-gnutls-dev

View File

@ -49,6 +49,7 @@ Code change should conform to the programming style guide of the respective lang
- C++: https://google.github.io/styleguide/cppguide.html
- C++ (Tizen): https://wiki.tizen.org/Native_Platform_Coding_Idiom_and_Style_Guide#C.2B.2B_Coding_Style
- Clojure: https://github.com/bbatsov/clojure-style-guide
- Crystal: https://crystal-lang.org/reference/conventions/coding_style.html
- Dart: https://www.dartlang.org/guides/language/effective-dart/style
- Elixir: https://github.com/christopheradams/elixir_style_guide
- Eiffel: https://www.eiffel.org/doc/eiffel/Coding%20Standards

View File

@ -9,7 +9,7 @@
<div align="center">
[Master](https://github.com/OpenAPITools/openapi-generator/tree/master) (`5.0.0`):
[Master](https://github.com/OpenAPITools/openapi-generator/tree/master) (`5.0.1`):
[![Build Status](https://img.shields.io/travis/OpenAPITools/openapi-generator/master.svg?label=Integration%20Test)](https://travis-ci.org/OpenAPITools/openapi-generator)
[![Integration Test2](https://circleci.com/gh/OpenAPITools/openapi-generator.svg?style=shield)](https://circleci.com/gh/OpenAPITools/openapi-generator)
[![Run Status](https://api.shippable.com/projects/5af6bf74e790f4070084a115/badge?branch=master)](https://app.shippable.com/github/OpenAPITools/openapi-generator)
@ -18,6 +18,22 @@
[![Bitrise](https://img.shields.io/bitrise/4a2b10a819d12b67/master?label=bitrise%3A%20Swift+4,5&token=859FMDR8QHwabCzwvZK6vQ)](https://app.bitrise.io/app/4a2b10a819d12b67)
[![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/openapitools/openapi-generator/Check%20Supported%20Java%20Versions/master?label=Check%20Supported%20Java%20Versions&logo=github&logoColor=green)](https://github.com/OpenAPITools/openapi-generator/actions?query=workflow%3A%22Check+Supported+Java+Versions%22)
[5.1.x](https://github.com/OpenAPITools/openapi-generator/tree/5.1.x) (`5.1.x`):
[![Build Status](https://img.shields.io/travis/OpenAPITools/openapi-generator/5.1.x.svg?label=Integration%20Test)](https://travis-ci.org/OpenAPITools/openapi-generator)
[![Integration Test2](https://circleci.com/gh/OpenAPITools/openapi-generator/tree/5.1.x.svg?style=shield)](https://circleci.com/gh/OpenAPITools/openapi-generator)
[![Run Status](https://api.shippable.com/projects/5af6bf74e790f4070084a115/badge?branch=5.1.x)](https://app.shippable.com/github/OpenAPITools/openapi-generator)
[![Windows Test](https://ci.appveyor.com/api/projects/status/github/openapitools/openapi-generator?branch=5.1.x&svg=true&passingText=Windows%20Test%20-%20OK&failingText=Windows%20Test%20-%20Fails)](https://ci.appveyor.com/project/WilliamCheng/openapi-generator-wh2wu)
[![JDK11 Build](https://cloud.drone.io/api/badges/OpenAPITools/openapi-generator/status.svg?ref=refs/heads/5.1.x)](https://cloud.drone.io/OpenAPITools/openapi-generator)
[![Bitrise](https://img.shields.io/bitrise/4a2b10a819d12b67/5.1.x?label=bitrise%3A%20Swift+4,5&token=859FMDR8QHwabCzwvZK6vQ)](https://app.bitrise.io/app/4a2b10a819d12b67)
[6.0.x](https://github.com/OpenAPITools/openapi-generator/tree/6.0.x) (`6.0.x`):
[![Build Status](https://img.shields.io/travis/OpenAPITools/openapi-generator/6.0.x.svg?label=Integration%20Test)](https://travis-ci.org/OpenAPITools/openapi-generator)
[![Integration Test2](https://circleci.com/gh/OpenAPITools/openapi-generator/tree/6.0.x.svg?style=shield)](https://circleci.com/gh/OpenAPITools/openapi-generator)
[![Run Status](https://api.shippable.com/projects/5af6bf74e790f4070084a115/badge?branch=6.0.x)](https://app.shippable.com/github/OpenAPITools/openapi-generator)
[![Windows Test](https://ci.appveyor.com/api/projects/status/github/openapitools/openapi-generator?branch=6.0.x&svg=true&passingText=Windows%20Test%20-%20OK&failingText=Windows%20Test%20-%20Fails)](https://ci.appveyor.com/project/WilliamCheng/openapi-generator-wh2wu)
[![JDK11 Build](https://cloud.drone.io/api/badges/OpenAPITools/openapi-generator/status.svg?ref=refs/heads/6.0.x)](https://cloud.drone.io/OpenAPITools/openapi-generator)
[![Bitrise](https://img.shields.io/bitrise/4a2b10a819d12b67/6.0.x?label=bitrise%3A%20Swift+4,5&token=859FMDR8QHwabCzwvZK6vQ)](https://app.bitrise.io/app/4a2b10a819d12b67)
</div>
<div align="center">
@ -60,11 +76,11 @@ OpenAPI Generator allows generation of API client libraries (SDK generation), se
| | Languages/Frameworks |
| -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **API clients** | **ActionScript**, **Ada**, **Apex**, **Bash**, **C**, **C#** (.net 2.0, 3.5 or later, .NET Standard 1.3 - 2.0, .NET Core 2.0), **C++** (cpp-restsdk, Qt5, Tizen), **Clojure**, **Dart**, **Elixir**, **Elm**, **Eiffel**, **Erlang**, **Go**, **Groovy**, **Haskell** (http-client, Servant), **Java** (Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign, RestTemplate, RESTEasy, Vertx, Google API Client Library for Java, Rest-assured, Spring 5 Web Client, MicroProfile Rest Client), **k6**, **Kotlin**, **Lua**, **Nim**, **Node.js/JavaScript** (ES5, ES6, AngularJS with Google Closure Compiler annotations, Flow types, Apollo GraphQL DataStore), **Objective-C**, **OCaml**, **Perl**, **PHP**, **PowerShell**, **Python**, **R**, **Ruby**, **Rust** (rust, rust-server), **Scala** (akka, http4s, scalaz, sttp, swagger-async-httpclient), **Swift** (2.x, 3.x, 4.x, 5.x), **Typescript** (AngularJS, Angular (2.x - 8.x), Aurelia, Axios, Fetch, Inversify, jQuery, Node, Rxjs) |
| **API clients** | **ActionScript**, **Ada**, **Apex**, **Bash**, **C**, **C#** (.net 2.0, 3.5 or later, .NET Standard 1.3 - 2.0, .NET Core 2.0), **C++** (cpp-restsdk, Qt5, Tizen), **Clojure**, **Crystal**, **Dart**, **Elixir**, **Elm**, **Eiffel**, **Erlang**, **Go**, **Groovy**, **Haskell** (http-client, Servant), **Java** (Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign, RestTemplate, RESTEasy, Vertx, Google API Client Library for Java, Rest-assured, Spring 5 Web Client, MicroProfile Rest Client), **k6**, **Kotlin**, **Lua**, **Nim**, **Node.js/JavaScript** (ES5, ES6, AngularJS with Google Closure Compiler annotations, Flow types, Apollo GraphQL DataStore), **Objective-C**, **OCaml**, **Perl**, **PHP**, **PowerShell**, **Python**, **R**, **Ruby**, **Rust** (rust, rust-server), **Scala** (akka, http4s, scalaz, sttp, swagger-async-httpclient), **Swift** (2.x, 3.x, 4.x, 5.x), **Typescript** (AngularJS, Angular (2.x - 8.x), Aurelia, Axios, Fetch, Inversify, jQuery, Node, Rxjs) |
| **Server stubs** | **Ada**, **C#** (ASP.NET Core, NancyFx), **C++** (Pistache, Restbed, Qt5 QHTTPEngine), **Erlang**, **F#** (Giraffe), **Go** (net/http, Gin), **Haskell** (Servant), **Java** (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, Jersey, RestEasy, Play Framework, [PKMST](https://github.com/ProKarma-Inc/pkmst-getting-started-examples), [Vert.x](https://vertx.io/)), **Kotlin** (Spring Boot, Ktor, Vertx), **PHP** (Laravel, Lumen, Slim, Silex, [Symfony](https://symfony.com/), [Zend Expressive](https://github.com/zendframework/zend-expressive)), **Python** (Flask), **NodeJS**, **Ruby** (Sinatra, Rails5), **Rust** (rust-server), **Scala** (Akka, [Finch](https://github.com/finagle/finch), [Lagom](https://github.com/lagom/lagom), [Play](https://www.playframework.com/), Scalatra) |
| **API documentation generators** | **HTML**, **Confluence Wiki**, **Asciidoc** |
| **Configuration files** | [**Apache2**](https://httpd.apache.org/) |
| **Others** | **GraphQL**, **JMeter**, **MySQL Schema**, **Protocol Buffer** |
| **Others** | **GraphQL**, **JMeter**, **Ktorm**, **MySQL Schema**, **Protocol Buffer** |
## Table of contents
@ -102,7 +118,9 @@ The OpenAPI Specification has undergone 3 revisions since initial creation in 20
| OpenAPI Generator Version | Release Date | Notes |
| --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | ------------------------------------------------- |
| 5.0.1 (upcoming patch release) [SNAPSHOT](https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator-cli/5.0.1-SNAPSHOT/) | TBD | Patch release with enhancements, bug fixes, etc |
| 6.0.0 (upcoming major release) [SNAPSHOT](https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator-cli/6.0.0-SNAPSHOT/) | Nov/Dec 2021 | Minor release with breaking changes (no fallback) |
| 5.1.0 (upcoming minor release) [SNAPSHOT](https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator-cli/5.1.0-SNAPSHOT/) | Mar/Apr 2021 | Minor release with breaking changes (with fallback) |
| 5.0.1 (upcoming patch release) [SNAPSHOT](https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator-cli/5.0.1-SNAPSHOT/) | Jan/Feb 2021 | Patch release with enhancements, bug fixes, etc |
| [5.0.0](https://github.com/OpenAPITools/openapi-generator/releases/tag/v5.0.0) (latest stable release) | 21.12.2020 | Major release with breaking changes (no fallback) |
| [4.3.1](https://github.com/OpenAPITools/openapi-generator/releases/tag/v4.3.1) | 06.05.2020 | Patch release (enhancements, bug fixes, etc) |
@ -824,6 +842,7 @@ Here is a list of template creators:
* C# (.NET Standard 1.3 ): @Gronsak
* C# (.NET 4.5 refactored): @jimschubert [:heart:](https://www.patreon.com/jimschubert)
* Clojure: @xhh
* Crystal: @wing328
* Dart: @yissachar
* Dart (refactor): @joernahrens
* Dart 2: @swipesight
@ -939,6 +958,7 @@ Here is a list of template creators:
* Schema
* Avro: @sgadouar
* GraphQL: @wing328 [:heart:](https://www.patreon.com/wing328)
* Ktorm: @Luiz-Monad
* MySQL: @ybelenko
* Protocol Buffer: @wing328
@ -990,11 +1010,11 @@ If you want to join the committee, please kindly apply by sending an email to te
| Elm | @eriktim (2018/09) |
| Erlang | @tsloughter (2017/11) @jfacorro (2018/10) @robertoaloi (2018/10) |
| F# | @nmfisher (2019/05) |
| Go | @antihax (2017/11) @grokify (2018/07) @kemokemo (2018/09) @bkabrda (2019/07) |
| Go | @antihax (2017/11) @grokify (2018/07) @kemokemo (2018/09) @jirikuncar (2021/01) |
| GraphQL | @renepardon (2018/12) |
| Groovy | |
| Haskell | |
| Java | @bbdouglas (2017/07) @sreeshas (2017/08) @jfiala (2017/08) @lukoyanov (2017/09) @cbornet (2017/09) @jeff9finger (2018/01) @karismann (2019/03) @Zomzog (2019/04) @lwlee2608 (2019/10) @bkabrda (2020/01) |
| Java | @bbdouglas (2017/07) @sreeshas (2017/08) @jfiala (2017/08) @lukoyanov (2017/09) @cbornet (2017/09) @jeff9finger (2018/01) @karismann (2019/03) @Zomzog (2019/04) @lwlee2608 (2019/10) @nmuesch (2021/01) |
| Kotlin | @jimschubert (2017/09) [:heart:](https://www.patreon.com/jimschubert), @dr4ke616 (2018/08) @karismann (2019/03) @Zomzog (2019/04) @andrewemery (2019/10) @4brunu (2019/11) @yutaka0m (2020/03) |
| Lua | @daurnimator (2017/08) |
| Nim | |

9
bin/configs/crystal.yaml Normal file
View File

@ -0,0 +1,9 @@
generatorName: crystal
outputDir: samples/client/petstore/crystal
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/crystal
additionalProperties:
shardVersion: 1.0.0
moduleName: Petstore
shardName: petstore
strictSpecBehavior: false

View File

@ -0,0 +1,7 @@
generatorName: ktorm-schema
outputDir: samples/schema/petstore/ktorm
inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/ktorm-schema
additionalProperties:
hideGenerationTimestamp: true
importModelPackageName: org.openapitools.client.models

View File

@ -0,0 +1,8 @@
generatorName: ruby
outputDir: samples/openapi3/client/extensions/x-auth-id-alias/ruby-client
inputSpec: modules/openapi-generator/src/test/resources/3_0/extensions/x-auth-id-alias.yaml
templateDir: modules/openapi-generator/src/main/resources/ruby-client
additionalProperties:
gemName: x_auth_id_alias
gemVersion: 1.0.0
moduleName: XAuthIDAlias

View File

@ -0,0 +1,6 @@
generatorName: typescript-angular
outputDir: samples/client/petstore/typescript-angular-v9-provided-in-any/builds/default
inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore.yaml
additionalProperties:
ngVersion: 9.0.0
providedIn: any

View File

@ -53,6 +53,7 @@ Code change should conform to the programming style guide of the respective lang
- C++: https://google.github.io/styleguide/cppguide.html
- C++ (Tizen): https://wiki.tizen.org/Native_Platform_Coding_Idiom_and_Style_Guide#C.2B.2B_Coding_Style
- Clojure: https://github.com/bbatsov/clojure-style-guide
- Crystal: https://crystal-lang.org/reference/conventions/coding_style.html
- Dart: https://www.dartlang.org/guides/language/effective-dart/style
- Elixir: https://github.com/christopheradams/elixir_style_guide
- Eiffel: https://www.eiffel.org/doc/eiffel/Coding%20Standards

View File

@ -16,6 +16,7 @@ The following generators are available:
* [cpp-restsdk](generators/cpp-restsdk.md)
* [cpp-tizen](generators/cpp-tizen.md)
* [cpp-ue4 (beta)](generators/cpp-ue4.md)
* [crystal (beta)](generators/crystal.md)
* [csharp](generators/csharp.md)
* [csharp-dotnet2 (deprecated)](generators/csharp-dotnet2.md)
* [csharp-netcore](generators/csharp-netcore.md)
@ -141,6 +142,7 @@ The following generators are available:
## SCHEMA generators
* [avro-schema (beta)](generators/avro-schema.md)
* [graphql-schema](generators/graphql-schema.md)
* [ktorm-schema (beta)](generators/ktorm-schema.md)
* [mysql-schema](generators/mysql-schema.md)
* [protobuf-schema (beta)](generators/protobuf-schema.md)

View File

@ -56,41 +56,109 @@ These options may be applied as additional-properties (cli) or configOptions (pl
<li>_noreturn</li>
<li>_static_assert</li>
<li>_thread_local</li>
<li>alignas</li>
<li>alignof</li>
<li>and</li>
<li>and_eq</li>
<li>asm</li>
<li>atomic_cancel</li>
<li>atomic_commit</li>
<li>atomic_noexcept</li>
<li>auto</li>
<li>bitand</li>
<li>bitor</li>
<li>bool</li>
<li>break</li>
<li>case</li>
<li>catch</li>
<li>char</li>
<li>char16_t</li>
<li>char32_t</li>
<li>char8_t</li>
<li>class</li>
<li>co_await</li>
<li>co_return</li>
<li>co_yield</li>
<li>compl</li>
<li>concept</li>
<li>const</li>
<li>const_cast</li>
<li>consteval</li>
<li>constexpr</li>
<li>constinit</li>
<li>continue</li>
<li>decltype</li>
<li>default</li>
<li>delete</li>
<li>do</li>
<li>double</li>
<li>dynamic_cast</li>
<li>else</li>
<li>enum</li>
<li>explicit</li>
<li>export</li>
<li>extern</li>
<li>false</li>
<li>final</li>
<li>float</li>
<li>for</li>
<li>friend</li>
<li>goto</li>
<li>if</li>
<li>inline</li>
<li>int</li>
<li>long</li>
<li>mutable</li>
<li>namespace</li>
<li>new</li>
<li>noexcept</li>
<li>not</li>
<li>not_eq</li>
<li>nullptr</li>
<li>operator</li>
<li>or</li>
<li>or_eq</li>
<li>override</li>
<li>private</li>
<li>protected</li>
<li>public</li>
<li>reflexpr</li>
<li>register</li>
<li>reinterpret_cast</li>
<li>remove</li>
<li>requires</li>
<li>restrict</li>
<li>return</li>
<li>short</li>
<li>signed</li>
<li>sizeof</li>
<li>static</li>
<li>static_assert</li>
<li>static_cast</li>
<li>struct</li>
<li>switch</li>
<li>synchronized</li>
<li>template</li>
<li>this</li>
<li>thread_local</li>
<li>throw</li>
<li>transaction_safe</li>
<li>transaction_safe_dynamic</li>
<li>true</li>
<li>try</li>
<li>typedef</li>
<li>typeid</li>
<li>typename</li>
<li>union</li>
<li>unsigned</li>
<li>using</li>
<li>virtual</li>
<li>void</li>
<li>volatile</li>
<li>wchar_t</li>
<li>while</li>
<li>xor</li>
<li>xor_eq</li>
</ul>
## FEATURE SET

226
docs/generators/crystal.md Normal file
View File

@ -0,0 +1,226 @@
---
title: Config Options for crystal
sidebar_label: crystal
---
These options may be applied as additional-properties (cli) or configOptions (plugins). Refer to [configuration docs](https://openapi-generator.tech/docs/configuration) for more details.
| Option | Description | Values | Default |
| ------ | ----------- | ------ | ------- |
|allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false|
|disallowAdditionalPropertiesIfNotPresent|If false, the 'additionalProperties' implementation (set to true by default) is compliant with the OAS and JSON schema specifications. If true (default), keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.|<dl><dt>**false**</dt><dd>The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications.</dd><dt>**true**</dt><dd>Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.</dd></dl>|true|
|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true|
|legacyDiscriminatorBehavior|Set to true for generators with better support for discriminators. (Python, Java, Go, PowerShell, C#have this enabled by default).|<dl><dt>**true**</dt><dd>The mapping in the discriminator includes descendent schemas that allOf inherit from self and the discriminator mapping schemas in the OAS document.</dd><dt>**false**</dt><dd>The mapping in the discriminator includes any descendent schemas that allOf inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values, and the discriminator mapping schemas in the OAS document AND Codegen validates that oneOf and anyOf schemas contain the required discriminator and throws an error if the discriminator is missing.</dd></dl>|true|
|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|
|shardAuthor|shard author (only one is supported).| |null|
|shardAuthorEmail|shard author email (only one is supported).| |null|
|shardDescription|shard description.| |This shard maps to a REST API|
|shardHomepage|shard homepage.| |http://org.openapitools|
|shardLicense|shard license.| |unlicense|
|shardName|shard name (e.g. twitter_client| |openapi_client|
|shardVersion|shard version.| |1.0.0|
|sortModelPropertiesByRequiredFlag|Sort model properties to place required parameters before optional parameters.| |true|
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
## IMPORT MAPPING
| Type/Alias | Imports |
| ---------- | ------- |
## INSTANTIATION TYPES
| Type/Alias | Instantiated By |
| ---------- | --------------- |
|array|Array|
|map|Hash|
|set|Set|
## LANGUAGE PRIMITIVES
<ul class="column-ul">
<li>Array</li>
<li>Boolean</li>
<li>Date</li>
<li>File</li>
<li>Float</li>
<li>Hash</li>
<li>Integer</li>
<li>Object</li>
<li>String</li>
<li>Time</li>
</ul>
## RESERVED WORDS
<ul class="column-ul">
<li>abstract</li>
<li>alias</li>
<li>as</li>
<li>as?</li>
<li>asm</li>
<li>begin</li>
<li>break</li>
<li>case</li>
<li>class</li>
<li>def</li>
<li>do</li>
<li>else</li>
<li>elsif</li>
<li>end</li>
<li>ensure</li>
<li>enum</li>
<li>extend</li>
<li>false</li>
<li>for</li>
<li>fun</li>
<li>if</li>
<li>in</li>
<li>include</li>
<li>instance</li>
<li>is_a?</li>
<li>lib</li>
<li>macro</li>
<li>module</li>
<li>next</li>
<li>nil</li>
<li>nil?</li>
<li>of</li>
<li>out</li>
<li>pointerof</li>
<li>private</li>
<li>protected</li>
<li>require</li>
<li>rescue</li>
<li>responds_to?</li>
<li>return</li>
<li>select</li>
<li>self</li>
<li>sizeof</li>
<li>struct</li>
<li>super</li>
<li>then</li>
<li>true</li>
<li>type</li>
<li>typeof</li>
<li>uninitialized</li>
<li>union</li>
<li>unless</li>
<li>until</li>
<li>verbatim</li>
<li>when</li>
<li>while</li>
<li>with</li>
<li>yield</li>
</ul>
## FEATURE SET
### Client Modification Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|BasePath|✓|ToolingExtension
|Authorizations|✗|ToolingExtension
|UserAgent|✓|ToolingExtension
|MockServer|✗|ToolingExtension
### Data Type Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Custom|✗|OAS2,OAS3
|Int32|✓|OAS2,OAS3
|Int64|✓|OAS2,OAS3
|Float|✓|OAS2,OAS3
|Double|✓|OAS2,OAS3
|Decimal|✓|ToolingExtension
|String|✓|OAS2,OAS3
|Byte|✓|OAS2,OAS3
|Binary|✓|OAS2,OAS3
|Boolean|✓|OAS2,OAS3
|Date|✓|OAS2,OAS3
|DateTime|✓|OAS2,OAS3
|Password|✓|OAS2,OAS3
|File|✓|OAS2
|Array|✓|OAS2,OAS3
|Maps|✓|ToolingExtension
|CollectionFormat|✓|OAS2
|CollectionFormatMulti|✓|OAS2
|Enum|✓|OAS2,OAS3
|ArrayOfEnum|✓|ToolingExtension
|ArrayOfModel|✓|ToolingExtension
|ArrayOfCollectionOfPrimitives|✓|ToolingExtension
|ArrayOfCollectionOfModel|✓|ToolingExtension
|ArrayOfCollectionOfEnum|✓|ToolingExtension
|MapOfEnum|✓|ToolingExtension
|MapOfModel|✓|ToolingExtension
|MapOfCollectionOfPrimitives|✓|ToolingExtension
|MapOfCollectionOfModel|✓|ToolingExtension
|MapOfCollectionOfEnum|✓|ToolingExtension
### Documentation Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Readme|✓|ToolingExtension
|Model|✓|ToolingExtension
|Api|✓|ToolingExtension
### Global Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Host|✓|OAS2,OAS3
|BasePath|✓|OAS2,OAS3
|Info|✓|OAS2,OAS3
|Schemes|✗|OAS2,OAS3
|PartialSchemes|✓|OAS2,OAS3
|Consumes|✓|OAS2
|Produces|✓|OAS2
|ExternalDocumentation|✓|OAS2,OAS3
|Examples|✓|OAS2,OAS3
|XMLStructureDefinitions|✗|OAS2,OAS3
|MultiServer|✗|OAS3
|ParameterizedServer|✗|OAS3
|ParameterStyling|✗|OAS3
|Callbacks|✗|OAS3
|LinkObjects|✗|OAS3
### Parameter Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Path|✓|OAS2,OAS3
|Query|✓|OAS2,OAS3
|Header|✓|OAS2,OAS3
|Body|✓|OAS2
|FormUnencoded|✓|OAS2
|FormMultipart|✓|OAS2
|Cookie|✗|OAS3
### Schema Support Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Simple|✓|OAS2,OAS3
|Composite|✓|OAS2,OAS3
|Polymorphism|✓|OAS2,OAS3
|Union|✗|OAS3
### Security Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|BasicAuth|✓|OAS2,OAS3
|ApiKey|✓|OAS2,OAS3
|OpenIDConnect|✗|OAS3
|BearerToken|✓|OAS3
|OAuth2_Implicit|✓|OAS2,OAS3
|OAuth2_Password|✗|OAS2,OAS3
|OAuth2_ClientCredentials|✗|OAS2,OAS3
|OAuth2_AuthorizationCode|✗|OAS2,OAS3
### Wire Format Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|JSON|✓|OAS2,OAS3
|XML|✓|OAS2,OAS3
|PROTOBUF|✗|ToolingExtension
|Custom|✓|OAS2,OAS3

View File

@ -0,0 +1,355 @@
---
title: Config Options for ktorm-schema
sidebar_label: ktorm-schema
---
These options may be applied as additional-properties (cli) or configOptions (plugins). Refer to [configuration docs](https://openapi-generator.tech/docs/configuration) for more details.
| Option | Description | Values | Default |
| ------ | ----------- | ------ | ------- |
|addSurrogateKey|Adds the surrogate key for all models that don't already have a primary key (named by the above convention)| |false|
|artifactId|Generated artifact id (name of jar).| |ktorm|
|artifactVersion|Generated artifact's package version.| |1.0.0|
|defaultDatabaseName|Default database name for all queries| |sqlite.db|
|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |camelCase|
|groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools|
|identifierNamingConvention|Naming convention of Ktorm 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|
|importModelPackageName|Package name of the imported models| |org.openapitools.database.models|
|modelMutable|Create mutable models| |false|
|packageName|Generated artifact package name.| |org.openapitools.database|
|primaryKeyConvention|Primary key naming convention| |id|
|sortModelPropertiesByRequiredFlag|Sort model properties to place required parameters before optional parameters.| |null|
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |null|
|sourceFolder|source folder for generated code| |src/main/kotlin|
## IMPORT MAPPING
| Type/Alias | Imports |
| ---------- | ------- |
|BigDecimal|java.math.BigDecimal|
|Date|java.util.Date|
|DateTime|java.time.LocalDateTime|
|File|java.io.File|
|LocalDate|java.time.LocalDate|
|LocalDateTime|java.time.LocalDateTime|
|LocalTime|java.time.LocalTime|
|Timestamp|java.sql.Timestamp|
|URI|java.net.URI|
|UUID|java.util.UUID|
## INSTANTIATION TYPES
| Type/Alias | Instantiated By |
| ---------- | --------------- |
|array|kotlin.collections.ArrayList|
|list|kotlin.collections.ArrayList|
|map|kotlin.collections.HashMap|
## LANGUAGE PRIMITIVES
<ul class="column-ul">
<li>kotlin.Array</li>
<li>kotlin.Boolean</li>
<li>kotlin.Byte</li>
<li>kotlin.ByteArray</li>
<li>kotlin.Char</li>
<li>kotlin.Double</li>
<li>kotlin.Float</li>
<li>kotlin.Int</li>
<li>kotlin.Long</li>
<li>kotlin.Short</li>
<li>kotlin.String</li>
<li>kotlin.collections.List</li>
<li>kotlin.collections.Map</li>
<li>kotlin.collections.Set</li>
</ul>
## RESERVED WORDS
<ul class="column-ul">
<li>abort</li>
<li>action</li>
<li>add</li>
<li>after</li>
<li>all</li>
<li>alter</li>
<li>always</li>
<li>analyze</li>
<li>and</li>
<li>any</li>
<li>as</li>
<li>asc</li>
<li>attach</li>
<li>autoincr</li>
<li>autoincrement</li>
<li>before</li>
<li>begin</li>
<li>between</li>
<li>bitand</li>
<li>bitnot</li>
<li>bitor</li>
<li>blob</li>
<li>by</li>
<li>cascade</li>
<li>case</li>
<li>cast</li>
<li>check</li>
<li>collate</li>
<li>column</li>
<li>comma</li>
<li>commit</li>
<li>concat</li>
<li>conflict</li>
<li>constraint</li>
<li>create</li>
<li>cross</li>
<li>current</li>
<li>current_date</li>
<li>current_time</li>
<li>current_timestamp</li>
<li>database</li>
<li>default</li>
<li>deferrable</li>
<li>deferred</li>
<li>delete</li>
<li>desc</li>
<li>detach</li>
<li>distinct</li>
<li>do</li>
<li>dot</li>
<li>drop</li>
<li>each</li>
<li>else</li>
<li>end</li>
<li>eq</li>
<li>escape</li>
<li>except</li>
<li>exclude</li>
<li>exclusive</li>
<li>exists</li>
<li>explain</li>
<li>fail</li>
<li>filter</li>
<li>first</li>
<li>float</li>
<li>following</li>
<li>for</li>
<li>foreign</li>
<li>from</li>
<li>full</li>
<li>ge</li>
<li>generated</li>
<li>glob</li>
<li>group</li>
<li>groups</li>
<li>gt</li>
<li>having</li>
<li>id</li>
<li>if</li>
<li>ignore</li>
<li>immediate</li>
<li>in</li>
<li>index</li>
<li>indexed</li>
<li>initially</li>
<li>inner</li>
<li>insert</li>
<li>instead</li>
<li>integer</li>
<li>intersect</li>
<li>into</li>
<li>is</li>
<li>isnull</li>
<li>join</li>
<li>key</li>
<li>last</li>
<li>le</li>
<li>left</li>
<li>like</li>
<li>limit</li>
<li>lp</li>
<li>lshift</li>
<li>lt</li>
<li>match</li>
<li>minus</li>
<li>natural</li>
<li>ne</li>
<li>no</li>
<li>not</li>
<li>nothing</li>
<li>notnull</li>
<li>null</li>
<li>nulls</li>
<li>of</li>
<li>offset</li>
<li>on</li>
<li>or</li>
<li>order</li>
<li>others</li>
<li>outer</li>
<li>over</li>
<li>partition</li>
<li>plan</li>
<li>plus</li>
<li>pragma</li>
<li>preceding</li>
<li>primary</li>
<li>query</li>
<li>raise</li>
<li>range</li>
<li>recursive</li>
<li>references</li>
<li>regexp</li>
<li>reindex</li>
<li>release</li>
<li>rem</li>
<li>rename</li>
<li>replace</li>
<li>restrict</li>
<li>right</li>
<li>rollback</li>
<li>row</li>
<li>rows</li>
<li>rp</li>
<li>rshift</li>
<li>savepoint</li>
<li>select</li>
<li>set</li>
<li>slash</li>
<li>star</li>
<li>string</li>
<li>table</li>
<li>temp</li>
<li>temporary</li>
<li>then</li>
<li>ties</li>
<li>to</li>
<li>transaction</li>
<li>trigger</li>
<li>unbounded</li>
<li>union</li>
<li>unique</li>
<li>update</li>
<li>using</li>
<li>vacuum</li>
<li>values</li>
<li>variable</li>
<li>view</li>
<li>virtual</li>
<li>when</li>
<li>where</li>
<li>window</li>
<li>with</li>
<li>without</li>
</ul>
## FEATURE SET
### Client Modification Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|BasePath|✗|ToolingExtension
|Authorizations|✗|ToolingExtension
|UserAgent|✗|ToolingExtension
|MockServer|✗|ToolingExtension
### Data Type Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Custom|✗|OAS2,OAS3
|Int32|✓|OAS2,OAS3
|Int64|✓|OAS2,OAS3
|Float|✓|OAS2,OAS3
|Double|✓|OAS2,OAS3
|Decimal|✓|ToolingExtension
|String|✓|OAS2,OAS3
|Byte|✓|OAS2,OAS3
|Binary|✓|OAS2,OAS3
|Boolean|✓|OAS2,OAS3
|Date|✓|OAS2,OAS3
|DateTime|✓|OAS2,OAS3
|Password|✓|OAS2,OAS3
|File|✓|OAS2
|Array|✓|OAS2,OAS3
|Maps|✓|ToolingExtension
|CollectionFormat|✓|OAS2
|CollectionFormatMulti|✓|OAS2
|Enum|✓|OAS2,OAS3
|ArrayOfEnum|✓|ToolingExtension
|ArrayOfModel|✓|ToolingExtension
|ArrayOfCollectionOfPrimitives|✓|ToolingExtension
|ArrayOfCollectionOfModel|✓|ToolingExtension
|ArrayOfCollectionOfEnum|✓|ToolingExtension
|MapOfEnum|✓|ToolingExtension
|MapOfModel|✓|ToolingExtension
|MapOfCollectionOfPrimitives|✓|ToolingExtension
|MapOfCollectionOfModel|✓|ToolingExtension
|MapOfCollectionOfEnum|✓|ToolingExtension
### Documentation Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Readme|✓|ToolingExtension
|Model|✓|ToolingExtension
|Api|✓|ToolingExtension
### Global Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Host|✓|OAS2,OAS3
|BasePath|✓|OAS2,OAS3
|Info|✓|OAS2,OAS3
|Schemes|✗|OAS2,OAS3
|PartialSchemes|✓|OAS2,OAS3
|Consumes|✓|OAS2
|Produces|✓|OAS2
|ExternalDocumentation|✓|OAS2,OAS3
|Examples|✓|OAS2,OAS3
|XMLStructureDefinitions|✗|OAS2,OAS3
|MultiServer|✗|OAS3
|ParameterizedServer|✗|OAS3
|ParameterStyling|✗|OAS3
|Callbacks|✗|OAS3
|LinkObjects|✗|OAS3
### Parameter Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Path|✓|OAS2,OAS3
|Query|✓|OAS2,OAS3
|Header|✓|OAS2,OAS3
|Body|✓|OAS2
|FormUnencoded|✓|OAS2
|FormMultipart|✓|OAS2
|Cookie|✓|OAS3
### Schema Support Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Simple|✓|OAS2,OAS3
|Composite|✓|OAS2,OAS3
|Polymorphism|✗|OAS2,OAS3
|Union|✗|OAS3
### Security Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|BasicAuth|✗|OAS2,OAS3
|ApiKey|✗|OAS2,OAS3
|OpenIDConnect|✗|OAS3
|BearerToken|✗|OAS3
|OAuth2_Implicit|✗|OAS2,OAS3
|OAuth2_Password|✗|OAS2,OAS3
|OAuth2_ClientCredentials|✗|OAS2,OAS3
|OAuth2_AuthorizationCode|✗|OAS2,OAS3
### Wire Format Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|JSON|✗|OAS2,OAS3
|XML|✗|OAS2,OAS3
|PROTOBUF|✗|ToolingExtension
|Custom|✗|OAS2,OAS3

View File

@ -19,6 +19,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|powershellGalleryUrl|URL to the module in PowerShell Gallery (e.g. https://www.powershellgallery.com/packages/PSTwitter/).| |null|
|projectUri|A URL to the main website for this project| |null|
|releaseNotes|Release notes of the generated PowerShell module| |null|
|skipVerbParsing|Set skipVerbParsing to not try get powershell verbs of operation names| |null|
|tags|Tags applied to the generated PowerShell module. These help with module discovery in online galleries| |null|
|useOneOfDiscriminatorLookup|Use the discriminator's mapping in oneOf to speed up the model lookup. IMPORTANT: Validation (e.g. one and onlye one match in oneOf's schemas) will be skipped.| |null|

View File

@ -25,7 +25,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|npmVersion|The version of your npm package. If not provided, using the version from the OpenAPI specification file.| |1.0.0|
|nullSafeAdditionalProps|Set to make additional properties types declare that their indexer may return undefined| |false|
|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|
|providedInRoot|Use this property to provide Injectables in root (it is only valid in angular version greater or equal to 6.0.0).| |false|
|providedIn|Use this property to provide Injectables in wanted level (it is only valid in angular version greater or equal to 9.0.0).|<dl><dt>**root**</dt><dd>The application-level injector in most apps.</dd><dt>**none**</dt><dd>No providedIn (same as providedInRoot=false)</dd><dt>**any**</dt><dd>Provides a unique instance in each lazy loaded module while all eagerly loaded modules share one instance.</dd><dt>**platform**</dt><dd>A special singleton platform injector shared by all applications on the page.</dd></dl>|root|
|providedInRoot|Use this property to provide Injectables in root (it is only valid in angular version greater or equal to 6.0.0). IMPORTANT: Deprecated for angular version greater or equal to 9.0.0, use **providedIn** instead.| |false|
|queryParamObjectFormat|The format for query param objects: 'dot', 'json', 'key'.| |dot|
|serviceFileSuffix|The suffix of the file of the generated service (service&lt;suffix&gt;.ts).| |.service|
|serviceSuffix|The suffix of the generated service.| |Service|

View File

@ -1,5 +1,6 @@
# RELEASE_VERSION
openApiGeneratorVersion=5.1.0-SNAPSHOT
>>>>>>> origin/master
# /RELEASE_VERSION
# BEGIN placeholders

View File

@ -143,7 +143,111 @@ public class CLibcurlClientCodegen extends DefaultCodegen implements CodegenConf
"_Imaginary",
"_Noreturn",
"_Static_assert",
"_Thread_local")
"_Thread_local",
// cpp reserved keywords
// ref: https://en.cppreference.com/w/cpp/keyword
"alignas",
"alignof",
"and",
"and_eq",
"asm",
"atomic_cancel",
"atomic_commit",
"atomic_noexcept",
//"auto",
"bitand",
"bitor",
"bool",
//"break",
//"case",
"catch",
//"char",
"char8_t",
"char16_t",
"char32_t",
"class",
"compl",
"concept",
//"const",
"consteval",
"constexpr",
"constinit",
"const_cast",
//"continue",
"co_await",
"co_return",
"co_yield",
"decltype",
//"default",
"delete",
//"do",
//"double",
"dynamic_cast",
//"else",
//"enum",
"explicit",
"export",
//"extern",
"false",
//"float",
//"for",
"friend",
//"goto",
//"if",
//"inline",
//"int",
//"long",
"mutable",
"namespace",
"new",
"noexcept",
"not",
"not_eq",
"nullptr",
"operator",
"or",
"or_eq",
"private",
"protected",
"public",
"reflexpr",
//"register",
"reinterpret_cast",
"requires",
//"return",
//"short",
//"signed",
//"sizeof",
//"static",
"static_assert",
"static_cast",
//"struct",
//"switch",
"synchronized",
"template",
"this",
"thread_local",
"throw",
"true",
"try",
//"typedef",
"typeid",
"typename",
//"union",
//"unsigned",
"using",
"virtual",
//"void",
//"volatile",
"wchar_t",
//"while",
"xor",
"xor_eq",
"final",
"override",
"transaction_safe",
"transaction_safe_dynamic")
);
instantiationTypes.clear();

View File

@ -787,8 +787,7 @@ public class CSharpNetCoreClientCodegen extends AbstractCSharpCodegen {
}
// string
String var = value.replaceAll("_", " ");
//var = WordUtils.capitalizeFully(var);
String var = value.replaceAll(" ", "_");
var = camelize(var);
var = var.replaceAll("\\W+", "");

View File

@ -22,6 +22,7 @@ import io.swagger.v3.oas.models.media.Schema;
import org.openapitools.codegen.*;
import org.openapitools.codegen.meta.features.*;
import org.openapitools.codegen.utils.ModelUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
@ -123,6 +124,11 @@ public class ConfluenceWikiCodegen extends DefaultCodegen implements CodegenConf
return objs;
}
@Override
public Map<String, Object> postProcessModels(Map<String, Object> objs) {
return postProcessModelsEnum(objs);
}
@Override
public String escapeQuotationMark(String input) {
// just return the original string
@ -134,4 +140,14 @@ public class ConfluenceWikiCodegen extends DefaultCodegen implements CodegenConf
// just return the original string
return input;
}
@Override
public String escapeText(String input) {
if (input == null) {
return input;
}
// chomp tailing newline because it breaks the tables and keep all other sign to show documentation properly
return StringUtils.chomp(input);
}
}

View File

@ -0,0 +1,891 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.codegen.languages;
import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.Schema;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.*;
import org.openapitools.codegen.meta.GeneratorMetadata;
import org.openapitools.codegen.meta.Stability;
import org.openapitools.codegen.meta.features.*;
import org.openapitools.codegen.templating.mustache.PrefixWithHashLambda;
import org.openapitools.codegen.templating.mustache.TrimWhitespaceLambda;
import org.openapitools.codegen.utils.ModelUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import static org.openapitools.codegen.utils.StringUtils.camelize;
import static org.openapitools.codegen.utils.StringUtils.underscore;
public class CrystalClientCodegen extends DefaultCodegen {
private static final Logger LOGGER = LoggerFactory.getLogger(CrystalClientCodegen.class);
private static final String NUMERIC_ENUM_PREFIX = "N";
protected static int emptyMethodNameCounter = 0;
protected String shardName;
protected String moduleName;
protected String shardVersion = "1.0.0";
protected String specFolder = "spec";
protected String srcFolder = "src";
protected String shardLicense = "unlicense";
protected String shardHomepage = "https://openapitools.org";
protected String shardSummary = "A Crystal SDK for the REST API";
protected String shardDescription = "This shard maps to a REST API";
protected String shardAuthor = "";
protected String shardAuthorEmail = "";
protected String apiDocPath = "docs/";
protected String modelDocPath = "docs/";
public static final String SHARD_NAME = "shardName";
public static final String SHARD_VERSION = "shardVersion";
public static final String SHARD_LICENSE = "shardLicense";
public static final String SHARD_HOMEPAGE = "shardHomepage";
public static final String SHARD_SUMMARY = "shardSummary";
public static final String SHARD_DESCRIPTION = "shardDescription";
public static final String SHARD_AUTHOR = "shardAuthor";
public static final String SHARD_AUTHOR_EMAIL = "shardAuthorEmail";
public CrystalClientCodegen() {
super();
modifyFeatureSet(features -> features
.includeDocumentationFeatures(DocumentationFeature.Readme)
.wireFormatFeatures(EnumSet.of(WireFormatFeature.JSON, WireFormatFeature.XML, WireFormatFeature.Custom))
.securityFeatures(EnumSet.of(
SecurityFeature.BasicAuth,
SecurityFeature.BearerToken,
SecurityFeature.ApiKey,
SecurityFeature.OAuth2_Implicit
))
.excludeGlobalFeatures(
GlobalFeature.XMLStructureDefinitions,
GlobalFeature.Callbacks,
GlobalFeature.LinkObjects,
GlobalFeature.ParameterStyling,
GlobalFeature.ParameterizedServer,
GlobalFeature.MultiServer
)
.includeSchemaSupportFeatures(
SchemaSupportFeature.Polymorphism
)
.excludeParameterFeatures(
ParameterFeature.Cookie
)
.includeClientModificationFeatures(
ClientModificationFeature.BasePath,
ClientModificationFeature.UserAgent
)
);
generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
.stability(Stability.BETA)
.build();
supportsInheritance = true;
// clear import mapping (from default generator) as crystal does not use it
// at the moment
importMapping.clear();
embeddedTemplateDir = templateDir = "crystal";
outputFolder = "generated-code" + File.separator + "crystal";
modelPackage = "models";
apiPackage = "api";
modelTemplateFiles.put("model.mustache", ".cr");
apiTemplateFiles.put("api.mustache", ".cr");
modelTestTemplateFiles.put("model_test.mustache", ".cr");
apiTestTemplateFiles.put("api_test.mustache", ".cr");
// TODO support auto-generated doc
//modelDocTemplateFiles.put("model_doc.mustache", ".md");
//apiDocTemplateFiles.put("api_doc.mustache", ".md");
// default HIDE_GENERATION_TIMESTAMP to true
hideGenerationTimestamp = Boolean.TRUE;
// reserved word. Ref: https://github.com/crystal-lang/crystal/wiki/Crystal-for-Rubyists#available-keywords
reservedWords = new HashSet<String>(
Arrays.asList(
"abstract", "do", "if", "nil?", "select", "union",
"alias", "else", "in", "of", "self", "unless",
"as", "elsif", "include", "out", "sizeof", "until",
"as?", "end", "instance", "sizeof", "pointerof", "struct", "verbatim",
"asm", "ensure", "is_a?", "private", "super", "when",
"begin", "enum", "lib", "protected", "then", "while",
"break", "extend", "macro", "require", "true", "with",
"case", "false", "module", "rescue", "type", "yield",
"class", "for", "next", "responds_to?", "typeof",
"def", "fun", "nil", "return", "uninitialized")
);
languageSpecificPrimitives.clear();
languageSpecificPrimitives.add("String");
languageSpecificPrimitives.add("Boolean");
languageSpecificPrimitives.add("Integer");
languageSpecificPrimitives.add("Float");
languageSpecificPrimitives.add("Date");
languageSpecificPrimitives.add("Time");
languageSpecificPrimitives.add("Array");
languageSpecificPrimitives.add("Hash");
languageSpecificPrimitives.add("File");
languageSpecificPrimitives.add("Object");
typeMapping.clear();
typeMapping.put("string", "String");
typeMapping.put("boolean", "Bool");
typeMapping.put("char", "Char");
typeMapping.put("int", "Int32");
typeMapping.put("integer", "Int32");
typeMapping.put("long", "Int64");
typeMapping.put("short", "Int32");
typeMapping.put("float", "Float32");
typeMapping.put("double", "Float64");
typeMapping.put("number", "Float64");
typeMapping.put("date", "Time");
typeMapping.put("DateTime", "Time");
typeMapping.put("array", "Array");
typeMapping.put("List", "Array");
typeMapping.put("set", "Set");
typeMapping.put("map", "Hash");
typeMapping.put("object", "Object");
typeMapping.put("file", "File");
typeMapping.put("binary", "String");
typeMapping.put("ByteArray", "String");
typeMapping.put("UUID", "String");
typeMapping.put("URI", "String");
instantiationTypes.put("map", "Hash");
instantiationTypes.put("array", "Array");
instantiationTypes.put("set", "Set");
// remove modelPackage and apiPackage added by default
cliOptions.removeIf(opt -> CodegenConstants.MODEL_PACKAGE.equals(opt.getOpt()) ||
CodegenConstants.API_PACKAGE.equals(opt.getOpt()));
cliOptions.add(new CliOption(SHARD_NAME, "shard name (e.g. twitter_client").
defaultValue("openapi_client"));
cliOptions.add(new CliOption(SHARD_VERSION, "shard version.").defaultValue("1.0.0"));
cliOptions.add(new CliOption(SHARD_LICENSE, "shard license.").
defaultValue("unlicense"));
cliOptions.add(new CliOption(SHARD_HOMEPAGE, "shard homepage.").
defaultValue("http://org.openapitools"));
cliOptions.add(new CliOption(SHARD_DESCRIPTION, "shard description.").
defaultValue("This shard maps to a REST API"));
cliOptions.add(new CliOption(SHARD_AUTHOR, "shard author (only one is supported)."));
cliOptions.add(new CliOption(SHARD_AUTHOR_EMAIL, "shard author email (only one is supported)."));
cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC).
defaultValue(Boolean.TRUE.toString()));
}
@Override
public void processOpts() {
super.processOpts();
if (StringUtils.isEmpty(System.getenv("CRYSTAL_POST_PROCESS_FILE"))) {
LOGGER.info("Hint: Environment variable 'CRYSTAL_POST_PROCESS_FILE' (optional) not defined. E.g. to format the source code, please try 'export CRYSTAL_POST_PROCESS_FILE=\"/usr/local/bin/crystal tool format\"' (Linux/Mac)");
}
if (additionalProperties.containsKey(SHARD_NAME)) {
setShardName((String) additionalProperties.get(SHARD_NAME));
}
additionalProperties.put(SHARD_NAME, shardName);
if (additionalProperties.containsKey(SHARD_VERSION)) {
setShardVersion((String) additionalProperties.get(SHARD_VERSION));
} else {
// not set, pass the default value to template
additionalProperties.put(SHARD_VERSION, shardVersion);
}
if (additionalProperties.containsKey(SHARD_LICENSE)) {
setShardLicense((String) additionalProperties.get(SHARD_LICENSE));
}
if (additionalProperties.containsKey(SHARD_HOMEPAGE)) {
setShardHomepage((String) additionalProperties.get(SHARD_HOMEPAGE));
}
if (additionalProperties.containsKey(SHARD_SUMMARY)) {
setShardSummary((String) additionalProperties.get(SHARD_SUMMARY));
}
if (additionalProperties.containsKey(SHARD_DESCRIPTION)) {
setShardDescription((String) additionalProperties.get(SHARD_DESCRIPTION));
}
if (additionalProperties.containsKey(SHARD_AUTHOR)) {
setShardAuthor((String) additionalProperties.get(SHARD_AUTHOR));
}
if (additionalProperties.containsKey(SHARD_AUTHOR_EMAIL)) {
setShardAuthorEmail((String) additionalProperties.get(SHARD_AUTHOR_EMAIL));
}
// make api and model doc path available in mustache template
additionalProperties.put("apiDocPath", apiDocPath);
additionalProperties.put("modelDocPath", modelDocPath);
// use constant model/api package (folder path)
setModelPackage("models");
setApiPackage("api");
supportingFiles.add(new SupportingFile("shard_name.mustache", srcFolder, shardName + ".cr"));
String shardFolder = srcFolder + File.separator + shardName;
supportingFiles.add(new SupportingFile("api_error.mustache", shardFolder, "api_error.cr"));
supportingFiles.add(new SupportingFile("configuration.mustache", shardFolder, "configuration.cr"));
supportingFiles.add(new SupportingFile("api_client.mustache", shardFolder, "api_client.cr"));
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
supportingFiles.add(new SupportingFile("travis.mustache", "", ".travis.yml"));
supportingFiles.add(new SupportingFile("shard.mustache", "", "shard.yml"));
// crystal spec files
supportingFiles.add(new SupportingFile("spec_helper.mustache", specFolder, "spec_helper.cr")
.doNotOverwrite());
// add lambda for mustache templates
additionalProperties.put("lambdaPrefixWithHash", new PrefixWithHashLambda());
}
@Override
public String getHelp() {
return "Generates a Crystal client library (beta).";
}
@Override
public CodegenType getTag() {
return CodegenType.CLIENT;
}
@Override
public String getName() {
return "crystal";
}
@Override
public String apiFileFolder() {
return outputFolder + File.separator + srcFolder + File.separator + shardName + File.separator + apiPackage.replace("/", File.separator);
}
@Override
public String modelFileFolder() {
return outputFolder + File.separator + srcFolder + File.separator + shardName + File.separator + modelPackage.replace("/", File.separator);
}
@Override
public String apiTestFileFolder() {
return outputFolder + File.separator + specFolder + File.separator + apiPackage.replace("/", File.separator);
}
@Override
public String modelTestFileFolder() {
return outputFolder + File.separator + specFolder + File.separator + modelPackage.replace("/", File.separator);
}
@Override
public String apiDocFileFolder() {
return (outputFolder + "/" + apiDocPath).replace('/', File.separatorChar);
}
@Override
public String modelDocFileFolder() {
return (outputFolder + "/" + modelDocPath).replace('/', File.separatorChar);
}
@Override
public String getSchemaType(Schema schema) {
String openAPIType = super.getSchemaType(schema);
String type = null;
if (typeMapping.containsKey(openAPIType)) {
type = typeMapping.get(openAPIType);
if (languageSpecificPrimitives.contains(type)) {
return type;
}
} else {
type = openAPIType;
}
if (type == null) {
return null;
}
return toModelName(type);
}
@Override
public String toModelName(final String name) {
String modelName;
modelName = sanitizeName(name);
if (!StringUtils.isEmpty(modelNamePrefix)) {
modelName = modelNamePrefix + "_" + modelName;
}
if (!StringUtils.isEmpty(modelNameSuffix)) {
modelName = modelName + "_" + modelNameSuffix;
}
// model name cannot use reserved keyword, e.g. return
if (isReservedWord(modelName)) {
modelName = camelize("Model" + modelName);
LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + modelName);
return modelName;
}
// model name starts with number
if (modelName.matches("^\\d.*")) {
LOGGER.warn(modelName + " (model name starts with number) cannot be used as model name. Renamed to " + camelize("model_" + modelName));
modelName = "model_" + modelName; // e.g. 200Response => Model200Response (after camelize)
}
// camelize the model name
// phone_number => PhoneNumber
return camelize(modelName);
}
@Override
public String toModelFilename(String name) {
return underscore(toModelName(name));
}
@Override
public String toModelDocFilename(String name) {
return toModelName(name);
}
@Override
public String toApiFilename(final String name) {
// replace - with _ e.g. created-at => created_at
String filename = name;
if (apiNameSuffix != null && apiNameSuffix.length() > 0) {
filename = filename + "_" + apiNameSuffix;
}
filename = filename.replaceAll("-", "_");
// e.g. PhoneNumberApi.cr => phone_number_api.cr
return underscore(filename);
}
@Override
public String toApiDocFilename(String name) {
return toApiName(name);
}
@Override
public String toApiTestFilename(String name) {
return toApiFilename(name) + "_spec";
}
@Override
public String toModelTestFilename(String name) {
return toModelFilename(name) + "_spec";
}
@Override
public String toApiName(String name) {
return super.toApiName(name);
}
@Override
public String toEnumValue(String value, String datatype) {
if ("Integer".equals(datatype) || "Float".equals(datatype)) {
return value;
} else {
return "\"" + escapeText(value) + "\"";
}
}
@Override
public String toEnumVarName(String name, String datatype) {
if (name.length() == 0) {
return "EMPTY";
}
// number
if ("Integer".equals(datatype) || "Float".equals(datatype)) {
String varName = name;
varName = varName.replaceAll("-", "MINUS_");
varName = varName.replaceAll("\\+", "PLUS_");
varName = varName.replaceAll("\\.", "_DOT_");
return NUMERIC_ENUM_PREFIX + varName;
}
// string
String enumName = sanitizeName(underscore(name).toUpperCase(Locale.ROOT));
enumName = enumName.replaceFirst("^_", "");
enumName = enumName.replaceFirst("_$", "");
if (enumName.matches("\\d.*")) { // starts with number
return NUMERIC_ENUM_PREFIX + enumName;
} else {
return enumName;
}
}
@Override
public String toEnumName(CodegenProperty property) {
String enumName = underscore(toModelName(property.name)).toUpperCase(Locale.ROOT);
enumName = enumName.replaceFirst("^_", "");
enumName = enumName.replaceFirst("_$", "");
if (enumName.matches("\\d.*")) { // starts with number
return NUMERIC_ENUM_PREFIX + enumName;
} else {
return enumName;
}
}
@Override
public Map<String, Object> postProcessModels(Map<String, Object> objs) {
// process enum in models
return postProcessModelsEnum(objs);
}
@Override
public String toOperationId(String operationId) {
// rename to empty_method_name_1 (e.g.) if method name is empty
if (StringUtils.isEmpty(operationId)) {
operationId = underscore("empty_method_name_" + emptyMethodNameCounter++);
LOGGER.warn("Empty method name (operationId) found. Renamed to " + operationId);
return operationId;
}
// method name cannot use reserved keyword, e.g. return
if (isReservedWord(operationId)) {
String newOperationId = underscore("call_" + operationId);
LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + newOperationId);
return newOperationId;
}
// operationId starts with a number
if (operationId.matches("^\\d.*")) {
LOGGER.warn(operationId + " (starting with a number) cannot be used as method name. Renamed to " + underscore(sanitizeName("call_" + operationId)));
operationId = "call_" + operationId;
}
return underscore(sanitizeName(operationId));
}
@Override
public String toApiImport(String name) {
return shardName + "/" + apiPackage() + "/" + toApiFilename(name);
}
public void setShardName(String shardName) {
this.shardName = shardName;
}
public void setModuleName(String moduleName) {
this.moduleName = moduleName;
}
public void setShardVersion(String shardVersion) {
this.shardVersion = shardVersion;
}
public void setShardDescription(String shardDescription) {
this.shardDescription = shardDescription;
}
public void setShardSummary(String shardSummary) {
this.shardSummary = shardSummary;
}
public void setShardLicense(String shardLicense) {
this.shardLicense = shardLicense;
}
public void setShardHomepage(String shardHomepage) {
this.shardHomepage = shardHomepage;
}
public void setShardAuthor(String shardAuthor) {
this.shardAuthor = shardAuthor;
}
public void setShardAuthorEmail(String shardAuthorEmail) {
this.shardAuthorEmail = shardAuthorEmail;
}
@Override
protected void addAdditionPropertiesToCodeGenModel(CodegenModel codegenModel, Schema schema) {
final Schema additionalProperties = getAdditionalProperties(schema);
if (additionalProperties != null) {
codegenModel.additionalPropertiesType = getSchemaType(additionalProperties);
}
}
@Override
public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> objs, List<Object> allModels) {
objs = super.postProcessOperationsWithModels(objs, allModels);
Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
HashMap<String, CodegenModel> modelMaps = new HashMap<String, CodegenModel>();
HashMap<String, Integer> processedModelMaps = new HashMap<String, Integer>();
for (Object o : allModels) {
HashMap<String, Object> h = (HashMap<String, Object>) o;
CodegenModel m = (CodegenModel) h.get("model");
modelMaps.put(m.classname, m);
}
List<CodegenOperation> operationList = (List<CodegenOperation>) operations.get("operation");
for (CodegenOperation op : operationList) {
for (CodegenParameter p : op.allParams) {
p.vendorExtensions.put("x-crystal-example", constructExampleCode(p, modelMaps, processedModelMaps));
}
processedModelMaps.clear();
for (CodegenParameter p : op.requiredParams) {
p.vendorExtensions.put("x-crystal-example", constructExampleCode(p, modelMaps, processedModelMaps));
}
processedModelMaps.clear();
for (CodegenParameter p : op.optionalParams) {
p.vendorExtensions.put("x-crystal-example", constructExampleCode(p, modelMaps, processedModelMaps));
}
processedModelMaps.clear();
for (CodegenParameter p : op.bodyParams) {
p.vendorExtensions.put("x-crystal-example", constructExampleCode(p, modelMaps, processedModelMaps));
}
processedModelMaps.clear();
for (CodegenParameter p : op.pathParams) {
p.vendorExtensions.put("x-crystal-example", constructExampleCode(p, modelMaps, processedModelMaps));
}
processedModelMaps.clear();
}
return objs;
}
private String constructExampleCode(CodegenParameter codegenParameter, HashMap<String, CodegenModel> modelMaps, HashMap<String, Integer> processedModelMap) {
if (codegenParameter.isArray) { // array
return "[" + constructExampleCode(codegenParameter.items, modelMaps, processedModelMap) + "]";
} else if (codegenParameter.isMap) {
return "{ key: " + constructExampleCode(codegenParameter.items, modelMaps, processedModelMap) + "}";
} else if (codegenParameter.isPrimitiveType) { // primitive type
if (codegenParameter.isEnum) {
// When inline enum, set example to first allowable value
List<Object> values = (List<Object>) codegenParameter.allowableValues.get("values");
codegenParameter.example = String.valueOf(values.get(0));
}
if (codegenParameter.isString || "String".equalsIgnoreCase(codegenParameter.baseType)) {
if (!StringUtils.isEmpty(codegenParameter.example) && !"null".equals(codegenParameter.example)) {
return "'" + codegenParameter.example + "'";
}
return "'" + codegenParameter.paramName + "_example'";
} else if (codegenParameter.isBoolean) { // boolean
if (Boolean.parseBoolean(codegenParameter.example)) {
return "true";
}
return "false";
} else if (codegenParameter.isUri) {
if (!StringUtils.isEmpty(codegenParameter.example) && !"null".equals(codegenParameter.example)) {
return "'" + codegenParameter.example + "'";
}
return "'https://example.com'";
} else if (codegenParameter.isDateTime) {
if (!StringUtils.isEmpty(codegenParameter.example) && !"null".equals(codegenParameter.example)) {
return "Time.parse('" + codegenParameter.example + "')";
}
return "Time.now";
} else if (codegenParameter.isDate) {
if (!StringUtils.isEmpty(codegenParameter.example) && !"null".equals(codegenParameter.example)) {
return "Date.parse('" + codegenParameter.example + "')";
}
return "Date.today";
} else if (codegenParameter.isFile) {
return "File.new('/path/to/some/file')";
} else if (codegenParameter.isInteger) {
if (!StringUtils.isEmpty(codegenParameter.example) && !"null".equals(codegenParameter.example)) {
return codegenParameter.example;
}
return "37";
} else { // number
if (!StringUtils.isEmpty(codegenParameter.example) && !"null".equals(codegenParameter.example)) {
return codegenParameter.example;
}
return "3.56";
}
} else { // model
// look up the model
if (modelMaps.containsKey(codegenParameter.dataType)) {
return constructExampleCode(modelMaps.get(codegenParameter.dataType), modelMaps, processedModelMap);
} else {
//LOGGER.error("Error in constructing examples. Failed to look up the model " + codegenParameter.dataType);
return "TODO";
}
}
}
private String constructExampleCode(CodegenProperty codegenProperty, HashMap<String, CodegenModel> modelMaps, HashMap<String, Integer> processedModelMap) {
if (codegenProperty.isArray) { // array
return "[" + constructExampleCode(codegenProperty.items, modelMaps, processedModelMap) + "]";
} else if (codegenProperty.isMap) {
return "{ key: " + constructExampleCode(codegenProperty.items, modelMaps, processedModelMap) + "}";
} else if (codegenProperty.isPrimitiveType) { // primitive type
if (codegenProperty.isEnum) {
// When inline enum, set example to first allowable value
List<Object> values = (List<Object>) codegenProperty.allowableValues.get("values");
codegenProperty.example = String.valueOf(values.get(0));
}
if (codegenProperty.isString || "String".equalsIgnoreCase(codegenProperty.baseType)) {
if (!StringUtils.isEmpty(codegenProperty.example) && !"null".equals(codegenProperty.example)) {
return "'" + codegenProperty.example + "'";
} else {
return "'" + codegenProperty.name + "_example'";
}
} else if (codegenProperty.isBoolean) { // boolean
if (Boolean.parseBoolean(codegenProperty.example)) {
return "true";
} else {
return "false";
}
} else if (codegenProperty.isUri) {
if (!StringUtils.isEmpty(codegenProperty.example) && !"null".equals(codegenProperty.example)) {
return "'" + codegenProperty.example + "'";
}
return "'https://example.com'";
} else if (codegenProperty.isDateTime) {
if (!StringUtils.isEmpty(codegenProperty.example) && !"null".equals(codegenProperty.example)) {
return "Time.parse('" + codegenProperty.example + "')";
}
return "Time.now";
} else if (codegenProperty.isDate) {
if (!StringUtils.isEmpty(codegenProperty.example) && !"null".equals(codegenProperty.example)) {
return "Date.parse('" + codegenProperty.example + "')";
}
return "Date.today";
} else if (codegenProperty.isFile) {
return "File.new('/path/to/some/file')";
} else if (codegenProperty.isInteger) {
if (!StringUtils.isEmpty(codegenProperty.example) && !"null".equals(codegenProperty.example)) {
return codegenProperty.example;
}
return "37";
} else { // number
if (!StringUtils.isEmpty(codegenProperty.example) && !"null".equals(codegenProperty.example)) {
return codegenProperty.example;
}
return "3.56";
}
} else { // model
// look up the model
if (modelMaps.containsKey(codegenProperty.dataType)) {
return constructExampleCode(modelMaps.get(codegenProperty.dataType), modelMaps, processedModelMap);
} else {
//LOGGER.error("Error in constructing examples. Failed to look up the model " + codegenParameter.dataType);
return "TODO";
}
}
}
private String constructExampleCode(CodegenModel codegenModel, HashMap<String, CodegenModel> modelMaps, HashMap<String, Integer> processedModelMap) {
// break infinite recursion. Return, in case a model is already processed in the current context.
String model = codegenModel.name;
if (processedModelMap.containsKey(model)) {
int count = processedModelMap.get(model);
if (count == 1) {
processedModelMap.put(model, 2);
} else if (count == 2) {
return "";
} else {
throw new RuntimeException("Invalid count when constructing example: " + count);
}
} else if (codegenModel.isEnum) {
List<Map<String, String>> enumVars = (List<Map<String, String>>) codegenModel.allowableValues.get("enumVars");
return moduleName + "::" + codegenModel.classname + "::" + enumVars.get(0).get("name");
} else if (codegenModel.oneOf != null && !codegenModel.oneOf.isEmpty()) {
String subModel = (String) codegenModel.oneOf.toArray()[0];
String oneOf = constructExampleCode(modelMaps.get(subModel), modelMaps, processedModelMap);
return oneOf;
} else {
processedModelMap.put(model, 1);
}
List<String> propertyExamples = new ArrayList<>();
for (CodegenProperty codegenProperty : codegenModel.requiredVars) {
propertyExamples.add(codegenProperty.name + ": " + constructExampleCode(codegenProperty, modelMaps, processedModelMap));
}
String example = moduleName + "::" + toModelName(model) + ".new";
if (!propertyExamples.isEmpty()) {
example += "({" + StringUtils.join(propertyExamples, ", ") + "})";
}
return example;
}
@Override
public String escapeReservedWord(String name) {
if (this.reservedWordsMappings().containsKey(name)) {
return this.reservedWordsMappings().get(name);
}
return "_" + name;
}
@Override
public String getTypeDeclaration(Schema schema) {
if (ModelUtils.isArraySchema(schema)) {
Schema inner = ((ArraySchema) schema).getItems();
return getSchemaType(schema) + "(" + getTypeDeclaration(inner) + ")";
} else if (ModelUtils.isMapSchema(schema)) {
Schema inner = getAdditionalProperties(schema);
return getSchemaType(schema) + "(String, " + getTypeDeclaration(inner) + ")";
}
return super.getTypeDeclaration(schema);
}
@Override
public String toInstantiationType(Schema schema) {
if (ModelUtils.isMapSchema(schema)) {
return instantiationTypes.get("map");
} else if (ModelUtils.isArraySchema(schema)) {
String parentType;
if (ModelUtils.isSet(schema)) {
parentType = "set";
} else {
parentType = "array";
}
return instantiationTypes.get(parentType);
}
return super.toInstantiationType(schema);
}
@Override
public String toDefaultValue(Schema p) {
p = ModelUtils.getReferencedSchema(this.openAPI, p);
if (ModelUtils.isIntegerSchema(p) || ModelUtils.isNumberSchema(p) || ModelUtils.isBooleanSchema(p)) {
if (p.getDefault() != null) {
return p.getDefault().toString();
}
} else if (ModelUtils.isStringSchema(p)) {
if (p.getDefault() != null) {
if (p.getDefault() instanceof Date) {
Date date = (Date) p.getDefault();
LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
return "Date.parse(\"" + String.format(Locale.ROOT, localDate.toString(), "") + "\")";
} else if (p.getDefault() instanceof java.time.OffsetDateTime) {
return "Time.parse(\"" + String.format(Locale.ROOT, ((java.time.OffsetDateTime) p.getDefault()).atZoneSameInstant(ZoneId.systemDefault()).toString(), "") + "\")";
} else {
return "'" + escapeText((String) p.getDefault()) + "'";
}
}
}
return null;
}
@Override
public String toEnumDefaultValue(String value, String datatype) {
return datatype + "::" + value;
}
@Override
public String toVarName(final String name) {
String varName;
// sanitize name
varName = sanitizeName(name);
// if it's all uppper case, convert to lower case
if (name.matches("^[A-Z_]*$")) {
varName = varName.toLowerCase(Locale.ROOT);
}
// camelize (lower first character) the variable name
// petId => pet_id
varName = underscore(varName);
// for reserved word or word starting with number, append _
if (isReservedWord(varName) || varName.matches("^\\d.*")) {
varName = escapeReservedWord(varName);
}
return varName;
}
public String toRegularExpression(String pattern) {
return addRegularExpressionDelimiter(pattern);
}
@Override
public String toParamName(String name) {
// should be the same as variable name
return toVarName(name);
}
@Override
public String escapeQuotationMark(String input) {
// remove ' to avoid code injection
return input.replace("'", "");
}
@Override
public String escapeUnsafeCharacters(String input) {
return input.replace("=end", "=_end").replace("=begin", "=_begin").replace("#{", "\\#{");
}
@Override
public void postProcessFile(File file, String fileType) {
if (file == null) {
return;
}
String crystalPostProcessFile = System.getenv("CRYSTAL_POST_PROCESS_FILE");
if (StringUtils.isEmpty(crystalPostProcessFile)) {
return; // skip if CRYSTAL_POST_PROCESS_FILE env variable is not defined
}
// only process files with cr extension
if ("cr".equals(FilenameUtils.getExtension(file.toString()))) {
String command = crystalPostProcessFile + " " + file.toString();
try {
Process p = Runtime.getRuntime().exec(command);
int exitValue = p.waitFor();
if (exitValue != 0) {
BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream(), StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
LOGGER.error("Error running the command ({}). Exit value: {}, Error output: {}", command, exitValue, sb.toString());
} else {
LOGGER.info("Successfully executed: " + command);
}
} catch (Exception e) {
LOGGER.error("Error running the command ({}). Exception: {}", command, e.getMessage());
}
}
}
}

View File

@ -472,13 +472,16 @@ public class DartClientCodegen extends DefaultCodegen {
}
if (schema.getDefault() != null) {
if (ModelUtils.isDateSchema(schema) || ModelUtils.isDateTimeSchema(schema)) {
// this is currently not supported and would create compile errors
return null;
}
if (ModelUtils.isStringSchema(schema)) {
return "'" + schema.getDefault().toString().replace("'", "\\'") + "'";
}
return schema.getDefault().toString();
} else {
return null;
}
return null;
}
@Override
@ -555,6 +558,18 @@ public class DartClientCodegen extends DefaultCodegen {
}
}
}
for (CodegenParameter p : op.allParams) {
if (p.isContainer) {
final String type = p.isArray ? "array" : "map";
if (typeMapping().containsKey(type)) {
final String value = typeMapping().get(type);
// Also add container imports for parameters.
if (needToImport(value)) {
op.imports.add(value);
}
}
}
}
return op;
}

View File

@ -126,6 +126,16 @@ public class DartDioClientCodegen extends DartClientCodegen {
@Override
public String toDefaultValue(Schema schema) {
if (schema.getDefault() != null) {
if (ModelUtils.isArraySchema(schema)) {
return "ListBuilder()";
}
if (ModelUtils.isMapSchema(schema)) {
return "MapBuilder()";
}
if (ModelUtils.isDateSchema(schema) || ModelUtils.isDateTimeSchema(schema)) {
// this is currently not supported and would create compile errors
return null;
}
if (ModelUtils.isStringSchema(schema)) {
return "'" + schema.getDefault().toString().replaceAll("'", "\\'") + "'";
}
@ -279,6 +289,7 @@ public class DartDioClientCodegen extends DartClientCodegen {
Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
List<CodegenOperation> operationList = (List<CodegenOperation>) operations.get("operation");
Set<Map<String, Object>> serializers = new HashSet<>();
Set<String> modelImports = new HashSet<>();
Set<String> fullImports = new HashSet<>();
@ -304,6 +315,13 @@ public class DartDioClientCodegen extends DartClientCodegen {
param.baseType = "MultipartFile";
param.dataType = "MultipartFile";
}
if (param.isContainer) {
final Map<String, Object> serializer = new HashMap<>();
serializer.put("isArray", param.isArray);
serializer.put("isMap", param.isMap);
serializer.put("baseType", param.baseType);
serializers.add(serializer);
}
}
op.vendorExtensions.put("x-is-json", isJson);
@ -317,7 +335,7 @@ public class DartDioClientCodegen extends DartClientCodegen {
Set<String> imports = new HashSet<>();
for (String item : op.imports) {
if (needToImport(item)) {
if (importMapping().containsKey(item) && needToImport(item)) {
if (importMapping().containsKey(item)) {
fullImports.add(importMapping().get(item));
} else {
imports.add(underscore(item));
@ -326,10 +344,19 @@ public class DartDioClientCodegen extends DartClientCodegen {
}
modelImports.addAll(imports);
op.imports = imports;
if (op.returnContainer != null) {
final Map<String, Object> serializer = new HashMap<>();
serializer.put("isArray", Objects.equals("array", op.returnContainer));
serializer.put("isMap", Objects.equals("map", op.returnContainer));
serializer.put("baseType", op.returnBaseType);
serializers.add(serializer);
}
}
objs.put("modelImports", modelImports);
objs.put("fullImports", fullImports);
objs.put("serializers", serializers);
return objs;
}

View File

@ -135,7 +135,7 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
protected Set<String> typeNames = new HashSet<String>();
protected Set<String> modelTypeNames = new HashSet<String>();
final private static Pattern JSON_MIME_PATTERN = Pattern.compile("(?i)application/.*json(;.*)?");
final private static Pattern CONTAINS_JSON_MIME_PATTERN = Pattern.compile("(?i)application/.*json(;.*)?");
public CodegenType getTag() {
return CodegenType.CLIENT;
@ -1054,7 +1054,7 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
String mimeType = getMimeDataType(mediaType);
typeNames.add(mimeType);
m.put(X_MEDIA_DATA_TYPE, mimeType);
if (isJsonMimeType(mediaType)) {
if (isJsonMimeType(mediaType) || ContainsJsonMimeType(mediaType)) {
m.put(X_MEDIA_IS_JSON, "true");
}
if (isWildcardMimeType(mediaType)) {
@ -1461,4 +1461,7 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
}
}
}
static boolean ContainsJsonMimeType(String mime) {
return mime != null && CONTAINS_JSON_MIME_PATTERN.matcher(mime).matches();
}
}

View File

@ -55,6 +55,7 @@ public class PowerShellClientCodegen extends DefaultCodegen implements CodegenCo
protected HashSet methodNames; // store a list of method names to detect duplicates
protected boolean useOneOfDiscriminatorLookup = false; // use oneOf discriminator's mapping for model lookup
protected boolean discardReadOnly = false; // Discard the readonly property in initialize cmdlet
protected boolean skipVerbParsing = false; // Attempt to parse cmdlets from operation names
protected String projectUri;
protected String licenseUri;
protected String releaseNotes;
@ -511,6 +512,8 @@ public class PowerShellClientCodegen extends DefaultCodegen implements CodegenCo
cliOptions.add(new CliOption("licenseUri","A URL to the license for the generated PowerShell module"));
cliOptions.add(new CliOption("iconUri","A URL to an icon representing the generated PowerShell module"));
cliOptions.add(new CliOption("releaseNotes","Release notes of the generated PowerShell module"));
cliOptions.add(new CliOption("skipVerbParsing", "Set skipVerbParsing to not try get powershell verbs of operation names"));
// option to change how we process + set the data in the 'additionalProperties' keyword.
CliOption disallowAdditionalPropertiesIfNotPresentOpt = CliOption.newBoolean(
CodegenConstants.DISALLOW_ADDITIONAL_PROPERTIES_IF_NOT_PRESENT,
@ -601,6 +604,7 @@ public class PowerShellClientCodegen extends DefaultCodegen implements CodegenCo
this.iconUri = iconUri;
}
public void setSkipVerbParsing(boolean skipVerbParsing) { this.skipVerbParsing = skipVerbParsing; };
@Override
public void processOpts() {
@ -628,7 +632,13 @@ public class PowerShellClientCodegen extends DefaultCodegen implements CodegenCo
setDiscardReadOnly(convertPropertyToBooleanAndWriteBack("discardReadOnly"));
} else {
additionalProperties.put("discardReadOnly", discardReadOnly);
}
}
if (additionalProperties.containsKey("skipVerbParsing")) {
setSkipVerbParsing(convertPropertyToBoolean("skipVerbParsing"));
} else {
additionalProperties.put("skipVerbParsing", skipVerbParsing);
}
if (additionalProperties.containsKey("tags")) {
String[] entries = ((String) additionalProperties.get("tags")).split(",");
@ -1212,20 +1222,22 @@ public class PowerShellClientCodegen extends DefaultCodegen implements CodegenCo
private String toMethodName(String operationId) {
String methodName = camelize(operationId);
// check if method name starts with powershell verbs
for (String verb : (HashSet<String>) powershellVerbs) {
if (methodName.startsWith(verb)) {
methodName = verb + "-" + apiNamePrefix + methodName.substring(verb.length());
LOGGER.info("Naming the method using the PowerShell verb: {} => {}", operationId, methodName);
return methodName;
if (!skipVerbParsing) {
// check if method name starts with powershell verbs
for (String verb : (HashSet<String>) powershellVerbs) {
if (methodName.startsWith(verb)) {
methodName = verb + "-" + apiNamePrefix + methodName.substring(verb.length());
LOGGER.info("Naming the method using the PowerShell verb: {} => {}", operationId, methodName);
return methodName;
}
}
}
for (Map.Entry<String, String> entry : commonVerbs.entrySet()) {
if (methodName.startsWith(entry.getKey())) {
methodName = entry.getValue() + "-" + apiNamePrefix + methodName.substring(entry.getKey().length());
LOGGER.info("Naming the method by mapping the common verbs (e.g. Create, Change) to PS verbs: {} => {}", operationId, methodName);
return methodName;
for (Map.Entry<String, String> entry : commonVerbs.entrySet()) {
if (methodName.startsWith(entry.getKey())) {
methodName = entry.getValue() + "-" + apiNamePrefix + methodName.substring(entry.getKey().length());
LOGGER.info("Naming the method by mapping the common verbs (e.g. Create, Change) to PS verbs: {} => {}", operationId, methodName);
return methodName;
}
}
}

View File

@ -16,6 +16,7 @@
package org.openapitools.codegen.languages;
import com.google.common.collect.Sets;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.oas.models.media.*;
import io.swagger.v3.oas.models.media.ArraySchema;
@ -879,7 +880,7 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen {
public String toExampleValue(Schema schema, Object objExample) {
String modelName = getModelName(schema);
return toExampleValueRecursive(modelName, schema, objExample, 1, "", 0);
return toExampleValueRecursive(modelName, schema, objExample, 1, "", 0, Sets.newHashSet());
}
private Boolean simpleStringSchema(Schema schema) {
@ -925,9 +926,12 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen {
* ModelName( line 0
* some_property='some_property_example' line 1
* ) line 2
* @param seenSchemas This set contains all the schemas passed into the recursive function. It is used to check
* if a schema was already passed into the function and breaks the infinite recursive loop. The
* only schemas that are not added are ones that contain $ref != null
* @return the string example
*/
private String toExampleValueRecursive(String modelName, Schema schema, Object objExample, int indentationLevel, String prefix, Integer exampleLine) {
private String toExampleValueRecursive(String modelName, Schema schema, Object objExample, int indentationLevel, String prefix, Integer exampleLine, Set<Schema> seenSchemas) {
final String indentionConst = " ";
String currentIndentation = "";
String closingIndentation = "";
@ -951,6 +955,27 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen {
if (objExample != null) {
example = objExample.toString();
}
// checks if the current schema has already been passed in. If so, breaks the current recursive pass
if (seenSchemas.contains(schema)){
if (modelName != null) {
return fullPrefix + modelName + closeChars;
} else {
// this is a recursive schema
// need to add a reasonable example to avoid
// infinite recursion
if(ModelUtils.isNullable(schema)) {
// if the schema is nullable, then 'None' is a valid value
return fullPrefix + "None" + closeChars;
} else if(ModelUtils.isArraySchema(schema)) {
// the schema is an array, add an empty array
return fullPrefix + "[]" + closeChars;
} else {
// the schema is an object, make an empty object
return fullPrefix + "{}" + closeChars;
}
}
}
if (null != schema.get$ref()) {
Map<String, Schema> allDefinitions = ModelUtils.getSchemas(this.openAPI);
String ref = ModelUtils.getSimpleRef(schema.get$ref());
@ -960,7 +985,7 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen {
return fullPrefix + "None" + closeChars;
}
String refModelName = getModelName(schema);
return toExampleValueRecursive(refModelName, refSchema, objExample, indentationLevel, prefix, exampleLine);
return toExampleValueRecursive(refModelName, refSchema, objExample, indentationLevel, prefix, exampleLine, seenSchemas);
} else if (ModelUtils.isNullType(schema) || isAnyTypeSchema(schema)) {
// The 'null' type is allowed in OAS 3.1 and above. It is not supported by OAS 3.0.x,
// though this tooling supports it.
@ -1058,7 +1083,8 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen {
ArraySchema arrayschema = (ArraySchema) schema;
Schema itemSchema = arrayschema.getItems();
String itemModelName = getModelName(itemSchema);
example = fullPrefix + "[" + "\n" + toExampleValueRecursive(itemModelName, itemSchema, objExample, indentationLevel + 1, "", exampleLine + 1) + ",\n" + closingIndentation + "]" + closeChars;
seenSchemas.add(schema);
example = fullPrefix + "[" + "\n" + toExampleValueRecursive(itemModelName, itemSchema, objExample, indentationLevel + 1, "", exampleLine + 1, seenSchemas) + ",\n" + closingIndentation + "]" + closeChars;
return example;
} else if (ModelUtils.isMapSchema(schema)) {
if (modelName == null) {
@ -1080,7 +1106,8 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen {
addPropPrefix = ensureQuotes(key) + ": ";
}
String addPropsModelName = getModelName(addPropsSchema);
example = fullPrefix + "\n" + toExampleValueRecursive(addPropsModelName, addPropsSchema, addPropsExample, indentationLevel + 1, addPropPrefix, exampleLine + 1) + ",\n" + closingIndentation + closeChars;
seenSchemas.add(schema);
example = fullPrefix + "\n" + toExampleValueRecursive(addPropsModelName, addPropsSchema, addPropsExample, indentationLevel + 1, addPropPrefix, exampleLine + 1, seenSchemas) + ",\n" + closingIndentation + closeChars;
} else {
example = fullPrefix + closeChars;
}
@ -1103,7 +1130,12 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen {
return fullPrefix + closeChars;
}
}
return exampleForObjectModel(schema, fullPrefix, closeChars, null, indentationLevel, exampleLine, closingIndentation);
// Adds schema to seenSchemas before running example model function. romoves schema after running
// the function. It also doesnt keep track of any schemas within the ObjectModel.
seenSchemas.add(schema);
String exampleForObjectModel = exampleForObjectModel(schema, fullPrefix, closeChars, null, indentationLevel, exampleLine, closingIndentation, seenSchemas);
seenSchemas.remove(schema);
return exampleForObjectModel;
} else if (ModelUtils.isComposedSchema(schema)) {
// TODO add examples for composed schema models without discriminators
@ -1117,7 +1149,12 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen {
CodegenProperty cp = new CodegenProperty();
cp.setName(disc.getPropertyName());
cp.setExample(discPropNameValue);
return exampleForObjectModel(modelSchema, fullPrefix, closeChars, cp, indentationLevel, exampleLine, closingIndentation);
// Adds schema to seenSchemas before running example model function. romoves schema after running
// the function. It also doesnt keep track of any schemas within the ObjectModel.
seenSchemas.add(modelSchema);
String exampleForObjectModel = exampleForObjectModel(modelSchema, fullPrefix, closeChars, cp, indentationLevel, exampleLine, closingIndentation, seenSchemas);
seenSchemas.remove(modelSchema);
return exampleForObjectModel;
} else {
return fullPrefix + closeChars;
}
@ -1130,7 +1167,7 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen {
return example;
}
private String exampleForObjectModel(Schema schema, String fullPrefix, String closeChars, CodegenProperty discProp, int indentationLevel, int exampleLine, String closingIndentation) {
private String exampleForObjectModel(Schema schema, String fullPrefix, String closeChars, CodegenProperty discProp, int indentationLevel, int exampleLine, String closingIndentation, Set<Schema> seenSchemas) {
Map<String, Schema> requiredAndOptionalProps = schema.getProperties();
if (requiredAndOptionalProps == null || requiredAndOptionalProps.isEmpty()) {
return fullPrefix + closeChars;
@ -1150,7 +1187,7 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen {
propModelName = getModelName(propSchema);
propExample = exampleFromStringOrArraySchema(propSchema, null, propName);
}
example += toExampleValueRecursive(propModelName, propSchema, propExample, indentationLevel + 1, propName + "=", exampleLine + 1) + ",\n";
example += toExampleValueRecursive(propModelName, propSchema, propExample, indentationLevel + 1, propName + "=", exampleLine + 1, seenSchemas) + ",\n";
}
// TODO handle additionalProperties also
example += closingIndentation + closeChars;

View File

@ -522,7 +522,7 @@ public class Swift5ClientCodegen extends DefaultCodegen implements CodegenConfig
return ModelUtils.isSet(p) ? "Set<" + getTypeDeclaration(inner) + ">" : "[" + getTypeDeclaration(inner) + "]";
} else if (ModelUtils.isMapSchema(p)) {
Schema inner = getAdditionalProperties(p);
return "[String:" + getTypeDeclaration(inner) + "]";
return "[String: " + getTypeDeclaration(inner) + "]";
}
return super.getTypeDeclaration(p);
}
@ -807,7 +807,7 @@ public class Swift5ClientCodegen extends DefaultCodegen implements CodegenConfig
@Override
public String toEnumValue(String value, String datatype) {
// for string, array of string
if ("String".equals(datatype) || "[String]".equals(datatype) || "[String:String]".equals(datatype)) {
if ("String".equals(datatype) || "[String]".equals(datatype) || "[String: String]".equals(datatype)) {
return "\"" + String.valueOf(value) + "\"";
} else {
return String.valueOf(value);

View File

@ -41,6 +41,7 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
private static String FILE_NAME_SUFFIX_PATTERN = "^[a-zA-Z0-9.-]*$";
public static enum QUERY_PARAM_OBJECT_FORMAT_TYPE {dot, json, key};
public static enum PROVIDED_IN_LEVEL {none, root, any, platform};
private static final String DEFAULT_IMPORT_PREFIX = "./";
@ -50,6 +51,7 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
public static final String TAGGED_UNIONS = "taggedUnions";
public static final String NG_VERSION = "ngVersion";
public static final String PROVIDED_IN_ROOT = "providedInRoot";
public static final String PROVIDED_IN = "providedIn";
public static final String ENFORCE_GENERIC_MODULE_WITH_PROVIDERS = "enforceGenericModuleWithProviders";
public static final String API_MODULE_PREFIX = "apiModulePrefix";
public static final String CONFIGURATION_PREFIX = "configurationPrefix";
@ -72,6 +74,7 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
protected String fileNaming = "camelCase";
protected Boolean stringEnums = false;
protected QUERY_PARAM_OBJECT_FORMAT_TYPE queryParamObjectFormat = QUERY_PARAM_OBJECT_FORMAT_TYPE.dot;
protected PROVIDED_IN_LEVEL providedIn = PROVIDED_IN_LEVEL.root;
private boolean taggedUnions = false;
@ -104,8 +107,17 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
"Use discriminators to create tagged unions instead of extending interfaces.",
this.taggedUnions));
this.cliOptions.add(CliOption.newBoolean(PROVIDED_IN_ROOT,
"Use this property to provide Injectables in root (it is only valid in angular version greater or equal to 6.0.0).",
"Use this property to provide Injectables in root (it is only valid in angular version greater or equal to 6.0.0). IMPORTANT: Deprecated for angular version greater or equal to 9.0.0, use **providedIn** instead.",
false));
CliOption providedInCliOpt = new CliOption(PROVIDED_IN,
"Use this property to provide Injectables in wanted level (it is only valid in angular version greater or equal to 9.0.0).").defaultValue("root");
Map<String, String> providedInOptions = new HashMap<>();
providedInOptions.put(PROVIDED_IN_LEVEL.none.toString(), "No providedIn (same as providedInRoot=false)");
providedInOptions.put(PROVIDED_IN_LEVEL.root.toString(), "The application-level injector in most apps.");
providedInOptions.put(PROVIDED_IN_LEVEL.platform.toString(), "A special singleton platform injector shared by all applications on the page.");
providedInOptions.put(PROVIDED_IN_LEVEL.any.toString(), "Provides a unique instance in each lazy loaded module while all eagerly loaded modules share one instance.");
providedInCliOpt.setEnum(providedInOptions);
this.cliOptions.add(providedInCliOpt);
this.cliOptions.add(new CliOption(NG_VERSION, "The version of Angular. (At least 6.0.0)").defaultValue(this.ngVersion));
this.cliOptions.add(new CliOption(API_MODULE_PREFIX, "The prefix of the generated ApiModule."));
this.cliOptions.add(new CliOption(CONFIGURATION_PREFIX, "The prefix of the generated Configuration."));
@ -188,13 +200,28 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
taggedUnions = Boolean.parseBoolean(additionalProperties.get(TAGGED_UNIONS).toString());
}
if (!additionalProperties.containsKey(PROVIDED_IN_ROOT)) {
additionalProperties.put(PROVIDED_IN_ROOT, true);
if (ngVersion.atLeast("9.0.0") && additionalProperties.containsKey(PROVIDED_IN)) {
setProvidedIn(additionalProperties.get(PROVIDED_IN).toString());
} else {
additionalProperties.put(PROVIDED_IN_ROOT, Boolean.parseBoolean(
additionalProperties.get(PROVIDED_IN_ROOT).toString()
));
// Keep for backward compatibility
if (!additionalProperties.containsKey(PROVIDED_IN_ROOT)) {
additionalProperties.put(PROVIDED_IN_ROOT, true);
} else {
if (ngVersion.atLeast("9.0.0")) {
LOGGER.warn("{} will be deprecated, use {} {} instead", PROVIDED_IN_ROOT, PROVIDED_IN, PROVIDED_IN_LEVEL.values());
}
additionalProperties.put(PROVIDED_IN_ROOT, Boolean.parseBoolean(
additionalProperties.get(PROVIDED_IN_ROOT).toString()
));
}
if ((Boolean) additionalProperties.get(PROVIDED_IN_ROOT)) {
providedIn = PROVIDED_IN_LEVEL.root;
} else {
providedIn = PROVIDED_IN_LEVEL.none;
}
}
additionalProperties.put("providedIn", providedIn);
additionalProperties.put("isProvidedInNone", getIsProvidedInNone());
if (ngVersion.atLeast("9.0.0")) {
additionalProperties.put(ENFORCE_GENERIC_MODULE_WITH_PROVIDERS, true);
@ -714,5 +741,29 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
}
return name;
}
/**
* Set the Injectable level
*
* @param level the wanted level
*/
public void setProvidedIn (String level) {
try {
providedIn = PROVIDED_IN_LEVEL.valueOf(level);
} catch (IllegalArgumentException e) {
String values = Stream.of(PROVIDED_IN_LEVEL.values())
.map(value -> "'" + value.name() + "'")
.collect(Collectors.joining(", "));
String msg = String.format(Locale.ROOT, "Invalid providedIn level '%s'. Must be one of %s.", level, values);
throw new IllegalArgumentException(msg);
}
}
/**
*
*/
private boolean getIsProvidedInNone() {
return PROVIDED_IN_LEVEL.none.equals(providedIn);
}
}

View File

@ -219,6 +219,14 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
return objs;
}
@Override
public void postProcessParameter(CodegenParameter parameter) {
super.postProcessParameter(parameter);
if (parameter.isFormParam && parameter.isArray && "binary".equals(parameter.dataFormat)) {
parameter.isCollectionFormatMulti = true;
}
}
@Override
public Map<String, Object> postProcessAllModels(Map<String, Object> objs) {
Map<String, Object> result = super.postProcessAllModels(objs);

View File

@ -0,0 +1,49 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.codegen.templating.mustache;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template.Fragment;
import java.io.IOException;
import java.io.Writer;
/**
* Replaces duplicate whitespace characters in a fragment with single space.
*
* Register:
* <pre>
* additionalProperties.put("lambdaPrefixWithHash", new PrefixWithHashLambda());
* </pre>
*
* Use:
* <pre>
* {{#lambdaPrefixWithHash}}{{name}}{{/lambdaPrefixWithHash}}
* </pre>
*/
public class PrefixWithHashLambda implements Mustache.Lambda {
private static final String WITH_HASH = "\n#";
private static final String NEWLINE_REGEX = "\\R";
@Override
public void execute(Fragment fragment, Writer writer) throws IOException {
writer.write(fragment.execute().replaceAll(NEWLINE_REGEX, WITH_HASH));
}
}

View File

@ -61,7 +61,7 @@ public class StringUtils {
.build();
}
private static Pattern capitalLetterPattern = Pattern.compile("([A-Z]+)([A-Z][a-z])");
private static Pattern capitalLetterPattern = Pattern.compile("([A-Z]+)([A-Z][a-z][a-z]+)");
private static Pattern lowercasePattern = Pattern.compile("([a-z\\d])([A-Z])");
private static Pattern pkgSeparatorPattern = Pattern.compile("\\.");
private static Pattern dollarPattern = Pattern.compile("\\$");

View File

@ -116,13 +116,13 @@ end:
{{#pathParams}}
// Path Params
long sizeOfPathParams_{{{paramName}}} = {{#pathParams}}{{#isLong}}sizeof({{paramName}})+3{{/isLong}}{{#isString}}strlen({{paramName}})+3{{/isString}}{{^-last}} + {{/-last}}{{/pathParams}} + strlen("{ {{paramName}} }");
long sizeOfPathParams_{{{paramName}}} = {{#pathParams}}{{#isLong}}sizeof({{paramName}})+3{{/isLong}}{{#isString}}strlen({{paramName}})+3{{/isString}}{{^-last}} + {{/-last}}{{/pathParams}} + strlen("{ {{baseName}} }");
{{#isNumeric}}
if({{paramName}} == 0){
goto end;
}
char* localVarToReplace_{{paramName}} = malloc(sizeOfPathParams_{{paramName}});
snprintf(localVarToReplace_{{paramName}}, sizeOfPathParams_{{paramName}}, "{%s}", "{{paramName}}");
snprintf(localVarToReplace_{{paramName}}, sizeOfPathParams_{{paramName}}, "{%s}", "{{baseName}}");
char localVarBuff_{{paramName}}[256];
intToStr(localVarBuff_{{paramName}}, {{paramName}});
@ -135,7 +135,7 @@ end:
goto end;
}
char* localVarToReplace_{{paramName}} = malloc(sizeOfPathParams_{{paramName}});
snprintf(localVarToReplace_{{paramName}}, sizeOfPathParams_{{paramName}}, "{%s}", "{{paramName}}");
snprintf(localVarToReplace_{{paramName}}, sizeOfPathParams_{{paramName}}, "{%s}", "{{baseName}}");
char localVarBuff_{{paramName}}[256];
intToStr(localVarBuff_{{paramName}}, {{paramName}});
@ -148,7 +148,7 @@ end:
goto end;
}
char* localVarToReplace_{{paramName}} = malloc(sizeOfPathParams_{{paramName}});
snprintf(localVarToReplace_{{paramName}}, sizeOfPathParams_{{paramName}}, "{%s}", "{{paramName}}");
snprintf(localVarToReplace_{{paramName}}, sizeOfPathParams_{{paramName}}, "{%s}", "{{baseName}}");
char localVarBuff_{{paramName}}[256];
intToStr(localVarBuff_{{paramName}}, {{paramName}});
@ -161,7 +161,7 @@ end:
goto end;
}
char* localVarToReplace_{{paramName}} = malloc(sizeOfPathParams_{{paramName}});
snprintf(localVarToReplace_{{paramName}}, sizeOfPathParams_{{paramName}}, "{%s}", "{{paramName}}");
snprintf(localVarToReplace_{{paramName}}, sizeOfPathParams_{{paramName}}, "{%s}", "{{baseName}}");
char localVarBuff_{{paramName}}[256];
intToStr(localVarBuff_{{paramName}}, {{paramName}});
@ -174,7 +174,7 @@ end:
goto end;
}
char* localVarToReplace_{{paramName}} = malloc(sizeOfPathParams_{{paramName}});
sprintf(localVarToReplace_{{paramName}}, "{%s}", "{{paramName}}");
sprintf(localVarToReplace_{{paramName}}, "{%s}", "{{baseName}}");
localVarPath = strReplace(localVarPath, localVarToReplace_{{paramName}}, {{paramName}});
{{/isString}}
@ -183,7 +183,7 @@ end:
goto end;
}
char* localVarToReplace_{{paramName}} = malloc(sizeOfPathParams_{{paramName}});
sprintf(localVarToReplace_{{paramName}}, "{%s}", "{{paramName}}");
sprintf(localVarToReplace_{{paramName}}, "{%s}", "{{baseName}}");
localVarPath = strReplace(localVarPath, localVarToReplace_{{paramName}}, {{paramName}});
{{/isUuid}}

View File

@ -396,7 +396,7 @@ public class ApiClient{{#java8}} extends JavaTimeFormatter{{/java8}} {
*
* @param secrets Hash map from authentication name to its secret.
*/
public ApiClient configureApiKeys(HashMap<String, String> secrets) {
public ApiClient configureApiKeys(Map<String, String> secrets) {
for (Map.Entry<String, Authentication> authEntry : authentications.entrySet()) {
Authentication auth = authEntry.getValue();
if (auth instanceof ApiKeyAuth) {

View File

@ -522,6 +522,15 @@ public class ApiClient{{#java8}} extends JavaTimeFormatter{{/java8}} {
return mediaType != null && (MediaType.APPLICATION_JSON.isCompatibleWith(mediaType) || mediaType.getSubtype().matches("^.*\\+json[;]?\\s*$"));
}
/**
* Check if the given {@code String} is a Problem JSON MIME (RFC-7807).
* @param mediaType the input MediaType
* @return boolean true if the MediaType represents Problem JSON, false otherwise
*/
public boolean isProblemJsonMime(String mediaType) {
return "application/problem+json".equalsIgnoreCase(mediaType);
}
/**
* Select the Accept header's value from the given accepts array:
* if JSON exists in the given array, use it;
@ -536,7 +545,7 @@ public class ApiClient{{#java8}} extends JavaTimeFormatter{{/java8}} {
}
for (String accept : accepts) {
MediaType mediaType = MediaType.parseMediaType(accept);
if (isJsonMime(mediaType)) {
if (isJsonMime(mediaType) && !isProblemJsonMime(accept)) {
return Collections.singletonList(mediaType);
}
}

View File

@ -7,6 +7,7 @@ org.openapitools.codegen.languages.AsciidocDocumentationCodegen
org.openapitools.codegen.languages.AspNetCoreServerCodegen
org.openapitools.codegen.languages.AvroSchemaCodegen
org.openapitools.codegen.languages.BashClientCodegen
org.openapitools.codegen.languages.CrystalClientCodegen
org.openapitools.codegen.languages.CLibcurlClientCodegen
org.openapitools.codegen.languages.ClojureClientCodegen
org.openapitools.codegen.languages.ConfluenceWikiCodegen
@ -44,6 +45,7 @@ org.openapitools.codegen.languages.KotlinClientCodegen
org.openapitools.codegen.languages.KotlinServerCodegen
org.openapitools.codegen.languages.KotlinSpringServerCodegen
org.openapitools.codegen.languages.KotlinVertxServerCodegen
org.openapitools.codegen.languages.KtormSchemaCodegen
org.openapitools.codegen.languages.HaskellHttpClientCodegen
org.openapitools.codegen.languages.HaskellServantCodegen
org.openapitools.codegen.languages.JavaClientCodegen

View File

@ -75,10 +75,14 @@ h2. Models
{anchor:{{classname}}ModelAnchor}
h3. {{classname}}
{{description}}
||Field Name||Required||Type||Description||Enum||
{{{description}}}
{{#isEnum}} ||Name||Value||Description||
{{#allowableValues}} {{#enumVars}} |{{{name}}} |{{{value}}} |{{{enumDescription}}} |
{{/enumVars}}
{{/allowableValues}} {{/isEnum}}
{{^isEnum}}||Field Name||Required||Type||Description||Enum||
{{#vars}} |{{baseName}} |{{#required}}(/){{/required}}{{^required}}(x){{/required}} |{noformat:nopanel=true}{{{dataType}}}{noformat} |{{description}} | {{#isEnum}} {{_enum}} {{/isEnum}} |
{{/vars}}
{{/vars}} {{/isEnum}}
{{/model}}
{{/models}}

View File

@ -0,0 +1,9 @@
source 'https://rubygems.org'
gemspec
group :development, :test do
gem 'rake', '~> 13.0.1'
gem 'pry-byebug'
gem 'rubocop', '~> 0.66.0'
end

View File

@ -0,0 +1,46 @@
# {{shardName}}
The Crystsal module for the {{appName}}
{{#appDescriptionWithNewLines}}
{{{appDescriptionWithNewLines}}}
{{/appDescriptionWithNewLines}}
This SDK is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
- API version: {{appVersion}}
- Package version: {{shardVersion}}
{{^hideGenerationTimestamp}}
- Build date: {{generatedDate}}
{{/hideGenerationTimestamp}}
- Build package: {{generatorClass}}
{{#infoUrl}}
For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}})
{{/infoUrl}}
## Installation
### Install from Git
Add the following to shard.yaml
```yaml
dependencies:
{{{shardName}}}:
github: {{#gitUserId}}{{.}}{{/gitUserId}}{{^gitUserId}}YOUR_GIT_USERNAME{{/gitUserId}}/{{#gitRepoId}}{{.}}{{/gitRepoId}}{{^gitRepoId}}YOUR_GIT_REPO{{/gitRepoId}}
version: ~> {{shardVersion}}
```
## Development
Install dependencies
```shell
shards
```
Run the tests:
```shell
crystal spec
```

View File

@ -0,0 +1,10 @@
require "bundler/gem_tasks"
begin
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec)
task default: :spec
rescue LoadError
# no rspec available
end

View File

@ -0,0 +1,185 @@
# {{#lambdaPrefixWithHash}}{{> api_info}}{{/lambdaPrefixWithHash}}
require "uri"
module {{moduleName}}
{{#operations}}
class {{classname}}
property api_client : ApiClient
def initialize(api_client = ApiClient.default)
@api_client = api_client
end
{{#operation}}
{{#summary}}
# {{{summary}}}
{{/summary}}
{{#notes}}
# {{{notes}}}
{{/notes}}
{{#allParams}}
{{#required}}
# @param {{paramName}} [{{{dataType}}}{{^required}}?{{/required}}] {{description}}
{{/required}}
{{/allParams}}
# @return [{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}nil{{/returnType}}]
def {{operationId}}({{#allParams}}{{paramName}} : {{{dataType}}}{{^required}}?{{/required}}{{^-last}}, {{/-last}}{{/allParams}})
{{#returnType}}data, _status_code, _headers = {{/returnType}}{{operationId}}_with_http_info({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}})
{{#returnType}}data{{/returnType}}{{^returnType}}nil{{/returnType}}
end
{{#summary}}
# {{summary}}
{{/summary}}
{{#notes}}
# {{notes}}
{{/notes}}
{{#allParams}}
{{#required}}
# @param {{paramName}} [{{{dataType}}}{{^required}}?{{/required}}] {{description}}
{{/required}}
{{/allParams}}
# @return [Array<({{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}nil{{/returnType}}, Integer, Hash)>] {{#returnType}}{{{returnType}}} data{{/returnType}}{{^returnType}}nil{{/returnType}}, response status code and response headers
def {{operationId}}_with_http_info({{#allParams}}{{paramName}} : {{{dataType}}}{{^required}}?{{/required}}{{^-last}}, {{/-last}}{{/allParams}})
if @api_client.config.debugging
Log.debug {"Calling API: {{classname}}.{{operationId}} ..."}
end
{{#allParams}}
{{^isNullable}}
{{#required}}
# verify the required parameter "{{paramName}}" is set
if @api_client.config.client_side_validation && {{{paramName}}}.nil?
raise ArgumentError.new("Missing the required parameter '{{paramName}}' when calling {{classname}}.{{operationId}}")
end
{{#isEnum}}
{{^isContainer}}
# verify enum value
allowable_values = [{{#allowableValues}}{{#enumVars}}{{{value}}}{{^-last}}, {{/-last}}{{/enumVars}}{{/allowableValues}}]
if @api_client.config.client_side_validation && !allowable_values.include?({{{paramName}}})
raise ArgumentError.new("invalid value for \"{{{paramName}}}\", must be one of #{allowable_values}")
end
{{/isContainer}}
{{/isEnum}}
{{/required}}
{{/isNullable}}
{{^required}}
{{#isEnum}}
{{#collectionFormat}}
allowable_values = [{{#allowableValues}}{{#enumVars}}{{{value}}}{{^-last}}, {{/-last}}{{/enumVars}}{{/allowableValues}}]
if @api_client.config.client_side_validation && {{{paramName}}} && {{{paramName}}}.all? { |item| allowable_values.include?(item) }
raise ArgumentError.new("invalid value for \"{{{paramName}}}\", must include one of #{allowable_values}")
end
{{/collectionFormat}}
{{^collectionFormat}}
allowable_values = [{{#allowableValues}}{{#enumVars}}{{{value}}}{{^-last}}, {{/-last}}{{/enumVars}}{{/allowableValues}}]
if @api_client.config.client_side_validation && {{{paramName}}} && !allowable_values.include?({{{paramName}}}])
raise ArgumentError.new("invalid value for \"{{{paramName}}}\", must be one of #{allowable_values}")
end
{{/collectionFormat}}
{{/isEnum}}
{{/required}}
{{#hasValidation}}
{{#maxLength}}
if @api_client.config.client_side_validation && {{^required}}!{{{paramName}}}.nil? && {{/required}}{{{paramName}}}.to_s.length > {{{maxLength}}}
raise ArgumentError.new("invalid value for \"{{{paramName}}}\" when calling {{classname}}.{{operationId}}, the character length must be smaller than or equal to {{{maxLength}}}.")
end
{{/maxLength}}
{{#minLength}}
if @api_client.config.client_side_validation && {{^required}}!{{{paramName}}}.nil? && {{/required}}{{{paramName}}}.to_s.length < {{{minLength}}}
raise ArgumentError.new("invalid value for \"{{{paramName}}}\" when calling {{classname}}.{{operationId}}, the character length must be great than or equal to {{{minLength}}}.")
end
{{/minLength}}
{{#maximum}}
if @api_client.config.client_side_validation && {{^required}}!{{{paramName}}}.nil? && {{/required}}{{{paramName}}} >{{#exclusiveMaximum}}={{/exclusiveMaximum}} {{{maximum}}}
raise ArgumentError.new("invalid value for \"{{{paramName}}}\" when calling {{classname}}.{{operationId}}, must be smaller than {{^exclusiveMaximum}}or equal to {{/exclusiveMaximum}}{{{maximum}}}.")
end
{{/maximum}}
{{#minimum}}
if @api_client.config.client_side_validation && {{^required}}!{{{paramName}}}.nil? && {{/required}}{{{paramName}}} <{{#exclusiveMinimum}}={{/exclusiveMinimum}} {{{minimum}}}
raise ArgumentError.new("invalid value for \"{{{paramName}}}\" when calling {{classname}}.{{operationId}}, must be greater than {{^exclusiveMinimum}}or equal to {{/exclusiveMinimum}}{{{minimum}}}.")
end
{{/minimum}}
{{#pattern}}
pattern = Regexp.new({{{pattern}}})
if @api_client.config.client_side_validation && {{^required}}{{{paramName}}}.nil? && {{/required}}{{{paramName}}} !~ pattern
raise ArgumentError.new("invalid value for \"{{{paramName}}}\" when calling {{classname}}.{{operationId}}, must conform to the pattern #{pattern}.")
end
{{/pattern}}
{{#maxItems}}
if @api_client.config.client_side_validation && {{^required}}{{{paramName}}}.nil? && {{/required}}{{{paramName}}}.length > {{{maxItems}}}
raise ArgumentError.new("invalid value for \"{{{paramName}}}\" when calling {{classname}}.{{operationId}}, number of items must be less than or equal to {{{maxItems}}}.")
end
{{/maxItems}}
{{#minItems}}
if @api_client.config.client_side_validation && {{^required}}{{{paramName}}}.nil? && {{/required}}{{{paramName}}}.length < {{{minItems}}}
raise ArgumentError.new("invalid value for \"{{{paramName}}}\" when calling {{classname}}.{{operationId}}, number of items must be greater than or equal to {{{minItems}}}.")
end
{{/minItems}}
{{/hasValidation}}
{{/allParams}}
# resource path
local_var_path = "{{{path}}}"{{#pathParams}}.sub("{" + "{{baseName}}" + "}", URI.encode({{paramName}}.to_s){{^strictSpecBehavior}}.gsub("%2F", "/"){{/strictSpecBehavior}}){{/pathParams}}
# query parameters
query_params = Hash(Symbol, String).new
{{#queryParams}}
query_params[:"{{{baseName}}}"] = {{#collectionFormat}}@api_client.build_collection_param({{{paramName}}}, :{{{collectionFormat}}}){{/collectionFormat}}{{^collectionFormat}}{{{paramName}}}{{/collectionFormat}}
{{/queryParams}}
# header parameters
header_params = Hash(String, String).new
{{#hasProduces}}
# HTTP header "Accept" (if needed)
header_params["Accept"] = @api_client.select_header_accept([{{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}}])
{{/hasProduces}}
{{#hasConsumes}}
# HTTP header "Content-Type"
header_params["Content-Type"] = @api_client.select_header_content_type([{{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}}])
{{/hasConsumes}}
{{#headerParams}}
header_params["{{{baseName}}}"] = {{#collectionFormat}}@api_client.build_collection_param({{{paramName}}}, :{{{collectionFormat}}}){{/collectionFormat}}{{^collectionFormat}}{{{paramName}}}{{/collectionFormat}}
{{/headerParams}}
# form parameters
form_params = Hash(Symbol, String).new
{{#formParams}}
form_params[:"{{baseName}}"] = {{#collectionFormat}}@api_client.build_collection_param({{{paramName}}}, :{{{collectionFormat}}}){{/collectionFormat}}{{^collectionFormat}}{{{paramName}}}{{/collectionFormat}}
{{/formParams}}
# http body (model)
post_body = {{#bodyParam}}{{{paramName}}}.to_json{{/bodyParam}}{{^bodyParam}}nil{{/bodyParam}}
# return_type
return_type = {{#returnType}}"{{{.}}}"{{/returnType}}{{^returnType}}nil{{/returnType}}
# auth_names
auth_names = {{#authMethods}}{{#-first}}[{{/-first}}"{{name}}"{{^-last}}, {{/-last}}{{#-last}}]{{/-last}}{{/authMethods}}{{^authMethods}}[] of String{{/authMethods}}
data, status_code, headers = @api_client.call_api(:{{httpMethod}},
local_var_path,
:"{{classname}}.{{operationId}}",
return_type,
post_body,
auth_names,
header_params,
query_params,
form_params)
if @api_client.config.debugging
Log.debug {"API called: {{classname}}#{{operationId}}\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"}
end
return {{#returnType}}{{{.}}}.from_json(data){{/returnType}}{{^returnType}}nil{{/returnType}}, status_code, headers
end
{{^-last}}
{{/-last}}
{{/operation}}
end
{{/operations}}
end

View File

@ -0,0 +1,402 @@
# {{#lambdaPrefixWithHash}}{{> api_info}}{{/lambdaPrefixWithHash}}
require "json"
require "time"
module {{moduleName}}
class ApiClient
# The Configuration object holding settings to be used in the API client.
property config : Configuration
# Defines the headers to be used in HTTP requests of all API calls by default.
#
# @return [Hash]
property default_headers : Hash(String, String)
# Initializes the ApiClient
# @option config [Configuration] Configuration for initializing the object, default to Configuration.default
def initialize(@config = Configuration.default)
@user_agent = "{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}OpenAPI-Generator/#{VERSION}/crystal{{/httpUserAgent}}"
@default_headers = {
"User-Agent" => @user_agent
}
end
def self.default
@@default ||= ApiClient.new
end
# Check if the given MIME is a JSON MIME.
# JSON MIME examples:
# application/json
# application/json; charset=UTF8
# APPLICATION/JSON
# */*
# @param [String] mime MIME
# @return [Boolean] True if the MIME is application/json
def json_mime?(mime)
(mime == "*/*") || !(mime =~ /Application\/.*json(?!p)(;.*)?/i).nil?
end
# Deserialize the response to the given return type.
#
# @param [Response] response HTTP response
# @param [String] return_type some examples: "User", "Array<User>", "Hash<String, Integer>"
def deserialize(response, return_type)
body = response.body
# handle file downloading - return the File instance processed in request callbacks
# note that response body is empty when the file is written in chunks in request on_body callback
if return_type == "File"
content_disposition = response.headers["Content-Disposition"].to_s
if content_disposition && content_disposition =~ /filename=/i
filename = content_disposition.match(/filename=[""]?([^""\s]+)[""]?/i).try &.[0]
prefix = sanitize_filename(filename)
else
prefix = "download-"
end
if !prefix.nil? && prefix.ends_with?("-")
prefix = prefix + "-"
end
encoding = response.headers["Content-Encoding"].to_s
# TODO add file support
raise ApiError.new(code: 0, message: "File response not yet supported in the client.") if return_type
return nil
#@tempfile = Tempfile.open(prefix, @config.temp_folder_path, encoding: encoding)
#@tempfile.write(@stream.join.force_encoding(encoding))
#@tempfile.close
#Log.info { "Temp file written to #{@tempfile.path}, please copy the file to a proper folder "\
# "with e.g. `FileUtils.cp(tempfile.path, \"/new/file/path\")` otherwise the temp file "\
# "will be deleted automatically with GC. It's also recommended to delete the temp file "\
# "explicitly with `tempfile.delete`" }
#return @tempfile
end
return nil if body.nil? || body.empty?
# return response body directly for String return type
return body if return_type == "String"
# ensuring a default content type
content_type = response.headers["Content-Type"] || "application/json"
raise ApiError.new(code: 0, message: "Content-Type is not supported: #{content_type}") unless json_mime?(content_type)
begin
data = JSON.parse("[#{body}]")[0]
rescue e : Exception
if %w(String Date Time).includes?(return_type)
data = body
else
raise e
end
end
convert_to_type data, return_type
end
# Convert data to the given return type.
# @param [Object] data Data to be converted
# @param [String] return_type Return type
# @return [Mixed] Data in a particular type
def convert_to_type(data, return_type)
return nil if data.nil?
case return_type
when "String"
data.to_s
when "Integer"
data.to_s.to_i
when "Float"
data.to_s.to_f
when "Boolean"
data == true
when "Time"
# parse date time (expecting ISO 8601 format)
Time.parse! data.to_s, "%Y-%m-%dT%H:%M:%S%Z"
when "Date"
# parse date (expecting ISO 8601 format)
Time.parse! data.to_s, "%Y-%m-%d"
when "Object"
# generic object (usually a Hash), return directly
data
when /\AArray<(.+)>\z/
# e.g. Array<Pet>
sub_type = $1
data.map { |item| convert_to_type(item, sub_type) }
when /\AHash\<String, (.+)\>\z/
# e.g. Hash<String, Integer>
sub_type = $1
({} of Symbol => String).tap do |hash|
data.each { |k, v| hash[k] = convert_to_type(v, sub_type) }
end
else
# models (e.g. Pet) or oneOf
klass = Petstore.const_get(return_type)
klass.respond_to?(:openapi_one_of) ? klass.build(data) : klass.build_from_hash(data)
end
end
# Sanitize filename by removing path.
# e.g. ../../sun.gif becomes sun.gif
#
# @param [String] filename the filename to be sanitized
# @return [String] the sanitized filename
def sanitize_filename(filename)
if filename.nil?
return nil
else
filename.gsub(/.*[\/\\]/, "")
end
end
def build_request_url(path : String, operation : Symbol)
# Add leading and trailing slashes to path
path = "/#{path}".gsub(/\/+/, "/")
@config.base_url(operation) + path
end
# Update hearder and query params based on authentication settings.
#
# @param [Hash] header_params Header parameters
# @param [Hash] query_params Query parameters
# @param [String] auth_names Authentication scheme name
def update_params_for_auth!(header_params, query_params, auth_names)
Array{auth_names}.each do |auth_name|
auth_setting = @config.auth_settings[auth_name]
next unless auth_setting
case auth_setting[:in]
when "header" then header_params[auth_setting[:key]] = auth_setting[:value]
when "query" then query_params[auth_setting[:key]] = auth_setting[:value]
else raise ArgumentError.new("Authentication token must be in `query` of `header`")
end
end
end
# Sets user agent in HTTP header
#
# @param [String] user_agent User agent (e.g. openapi-generator/ruby/1.0.0)
def user_agent=(user_agent)
@user_agent = user_agent
@default_headers["User-Agent"] = @user_agent
end
# Return Accept header based on an array of accepts provided.
# @param [Array] accepts array for Accept
# @return [String] the Accept header (e.g. application/json)
def select_header_accept(accepts) : String
#return nil if accepts.nil? || accepts.empty?
# use JSON when present, otherwise use all of the provided
json_accept = accepts.find { |s| json_mime?(s) }
if json_accept.nil?
accepts.join(",")
else
json_accept
end
end
# Return Content-Type header based on an array of content types provided.
# @param [Array] content_types array for Content-Type
# @return [String] the Content-Type header (e.g. application/json)
def select_header_content_type(content_types)
# use application/json by default
return "application/json" if content_types.nil? || content_types.empty?
# use JSON when present, otherwise use the first one
json_content_type = content_types.find { |s| json_mime?(s) }
json_content_type || content_types.first
end
# Convert object (array, hash, object, etc) to JSON string.
# @param [Object] model object to be converted into JSON string
# @return [String] JSON string representation of the object
def object_to_http_body(model)
return model if model.nil? || model.is_a?(String)
local_body = nil
if model.is_a?(Array)
local_body = model.map { |m| object_to_hash(m) }
else
local_body = object_to_hash(model)
end
local_body.to_json
end
# Convert object(non-array) to hash.
# @param [Object] obj object to be converted into JSON string
# @return [String] JSON string representation of the object
def object_to_hash(obj)
if obj.respond_to?(:to_hash)
obj.to_hash
else
obj
end
end
# Build parameter value according to the given collection format.
# @param [String] collection_format one of :csv, :ssv, :tsv, :pipes and :multi
def build_collection_param(param, collection_format)
case collection_format
when :csv
param.join(",")
when :ssv
param.join(" ")
when :tsv
param.join("\t")
when :pipes
param.join("|")
when :multi
# return the array directly as typhoeus will handle it as expected
param
else
fail "unknown collection format: #{collection_format.inspect}"
end
end
# Call an API with given options.
#
# @return [Array<(Object, Integer, Hash)>] an array of 3 elements:
# the data deserialized from response body (could be nil), response status code and response headers.
def call_api(http_method : Symbol, path : String, operation : Symbol, return_type : String, post_body : String?, auth_names = [] of String, header_params = {} of String => String, query_params = {} of Symbol => String, form_params = {} of Symbol => String)
#ssl_options = {
# :ca_file => @config.ssl_ca_file,
# :verify => @config.ssl_verify,
# :verify_mode => @config.ssl_verify_mode,
# :client_cert => @config.ssl_client_cert,
# :client_key => @config.ssl_client_key
#}
#connection = Faraday.new(:url => config.base_url, :ssl => ssl_options) do |conn|
# conn.basic_auth(config.username, config.password)
# if opts[:header_params]["Content-Type"] == "multipart/form-data"
# conn.request :multipart
# conn.request :url_encoded
# end
# conn.adapter(Faraday.default_adapter)
#end
if !post_body.nil? && !post_body.empty?
# use JSON string in the payload
form_or_body = post_body
else
# use HTTP forms in the payload
# TDOD use HTTP form encoding
form_or_body = form_params
end
request = Crest::Request.new(http_method,
build_request_url(path, operation),
params: query_params,
headers: header_params,
#cookies: cookie_params, # TODO add cookies support
form: form_or_body,
logging: @config.debugging,
handle_errors: false
)
response = request.execute
if @config.debugging
Log.debug {"HTTP response body ~BEGIN~\n#{response.body}\n~END~\n"}
end
if !response.success?
if response.status == 0
# Errors from libcurl will be made visible here
raise ApiError.new(code: 0,
message: response.body)
else
raise ApiError.new(code: response.status_code,
response_headers: response.headers,
message: response.body)
end
end
return response.body, response.status_code, response.headers
end
# Builds the HTTP request
#
# @param [String] http_method HTTP method/verb (e.g. POST)
# @param [String] path URL path (e.g. /account/new)
# @option opts [Hash] :header_params Header parameters
# @option opts [Hash] :query_params Query parameters
# @option opts [Hash] :form_params Query parameters
# @option opts [Object] :body HTTP body (JSON/XML)
# @return [Typhoeus::Request] A Typhoeus Request
def build_request(http_method, path, request, opts = {} of Symbol => String)
url = build_request_url(path, opts)
http_method = http_method.to_sym.downcase
header_params = @default_headers.merge(opts[:header_params] || {} of Symbole => String)
query_params = opts[:query_params] || {} of Symbol => String
form_params = opts[:form_params] || {} of Symbol => String
update_params_for_auth! header_params, query_params, opts[:auth_names]
req_opts = {
:method => http_method,
:headers => header_params,
:params => query_params,
:params_encoding => @config.params_encoding,
:timeout => @config.timeout,
:verbose => @config.debugging
}
if [:post, :patch, :put, :delete].include?(http_method)
req_body = build_request_body(header_params, form_params, opts[:body])
req_opts.update body: req_body
if @config.debugging
Log.debug {"HTTP request body param ~BEGIN~\n#{req_body}\n~END~\n"}
end
end
request.headers = header_params
request.body = req_body
request.url url
request.params = query_params
download_file(request) if opts[:return_type] == "File"
request
end
# Builds the HTTP request body
#
# @param [Hash] header_params Header parameters
# @param [Hash] form_params Query parameters
# @param [Object] body HTTP body (JSON/XML)
# @return [String] HTTP body data in the form of string
def build_request_body(header_params, form_params, body)
# http form
if header_params["Content-Type"] == "application/x-www-form-urlencoded"
data = URI.encode_www_form(form_params)
elsif header_params["Content-Type"] == "multipart/form-data"
data = {} of Symbol => String
form_params.each do |key, value|
case value
when ::File, ::Tempfile
# TODO hardcode to application/octet-stream, need better way to detect content type
data[key] = Faraday::UploadIO.new(value.path, "application/octet-stream", value.path)
when ::Array, nil
# let Faraday handle Array and nil parameters
data[key] = value
else
data[key] = value.to_s
end
end
elsif body
data = body.is_a?(String) ? body : body.to_json
else
data = nil
end
data
end
# TODO fix streaming response
#def download_file(request)
# @stream = []
# # handle streaming Responses
# request.options.on_data = Proc.new do |chunk, overall_received_bytes|
# @stream << chunk
# end
#end
end
end

View File

@ -0,0 +1,138 @@
# Call an API with given options.
#
# @return [Array<(Object, Integer, Hash)>] an array of 3 elements:
# the data deserialized from response body (could be nil), response status code and response headers.
def call_api(http_method, path, opts = {} of Symbol => String)
ssl_options = {
:ca_file => @config.ssl_ca_file,
:verify => @config.ssl_verify,
:verify_mode => @config.ssl_verify_mode,
:client_cert => @config.ssl_client_cert,
:client_key => @config.ssl_client_key
}
connection = Faraday.new(:url => config.base_url, :ssl => ssl_options) do |conn|
conn.basic_auth(config.username, config.password)
if opts[:header_params]["Content-Type"] == "multipart/form-data"
conn.request :multipart
conn.request :url_encoded
end
conn.adapter(Faraday.default_adapter)
end
begin
response = connection.public_send(http_method.to_sym.downcase) do |req|
build_request(http_method, path, req, opts)
end
if @config.debugging
Log.debug {"HTTP response body ~BEGIN~\n#{response.body}\n~END~\n"}
end
unless response.success?
if response.status == 0
# Errors from libcurl will be made visible here
fail ApiError.new(code: 0,
message: response.return_message)
else
fail ApiError.new(code: response.status,
response_headers: response.headers,
response_body: response.body),
response.reason_phrase
end
end
rescue Faraday::TimeoutError
fail ApiError.new("Connection timed out")
end
if opts[:return_type]
data = deserialize(response, opts[:return_type])
else
data = nil
end
return data, response.status, response.headers
end
# Builds the HTTP request
#
# @param [String] http_method HTTP method/verb (e.g. POST)
# @param [String] path URL path (e.g. /account/new)
# @option opts [Hash] :header_params Header parameters
# @option opts [Hash] :query_params Query parameters
# @option opts [Hash] :form_params Query parameters
# @option opts [Object] :body HTTP body (JSON/XML)
# @return [Typhoeus::Request] A Typhoeus Request
def build_request(http_method, path, request, opts = {} of Symbol => String)
url = build_request_url(path, opts)
http_method = http_method.to_sym.downcase
header_params = @default_headers.merge(opts[:header_params] || {} of Symbole => String)
query_params = opts[:query_params] || {} of Symbol => String
form_params = opts[:form_params] || {} of Symbol => String
update_params_for_auth! header_params, query_params, opts[:auth_names]
req_opts = {
:method => http_method,
:headers => header_params,
:params => query_params,
:params_encoding => @config.params_encoding,
:timeout => @config.timeout,
:verbose => @config.debugging
}
if [:post, :patch, :put, :delete].include?(http_method)
req_body = build_request_body(header_params, form_params, opts[:body])
req_opts.update body: req_body
if @config.debugging
Log.debug {"HTTP request body param ~BEGIN~\n#{req_body}\n~END~\n"}
end
end
request.headers = header_params
request.body = req_body
request.url url
request.params = query_params
download_file(request) if opts[:return_type] == "File"
request
end
# Builds the HTTP request body
#
# @param [Hash] header_params Header parameters
# @param [Hash] form_params Query parameters
# @param [Object] body HTTP body (JSON/XML)
# @return [String] HTTP body data in the form of string
def build_request_body(header_params, form_params, body)
# http form
if header_params["Content-Type"] == "application/x-www-form-urlencoded"
data = URI.encode_www_form(form_params)
elsif header_params["Content-Type"] == "multipart/form-data"
data = {} of Symbol => String
form_params.each do |key, value|
case value
when ::File, ::Tempfile
# TODO hardcode to application/octet-stream, need better way to detect content type
data[key] = Faraday::UploadIO.new(value.path, "application/octet-stream", value.path)
when ::Array, nil
# let Faraday handle Array and nil parameters
data[key] = value
else
data[key] = value.to_s
end
end
elsif body
data = body.is_a?(String) ? body : body.to_json
else
data = nil
end
data
end
def download_file(request)
@stream = []
# handle streaming Responses
request.options.on_data = Proc.new do |chunk, overall_received_bytes|
@stream << chunk
end
end

View File

@ -0,0 +1,153 @@
# Call an API with given options.
#
# @return [Array<(Object, Integer, Hash)>] an array of 3 elements:
# the data deserialized from response body (could be nil), response status code and response headers.
def call_api(http_method, path, opts = {} of Symbol => String)
request = build_request(http_method, path, opts)
response = request.run
if @config.debugging
@config.logger.debug "HTTP response body ~BEGIN~\n#{response.body}\n~END~\n"
end
unless response.success?
if response.timed_out?
fail ApiError.new("Connection timed out")
elsif response.code == 0
# Errors from libcurl will be made visible here
fail ApiError.new(code: 0,
message: response.return_message)
else
fail ApiError.new(code: response.code,
response_headers: response.headers,
response_body: response.body),
response.status_message
end
end
if opts[:return_type]
data = deserialize(response, opts[:return_type])
else
data = nil
end
return data, response.code, response.headers
end
# Builds the HTTP request
#
# @param [String] http_method HTTP method/verb (e.g. POST)
# @param [String] path URL path (e.g. /account/new)
# @option opts [Hash] :header_params Header parameters
# @option opts [Hash] :query_params Query parameters
# @option opts [Hash] :form_params Query parameters
# @option opts [Object] :body HTTP body (JSON/XML)
# @return [Typhoeus::Request] A Typhoeus Request
def build_request(http_method, path, opts = {} of Symbol => String)
url = build_request_url(path, opts)
http_method = http_method.to_sym.downcase
header_params = @default_headers.merge(opts[:header_params] || {} of Symbol => String)
query_params = opts[:query_params] || {} of Symbol => String
form_params = opts[:form_params] || {} of Symbol => String
{{#hasAuthMethods}}
update_params_for_auth! header_params, query_params, opts[:auth_names]
{{/hasAuthMethods}}
# set ssl_verifyhosts option based on @config.verify_ssl_host (true/false)
_verify_ssl_host = @config.verify_ssl_host ? 2 : 0
req_opts = {
:method => http_method,
:headers => header_params,
:params => query_params,
:params_encoding => @config.params_encoding,
:timeout => @config.timeout,
:ssl_verifypeer => @config.verify_ssl,
:ssl_verifyhost => _verify_ssl_host,
:sslcert => @config.cert_file,
:sslkey => @config.key_file,
:verbose => @config.debugging
}
# set custom cert, if provided
req_opts[:cainfo] = @config.ssl_ca_cert if @config.ssl_ca_cert
if [:post, :patch, :put, :delete].include?(http_method)
req_body = build_request_body(header_params, form_params, opts[:body])
req_opts.update body: req_body
if @config.debugging
@config.logger.debug "HTTP request body param ~BEGIN~\n#{req_body}\n~END~\n"
end
end
request = Typhoeus::Request.new(url, req_opts)
download_file(request) if opts[:return_type] == "File"
request
end
# Builds the HTTP request body
#
# @param [Hash] header_params Header parameters
# @param [Hash] form_params Query parameters
# @param [Object] body HTTP body (JSON/XML)
# @return [String] HTTP body data in the form of string
def build_request_body(header_params, form_params, body)
# http form
if header_params["Content-Type"] == "application/x-www-form-urlencoded" ||
header_params["Content-Type"] == "multipart/form-data"
data = {} of Symbol => String
form_params.each do |key, value|
case value
when ::File, ::Array, nil
# let typhoeus handle File, Array and nil parameters
data[key] = value
else
data[key] = value.to_s
end
end
elsif body
data = body.is_a?(String) ? body : body.to_json
else
data = nil
end
data
end
# Save response body into a file in (the defined) temporary folder, using the filename
# from the "Content-Disposition" header if provided, otherwise a random filename.
# The response body is written to the file in chunks in order to handle files which
# size is larger than maximum Ruby String or even larger than the maximum memory a Ruby
# process can use.
#
# @see Configuration#temp_folder_path
def download_file(request)
tempfile = nil
encoding = nil
request.on_headers do |response|
content_disposition = response.headers["Content-Disposition"]
if content_disposition && content_disposition =~ /filename=/i
filename = content_disposition[/filename=[""]?([^""\s]+)[""]?/, 1]
prefix = sanitize_filename(filename)
else
prefix = "download-"
end
prefix = prefix + "-" unless prefix.end_with?("-")
encoding = response.body.encoding
tempfile = Tempfile.open(prefix, @config.temp_folder_path, encoding: encoding)
@tempfile = tempfile
end
request.on_body do |chunk|
chunk.force_encoding(encoding)
tempfile.write(chunk)
end
request.on_complete do |response|
if tempfile
tempfile.close
@config.logger.info "Temp file written to #{tempfile.path}, please copy the file to a proper folder "\
"with e.g. `FileUtils.cp(tempfile.path, \"/new/file/path\")` otherwise the temp file "\
"will be deleted automatically with GC. It's also recommended to delete the temp file "\
"explicitly with `tempfile.delete`"
end
end
end

View File

@ -0,0 +1,118 @@
# {{moduleName}}::{{classname}}{{#description}}
{{description}}{{/description}}
All URIs are relative to *{{basePath}}*
| Method | HTTP request | Description |
| ------ | ------------ | ----------- |
{{#operations}}
{{#operation}}
| [**{{operationId}}**]({{classname}}.md#{{operationId}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}} |
{{/operation}}
{{/operations}}
{{#operations}}
{{#operation}}
## {{operationId}}
> {{#returnType}}{{#returnTypeIsPrimitive}}{{returnType}}{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}<{{{returnType}}}>{{/returnTypeIsPrimitive}} {{/returnType}}{{operationId}}{{#hasParams}}({{#requiredParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/requiredParams}}{{#optionalParams}}{{#-last}}{{#hasRequiredParams}}, {{/hasRequiredParams}}opts{{/-last}}{{/optionalParams}}){{/hasParams}}
{{{summary}}}{{#notes}}
{{{notes}}}{{/notes}}
### Examples
```ruby
require 'time'
require '{{{gemName}}}'
{{#hasAuthMethods}}
# setup authorization
{{{moduleName}}}.configure do |config|{{#authMethods}}{{#isBasic}}{{#isBasicBasic}}
# Configure HTTP basic authorization: {{{name}}}
config.username = 'YOUR USERNAME'
config.password = 'YOUR PASSWORD'{{/isBasicBasic}}{{#isBasicBearer}}
# Configure Bearer authorization{{#bearerFormat}} ({{{.}}}){{/bearerFormat}}: {{{name}}}
config.access_token = 'YOUR_BEARER_TOKEN'{{/isBasicBearer}}{{/isBasic}}{{#isApiKey}}
# Configure API key authorization: {{{name}}}
config.api_key['{{{keyParamName}}}'] = 'YOUR API KEY'
# Uncomment the following line to set a prefix for the API key, e.g. 'Bearer' (defaults to nil)
# config.api_key_prefix['{{{keyParamName}}}'] = 'Bearer'{{/isApiKey}}{{#isOAuth}}
# Configure OAuth2 access token for authorization: {{{name}}}
config.access_token = 'YOUR ACCESS TOKEN'{{/isOAuth}}
{{/authMethods}}end
{{/hasAuthMethods}}
api_instance = {{{moduleName}}}::{{{classname}}}.new
{{#requiredParams}}
{{{paramName}}} = {{{vendorExtensions.x-ruby-example}}} # {{{dataType}}} | {{{description}}}
{{/requiredParams}}
{{#optionalParams}}
{{#-first}}
opts = {
{{/-first}}
{{{paramName}}}: {{{vendorExtensions.x-ruby-example}}}{{^-last}},{{/-last}} # {{{dataType}}} | {{{description}}}
{{#-last}}
}
{{/-last}}
{{/optionalParams}}
begin
{{#summary}}# {{{.}}}{{/summary}}
{{#returnType}}result = {{/returnType}}api_instance.{{{operationId}}}{{#hasParams}}({{#requiredParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/requiredParams}}{{#optionalParams}}{{#-last}}{{#hasRequiredParams}}, {{/hasRequiredParams}}opts{{/-last}}{{/optionalParams}}){{/hasParams}}
{{#returnType}}
p result
{{/returnType}}
rescue {{{moduleName}}}::ApiError => e
puts "Error when calling {{classname}}->{{{operationId}}}: #{e}"
end
```
#### Using the {{operationId}}_with_http_info variant
This returns an Array which contains the response data{{^returnType}} (`nil` in this case){{/returnType}}, status code and headers.
> <Array({{#returnType}}{{#returnTypeIsPrimitive}}{{returnType}}{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}<{{{returnType}}}>{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}nil{{/returnType}}, Integer, Hash)> {{operationId}}_with_http_info{{#hasParams}}({{#requiredParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/requiredParams}}{{#optionalParams}}{{#-last}}{{#hasRequiredParams}}, {{/hasRequiredParams}}opts{{/-last}}{{/optionalParams}}){{/hasParams}}
```ruby
begin
{{#summary}}# {{{.}}}{{/summary}}
data, status_code, headers = api_instance.{{{operationId}}}_with_http_info{{#hasParams}}({{#requiredParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/requiredParams}}{{#optionalParams}}{{#-last}}{{#hasRequiredParams}}, {{/hasRequiredParams}}opts{{/-last}}{{/optionalParams}}){{/hasParams}}
p status_code # => 2xx
p headers # => { ... }
p data # => {{#returnType}}{{#returnTypeIsPrimitive}}{{returnType}}{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}<{{{returnType}}}>{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}nil{{/returnType}}
rescue {{{moduleName}}}::ApiError => e
puts "Error when calling {{classname}}->{{{operationId}}}_with_http_info: #{e}"
end
```
### Parameters
{{^allParams}}
This endpoint does not need any parameter.
{{/allParams}}
{{#allParams}}
{{#-first}}
| Name | Type | Description | Notes |
| ---- | ---- | ----------- | ----- |
{{/-first}}
| **{{paramName}}** | {{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{#isFile}}**{{dataType}}**{{/isFile}}{{^isFile}}[**{{dataType}}**]({{baseType}}.md){{/isFile}}{{/isPrimitiveType}} | {{description}} | {{^required}}[optional]{{/required}}{{#defaultValue}}[default to {{defaultValue}}]{{/defaultValue}} |
{{/allParams}}
### Return type
{{#returnType}}{{#returnTypeIsPrimitive}}**{{returnType}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}[**{{returnType}}**]({{returnBaseType}}.md){{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}nil (empty response body){{/returnType}}
### Authorization
{{^authMethods}}No authorization required{{/authMethods}}{{#authMethods}}[{{name}}](../README.md#{{name}}){{^-last}}, {{/-last}}{{/authMethods}}
### HTTP request headers
- **Content-Type**: {{#consumes}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/consumes}}{{^consumes}}Not defined{{/consumes}}
- **Accept**: {{#produces}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/produces}}{{^produces}}Not defined{{/produces}}
{{/operation}}
{{/operations}}

View File

@ -0,0 +1,33 @@
# {{#lambdaPrefixWithHash}}{{> api_info}}{{/lambdaPrefixWithHash}}
module {{moduleName}}
class ApiError < Exception
getter code : Int32?
getter response_headers : Hash(String, Array(String) | String)?
# Usage examples:
# ApiError.new
# ApiError.new(message: "message")
# ApiError.new(code: 500, response_headers: {}, message: "")
# ApiError.new(code: 404, message: "Not Found")
def initialize(@code , @message, @response_headers)
end
def initialize(@code , @message)
end
# Override to_s to display a friendly error message
def to_s
msg = ""
msg = msg + "\nHTTP status code: #{code}" if @code
msg = msg + "\nResponse headers: #{response_headers}" if @response_headers
if @message.nil? || @message.empty?
msg = msg + "\nError message: the server returns an error but the HTTP respone body is empty."
else
msg = msg + "\nResponse body: #{@message}"
end
msg
end
end
end

View File

@ -0,0 +1,12 @@
{{#appName}}
#{{{appName}}}
{{/appName}}
{{#appDescription}}
#{{{appDescription}}}
{{/appDescription}}
{{#version}}The version of the OpenAPI document: {{version}}{{/version}}
{{#infoEmail}}Contact: {{{infoEmail}}}{{/infoEmail}}
Generated by: https://openapi-generator.tech
OpenAPI Generator version: {{{generatorVersion}}}

View File

@ -0,0 +1,38 @@
# {{#lambdaPrefixWithHash}}{{> api_info}}{{/lambdaPrefixWithHash}}
require "../spec_helper"
require "json"
require "time"
# Unit tests for {{moduleName}}::{{classname}}
# Automatically generated by openapi-generator (https://openapi-generator.tech)
# Please update as you see appropriate
{{#operations}}describe "{{classname}}" do
describe "test an instance of {{classname}}" do
it "should create an instance of {{classname}}" do
api_instance = {{moduleName}}::{{classname}}.new
# TODO expect(api_instance).to be_instance_of({{moduleName}}::{{classname}})
end
end
{{#operation}}
# unit tests for {{operationId}}
{{#summary}}
# {{summary}}
{{/summary}}
{{#notes}}
# {{notes}}
{{/notes}}
{{#allParams}}{{#required}} # @param {{paramName}} {{description}}
{{/required}}{{/allParams}} # @param [Hash] opts the optional parameters
{{#allParams}}{{^required}} # @option opts [{{{dataType}}}] :{{paramName}} {{description}}
{{/required}}{{/allParams}} # @return [{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}nil{{/returnType}}]
describe "{{operationId}} test" do
it "should work" do
# assertion here. ref: https://crystal-lang.org/reference/guides/testing.html
end
end
{{/operation}}
end
{{/operations}}

View File

@ -0,0 +1,120 @@
# Builds the object from hash
# @param [Hash] attributes Model attributes in the form of hash
# @return [Object] Returns the model itself
def self.build_from_hash(attributes)
new.build_from_hash(attributes)
end
# Builds the object from hash
# @param [Hash] attributes Model attributes in the form of hash
# @return [Object] Returns the model itself
def build_from_hash(attributes)
return nil unless attributes.is_a?(Hash)
{{#parent}}
super(attributes)
{{/parent}}
self.class.openapi_types.each_pair do |key, type|
if attributes[self.class.attribute_map[key]].nil? && self.class.openapi_nullable.include?(key)
self.send("#{key}=", nil)
elsif type =~ /\AArray<(.*)>/i
# check to ensure the input is an array given that the attribute
# is documented as an array but the input is not
if attributes[self.class.attribute_map[key]].is_a?(Array)
self.send("#{key}=", attributes[self.class.attribute_map[key]].map { |v| _deserialize($1, v) })
end
elsif !attributes[self.class.attribute_map[key]].nil?
self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]]))
end
end
self
end
# Deserializes the data based on type
# @param string type Data type
# @param string value Value to be deserialized
# @return [Object] Deserialized data
def _deserialize(type, value)
case type.to_sym
when :Time
Time.parse(value)
when :Date
Date.parse(value)
when :String
value.to_s
when :Integer
value.to_i
when :Float
value.to_f
when :Boolean
if value.to_s =~ /\A(true|t|yes|y|1)\z/i
true
else
false
end
when :Object
# generic object (usually a Hash), return directly
value
when /\AArray<(?<inner_type>.+)>\z/
inner_type = Regexp.last_match[:inner_type]
value.map { |v| _deserialize(inner_type, v) }
when /\AHash<(?<k_type>.+?), (?<v_type>.+)>\z/
k_type = Regexp.last_match[:k_type]
v_type = Regexp.last_match[:v_type]
({} of Symbol => String).tap do |hash|
value.each do |k, v|
hash[_deserialize(k_type, k)] = _deserialize(v_type, v)
end
end
else # model
# models (e.g. Pet) or oneOf
klass = {{moduleName}}.const_get(type)
klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value)
end
end
# Returns the string representation of the object
# @return [String] String presentation of the object
def to_s
to_hash.to_s
end
# to_body is an alias to to_hash (backward compatibility)
# @return [Hash] Returns the object in the form of hash
def to_body
to_hash
end
# Returns the object in the form of hash
# @return [Hash] Returns the object in the form of hash
def to_hash
hash = {{^parent}}{} of Symbol => String{{/parent}}{{#parent}}super{{/parent}}
self.class.attribute_map.each_pair do |attr, param|
value = self.send(attr)
if value.nil?
is_nullable = self.class.openapi_nullable.include?(attr)
next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
end
hash[param] = _to_hash(value)
end
hash
end
# Outputs non-array value in the form of hash
# For object, use to_hash. Otherwise, just return the value
# @param [Object] value Any valid value
# @return [Hash] Returns the value in the form of hash
def _to_hash(value)
if value.is_a?(Array)
value.compact.map { |v| _to_hash(v) }
elsif value.is_a?(Hash)
({} of Symbol => String).tap do |hash|
value.each { |k, v| hash[k] = _to_hash(v) }
end
elsif value.respond_to? :to_hash
value.to_hash
else
value
end
end

View File

@ -0,0 +1,356 @@
# {{#lambdaPrefixWithHash}}{{> api_info}}{{/lambdaPrefixWithHash}}
require "log"
module {{moduleName}}
class Configuration
# Defines url scheme
property scheme : String
# Defines url host
property host : String
# Defines url base path
property base_path : String
# Define server configuration index
property server_index : Int32
# Define server operation configuration index
property server_operation_index : Hash(Symbol, String)
# Default server variables
property server_variables : Hash(Symbol, String)
# Default server operation variables
property server_operation_variables : Hash(Symbol, String)
# Defines API keys used with API Key authentications.
#
# @return [Hash] key: parameter name, value: parameter value (API key)
#
# @example parameter name is "api_key", API key is "xxx" (e.g. "api_key=xxx" in query string)
# config.api_key[:"api_key"] = "xxx"
property api_key : Hash(Symbol, String)
# Defines API key prefixes used with API Key authentications.
#
# @return [Hash] key: parameter name, value: API key prefix
#
# @example parameter name is "Authorization", API key prefix is "Token" (e.g. "Authorization: Token xxx" in headers)
# config.api_key_prefix[:"api_key"] = "Token"
property api_key_prefix : Hash(Symbol, String)
# Defines the username used with HTTP basic authentication.
#
# @return [String]
property username : String?
# Defines the password used with HTTP basic authentication.
#
# @return [String]
property password : String?
# Defines the access token (Bearer) used with OAuth2.
property access_token : String?
# Set this to enable/disable debugging. When enabled (set to true), HTTP request/response
# details will be logged with `logger.debug` (see the `logger` attribute).
# Default to false.
#
# @return [true, false]
property debugging : Bool
# Defines the temporary folder to store downloaded files
# (for API endpoints that have file response).
# Default to use `Tempfile`.
#
# @return [String]
property temp_folder_path : String?
# The time limit for HTTP request in seconds.
# Default to 0 (never times out).
property timeout : Int32
# Set this to false to skip client side validation in the operation.
# Default to true.
# @return [true, false]
property client_side_validation : Bool
### TLS/SSL setting
# Set this to false to skip verifying SSL certificate when calling API from https server.
# Default to true.
#
# @note Do NOT set it to false in production code, otherwise you would face multiple types of cryptographic attacks.
#
# @return [true, false]
#TODO attr_accessor :verify_ssl
### TLS/SSL setting
# Set this to false to skip verifying SSL host name
# Default to true.
#
# @note Do NOT set it to false in production code, otherwise you would face multiple types of cryptographic attacks.
#
# @return [true, false]
# TODO attr_accessor :verify_ssl_host
### TLS/SSL setting
# Set this to customize the certificate file to verify the peer.
#
# @return [String] the path to the certificate file
#
# @see The `cainfo` option of Typhoeus, `--cert` option of libcurl. Related source code:
# https://github.com/typhoeus/typhoeus/blob/master/lib/typhoeus/easy_factory.rb#L145
# TODO attr_accessor :ssl_ca_cert
### TLS/SSL setting
# Client certificate file (for client certificate)
# TODO attr_accessor :cert_file
### TLS/SSL setting
# Client private key file (for client certificate)
# TODO attr_accessor :key_file
# Set this to customize parameters encoding of array parameter with multi collectionFormat.
# Default to Nil.
#
# @see The params_encoding option of Ethon. Related source code:
# https://github.com/typhoeus/ethon/blob/master/lib/ethon/easy/queryable.rb#L96
#property params_encoding : String?
def initialize
@scheme = "{{scheme}}"
@host = "{{host}}{{#port}}:{{{.}}}{{/port}}"
@base_path = "{{contextPath}}"
@server_index = 0
@server_operation_index = {} of Symbol => String
@server_variables = {} of Symbol => String
@server_operation_variables = {} of Symbol => String
@api_key = {} of Symbol => String
@api_key_prefix = {} of Symbol => String
@timeout = 0
@client_side_validation = true
@verify_ssl = true
@verify_ssl_host = true
#@params_encoding = nil
#@cert_file = nil
#@key_file = nil
@debugging = false
@username = nil
@password = nil
@access_token = nil
@temp_folder_path = nil
# TODO revise below to support block
#yield(self) if block_given?
end
# The default Configuration object.
def self.default
@@default ||= Configuration.new
end
def configure
yield(self) if block_given?
end
def scheme=(scheme)
# remove :// from scheme
@scheme = scheme.sub(/:\/\//, "")
end
def host=(host)
# remove http(s):// and anything after a slash
@host = host.sub(/https?:\/\//, "").split("/").first
end
def base_path=(base_path)
# Add leading and trailing slashes to base_path
@base_path = "/#{base_path}".gsub(/\/+/, "/")
@base_path = "" if @base_path == "/"
end
# Returns base URL for specified operation based on server settings
def base_url(operation = Nil)
# TODO revise below to support operation-level server setting
#index = server_operation_index.fetch(operation, server_index)
return "#{scheme}://#{[host, base_path].join("/").gsub(/\/+/, "/")}".sub(/\/+\z/, "") #if index == Nil
#server_url(index, server_operation_variables.fetch(operation, server_variables), operation_server_settings[operation])
end
# Gets API key (with prefix if set).
# @param [String] param_name the parameter name of API key auth
def api_key_with_prefix(param_name)
if @api_key_prefix[param_name]
"#{@api_key_prefix[param_name]} #{@api_key[param_name]}"
else
@api_key[param_name]
end
end
# Gets Basic Auth token string
def basic_auth_token
"Basic " + ["#{username}:#{password}"].pack("m").delete("\r\n")
end
# Returns Auth Settings hash for api client.
def auth_settings
Hash{ {{#authMethods}}{{#isApiKey}}"{{name}}" => {
type: "api_key",
in: {{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{#isKeyInQuery}}"query"{{/isKeyInQuery}},
key: "{{keyParamName}}",
value: api_key_with_prefix("{{keyParamName}}")
},
{{/isApiKey}}
{{#isBasic}}
{{#isBasicBasic}}
"{{name}}" =>
{
type: "basic",
in: "header",
key: "Authorization",
value: basic_auth_token
},
{{/isBasicBasic}}
{{#isBasicBearer}}
"{{name}}" =>
{
type: "bearer",
in: "header",
{{#bearerFormat}}
format: "{{{.}}}",
{{/bearerFormat}}
key: "Authorization",
value: "Bearer #{access_token}"
},
{{/isBasicBearer}}
{{/isBasic}}
{{#isOAuth}}
"{{name}}" =>
{
type: "oauth2",
in: "header",
key: "Authorization",
value: "Bearer #{access_token}"
},
{{/isOAuth}}
{{/authMethods}}
}
end
# Returns an array of Server setting
def server_settings
[
{{#servers}}
{
url: "{{{url}}}",
description: "{{{description}}}{{^description}}No description provided{{/description}}",
{{#variables}}
{{#-first}}
variables: {
{{/-first}}
{{{name}}}: {
description: "{{{description}}}{{^description}}No description provided{{/description}}",
default_value: "{{{defaultValue}}}",
{{#enumValues}}
{{#-first}}
enum_values: [
{{/-first}}
"{{{.}}}"{{^-last}},{{/-last}}
{{#-last}}
]
{{/-last}}
{{/enumValues}}
}{{^-last}},{{/-last}}
{{#-last}}
}
{{/-last}}
{{/variables}}
}{{^-last}},{{/-last}}
{{/servers}}
]
end
def operation_server_settings
{{#apiInfo}}
{{#apis}}
{{#operations}}
{{#operation}}
{{#servers}}
{{#-first}}
{
"{{{classname}}}.{{{nickname}}}": [
{{/-first}}
{
url: "{{{url}}}",
description: "{{{description}}}{{^description}}No description provided{{/description}}",
{{#variables}}
{{#-first}}
variables: {
{{/-first}}
{{{name}}}: {
description: "{{{description}}}{{^description}}No description provided{{/description}}",
default_value: "{{{defaultValue}}}",
{{#enumValues}}
{{#-first}}
enum_values: [
{{/-first}}
"{{{.}}}"{{^-last}},{{/-last}}
{{#-last}}
]
{{/-last}}
{{/enumValues}}
}{{^-last}},{{/-last}}
{{#-last}}
}
{{/-last}}
{{/variables}}
}{{^-last}},{{/-last}}
{{#-last}}
],
}
{{/-last}}
{{/servers}}
{{/operation}}
{{/operations}}
{{/apis}}
{{/apiInfo}}
end
# Returns URL based on server settings
#
# @param index array index of the server settings
# @param variables hash of variable and the corresponding value
def server_url(index, variables = {} of Symbol => String, servers = Nil)
servers = server_settings if servers == Nil
# check array index out of bound
if (index < 0 || index >= servers.size)
raise ArgumentError.new("Invalid index #{index} when selecting the server. Must be less than #{servers.size}")
end
server = servers[index]
url = server[:url]
return url unless server.key? :variables
# go through variable and assign a value
server[:variables].each do |name, variable|
if variables.key?(name)
if (!server[:variables][name].key?(:enum_values) || server[:variables][name][:enum_values].include?(variables[name]))
url.gsub! "{" + name.to_s + "}", variables[name]
else
raise ArgumentError.new("The variable `#{name}` in the server URL has invalid value #{variables[name]}. Must be #{server[:variables][name][:enum_values]}.")
end
else
# use default value
url.gsub! "{" + name.to_s + "}", server[:variables][name][:default_value]
end
end
url
end
end
end

View File

@ -0,0 +1,34 @@
=begin
{{> api_info}}
=end
require 'spec_helper'
describe {{moduleName}}::Configuration do
let(:config) { {{moduleName}}::Configuration.default }
before(:each) do
# uncomment below to setup host and base_path
# require 'URI'
# uri = URI.parse("{{{basePath}}}")
# {{moduleName}}.configure do |c|
# c.host = uri.host
# c.base_path = uri.path
# end
end
describe '#base_url' do
it 'should have the default value' do
# uncomment below to test default value of the base path
# expect(config.base_url).to eq("{{{basePath}}}")
end
it 'should remove trailing slashes' do
[nil, '', '/', '//'].each do |base_path|
config.base_path = base_path
# uncomment below to test trailing slashes
# expect(config.base_url).to eq("{{{basePath}}}")
end
end
end
end

View File

@ -0,0 +1,29 @@
### TLS/SSL setting
# Set this to false to skip verifying SSL certificate when calling API from https server.
# Default to true.
#
# @note Do NOT set it to false in production code, otherwise you would face multiple types of cryptographic attacks.
#
# @return [true, false]
#TODO attr_accessor :ssl_verify
### TLS/SSL setting
# Any `OpenSSL::SSL::` constant (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL.html)
#
# @note Do NOT set it to false in production code, otherwise you would face multiple types of cryptographic attacks.
#
#TODO attr_accessor :ssl_verify_mode
### TLS/SSL setting
# Set this to customize the certificate file to verify the peer.
#
# @return [String] the path to the certificate file
#TODO attr_accessor :ssl_ca_file
### TLS/SSL setting
# Client certificate file (for client certificate)
#TODO attr_accessor :ssl_client_cert
### TLS/SSL setting
# Client private key file (for client certificate)
#TODO attr_accessor :ssl_client_key

View File

@ -0,0 +1,34 @@
### TLS/SSL setting
# Set this to false to skip verifying SSL certificate when calling API from https server.
# Default to true.
#
# @note Do NOT set it to false in production code, otherwise you would face multiple types of cryptographic attacks.
#
# @return [true, false]
#TODO attr_accessor :verify_ssl
### TLS/SSL setting
# Set this to false to skip verifying SSL host name
# Default to true.
#
# @note Do NOT set it to false in production code, otherwise you would face multiple types of cryptographic attacks.
#
# @return [true, false]
# TODO attr_accessor :verify_ssl_host
### TLS/SSL setting
# Set this to customize the certificate file to verify the peer.
#
# @return [String] the path to the certificate file
#
# @see The `cainfo` option of Typhoeus, `--cert` option of libcurl. Related source code:
# https://github.com/typhoeus/typhoeus/blob/master/lib/typhoeus/easy_factory.rb#L145
# TODO attr_accessor :ssl_ca_cert
### TLS/SSL setting
# Client certificate file (for client certificate)
# TODO attr_accessor :cert_file
### TLS/SSL setting
# Client private key file (for client certificate)
# TODO attr_accessor :key_file

View File

@ -0,0 +1,58 @@
#!/bin/sh
# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/
#
# Usage example: /bin/sh ./git_push.sh wing328 openapi-pestore-perl "minor update" "gitlab.com"
git_user_id=$1
git_repo_id=$2
release_note=$3
git_host=$4
if [ "$git_host" = "" ]; then
git_host="{{{gitHost}}}"
echo "[INFO] No command line input provided. Set \$git_host to $git_host"
fi
if [ "$git_user_id" = "" ]; then
git_user_id="{{{gitUserId}}}"
echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id"
fi
if [ "$git_repo_id" = "" ]; then
git_repo_id="{{{gitRepoId}}}"
echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id"
fi
if [ "$release_note" = "" ]; then
release_note="{{{releaseNote}}}"
echo "[INFO] No command line input provided. Set \$release_note to $release_note"
fi
# Initialize the local directory as a Git repository
git init
# Adds the files in the local repository and stages them for commit.
git add .
# Commits the tracked changes and prepares them to be pushed to a remote repository.
git commit -m "$release_note"
# Sets the new remote
git_remote=`git remote`
if [ "$git_remote" = "" ]; then # git remote not defined
if [ "$GIT_TOKEN" = "" ]; then
echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment."
git remote add origin https://${git_host}/${git_user_id}/${git_repo_id}.git
else
git remote add origin https://${git_user_id}:${GIT_TOKEN}@${git_host}/${git_user_id}/${git_repo_id}.git
fi
fi
git pull origin master
# Pushes (Forces) the changes in the local repository up to the remote repository
echo "Git pushing to https://${git_host}/${git_user_id}/${git_repo_id}.git"
git push origin master 2>&1 | grep -v 'To https'

View File

@ -0,0 +1,39 @@
# Generated by: https://openapi-generator.tech
#
*.gem
*.rbc
/.config
/coverage/
/InstalledFiles
/pkg/
/spec/reports/
/spec/examples.txt
/test/tmp/
/test/version_tmp/
/tmp/
## Specific to RubyMotion:
.dat*
.repl_history
build/
## Documentation cache and generated files:
/.yardoc/
/_yardoc/
/doc/
/rdoc/
## Environment normalization:
/.bundle/
/vendor/bundle
/lib/bundler/man/
# for a library or gem, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# Gemfile.lock
# .ruby-version
# .ruby-gemset
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
.rvmrc

View File

@ -0,0 +1,23 @@
# {{#lambdaPrefixWithHash}}{{> api_info}}{{/lambdaPrefixWithHash}}
require "time"
module {{moduleName}}
{{#models}}
{{#model}}
{{#isEnum}}
{{>partial_model_enum_class}}
{{/isEnum}}
{{^isEnum}}
{{#oneOf}}
{{#-first}}
{{>partial_oneof_module}}
{{/-first}}
{{/oneOf}}
{{^oneOf}}
{{>partial_model_generic}}
{{/oneOf}}
{{/isEnum}}
{{/model}}
{{/models}}
end

View File

@ -0,0 +1,12 @@
{{#models}}
{{#model}}
{{#oneOf}}
{{#-first}}
{{>partial_oneof_module_doc}}
{{/-first}}
{{/oneOf}}
{{^oneOf}}
{{>partial_model_generic_doc}}
{{/oneOf}}
{{/model}}
{{/models}}

View File

@ -0,0 +1,75 @@
# {{#lambdaPrefixWithHash}}{{> api_info}}{{/lambdaPrefixWithHash}}
require "../spec_helper"
require "json"
require "time"
# Unit tests for {{moduleName}}::{{classname}}
# Automatically generated by openapi-generator (https://openapi-generator.tech)
# Please update as you see appropriate
{{#models}}
{{#model}}
describe {{moduleName}}::{{classname}} do
{{^oneOf}}
describe "test an instance of {{classname}}" do
it "should create an instance of {{classname}}" do
#instance = {{moduleName}}::{{classname}}.new
#expect(instance).to be_instance_of({{moduleName}}::{{classname}})
end
end
{{#vars}}
describe "test attribute '{{{name}}}'" do
it "should work" do
{{#isEnum}}
# assertion here. ref: https://crystal-lang.org/reference/guides/testing.html
# validator = Petstore::EnumTest::EnumAttributeValidator.new("{{{dataType}}}", [{{#allowableValues}}{{#enumVars}}{{{value}}}{{^-last}}, {{/-last}}{{/enumVars}}{{/allowableValues}}])
# validator.allowable_values.each do |value|
# expect { instance.{{name}} = value }.not_to raise_error
# end
{{/isEnum}}
{{^isEnum}}
# assertion here. ref: https://crystal-lang.org/reference/guides/testing.html
{{/isEnum}}
end
end
{{/vars}}
{{/oneOf}}
{{#oneOf}}
{{#-first}}
describe ".openapi_one_of" do
it "lists the items referenced in the oneOf array" do
expect(described_class.openapi_one_of).to_not be_empty
end
end
{{#discriminator}}
{{#propertyName}}
describe ".openapi_discriminator_name" do
it "returns the value of the "discriminator" property" do
expect(described_class.openapi_discriminator_name).to_not be_empty
end
end
{{/propertyName}}
{{#mappedModels}}
{{#-first}}
describe ".openapi_discriminator_mapping" do
it "returns the key/values of the "mapping" property" do
expect(described_class.openapi_discriminator_mapping.values.sort).to eq(described_class.openapi_one_of.sort)
end
end
{{/-first}}
{{/mappedModels}}
{{/discriminator}}
describe ".build" do
it "returns the correct model" do
end
end
{{/-first}}
{{/oneOf}}
end
{{/model}}
{{/models}}

View File

@ -0,0 +1,20 @@
class {{classname}}{{#allowableValues}}{{#enumVars}}
{{{name}}} = {{{value}}}.freeze{{/enumVars}}
{{/allowableValues}}
# Builds the enum from string
# @param [String] The enum value in the form of the string
# @return [String] The enum value
def self.build_from_hash(value)
new.build_from_hash(value)
end
# Builds the enum from string
# @param [String] The enum value in the form of the string
# @return [String] The enum value
def build_from_hash(value)
constantValues = {{classname}}.constants.select { |c| {{classname}}::const_get(c) == value }
raise "Invalid ENUM value #{value} for class #{{{classname}}}" if constantValues.empty?
value
end
end

View File

@ -0,0 +1,296 @@
{{#description}}
# {{{description}}}
{{/description}}
class {{classname}}{{#parent}} < {{{.}}}{{/parent}} include JSON::Serializable
include JSON::Serializable {{#vars}}
{{#description}}
# {{{description}}}
{{/description}}
@[JSON::Field(key: {{{baseName}}}, type: {{{dataType}}}{{#default}}, default: {{{.}}}{{/default}}{{#isNullable}}, nilable: true, emit_null: true{{/isNullable}})]
property {{{name}}} : {{{dataType}}}
{{/vars}}
{{#hasEnums}}
class EnumAttributeValidator
getter datatype : String
getter allowable_values : Array(String)
def initialize(datatype, allowable_values)
@datatype = datatype
@allowable_values = allowable_values.map do |value|
case datatype.to_s
when /Integer/i
value.to_i
when /Float/i
value.to_f
else
value
end
end
end
def valid?(value)
!value || allowable_values.include?(value)
end
end
{{/hasEnums}}
{{#anyOf}}
{{#-first}}
# List of class defined in anyOf (OpenAPI v3)
def self.openapi_any_of
[
{{/-first}}
:"{{{.}}}"{{^-last}},{{/-last}}
{{#-last}}
]
end
{{/-last}}
{{/anyOf}}
{{#allOf}}
{{#-first}}
# List of class defined in allOf (OpenAPI v3)
def self.openapi_all_of
[
{{/-first}}
:"{{{.}}}"{{^-last}},{{/-last}}
{{#-last}}
]
end
{{/-last}}
{{/allOf}}
{{#discriminator}}
{{#propertyName}}
# discriminator's property name in OpenAPI v3
def self.openapi_discriminator_name
:"{{{.}}}"
end
{{/propertyName}}
{{/discriminator}}
# Initializes the object
# @param [Hash] attributes Model attributes in the form of hash
def initialize({{#vars}}@{{{name}}} : {{{dataType}}}{{^required}} | Nil{{/required}}{{^-last}}, {{/-last}}{{/vars}})
end
# Show invalid properties with the reasons. Usually used together with valid?
# @return Array for valid properties with the reasons
def list_invalid_properties
invalid_properties = {{^parent}}Array.new{{/parent}}{{#parent}}super{{/parent}}
{{#vars}}
{{^isNullable}}
{{#required}}
if @{{{name}}}.nil?
invalid_properties.push("invalid value for \"{{{name}}}\", {{{name}}} cannot be nil.")
end
{{/required}}
{{/isNullable}}
{{#hasValidation}}
{{#maxLength}}
if {{^required}}!@{{{name}}}.nil? && {{/required}}@{{{name}}}.to_s.length > {{{maxLength}}}
invalid_properties.push("invalid value for \"{{{name}}}\", the character length must be smaller than or equal to {{{maxLength}}}.")
end
{{/maxLength}}
{{#minLength}}
if {{^required}}!@{{{name}}}.nil? && {{/required}}@{{{name}}}.to_s.length < {{{minLength}}}
invalid_properties.push("invalid value for \"{{{name}}}\", the character length must be great than or equal to {{{minLength}}}.")
end
{{/minLength}}
{{#maximum}}
if {{^required}}!@{{{name}}}.nil? && {{/required}}@{{{name}}} >{{#exclusiveMaximum}}={{/exclusiveMaximum}} {{{maximum}}}
invalid_properties.push("invalid value for \"{{{name}}}\", must be smaller than {{^exclusiveMaximum}}or equal to {{/exclusiveMaximum}}{{{maximum}}}.")
end
{{/maximum}}
{{#minimum}}
if {{^required}}!@{{{name}}}.nil? && {{/required}}@{{{name}}} <{{#exclusiveMinimum}}={{/exclusiveMinimum}} {{{minimum}}}
invalid_properties.push("invalid value for \"{{{name}}}\", must be greater than {{^exclusiveMinimum}}or equal to {{/exclusiveMinimum}}{{{minimum}}}.")
end
{{/minimum}}
{{#pattern}}
pattern = Regexp.new({{{pattern}}})
if {{^required}}!@{{{name}}}.nil? && {{/required}}@{{{name}}} !~ pattern
invalid_properties.push("invalid value for \"{{{name}}}\", must conform to the pattern #{pattern}.")
end
{{/pattern}}
{{#maxItems}}
if {{^required}}!@{{{name}}}.nil? && {{/required}}@{{{name}}}.length > {{{maxItems}}}
invalid_properties.push("invalid value for \"{{{name}}}\", number of items must be less than or equal to {{{maxItems}}}."
end
{{/maxItems}}
{{#minItems}}
if {{^required}}!@{{{name}}}.nil? && {{/required}}@{{{name}}}.length < {{{minItems}}}
invalid_properties.push("invalid value for \"{{{name}}}\", number of items must be greater than or equal to {{{minItems}}}."
end
{{/minItems}}
{{/hasValidation}}
{{/vars}}
invalid_properties
end
# Check to see if the all the properties in the model are valid
# @return true if the model is valid
def valid?
{{#vars}}
{{^isNullable}}
{{#required}}
return false if @{{{name}}}.nil?
{{/required}}
{{/isNullable}}
{{#isEnum}}
{{^isContainer}}
{{{name}}}_validator = EnumAttributeValidator.new("{{{dataType}}}", [{{#allowableValues}}{{#enumVars}}{{{value}}}{{^-last}}, {{/-last}}{{/enumVars}}{{/allowableValues}}])
return false unless {{{name}}}_validator.valid?(@{{{name}}})
{{/isContainer}}
{{/isEnum}}
{{#hasValidation}}
{{#maxLength}}
return false if {{^required}}!@{{{name}}}.nil? && {{/required}}@{{{name}}}.to_s.length > {{{maxLength}}}
{{/maxLength}}
{{#minLength}}
return false if {{^required}}!@{{{name}}}.nil? && {{/required}}@{{{name}}}.to_s.length < {{{minLength}}}
{{/minLength}}
{{#maximum}}
return false if {{^required}}!@{{{name}}}.nil? && {{/required}}@{{{name}}} >{{#exclusiveMaximum}}={{/exclusiveMaximum}} {{{maximum}}}
{{/maximum}}
{{#minimum}}
return false if {{^required}}!@{{{name}}}.nil? && {{/required}}@{{{name}}} <{{#exclusiveMinimum}}={{/exclusiveMinimum}} {{{minimum}}}
{{/minimum}}
{{#pattern}}
return false if {{^required}}!@{{{name}}}.nil? && {{/required}}@{{{name}}} !~ Regexp.new({{{pattern}}})
{{/pattern}}
{{#maxItems}}
return false if {{^required}}!@{{{name}}}.nil? && {{/required}}@{{{name}}}.length > {{{maxItems}}}
{{/maxItems}}
{{#minItems}}
return false if {{^required}}!@{{{name}}}.nil? && {{/required}}@{{{name}}}.length < {{{minItems}}}
{{/minItems}}
{{/hasValidation}}
{{/vars}}
{{#anyOf}}
{{#-first}}
_any_of_found = false
self.class.openapi_any_of.each do |_class|
_any_of = {{moduleName}}.const_get(_class).build_from_hash(self.to_hash)
if _any_of.valid?
_any_of_found = true
end
end
if !_any_of_found
return false
end
{{/-first}}
{{/anyOf}}
true{{#parent}} && super{{/parent}}
end
{{#vars}}
{{#isEnum}}
{{^isContainer}}
# Custom attribute writer method checking allowed values (enum).
# @param [Object] {{{name}}} Object to be assigned
def {{{name}}}=({{{name}}})
validator = EnumAttributeValidator.new("{{{dataType}}}", [{{#allowableValues}}{{#enumVars}}{{{value}}}{{^-last}}, {{/-last}}{{/enumVars}}{{/allowableValues}}])
unless validator.valid?({{{name}}})
raise ArgumentError.new("invalid value for \"{{{name}}}\", must be one of #{validator.allowable_values}.")
end
@{{{name}}} = {{{name}}}
end
{{/isContainer}}
{{/isEnum}}
{{^isEnum}}
{{#hasValidation}}
# Custom attribute writer method with validation
# @param [Object] {{{name}}} Value to be assigned
def {{{name}}}=({{{name}}})
{{^isNullable}}
{{#required}}
if {{{name}}}.nil?
raise ArgumentError.new("{{{name}}} cannot be nil")
end
{{/required}}
{{/isNullable}}
{{#maxLength}}
if {{^required}}!{{{name}}}.nil? && {{/required}}{{{name}}}.to_s.length > {{{maxLength}}}
raise ArgumentError.new("invalid value for "{{{name}}}", the character length must be smaller than or equal to {{{maxLength}}}.")
end
{{/maxLength}}
{{#minLength}}
if {{^required}}!{{{name}}}.nil? && {{/required}}{{{name}}}.to_s.length < {{{minLength}}}
raise ArgumentError.new("invalid value for \"{{{name}}}\", the character length must be great than or equal to {{{minLength}}}.")
end
{{/minLength}}
{{#maximum}}
if {{^required}}!{{{name}}}.nil? && {{/required}}{{{name}}} >{{#exclusiveMaximum}}={{/exclusiveMaximum}} {{{maximum}}}
raise ArgumentError.new("invalid value for \"{{{name}}}\", must be smaller than {{^exclusiveMaximum}}or equal to {{/exclusiveMaximum}}{{{maximum}}}.")
end
{{/maximum}}
{{#minimum}}
if {{^required}}!{{{name}}}.nil? && {{/required}}{{{name}}} <{{#exclusiveMinimum}}={{/exclusiveMinimum}} {{{minimum}}}
raise ArgumentError.new("invalid value for \"{{{name}}}\", must be greater than {{^exclusiveMinimum}}or equal to {{/exclusiveMinimum}}{{{minimum}}}.")
end
{{/minimum}}
{{#pattern}}
pattern = Regexp.new({{{pattern}}})
if {{^required}}!{{{name}}}.nil? && {{/required}}{{{name}}} !~ pattern
raise ArgumentError.new("invalid value for \"{{{name}}}\", must conform to the pattern #{pattern}.")
end
{{/pattern}}
{{#maxItems}}
if {{^required}}!{{{name}}}.nil? && {{/required}}{{{name}}}.length > {{{maxItems}}}
raise ArgumentError.new("invalid value for \"{{{name}}}\", number of items must be less than or equal to {{{maxItems}}}.")
end
{{/maxItems}}
{{#minItems}}
if {{^required}}!{{{name}}}.nil? && {{/required}}{{{name}}}.length < {{{minItems}}}
raise ArgumentError.new("invalid value for \"{{{name}}}\", number of items must be greater than or equal to {{{minItems}}}.")
end
{{/minItems}}
@{{{name}}} = {{{name}}}
end
{{/hasValidation}}
{{/isEnum}}
{{/vars}}
# Checks equality by comparing each attribute.
# @param [Object] Object to be compared
def ==(o)
return true if self.equal?(o)
self.class == o.class{{#vars}} &&
{{name}} == o.{{name}}{{/vars}}{{#parent}} && super(o){{/parent}}
end
# @see the `==` method
# @param [Object] Object to be compared
def eql?(o)
self == o
end
# Calculates hash code according to all attributes.
# @return [Integer] Hash code
def hash
[{{#vars}}{{name}}{{^-last}}, {{/-last}}{{/vars}}].hash
end
{{> base_object}}
end

View File

@ -0,0 +1,28 @@
# {{moduleName}}::{{classname}}
## Properties
| Name | Type | Description | Notes |
| ---- | ---- | ----------- | ----- |
{{#vars}}
| **{{name}}** | {{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{dataType}}**]({{complexType}}.md){{/isPrimitiveType}} | {{description}} | {{^required}}[optional]{{/required}}{{#isReadOnly}}[readonly]{{/isReadOnly}}{{#defaultValue}}[default to {{defaultValue}}]{{/defaultValue}} |
{{/vars}}
## Example
```ruby
require '{{{gemName}}}'
{{^vars}}
instance = {{moduleName}}::{{classname}}.new()
{{/vars}}
{{#vars}}
{{#-first}}
instance = {{moduleName}}::{{classname}}.new(
{{/-first}}
{{name}}: {{example}}{{^-last}},{{/-last}}
{{#-last}}
)
{{/-last}}
{{/vars}}
```

View File

@ -0,0 +1,137 @@
{{#description}}
# {{{description}}}
{{/description}}
module {{classname}}
class << self
{{#oneOf}}
{{#-first}}
# List of class defined in oneOf (OpenAPI v3)
def openapi_one_of
[
{{/-first}}
:'{{{.}}}'{{^-last}},{{/-last}}
{{#-last}}
]
end
{{/-last}}
{{/oneOf}}
{{#discriminator}}
{{#propertyName}}
# Discriminator's property name (OpenAPI v3)
def openapi_discriminator_name
:'{{{.}}}'
end
{{/propertyName}}
{{#mappedModels}}
{{#-first}}
# Discriminator's mapping (OpenAPI v3)
def openapi_discriminator_mapping
{
{{/-first}}
:'{{{mappingName}}}' => :'{{{modelName}}}'{{^-last}},{{/-last}}
{{#-last}}
}
end
{{/-last}}
{{/mappedModels}}
{{/discriminator}}
# Builds the object
# @param [Mixed] Data to be matched against the list of oneOf items
# @return [Object] Returns the model or the data itself
def build(data)
{{#discriminator}}
discriminator_value = data[openapi_discriminator_name]
return nil unless discriminator_value
{{#mappedModels}}
{{#-first}}
klass = openapi_discriminator_mapping[discriminator_value.to_sym]
return nil unless klass
{{moduleName}}.const_get(klass).build_from_hash(data)
{{/-first}}
{{/mappedModels}}
{{^mappedModels}}
{{moduleName}}.const_get(discriminator_value).build_from_hash(data)
{{/mappedModels}}
{{/discriminator}}
{{^discriminator}}
# Go through the list of oneOf items and attempt to identify the appropriate one.
# Note:
# - We do not attempt to check whether exactly one item matches.
# - No advanced validation of types in some cases (e.g. "x: { type: string }" will happily match { x: 123 })
# due to the way the deserialization is made in the base_object template (it just casts without verifying).
# - TODO: scalar values are defacto behaving as if they were nullable.
# - TODO: logging when debugging is set.
openapi_one_of.each do |klass|
begin
next if klass == :AnyType # "nullable: true"
typed_data = find_and_cast_into_type(klass, data)
return typed_data if typed_data
rescue # rescue all errors so we keep iterating even if the current item lookup raises
end
end
openapi_one_of.include?(:AnyType) ? data : nil
{{/discriminator}}
end
{{^discriminator}}
private
SchemaMismatchError = Class.new(StandardError)
# Note: 'File' is missing here because in the regular case we get the data _after_ a call to JSON.parse.
def find_and_cast_into_type(klass, data)
return if data.nil?
case klass.to_s
when 'Boolean'
return data if data.instance_of?(TrueClass) || data.instance_of?(FalseClass)
when 'Float'
return data if data.instance_of?(Float)
when 'Integer'
return data if data.instance_of?(Integer)
when 'Time'
return Time.parse(data)
when 'Date'
return Date.parse(data)
when 'String'
return data if data.instance_of?(String)
when 'Object' # "type: object"
return data if data.instance_of?(Hash)
when /\AArray<(?<sub_type>.+)>\z/ # "type: array"
if data.instance_of?(Array)
sub_type = Regexp.last_match[:sub_type]
return data.map { |item| find_and_cast_into_type(sub_type, item) }
end
when /\AHash<String, (?<sub_type>.+)>\z/ # "type: object" with "additionalProperties: { ... }"
if data.instance_of?(Hash) && data.keys.all? { |k| k.instance_of?(Symbol) || k.instance_of?(String) }
sub_type = Regexp.last_match[:sub_type]
return data.each_with_object({}) { |(k, v), hsh| hsh[k] = find_and_cast_into_type(sub_type, v) }
end
else # model
const = {{moduleName}}.const_get(klass)
if const
if const.respond_to?(:openapi_one_of) # nested oneOf model
model = const.build(data)
return model if model
else
# raise if data contains keys that are not known to the model
raise unless (data.keys - const.acceptable_attributes).empty?
model = const.build_from_hash(data)
return model if model && model.valid?
end
end
end
raise # if no match by now, raise
rescue
raise SchemaMismatchError, "#{data} doesn't match the #{klass} type"
end
{{/discriminator}}
end
end

View File

@ -0,0 +1,92 @@
# {{moduleName}}::{{classname}}
## Class instance methods
### `openapi_one_of`
Returns the list of classes defined in oneOf.
#### Example
```ruby
require '{{{gemName}}}'
{{moduleName}}::{{classname}}.openapi_one_of
# =>
{{#oneOf}}
{{#-first}}
# [
{{/-first}}
# :'{{{.}}}'{{^-last}},{{/-last}}
{{#-last}}
# ]
{{/-last}}
{{/oneOf}}
```
{{#discriminator}}
{{#propertyName}}
### `openapi_discriminator_name`
Returns the discriminator's property name.
#### Example
```ruby
require '{{{gemName}}}'
{{moduleName}}::{{classname}}.openapi_discriminator_name
# => :'{{{.}}}'
```
{{/propertyName}}
{{#mappedModels}}
{{#-first}}
### `openapi_discriminator_name`
Returns the discriminator's mapping.
#### Example
```ruby
require '{{{gemName}}}'
{{moduleName}}::{{classname}}.openapi_discriminator_mapping
# =>
# {
{{/-first}}
# :'{{{mappingName}}}' => :'{{{modelName}}}'{{^-last}},{{/-last}}
{{#-last}}
# }
{{/-last}}
{{/mappedModels}}
{{/discriminator}}
### build
Find the appropriate object from the `openapi_one_of` list and casts the data into it.
#### Example
```ruby
require '{{{gemName}}}'
{{moduleName}}::{{classname}}.build(data)
# => {{#oneOf}}{{#-first}}#<{{{.}}}:0x00007fdd4aab02a0>{{/-first}}{{/oneOf}}
{{moduleName}}::{{classname}}.build(data_that_doesnt_match)
# => nil
```
#### Parameters
| Name | Type | Description |
| ---- | ---- | ----------- |
| **data** | **Mixed** | data to be matched against the list of oneOf items |
#### Return type
{{#oneOf}}
- `{{{.}}}`
{{/oneOf}}
- `nil` (if no type matches)

View File

@ -0,0 +1,2 @@
--color
--require spec_helper

View File

@ -0,0 +1,148 @@
# This file is based on https://github.com/rails/rails/blob/master/.rubocop.yml (MIT license)
# Automatically generated by OpenAPI Generator (https://openapi-generator.tech)
AllCops:
TargetRubyVersion: 2.4
# RuboCop has a bunch of cops enabled by default. This setting tells RuboCop
# to ignore them, so only the ones explicitly set in this file are enabled.
DisabledByDefault: true
Exclude:
- '**/templates/**/*'
- '**/vendor/**/*'
- 'actionpack/lib/action_dispatch/journey/parser.rb'
# Prefer &&/|| over and/or.
Style/AndOr:
Enabled: true
# Align `when` with `case`.
Layout/CaseIndentation:
Enabled: true
# Align comments with method definitions.
Layout/CommentIndentation:
Enabled: true
Layout/ElseAlignment:
Enabled: true
Layout/EmptyLineAfterMagicComment:
Enabled: true
# In a regular class definition, no empty lines around the body.
Layout/EmptyLinesAroundClassBody:
Enabled: true
# In a regular method definition, no empty lines around the body.
Layout/EmptyLinesAroundMethodBody:
Enabled: true
# In a regular module definition, no empty lines around the body.
Layout/EmptyLinesAroundModuleBody:
Enabled: true
Layout/FirstArgumentIndentation:
Enabled: true
# Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
Style/HashSyntax:
Enabled: false
# Method definitions after `private` or `protected` isolated calls need one
# extra level of indentation.
Layout/IndentationConsistency:
Enabled: true
EnforcedStyle: indented_internal_methods
# Two spaces, no tabs (for indentation).
Layout/IndentationWidth:
Enabled: true
Layout/LeadingCommentSpace:
Enabled: true
Layout/SpaceAfterColon:
Enabled: true
Layout/SpaceAfterComma:
Enabled: true
Layout/SpaceAroundEqualsInParameterDefault:
Enabled: true
Layout/SpaceAroundKeyword:
Enabled: true
Layout/SpaceAroundOperators:
Enabled: true
Layout/SpaceBeforeComma:
Enabled: true
Layout/SpaceBeforeFirstArg:
Enabled: true
Style/DefWithParentheses:
Enabled: true
# Defining a method with parameters needs parentheses.
Style/MethodDefParentheses:
Enabled: true
Style/FrozenStringLiteralComment:
Enabled: false
EnforcedStyle: always
# Use `foo {}` not `foo{}`.
Layout/SpaceBeforeBlockBraces:
Enabled: true
# Use `foo { bar }` not `foo {bar}`.
Layout/SpaceInsideBlockBraces:
Enabled: true
# Use `{ a: 1 }` not `{a:1}`.
Layout/SpaceInsideHashLiteralBraces:
Enabled: true
Layout/SpaceInsideParens:
Enabled: true
# Check quotes usage according to lint rule below.
#Style/StringLiterals:
# Enabled: true
# EnforcedStyle: single_quotes
# Detect hard tabs, no hard tabs.
Layout/IndentationStyle:
Enabled: true
# Blank lines should not have any spaces.
Layout/TrailingEmptyLines:
Enabled: true
# No trailing whitespace.
Layout/TrailingWhitespace:
Enabled: false
# Use quotes for string literals when they are enough.
Style/RedundantPercentQ:
Enabled: true
# Align `end` with the matching keyword or starting expression except for
# assignments, where it should be aligned with the LHS.
Layout/EndAlignment:
Enabled: true
EnforcedStyleAlignWith: variable
AutoCorrect: true
# Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
Lint/RequireParentheses:
Enabled: true
Style/RedundantReturn:
Enabled: true
AllowMultipleReturnValues: true
Style/Semicolon:
Enabled: true
AllowAsExpressionSeparator: true

View File

@ -0,0 +1,20 @@
name: {{{moduleName}}}
version: {{{shardVersion}}}
authors:
- {{{shardAuthors}}}
description: |
- {{{ shardDescription}}}
crystal: ">= 0.35.1"
dependencies:
crest:
github: mamantoha/crest
version: ~> 0.26.0
development_dependencies:
kemal:
github: kemalcr/kemal
version: ~>0.27.0
ameba:
github: crystal-ameba/ameba
license: {{{shardLicense}}}

View File

@ -0,0 +1,27 @@
# {{#lambdaPrefixWithHash}}{{> api_info}}{{/lambdaPrefixWithHash}}
# Dependencies
require "crest"
require "log"
module {{moduleName}}
Log = ::Log.for("{{moduleName}}") # => Log for {{moduleName}} source
VERSION = {{ `shards version #{__DIR__}`.chomp.stringify }}
# Customize default settings for the SDK using block.
# {{moduleName}}.configure do |config|
# config.username = "xxx"
# config.password = "xxx"
# end
# If no block given, return the default Configuration object.
def configure
if block_given?
yield(Configuration.default)
else
Configuration.default
end
end
end
require "./{{shardName}}/**"

View File

@ -0,0 +1,6 @@
# {{#lambdaPrefixWithHash}}{{> api_info}}{{/lambdaPrefixWithHash}}
# load modules
require "spec"
require "json"
require "../src/{{{shardName}}}"

View File

@ -0,0 +1,8 @@
# {{#lambdaPrefixWithHash}}{{> api_info}}{{/lambdaPrefixWithHash}}
language: crystal
script:
- crystal spec
# uncomment below to check the code format
# - crystal tool format --check

View File

@ -0,0 +1,5 @@
# {{#lambdaPrefixWithHash}}{{> api_info}}{{/lambdaPrefixWithHash}}
module {{moduleName}}
VERSION = '{{shardVersion}}'
end

View File

@ -65,10 +65,10 @@ namespace {{packageName}}.Client
/// <returns>A JSON string.</returns>
public string Serialize(object obj)
{
if (obj != null && obj is {{{packageName}}}.Model.AbstractOpenAPISchema)
if (obj != null && obj is {{{packageName}}}.{{modelPackage}}.AbstractOpenAPISchema)
{
// the object to be serialized is an oneOf/anyOf schema
return (({{{packageName}}}.Model.AbstractOpenAPISchema)obj).ToJson();
return (({{{packageName}}}.{{modelPackage}}.AbstractOpenAPISchema)obj).ToJson();
}
else
{
@ -576,7 +576,7 @@ namespace {{packageName}}.Client
}
// if the response type is oneOf/anyOf, call FromJSON to deserialize the data
if (typeof({{{packageName}}}.Model.AbstractOpenAPISchema).IsAssignableFrom(typeof(T)))
if (typeof({{{packageName}}}.{{modelPackage}}.AbstractOpenAPISchema).IsAssignableFrom(typeof(T)))
{
T instance = (T)Activator.CreateInstance(typeof(T));
MethodInfo method = typeof(T).GetMethod("FromJson");

View File

@ -1 +1,9 @@
analyzer:
analyzer:
language:
strict-inference: true
strict-raw-types: true
strong-mode:
implicit-dynamic: false
implicit-casts: false
exclude:
- test/*.dart

View File

@ -1,3 +1,4 @@
{{>header}}
import 'dart:async';
import 'dart:convert';
import 'package:dio/dio.dart';
@ -31,8 +32,8 @@ class {{classname}} {
}) async {
final String _path = '{{{path}}}'{{#pathParams}}.replaceAll('{' r'{{baseName}}' '}', {{{paramName}}}.toString()){{/pathParams}};
final Map<String, dynamic> queryParams = {};
final Map<String, dynamic> headerParams = {
final queryParams = <String, dynamic>{};
final headerParams = <String, dynamic>{
if (headers != null) ...headers,
};
dynamic bodyData;
@ -43,15 +44,15 @@ class {{classname}} {
{{#queryParams}}
queryParams[r'{{baseName}}'] = {{paramName}};
{{/queryParams}}
queryParams.removeWhere((key, value) => value == null);
headerParams.removeWhere((key, value) => value == null);
queryParams.removeWhere((key, dynamic value) => value == null);
headerParams.removeWhere((key, dynamic value) => value == null);
final List<String> contentTypes = [{{^hasConsumes}}];{{/hasConsumes}}{{#hasConsumes}}{{#consumes}}
final contentTypes = <String>[{{^hasConsumes}}];{{/hasConsumes}}{{#hasConsumes}}{{#consumes}}
'{{{mediaType}}}',{{/consumes}}
];{{/hasConsumes}}
{{#hasFormParams}}
final Map<String, dynamic> formData = {};
final formData = <String, dynamic>{};
{{#isMultipart}}
{{#formParams}}
{{^isFile}}
@ -76,18 +77,30 @@ class {{classname}} {
{{/hasFormParams}}
{{#bodyParam}}
{{#isArray}}
{{#isContainer}}
{{#isArray}}
const type = FullType(BuiltList, [FullType({{baseType}})]);
final serializedBody = _serializers.serialize({{paramName}}, specifiedType: type);
{{/isArray}}
{{^isArray}}
final serializedBody = _serializers.serialize({{paramName}});
{{/isArray}}
{{/isArray}}
{{#isMap}}
const type = FullType(BuiltMap, [FullType(String), FullType({{baseType}})]);
final serializedBody = _serializers.serialize({{paramName}}, specifiedType: type);
{{/isMap}}
{{/isContainer}}
{{^isContainer}}
{{#isPrimitiveType}}
var serializedBody = {{paramName}};
{{/isPrimitiveType}}
{{^isPrimitiveType}}
final bodySerializer = _serializers.serializerForType({{{baseType}}}) as Serializer<{{{baseType}}}>;
final serializedBody = _serializers.serializeWith(bodySerializer, {{paramName}});
{{/isPrimitiveType}}
{{/isContainer}}
final json{{paramName}} = json.encode(serializedBody);
bodyData = json{{paramName}};
{{/bodyParam}}
return _dio.request(
return _dio.request<dynamic>(
_path,
queryParameters: queryParams,
data: bodyData,
@ -97,8 +110,8 @@ class {{classname}} {
responseType: ResponseType.bytes,
{{/isResponseFile}}
headers: headerParams,
extra: {
'secure': [{{^hasAuthMethods}}],{{/hasAuthMethods}}{{#hasAuthMethods}}
extra: <String, dynamic>{
'secure': <Map<String, String>>[{{^hasAuthMethods}}],{{/hasAuthMethods}}{{#hasAuthMethods}}
{{#authMethods}}{
'type': '{{type}}',
'name': '{{name}}',{{#isApiKey}}
@ -124,14 +137,22 @@ class {{classname}} {
final data = response.data as {{{returnType}}};
{{/returnTypeIsPrimitive}}
{{^returnTypeIsPrimitive}}
final serializer = _serializers.serializerForType({{{returnType}}});
final data = _serializers.deserializeWith<{{{returnType}}}>(serializer, response.data is String ? jsonDecode(response.data) : response.data);
final serializer = _serializers.serializerForType({{{returnType}}}) as Serializer<{{{returnType}}}>;
final data = _serializers.deserializeWith<{{{returnType}}}>(
serializer,
response.data is String ? jsonDecode(response.data as String) : response.data,
);
{{/returnTypeIsPrimitive}}
{{/returnSimpleType}}
{{^returnSimpleType}}
const collectionType = {{#isMap}}BuiltMap{{/isMap}}{{^isMap}}BuiltList{{/isMap}};
const type = FullType(collectionType, [{{#isMap}}FullType(String), {{/isMap}}FullType({{{returnBaseType}}})]);
final {{{returnType}}} data = _serializers.deserialize(response.data is String ? jsonDecode(response.data) : response.data, specifiedType: type);
final data = _serializers.deserialize(
response.data is String
? jsonDecode(response.data as String)
: response.data,
specifiedType: type,
) as {{{returnType}}};
{{/returnSimpleType}}
{{/isResponseFile}}

View File

@ -1,3 +1,4 @@
{{>header}}
import 'dart:convert';
import 'package:built_value/serializer.dart';

View File

@ -1,3 +1,4 @@
{{>header}}
library {{pubName}}.api;
import 'package:dio/dio.dart';

View File

@ -1,3 +1,4 @@
{{>header}}
import 'dart:async';
import 'package:{{pubName}}/auth/auth.dart';
import 'package:dio/dio.dart';
@ -6,12 +7,12 @@ class ApiKeyAuthInterceptor extends AuthInterceptor {
Map<String, String> apiKeys = {};
@override
Future onRequest(RequestOptions options) {
final authInfo = getAuthInfo(options, "apiKey");
for (var info in authInfo) {
final authName = info["name"];
final authKeyName = info["keyName"];
final authWhere = info["where"];
Future<dynamic> onRequest(RequestOptions options) {
final authInfo = getAuthInfo(options, 'apiKey');
for (final info in authInfo) {
final authName = info['name'] as String;
final authKeyName = info['keyName'] as String;
final authWhere = info['where'] as String;
final apiKey = apiKeys[authName];
if (apiKey != null) {
if (authWhere == 'query') {

View File

@ -1,5 +1,4 @@
import 'dart:async';
{{>header}}
import 'package:dio/dio.dart';
abstract class AuthInterceptor extends Interceptor {
@ -8,11 +7,11 @@ abstract class AuthInterceptor extends Interceptor {
* Can return null if type is not present on auth data or if route doesn't need authentication
*/
List<Map<String, dynamic>> getAuthInfo(RequestOptions route, String type) {
if (route.extra.containsKey("secure")) {
final auth = route.extra["secure"];
List<Map<String, dynamic>> results = [];
for (var info in auth) {
if(info["type"] == type) {
if (route.extra.containsKey('secure')) {
final auth = route.extra['secure'] as List<Map<String, String>>;
final results = <Map<String, dynamic>>[];
for (final info in auth) {
if (info['type'] == type) {
results.add(info);
}
}

View File

@ -1,3 +1,4 @@
{{>header}}
import 'dart:async';
import 'dart:convert';
import 'package:{{pubName}}/auth/auth.dart';
@ -14,13 +15,13 @@ class BasicAuthInterceptor extends AuthInterceptor {
Map<String, BasicAuthInfo> authInfo = {};
@override
Future onRequest(RequestOptions options) {
Future<dynamic> onRequest(RequestOptions options) {
final metadataAuthInfo = getAuthInfo(options, 'basic');
for (var info in metadataAuthInfo) {
final authName = info['name'];
for (final info in metadataAuthInfo) {
final authName = info['name'] as String;
final basicAuthInfo = authInfo[authName];
if(basicAuthInfo != null) {
String basicAuth = 'Basic ' + base64Encode(utf8.encode('${basicAuthInfo.username}:${basicAuthInfo.password}'));
if (basicAuthInfo != null) {
final basicAuth = 'Basic ' + base64Encode(utf8.encode('${basicAuthInfo.username}:${basicAuthInfo.password}'));
options.headers['Authorization'] = basicAuth;
break;
}

View File

@ -1,3 +1,4 @@
{{>header}}
import 'dart:async';
import 'package:{{pubName}}/auth/auth.dart';
import 'package:dio/dio.dart';
@ -6,12 +7,12 @@ class OAuthInterceptor extends AuthInterceptor {
Map<String, String> tokens = {};
@override
Future onRequest(RequestOptions options) {
final authInfo = getAuthInfo(options, "oauth");
for (var info in authInfo) {
final token = tokens[info["name"]];
if(token != null) {
options.headers["Authorization"] = "Bearer ${token}";
Future<dynamic> onRequest(RequestOptions options) {
final authInfo = getAuthInfo(options, 'oauth');
for (final info in authInfo) {
final token = tokens[info['name']];
if (token != null) {
options.headers['Authorization'] = 'Bearer ${token}';
break;
}
}

View File

@ -25,7 +25,7 @@ abstract class {{classname}} implements Built<{{classname}}, {{classname}}Builde
static void _initializeBuilder({{{classname}}}Builder b) => b{{#vars}}{{#defaultValue}}
..{{{name}}} = {{#isEnum}}{{^isContainer}}const {{{classname}}}{{{enumName}}}._({{/isContainer}}{{/isEnum}}{{{defaultValue}}}{{#isEnum}}{{^isContainer}}){{/isContainer}}{{/isEnum}}{{/defaultValue}}{{/vars}};
factory {{classname}}([updates({{classname}}Builder b)]) = _${{classname}};
factory {{classname}}([void updates({{classname}}Builder b)]) = _${{classname}};
static Serializer<{{classname}}> get serializer => _${{#lambda.camelcase}}{{{classname}}}{{/lambda.camelcase}}Serializer;
}
{{!

View File

@ -0,0 +1,6 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.6
// ignore_for_file: unused_import

View File

@ -1,3 +1,4 @@
{{>header}}
import 'package:built_collection/built_collection.dart';
import 'package:built_value/serializer.dart';
import 'package:time_machine/time_machine.dart';

View File

@ -1,3 +1,4 @@
{{>header}}
{{#models}}
{{#model}}
{{#imports}}

View File

@ -2,7 +2,7 @@ name: {{pubName}}
version: {{pubVersion}}
description: {{pubDescription}}
environment:
sdk: ">=2.3.0 <3.0.0"
sdk: ">=2.6.0 <3.0.0"
dependencies:
dio: ^3.0.9
built_value: ^7.1.0

View File

@ -1,3 +1,4 @@
{{>header}}
library serializers;
import 'package:built_value/iso_8601_date_time_serializer.dart';
@ -9,25 +10,26 @@ import 'package:built_value/standard_json_plugin.dart';
import 'package:{{pubName}}/local_date_serializer.dart';{{/timeMachine}}
{{#models}}{{#model}}import 'package:{{pubName}}/model/{{classFilename}}.dart';
{{/model}}{{/models}}
part 'serializers.g.dart';
@SerializersFor(const [
{{#models}}{{#model}}{{classname}},
{{/model}}{{/models}}
@SerializersFor(const [{{#models}}{{#model}}
{{classname}},{{/model}}{{/models}}
])
//allow all models to be serialized within a list
Serializers serializers = (_$serializers.toBuilder()
{{#models}}{{#model}}..addBuilderFactory(
const FullType(BuiltList, const [const FullType({{classname}})]),
() => new ListBuilder<{{classname}}>())
{{/model}}{{/models}}
..add(Iso8601DateTimeSerializer())
).build();
Serializers serializers = (_$serializers.toBuilder(){{#apiInfo}}{{#apis}}{{#serializers}}
..addBuilderFactory(
{{#isArray}}
const FullType(BuiltList, [FullType({{baseType}})]),
() => ListBuilder<{{baseType}}>(),
{{/isArray}}
{{#isMap}}
const FullType(BuiltMap, [FullType(String), FullType({{baseType}})]),
() => MapBuilder<String, {{baseType}}>(),
{{/isMap}}
){{/serializers}}{{/apis}}{{/apiInfo}}{{#timeMachine}}
..add(OffsetDateSerializer())
..add(OffsetDateTimeSerializer()){{/timeMachine}}
..add(Iso8601DateTimeSerializer()))
.build();
Serializers standardSerializers =
(serializers.toBuilder()
{{#timeMachine}}..add(OffsetDateSerializer())
..add(OffsetDateTimeSerializer())
{{/timeMachine}}..addPlugin(StandardJsonPlugin())).build();
(serializers.toBuilder()..addPlugin(StandardJsonPlugin())).build();

View File

@ -33,7 +33,7 @@ import Uuid exposing (Uuid){{/includeUuid}}
{-| {{{notes}}}
-}
{{/notes}}
{{operationId}} : {{#allParams}}{{^required}}Maybe {{/required}}{{#isArray}}List {{/isArray}}{{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{#isModel}}Api.Data.{{/isModel}}{{dataType}}{{/datatypeWithEnum}} -> {{/allParams}}{{#authMethods}}{{#isBasicBearer}}String -> {{/isBasicBearer}}{{/authMethods}}Api.Request {{^responses}}(){{/responses}}{{#responses}}{{#is2xx}}{{^dataType}}(){{/dataType}}{{#isMap}}(Dict.Dict String {{/isMap}}{{#isArray}}(List {{/isArray}}{{^primitiveType}}{{^isUuid}}Api.Data.{{/isUuid}}{{/primitiveType}}{{#items}}{{#isModel}}Api.Data.{{/isModel}}{{/items}}{{dataType}}{{#isArray}}){{/isArray}}{{#isMap}}){{/isMap}}{{/is2xx}}{{/responses}}
{{operationId}} : {{#allParams}}{{^required}}Maybe {{/required}}{{#isArray}}List {{/isArray}}{{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{#isModel}}Api.Data.{{/isModel}}{{dataType}}{{/datatypeWithEnum}} -> {{/allParams}}{{#authMethods}}{{#isBasicBearer}}String -> {{/isBasicBearer}}{{/authMethods}}Api.Request {{^responses}}(){{/responses}}{{#responses}}{{#is2xx}}{{^dataType}}(){{/dataType}}{{#isMap}}(Dict.Dict String {{/isMap}}{{#isArray}}(List {{#items}}{{#isModel}}Api.Data.{{/isModel}}{{/items}}{{/isArray}}{{^isArray}}{{^primitiveType}}{{^isUuid}}Api.Data.{{/isUuid}}{{/primitiveType}}{{/isArray}}{{dataType}}{{#isArray}}){{/isArray}}{{#isMap}}){{/isMap}}{{/is2xx}}{{/responses}}
{{operationId}}{{#allParams}} {{>paramName}}{{/allParams}}{{#authMethods}}{{#isBasicBearer}} auth_token{{/isBasicBearer}}{{/authMethods}} =
Api.request
"{{httpMethod}}"

View File

@ -1 +1 @@
{{#isArray}}(Json.Decode.list {{/isArray}}{{#isMap}}(Json.Decode.dict {{/isMap}}{{#items}}{{>recordFieldValueDecoder}}{{/items}}{{^isContainer}}{{#isCircularReference}}(Json.Decode.lazy (\_ -> {{/isCircularReference}}{{>fieldDecoder}}{{#isCircularReference}})){{/isCircularReference}}{{/isContainer}}{{#isArray}}){{/isArray}}{{#isMap}}){{/isMap}}
{{#isArray}}(Json.Decode.list {{/isArray}}{{#isMap}}(Json.Decode.dict {{/isMap}}{{#items}}{{>recordFieldValueDecoder}}{{/items}}{{^isArray}}{{#isCircularReference}}(Json.Decode.lazy (\_ -> {{/isCircularReference}}{{>fieldDecoder}}{{#isCircularReference}})){{/isCircularReference}}{{/isArray}}{{#isArray}}){{/isArray}}{{#isMap}}){{/isMap}}

View File

@ -32,7 +32,7 @@ interface {{classname}}Delegate {
/**
* @see {{classname}}#{{operationId}}
*/
fun {{operationId}}({{#allParams}}{{paramName}}: {{^isFile}}{{^isBodyParam}}{{>optionalDataType}}{{/isBodyParam}}{{#isBodyParam}}{{{dataType}}}{{/isBodyParam}}{{/isFile}}{{#isFile}}Resource?{{/isFile}}{{^-last}},
fun {{operationId}}({{#allParams}}{{paramName}}: {{^isFile}}{{>optionalDataType}}{{/isFile}}{{#isFile}}Resource?{{/isFile}}{{^-last}},
{{/-last}}{{/allParams}}): {{#responseWrapper}}{{.}}<{{/responseWrapper}}ResponseEntity<{{>returnTypes}}>{{#responseWrapper}}>{{/responseWrapper}} {
{{>methodBody}}
}

View File

@ -1,5 +1,4 @@
{{#useBeanValidation}}{{#required}}{{^isReadOnly}}
@get:NotNull{{/isReadOnly}}{{/required}}{{>beanValidation}}{{>beanValidationModel}}{{/useBeanValidation}}{{#swaggerAnnotations}}
@ApiModelProperty({{#example}}example = "{{{example}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}{{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}value = "{{{description}}}"){{/swaggerAnnotations}}{{#deprecated}}
{{#useBeanValidation}}{{>beanValidation}}{{>beanValidationModel}}{{/useBeanValidation}}{{#swaggerAnnotations}}
@ApiModelProperty({{#example}}example = "{{{example}}}", {{/example}}{{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}value = "{{{description}}}"){{/swaggerAnnotations}}{{#deprecated}}
@Deprecated(message = ""){{/deprecated}}
@field:JsonProperty("{{{baseName}}}"){{#isInherited}} override{{/isInherited}} {{>modelMutable}} {{{name}}}: {{#isEnum}}{{#isArray}}{{baseType}}<{{/isArray}}{{classname}}.{{nameInCamelCase}}{{#isArray}}>{{/isArray}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}? = {{#defaultvalue}}{{defaultvalue}}{{/defaultvalue}}{{^defaultvalue}}null{{/defaultvalue}}

View File

@ -1,4 +1,3 @@
{{#useBeanValidation}}{{#required}}{{^isReadOnly}}
@get:NotNull {{/isReadOnly}}{{/required}}{{>beanValidation}}{{>beanValidationModel}}{{/useBeanValidation}}{{#swaggerAnnotations}}
@ApiModelProperty({{#example}}example = "{{{example}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}{{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}value = "{{{description}}}"){{/swaggerAnnotations}}
@field:JsonProperty("{{{baseName}}}"){{#isInherited}} override{{/isInherited}} {{>modelMutable}} {{{name}}}: {{#isEnum}}{{#isArray}}{{baseType}}<{{/isArray}}{{classname}}.{{nameInCamelCase}}{{#isArray}}>{{/isArray}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{#isReadOnly}}? = {{#defaultvalue}}{{defaultvalue}}{{/defaultvalue}}{{^defaultvalue}}null{{/defaultvalue}}{{/isReadOnly}}
{{#useBeanValidation}}{{>beanValidation}}{{>beanValidationModel}}{{/useBeanValidation}}{{#swaggerAnnotations}}
@ApiModelProperty({{#example}}example = "{{{example}}}", {{/example}}required = true, {{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}value = "{{{description}}}"){{/swaggerAnnotations}}
@field:JsonProperty("{{{baseName}}}", required = true){{#isInherited}} override{{/isInherited}} {{>modelMutable}} {{{name}}}: {{#isEnum}}{{#isArray}}{{baseType}}<{{/isArray}}{{classname}}.{{nameInCamelCase}}{{#isArray}}>{{/isArray}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{#isReadOnly}}? = {{#defaultvalue}}{{defaultvalue}}{{/defaultvalue}}{{^defaultvalue}}null{{/defaultvalue}}{{/isReadOnly}}

View File

@ -0,0 +1,48 @@
# {{packageName}} - Kotlin database library for {{appName}}
## Requires
{{#jvm}}
* Kotlin 1.3.61
* Gradle 4.9
{{/jvm}}
{{#multiplatform}}
* Kotlin 1.3.50
{{/multiplatform}}
## Build
{{#jvm}}
First, create the gradle wrapper script:
```
gradle wrapper
```
Then, run:
{{/jvm}}
```
./gradlew check assemble
```
This runs all tests and packages the library.
## Features/Implementation Notes
* Some Kotlin and Java types are fully qualified to avoid conflicts with types defined in OpenAPI definitions.
* Supports Mapper using API model classes.
* Supports SQLite types.
{{#generateModelDocs}}
<a name="documentation-for-models"></a>
## Documentation for Models
{{#modelPackage}}
{{#models}}{{#model}} - [{{{modelPackage}}}.{{{classname}}}]({{modelDocPath}}{{{classname}}}.md)
{{/model}}{{/models}}
{{/modelPackage}}
{{^modelPackage}}
No model defined in this package
{{/modelPackage}}
{{/generateModelDocs}}

View File

@ -0,0 +1,35 @@
group '{{groupId}}'
version '{{artifactVersion}}'
wrapper {
gradleVersion = '4.9'
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
}
buildscript {
ext.kotlin_version = '1.3.72'
ext.ktorm_version = '3.2.0'
repositories {
maven { url "https://repo1.maven.org/maven2" }
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'kotlin'
repositories {
maven { url "https://repo1.maven.org/maven2" }
}
test {
useJUnitPlatform()
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.ktorm:ktorm-core:$ktorm_version"
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.1.0"
}

View File

@ -0,0 +1,102 @@
{{#vendorExtensions}}{{#x-ktorm-schema}}{{^discriminator}}
/**
* {{{description}}}
{{#allVars}}
* @param {{{name}}} {{{description}}}
{{/allVars}}
*/
{{#isDeprecated}}
@Deprecated(message = "This schema is deprecated.")
{{/isDeprecated}}
{{#nonPublicApi}}internal {{/nonPublicApi}}object {{{classname}}}s : BaseTable<{{{classname}}}>("{{#tableDefinition}}{{{tblName}}}{{/tableDefinition}}") {
{{#allVars}}
{{^isArray}}
{{#isEnum}}
{{#required}}{{>data_class_enum_req}}{{/required}}{{^required}}{{>data_class_enum_opt}}{{/required}}
{{/isEnum}}
{{^isEnum}}
{{#required}}{{>data_class_field_req}}{{/required}}{{^required}}{{>data_class_field_opt}}{{/required}}
{{/isEnum}}
{{/isArray}}
{{/allVars}}
/**
* Create an entity of type {{{classname}}} from the model
*/
override fun doCreateEntity(row: QueryRowSet, withReferences: Boolean) = {{{classname}}}(
{{#allVars}}
{{#vendorExtensions}}
{{#x-ktorm-schema}}
{{^isArray}}
{{#relation}}
{{#required}}{{>data_class_bind_ref_req}}{{/required}}{{^required}}{{>data_class_bind_ref_opt}}{{/required}}{{^-last}},{{/-last}}
{{/relation}}
{{^relation}}
{{#required}}{{>data_class_bind_field_req}}{{/required}}{{^required}}{{>data_class_bind_field_opt}}{{/required}}{{^-last}},{{/-last}}
{{/relation}}
{{/isArray}}
{{#isArray}}
{{#required}}{{>data_class_bind_list_req}}{{/required}}{{^required}}{{>data_class_bind_list_opt}}{{/required}}{{^-last}},{{/-last}}
{{/isArray}}
{{/x-ktorm-schema}}
{{/vendorExtensions}}
{{/allVars}}
)
/**
* Assign all the columns from the entity of type {{{classname}}} to the DML expression.
*
* Usage:
*
* ```kotlin
* let entity = {{{classname}}}()
* database.update({{{classname}}}s, {
* assignFrom(entity)
* })
* ```
* @return the builder with the columns for the update or insert.
*/
fun AssignmentsBuilder.assignFrom(entity: {{{classname}}}) {
this.apply {
{{#allVars}}
{{^isArray}}
{{>data_class_set}}
{{/isArray}}
{{/allVars}}
}
}
}
{{#allVars}}
{{#isArray}}
{{#vendorExtensions}}
{{#x-ktorm-schema}}
{{#isDeprecated}}
@Deprecated(message = "This schema is deprecated.")
{{/isDeprecated}}
{{#relationDefinition}}
{{#nonPublicApi}}internal {{/nonPublicApi}}object {{{relName}}} : BaseTable<Pair<{{{pkColKotlinType}}}, {{{fkColKotlinType}}}>>("{{{relTblName}}}") {
val {{{pkName}}} = {{{pkColType}}}("{{{pkColName}}}")
val {{{fkName}}} = {{{fkColType}}}("{{{fkColName}}}")
override fun doCreateEntity(row: QueryRowSet, withReferences: Boolean): Pair<{{{pkColKotlinType}}}, {{{fkColKotlinType}}}> =
Pair(row[{{{pkName}}}] ?: {{#pkIsString}}""{{/pkIsString}}{{#pkIsNumeric}}0{{/pkIsNumeric}}, row[{{{fkName}}}] ?: {{#fkIsString}}""{{/fkIsString}}{{#fkIsNumeric}}0{{/fkIsNumeric}})
fun AssignmentsBuilder.assignFrom(entity: Pair<{{{pkColKotlinType}}}, {{{fkColKotlinType}}}>) {
this.apply {
set({{{relName}}}.{{{pkName}}}, entity.first)
set({{{relName}}}.{{{fkName}}}, entity.second)
}
}
}
{{/relationDefinition}}
{{/x-ktorm-schema}}
{{/vendorExtensions}}
{{/isArray}}
{{/allVars}}
{{/discriminator}}
{{/x-ktorm-schema}}
{{/vendorExtensions}}

View File

@ -0,0 +1 @@
{{#vendorExtensions}}{{#x-ktorm-schema}}{{#columnDefinition}} {{{name}}} = row[{{{name}}}] {{#defaultvalue}}?: {{{defaultvalue}}}{{/defaultvalue}} /* {{{colKotlinType}}}? */{{/columnDefinition}}{{/x-ktorm-schema}}{{/vendorExtensions}}{{#description}} /* {{{description}}} */{{/description}}

View File

@ -0,0 +1 @@
{{#vendorExtensions}}{{#x-ktorm-schema}}{{#columnDefinition}} {{{name}}} = row[{{{name}}}]{{#isEnum}} ?: {{{classname}}}.{{{nameInCamelCase}}}.valueOf({{#isString}}""{{/isString}}{{#isNumeric}}0{{/isNumeric}}){{/isEnum}}{{^isEnum}}{{#isString}} ?: ""{{/isString}}{{#isNumeric}} ?: 0{{/isNumeric}}{{#isBoolean}} ?: false{{/isBoolean}}{{/isEnum}} /* {{{colKotlinType}}} */{{/columnDefinition}}{{/x-ktorm-schema}}{{/vendorExtensions}}{{#description}} /* {{{description}}} */{{/description}}

View File

@ -0,0 +1 @@
{{#vendorExtensions}}{{#x-ktorm-schema}}{{#columnDefinition}} {{{name}}} = emptyList() /* {{{colKotlinType}}}? */{{/columnDefinition}}{{/x-ktorm-schema}}{{/vendorExtensions}}{{#description}} /* {{{description}}} */{{/description}}

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