Compare commits

..

58 Commits

Author SHA1 Message Date
Bodo Graumann
f3f5fef279 Typescript refactor: Platform select for browser and node (#4500)
* Use string form of filename parameter

This works for the form-data library and is also compatible with the
browser FormData object.

* Add new option to select platform node or browser

When no platform is selected, a default is chosen by the framework
option and likewise the file data type option is implied by the
platform.

* Remove redundant import of node dns module

* Only use form-data library for node platform

* Generate npm package from npmName option

* Use method convertPropertyToBooleanAndWriteBack

* Generate typescript samples with ensure-up-to-date
2020-01-18 06:31:27 -05:00
Bodo Graumann
6dfe637b21 Typescript refactor: stub rxjs (#4424)
* Remove unused supportsES6 field from codegen

* Add a new switch for RXJS

* Remove redundant npm dependency on rxjs4 types

* Fix return type of PromiseMiddleware methods

* Install webpack dependency to run jquery tests

* Update form-data to 2.5 which includes typings

* Add missing dependency on node typings

* Fix test artifact name typo

* Stub rxjs when it is not explicitly enabled
2019-11-19 11:48:08 -05:00
Bodo Graumann
a738e95aee Refactor typescript merge master (#4319)
Merge master into ts-refactor
2019-11-01 11:04:18 -04:00
Tino Fuhrmann
9d08f8bc5b Updated typescript docs 2019-05-06 12:07:03 +02:00
Tino Fuhrmann
9e49c7e942 Fixed missing fetch definition in TS default tests 2019-05-06 12:03:07 +02:00
Tino Fuhrmann
bc734da7d4 Ensured up to date 2019-05-05 22:58:45 +02:00
Tino Fuhrmann
abff890b90 Fixed a couple issues with pom.xml 2019-05-05 22:39:52 +02:00
Tino Fuhrmann
b796270880 Removed tabs in TypeScriptClientCodegen 2019-05-05 20:43:50 +02:00
Tino Fuhrmann
02c1d9ff64 Added pom.xmls, fixed packagejsons and hopefully webppack 2019-05-05 20:32:01 +02:00
Tino Fuhrmann
7d69d0b9cb Added jquery library 2019-05-05 16:44:32 +02:00
Tino Fuhrmann
3e94fd15cc Added gitignore and git_push 2019-05-03 20:22:29 +02:00
Tino Fuhrmann
491fae4c25 Updated docs 2019-05-02 15:10:13 +02:00
Tino Fuhrmann
be3e24b681 Added typescript to docs/generators 2019-05-01 11:26:25 +02:00
Tino Fuhrmann
7d0b3e1879 Fixed compilation issues in TypeScriptClientCodegen 2019-05-01 10:50:57 +02:00
Tino Fuhrmann
8b138ecd81 Reverted changes to README to master 2019-05-01 10:45:51 +02:00
Tino Fuhrmann
496c0c8bdc Removed accidentally created generated code 2019-05-01 10:45:07 +02:00
Tino Fuhrmann
b8e31fcddd Ignore openapi-generator-cli/bin 2019-05-01 10:43:47 +02:00
Tino Fuhrmann
64b8505010 Added comments 2019-04-30 23:25:24 +02:00
Tino Fuhrmann
5f163da848 Added comments & license info 2019-04-30 23:25:24 +02:00
Tino Fuhrmann
7f5615485d Fixed date-time and date handling 2019-04-30 23:25:24 +02:00
Tino Fuhrmann
e700a08a8f Set discriminator value automatically 2019-04-30 23:20:50 +02:00
Tino Fuhrmann
74bb8ccfe7 Configure discriminator correctly 2019-04-30 23:20:50 +02:00
Tino Fuhrmann
01b0ff6008 Made discriminator and attributeTypeMap readonly 2019-04-30 23:20:50 +02:00
Tino Fuhrmann
5323a5d7a6 Added promise based middleware 2019-04-30 23:20:50 +02:00
Tino Fuhrmann
8c03ea8ca5 Use observables internally 2019-04-30 23:20:50 +02:00
Tino Fuhrmann
c90c3f9d7b Restructured module layout 2019-04-30 23:20:50 +02:00
Tino Fuhrmann
9c17bc5721 Remove tab 2019-04-30 23:20:50 +02:00
Tino Fuhrmann
a0e3f18f2f Use string union for enums 2019-04-30 23:20:49 +02:00
Tino Fuhrmann
647474f3d9 Made api call configuration separately settable 2019-04-30 23:20:49 +02:00
Tino Fuhrmann
4720467cbb Fixed file uploads 2019-04-30 23:20:49 +02:00
Tino Fuhrmann
2468b748d3 Additional tests for pet store api 2019-04-30 23:20:49 +02:00
Tino Fuhrmann
9a9e62cfa5 Removed tabs in DefaultCodegen 2019-04-30 23:20:49 +02:00
Tino Fuhrmann
5174e7539b Removed tabs in TypeScriptClientCodegen 2019-04-30 23:20:49 +02:00
Tino Fuhrmann
fe0cb07afb Added handling for different http status codes and test for deletePet 2019-04-30 23:20:49 +02:00
Tino Fuhrmann
878ea6e1c1 Fixed ObjectSerializer test 2019-04-30 23:20:49 +02:00
Tino Fuhrmann
69dfdd57a6 Added simple test for PetApi 2019-04-30 23:20:49 +02:00
Tino Fuhrmann
502e209bfe [TS-Refactor] Added tests for Object Serializer 2019-04-30 23:20:49 +02:00
Tino Fuhrmann
8d29ca42d5 Added server variable configuration to ts-refactor 2019-04-30 23:20:49 +02:00
Tino Fuhrmann
49219fa48a Added ts client codegen to root pom.xml and travis 2019-04-30 23:20:49 +02:00
Tino Fuhrmann
f4b3eb011b Removed tabs from TypeScriptClientCodegen 2019-04-30 23:19:34 +02:00
Tino Fuhrmann
ef065f3013 Added pom.xml files to TypeScript PetStore client samples 2019-04-30 23:19:34 +02:00
Tino Fuhrmann
29940ef0b1 Removed TODOs 2019-04-30 23:19:34 +02:00
Tino Fuhrmann
dd7d8c0271 Reverted: http library.send returns string again 2019-04-30 23:19:34 +02:00
Tino Fuhrmann
0da5238e24 Restructured TypeScript generator 2019-04-30 23:19:33 +02:00
Tino Fuhrmann
2e8446ceee Added middleware to fetch 2019-04-30 23:19:33 +02:00
Tino Fuhrmann
662242157f Ignore dist folder in typescript client sample 2019-04-30 23:19:33 +02:00
Tino Fuhrmann
5adefaf53f Implemented fetch client 2019-04-30 23:19:33 +02:00
Tino Fuhrmann
8dca5e4cbe Implemented RequestFactory and Processor completely 2019-04-30 23:19:33 +02:00
Tino Fuhrmann
e21a48dd64 WIP: api modeling 2019-04-30 23:19:33 +02:00
Tino Fuhrmann
894bddac1b Updated auth 2019-04-30 23:19:33 +02:00
Tino Fuhrmann
fe2cc24f4d WIP: Models & API 2019-04-30 23:19:33 +02:00
Tino Fuhrmann
b0f8dc9505 Added sample for typescript client 2019-04-30 23:19:33 +02:00
Tino Fuhrmann
8f82cdec7d Added servers 2019-04-30 23:19:33 +02:00
Tino Fuhrmann
64f29483ce Added auth module 2019-04-30 23:19:33 +02:00
Tino Fuhrmann
94432cff92 Added model generation with imports 2019-04-30 23:19:33 +02:00
Tino Fuhrmann
3e745b71f2 Modified http lib, added config & middleware definition to ts-fetch 2019-04-30 23:19:32 +02:00
Tino Fuhrmann
f90e1b59f5 Added generic enum 2019-04-30 23:19:32 +02:00
Tino Fuhrmann
dd6835393d Added http module draft 2019-04-30 23:19:32 +02:00
319 changed files with 17703 additions and 327 deletions

1
.gitignore vendored
View File

@@ -7,6 +7,7 @@ out/
classpath.txt
version.properties
modules/openapi-generator-gradle-plugin/bin/
modules/openapi-generator-cli/bin/
!modules/openapi-generator-cli/src/main/resources/version.properties
.project
.classpath

View File

@@ -20,6 +20,7 @@ cache:
- $HOME/samples/client/petstore/php/OpenAPIToolsClient-php/vendor
- $HOME/samples/client/petstore/ruby/vendor/bundle
- $HOME/samples/client/petstore/python/.venv/
- $HOME/samples/client/petstore/typescript/tests/default/node_modules
- $HOME/samples/client/petstore/typescript-node/npm/node_modules
- $HOME/samples/client/petstore/typescript-node/npm/typings/
- $HOME/samples/client/petstore/typescript-fetch/tests/default/node_modules

View File

@@ -159,16 +159,16 @@ See the different versions of the [openapi-generator-cli](https://mvnrepository.
<!-- RELEASE_VERSION -->
If you're looking for the latest stable version, you can grab it directly from Maven.org (Java 8 runtime at a minimum):
JAR location: `http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/4.2.0/openapi-generator-cli-4.2.0.jar`
JAR location: `http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/4.1.3/openapi-generator-cli-4.1.3.jar`
For **Mac/Linux** users:
```sh
wget http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/4.2.0/openapi-generator-cli-4.2.0.jar -O openapi-generator-cli.jar
wget http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/4.1.3/openapi-generator-cli-4.1.3.jar -O openapi-generator-cli.jar
```
For **Windows** users, you will need to install [wget](http://gnuwin32.sourceforge.net/packages/wget.htm) or you can use Invoke-WebRequest in PowerShell (3.0+), e.g.
```
Invoke-WebRequest -OutFile openapi-generator-cli.jar http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/4.2.0/openapi-generator-cli-4.2.0.jar
Invoke-WebRequest -OutFile openapi-generator-cli.jar http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/4.1.3/openapi-generator-cli-4.1.3.jar
```
After downloading the JAR, run `java -jar openapi-generator-cli.jar help` to show the usage.
@@ -383,10 +383,10 @@ openapi-generator version
```
<!-- RELEASE_VERSION -->
Or install a particular OpenAPI Generator version (e.g. v4.2.0):
Or install a particular OpenAPI Generator version (e.g. v4.1.3):
```sh
npm install @openapitools/openapi-generator-cli@cli-4.2.0 -g
npm install @openapitools/openapi-generator-cli@cli-4.1.3 -g
```
Or install it as dev-dependency:
@@ -410,7 +410,7 @@ java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generat
(if you're on Windows, replace the last command with `java -jar modules\openapi-generator-cli\target\openapi-generator-cli.jar generate -i https://raw.githubusercontent.com/openapitools/openapi-generator/master/modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g php -o c:\temp\php_api_client`)
<!-- RELEASE_VERSION -->
You can also download the JAR (latest release) directly from [maven.org](http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/4.2.0/openapi-generator-cli-4.2.0.jar)
You can also download the JAR (latest release) directly from [maven.org](http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/4.1.3/openapi-generator-cli-4.1.3.jar)
<!-- /RELEASE_VERSION -->
To get a list of **general** options available, please run `java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar help generate`

37
bin/typescript.sh Executable file
View File

@@ -0,0 +1,37 @@
#!/bin/sh
SCRIPT="$0"
echo "# START SCRIPT: $SCRIPT"
while [ -h "$SCRIPT" ] ; do
ls=`ls -ld "$SCRIPT"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
SCRIPT="$link"
else
SCRIPT=`dirname "$SCRIPT"`/"$link"
fi
done
if [ ! -d "${APP_DIR}" ]; then
APP_DIR=`dirname "$SCRIPT"`/..
APP_DIR=`cd "${APP_DIR}"; pwd`
fi
executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"
if [ ! -f "$executable" ]
then
mvn -B clean package
fi
# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
echo "Creating default (fetch) client!"
ags="generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g typescript -o samples/client/petstore/typescript/builds/default --additional-properties=platform=node,npmName=ts-petstore-client $@"
java $JAVA_OPTS -jar $executable $ags
echo "Creating jquery client!"
ags="generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g typescript -o samples/client/petstore/typescript/builds/jquery --additional-properties=framework=jquery,npmName=ts-petstore-client $@"
java $JAVA_OPTS -jar $executable $ags

View File

@@ -73,6 +73,7 @@ declare -a scripts=(
"./bin/java-play-framework-petstore-server-all.sh"
"./bin/elm-petstore-all.sh"
"./bin/meta-codegen.sh"
"./bin/typescript.sh"
# OTHERS
"./bin/utils/export_docs_generators.sh"
"./bin/utils/copy-to-website.sh"

View File

@@ -57,6 +57,7 @@ The following generators are available:
* [swift2-deprecated (deprecated)](generators/swift2-deprecated.md)
* [swift3-deprecated (deprecated)](generators/swift3-deprecated.md)
* [swift4](generators/swift4.md)
* [typescript](generators/typescript.md)
* [typescript-angular](generators/typescript-angular.md)
* [typescript-angularjs](generators/typescript-angularjs.md)
* [typescript-aurelia](generators/typescript-aurelia.md)

View File

@@ -11,4 +11,3 @@ sidebar_label: haskell
|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|
|modelPackage|package for generated models| |null|
|apiPackage|package for generated api classes| |null|
|serveStatic|serve will serve files from the directory 'static'.| |true|

View File

@@ -0,0 +1,17 @@
---
title: Config Options for typescript
sidebar_label: typescript
---
| Option | Description | Values | Default |
| ------ | ----------- | ------ | ------- |
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
|allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false|
|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|
|modelPropertyNaming|Naming convention for the property: 'camelCase', 'PascalCase', 'snake_case' and 'original', which keeps the original name| |camelCase|
|supportsES6|Generate code that conforms to ES6.| |false|
|fileContentDataType|Specifies the type to use for the content of a file - i.e. Blob (Browser) / Buffer (node)| |Buffer|
|useRxJS|Enable this to internally use rxjs observables. If disabled, a stub is used instead. This is required for the 'angular' framework.| |false|
|platform|Specifies the platform the code should run on. The default is 'node' for the 'request' framework and 'browser' otherwise.| |null|
|framework|Specify the framework which should be used in the client code.|<dl><dt>**fetch-api**</dt><dd>fetch-api</dd><dt>**jquery**</dt><dd>jquery</dd><dl>|fetch-api|

View File

@@ -4,7 +4,7 @@
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-project</artifactId>
<!-- RELEASE_VERSION -->
<version>4.2.0</version>
<version>4.2.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION -->
<relativePath>../..</relativePath>
</parent>

View File

@@ -6,7 +6,7 @@
<artifactId>openapi-generator-project</artifactId>
<groupId>org.openapitools</groupId>
<!-- RELEASE_VERSION -->
<version>4.2.0</version>
<version>4.2.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION -->
<relativePath>../..</relativePath>
</parent>

View File

@@ -45,7 +45,7 @@ compileJava.dependsOn tasks.openApiGenerate
[source,group]
----
plugins {
id "org.openapi.generator" version "4.2.0"
id "org.openapi.generator" version "4.1.1"
}
----
@@ -61,7 +61,7 @@ buildscript {
// url "https://plugins.gradle.org/m2/"
}
dependencies {
classpath "org.openapitools:openapi-generator-gradle-plugin:4.2.0"
classpath "org.openapitools:openapi-generator-gradle-plugin:4.1.1"
}
}
@@ -626,7 +626,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
classpath('org.openapitools:openapi-generator-gradle-plugin:4.2.0') {
classpath('org.openapitools:openapi-generator-gradle-plugin:4.1.1') {
exclude group: 'com.google.guava'
}
}

View File

@@ -1,5 +1,5 @@
# RELEASE_VERSION
openApiGeneratorVersion=4.2.0
openApiGeneratorVersion=4.2.0-SNAPSHOT
# /RELEASE_VERSION
# BEGIN placeholders

View File

@@ -4,7 +4,7 @@
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-project</artifactId>
<!-- RELEASE_VERSION -->
<version>4.2.0</version>
<version>4.2.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION -->
<relativePath>../..</relativePath>
</parent>

View File

@@ -17,5 +17,5 @@ gradle generateGoWithInvalidSpec
The samples can be tested against other versions of the plugin using the `openApiGeneratorVersion` property. For example:
```bash
gradle -PopenApiGeneratorVersion=4.2.0 openApiValidate
gradle -PopenApiGeneratorVersion=4.1.1 openApiValidate
```

View File

@@ -12,7 +12,7 @@ Add to your `build->plugins` section (default phase is `generate-sources` phase)
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<!-- RELEASE_VERSION -->
<version>4.2.0</version>
<version>4.1.1</version>
<!-- /RELEASE_VERSION -->
<executions>
<execution>

View File

@@ -5,7 +5,7 @@
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-project</artifactId>
<!-- RELEASE_VERSION -->
<version>4.2.0</version>
<version>4.2.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION -->
<relativePath>../..</relativePath>
</parent>

View File

@@ -4,7 +4,7 @@
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-project</artifactId>
<!-- RELEASE_VERSION -->
<version>4.2.0</version>
<version>4.2.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION -->
<relativePath>../..</relativePath>
</parent>

View File

@@ -4,7 +4,7 @@
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-project</artifactId>
<!-- RELEASE_VERSION -->
<version>4.2.0</version>
<version>4.2.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION -->
<relativePath>../..</relativePath>
</parent>

View File

@@ -30,8 +30,8 @@ public class CodegenOperation {
isResponseBinary = false, isResponseFile = false, hasReference = false,
isRestfulIndex, isRestfulShow, isRestfulCreate, isRestfulUpdate, isRestfulDestroy,
isRestful, isDeprecated, isCallbackRequest;
public String path, operationId, returnType, httpMethod, returnBaseType,
returnContainer, summary, unescapedNotes, notes, baseName, defaultResponse;
public String path, operationId, returnType, returnFormat, httpMethod, returnBaseType,
returnContainer, summary, unescapedNotes, notes, baseName, defaultResponse;
public CodegenDiscriminator discriminator;
public List<Map<String, String>> consumes, produces, prioritizedContentTypes;
public List<CodegenServer> servers = new ArrayList<CodegenServer>();

View File

@@ -22,6 +22,7 @@ import java.util.*;
public class CodegenResponse {
public final List<CodegenProperty> headers = new ArrayList<CodegenProperty>();
public String code, message;
public boolean isSuccessCode;
public boolean hasMore;
public List<Map<String, Object>> examples;
public String dataType, baseType, containerType;

View File

@@ -2547,7 +2547,8 @@ public class DefaultCodegen implements CodegenConfig {
op.examples = new ExampleGenerator(schemas, this.openAPI).generateFromResponseSchema(exampleStatusCode, responseSchema, getProducesInfo(this.openAPI, operation));
op.defaultResponse = toDefaultValue(responseSchema);
op.returnType = cm.dataType;
op.hasReference = schemas.containsKey(op.returnBaseType);
op.returnFormat = cm.dataFormat;
op.hasReference = schemas != null && schemas.containsKey(op.returnBaseType);
// lookup discriminator
Schema schema = schemas.get(op.returnBaseType);
@@ -2869,6 +2870,7 @@ public class DefaultCodegen implements CodegenConfig {
r.code = "0";
} else {
r.code = responseCode;
r.isSuccessCode = r.code.startsWith("2");
}
Schema responseSchema;
if (this.openAPI != null && this.openAPI.getComponents() != null) {
@@ -3374,7 +3376,7 @@ public class DefaultCodegen implements CodegenConfig {
return false;
}
}
// TODO revise below as it should be replaced by ModelUtils.isFileSchema(parameterSchema)
public boolean isDataTypeFile(String dataType) {
if (dataType != null) {

View File

@@ -43,10 +43,6 @@ public class HaskellServantCodegen extends DefaultCodegen implements CodegenConf
protected String apiVersion = "0.0.1";
private static final Pattern LEADING_UNDERSCORE = Pattern.compile("^_+");
public static final String PROP_SERVE_STATIC = "serveStatic";
public static final String PROP_SERVE_STATIC_DESC = "serve will serve files from the directory 'static'.";
public static final Boolean PROP_SERVE_STATIC_DEFAULT = Boolean.TRUE;
/**
* Configures the type of generator.
*
@@ -187,15 +183,6 @@ public class HaskellServantCodegen extends DefaultCodegen implements CodegenConf
cliOptions.add(new CliOption(CodegenConstants.MODEL_PACKAGE, CodegenConstants.MODEL_PACKAGE_DESC));
cliOptions.add(new CliOption(CodegenConstants.API_PACKAGE, CodegenConstants.API_PACKAGE_DESC));
cliOptions.add(new CliOption(PROP_SERVE_STATIC, PROP_SERVE_STATIC_DESC).defaultValue(PROP_SERVE_STATIC_DEFAULT.toString()));
}
public void setBooleanProperty(String property, Boolean defaultValue) {
if (additionalProperties.containsKey(property)) {
additionalProperties.put(property, convertPropertyToBoolean(property));
} else {
additionalProperties.put(property, defaultValue);
}
}
@Override
@@ -205,8 +192,6 @@ public class HaskellServantCodegen extends DefaultCodegen implements CodegenConf
if (StringUtils.isEmpty(System.getenv("HASKELL_POST_PROCESS_FILE"))) {
LOGGER.info("Hint: Environment variable HASKELL_POST_PROCESS_FILE not defined so the Haskell code may not be properly formatted. To define it, try 'export HASKELL_POST_PROCESS_FILE=\"$HOME/.local/bin/hfmt -w\"' (Linux/Mac)");
}
setBooleanProperty(PROP_SERVE_STATIC, PROP_SERVE_STATIC_DEFAULT);
}
/**

View File

@@ -107,6 +107,7 @@ public class TypeScriptAxiosClientCodegen extends AbstractTypeScriptClientCodege
supportingFiles.add(new SupportingFile("baseApi.mustache", "", "base.ts"));
supportingFiles.add(new SupportingFile("api.mustache", "", "api.ts"));
supportingFiles.add(new SupportingFile("configuration.mustache", "", "configuration.ts"));
supportingFiles.add(new SupportingFile("custom.d.mustache", "", "custom.d.ts"));
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
supportingFiles.add(new SupportingFile("gitignore", "", ".gitignore"));

View File

@@ -0,0 +1,779 @@
/*
* 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
*
* 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.
*/
package org.openapitools.codegen.languages;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.NumberSchema;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.*;
import org.openapitools.codegen.utils.ModelUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.*;
import java.util.Map.Entry;
import static org.openapitools.codegen.utils.StringUtils.camelize;
import static org.openapitools.codegen.utils.StringUtils.underscore;
public class TypeScriptClientCodegen extends DefaultCodegen implements CodegenConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(TypeScriptClientCodegen.class);
private static final String X_DISCRIMINATOR_TYPE = "x-discriminator-value";
private static final String UNDEFINED_VALUE = "undefined";
private static final String FRAMEWORK_SWITCH = "framework";
private static final String FRAMEWORK_SWITCH_DESC = "Specify the framework which should be used in the client code.";
private static final String[] FRAMEWORKS = { "fetch-api", "jquery" };
private static final String PLATFORM_SWITCH = "platform";
private static final String PLATFORM_SWITCH_DESC = "Specifies the platform the code should run on. The default is 'node' for the 'request' framework and 'browser' otherwise.";
private static final String[] PLATFORMS = { "browser", "node" };
private static final String FILE_CONTENT_DATA_TYPE= "fileContentDataType";
private static final String FILE_CONTENT_DATA_TYPE_DESC = "Specifies the type to use for the content of a file - i.e. Blob (Browser) / Buffer (node)";
private static final String USE_RXJS_SWITCH = "useRxJS";
private static final String USE_RXJS_SWITCH_DESC = "Enable this to internally use rxjs observables. If disabled, a stub is used instead. This is required for the 'angular' framework.";
private final Map<String, String> frameworkToHttpLibMap;
protected String modelPropertyNaming = "camelCase";
protected HashSet<String> languageGenericTypes;
public TypeScriptClientCodegen() {
super();
this.frameworkToHttpLibMap = new HashMap<>();
this.frameworkToHttpLibMap.put("fetch-api", "isomorphic-fetch");
this.frameworkToHttpLibMap.put("jquery", "jquery");
// clear import mapping (from default generator) as TS does not use it
// at the moment
importMapping.clear();
outputFolder = "generated-code/typescript";
embeddedTemplateDir = templateDir = "typescript";
supportsInheritance = true;
// NOTE: TypeScript uses camel cased reserved words, while models are title cased. We don't want lowercase comparisons.
reservedWords.addAll(Arrays.asList(
// local variable names used in API methods (endpoints)
"varLocalPath", "queryParameters", "headerParams", "formParams", "useFormData", "varLocalDeferred",
"requestOptions",
// Typescript reserved words
"abstract", "await", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "debugger", "default", "delete", "do", "double", "else", "enum", "export", "extends", "false", "final", "finally", "float", "for", "function", "goto", "if", "implements", "import", "in", "instanceof", "int", "interface", "let", "long", "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static", "super", "switch", "synchronized", "this", "throw", "transient", "true", "try", "typeof", "var", "void", "volatile", "while", "with", "yield"));
languageSpecificPrimitives = new HashSet<>(Arrays.asList(
"string",
"String",
"boolean",
"Boolean",
"Double",
"Integer",
"Long",
"Float",
"Object",
"Array",
"Date",
"number",
"any",
"File",
"Error",
"Map"
));
languageGenericTypes = new HashSet<String>(Arrays.asList(
"Array"
));
instantiationTypes.put("array", "Array");
typeMapping = new HashMap<String, String>();
typeMapping.put("Array", "Array");
typeMapping.put("array", "Array");
typeMapping.put("List", "Array");
typeMapping.put("boolean", "boolean");
typeMapping.put("string", "string");
typeMapping.put("int", "number");
typeMapping.put("float", "number");
typeMapping.put("number", "number");
typeMapping.put("long", "number");
typeMapping.put("short", "number");
typeMapping.put("char", "string");
typeMapping.put("double", "number");
typeMapping.put("object", "any");
typeMapping.put("integer", "number");
typeMapping.put("Map", "any");
typeMapping.put("date", "string");
typeMapping.put("DateTime", "Date");
typeMapping.put("binary", "any");
// TODO: allow other types for file e.g. Blob
typeMapping.put("File", "any");
typeMapping.put("ByteArray", "string");
typeMapping.put("UUID", "string");
typeMapping.put("Error", "Error");
cliOptions.add(new CliOption(CodegenConstants.MODEL_PROPERTY_NAMING, CodegenConstants.MODEL_PROPERTY_NAMING_DESC).defaultValue("camelCase"));
cliOptions.add(new CliOption(CodegenConstants.SUPPORTS_ES6, CodegenConstants.SUPPORTS_ES6_DESC).defaultValue("false"));
cliOptions.add(new CliOption(TypeScriptClientCodegen.FILE_CONTENT_DATA_TYPE, TypeScriptClientCodegen.FILE_CONTENT_DATA_TYPE_DESC).defaultValue("Buffer"));
cliOptions.add(new CliOption(TypeScriptClientCodegen.USE_RXJS_SWITCH, TypeScriptClientCodegen.USE_RXJS_SWITCH_DESC).defaultValue("false"));
CliOption frameworkOption = new CliOption(TypeScriptClientCodegen.FRAMEWORK_SWITCH, TypeScriptClientCodegen.FRAMEWORK_SWITCH_DESC);
for (String option: TypeScriptClientCodegen.FRAMEWORKS) {
// TODO: improve description?
frameworkOption.addEnum(option, option);
}
frameworkOption.defaultValue(FRAMEWORKS[0]);
cliOptions.add(new CliOption(TypeScriptClientCodegen.PLATFORM_SWITCH, TypeScriptClientCodegen.PLATFORM_SWITCH_DESC));
CliOption platformOption = new CliOption(TypeScriptClientCodegen.PLATFORM_SWITCH, TypeScriptClientCodegen.PLATFORM_SWITCH_DESC);
for (String option: TypeScriptClientCodegen.PLATFORMS) {
// TODO: improve description?
platformOption.addEnum(option, option);
}
platformOption.defaultValue(PLATFORMS[0]);
cliOptions.add(frameworkOption);
// TODO: gen package.json?
//Documentation
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
supportingFiles.add(new SupportingFile("package.mustache", "", "package.json"));
supportingFiles.add(new SupportingFile("tsconfig.mustache", "", "tsconfig.json"));
supportingFiles.add(new SupportingFile(".gitignore.mustache", "", ".gitignore"));
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
// Util
supportingFiles.add(new SupportingFile("util.mustache", "", "util.ts"));
supportingFiles.add(new SupportingFile("api/exception.mustache", "apis", "exception.ts"));
// http
supportingFiles.add(new SupportingFile("http" + File.separator + "http.mustache", "http", "http.ts"));
supportingFiles.add(new SupportingFile("http/servers.mustache", "servers.ts"));
supportingFiles.add(new SupportingFile("configuration.mustache", "", "configuration.ts"));
supportingFiles.add(new SupportingFile("auth" + File.separator + "auth.mustache", "auth", "auth.ts"));
supportingFiles.add(new SupportingFile("model/models_all.mustache", "models", "all.ts"));
// TODO: add supporting files depending on cli parameter e.g. fetch vs angular
supportingFiles.add(new SupportingFile("generators/types/PromiseAPI.mustache", "types", "PromiseAPI.ts"));
supportingFiles.add(new SupportingFile("generators/types/ObservableAPI.mustache", "types", "ObservableAPI.ts"));
// models
// TODO: properly set model and api packages
this.setModelPackage("");
supportingFiles.add(new SupportingFile("model/ObjectSerializer.mustache", "models", "ObjectSerializer.ts"));
modelTemplateFiles.put("model/model.mustache", ".ts");
// api
this.setApiPackage("");
supportingFiles.add(new SupportingFile("api/middleware.mustache", "", "middleware.ts"));
this.supportingFiles.add(new SupportingFile("api/baseapi.mustache", "apis", "baseapi.ts"));
this.apiTemplateFiles.put("api/api.mustache", ".ts");
}
@Override
public CodegenType getTag() {
return CodegenType.CLIENT;
}
@Override
public Map<String, Object> postProcessSupportingFileData(Map<String, Object> objs) {
final Object propFramework = additionalProperties.get(FRAMEWORK_SWITCH);
Map<String, Boolean> frameworks = new HashMap<>();
for (String framework: FRAMEWORKS) {
frameworks.put(framework, framework.equals(propFramework));
}
objs.put("framework", propFramework);
objs.put("frameworks", frameworks);
objs.put("fileContentDataType", additionalProperties.get(FILE_CONTENT_DATA_TYPE));
return objs;
}
@Override
public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> operations, List<Object> models) {
// Add additional filename information for model imports in the apis
List<Map<String, Object>> imports = (List<Map<String, Object>>) operations.get("imports");
for (Map<String, Object> im : imports) {
im.put("filename", ((String) im.get("import")).replace('.', '/'));
im.put("classname", getModelnameFromModelFilename(im.get("import").toString()));
}
@SuppressWarnings("unchecked")
Map<String, Object> operationsMap = (Map<String, Object>) operations.get("operations");
List<CodegenOperation> operationList = (List<CodegenOperation>) operationsMap.get("operation");
for (CodegenOperation operation: operationList) {
List<CodegenResponse> responses = operation.responses;
operation.returnType = this.getReturnType(responses);
}
return operations;
}
private String getReturnType(List<CodegenResponse> responses) {
StringBuilder returnType = new StringBuilder();
boolean firstReturnType = true;
boolean atLeastOneSuccess = false;
boolean addVoid = false;
System.out.println(responses);
for (CodegenResponse response: responses) {
// TODO: we should probably catch an exception here
if (response.isSuccessCode) {
if (response.dataType != null) {
if (!firstReturnType) {
returnType.append(" | ");
}
returnType.append(response.dataType);
firstReturnType = false;
atLeastOneSuccess = true;
} else {
addVoid = true;
}
}
}
if (!atLeastOneSuccess) {
return null;
} else if (addVoid) {
returnType.append(" | void");
}
System.out.println("Return Type: " + returnType);
return returnType.toString();
}
private String getModelnameFromModelFilename(String filename) {
String name = filename.substring((modelPackage() + File.separator).length());
return camelize(name);
}
@Override
public String escapeReservedWord(String name) {
if (this.reservedWordsMappings().containsKey(name)) {
return this.reservedWordsMappings().get(name);
}
return "_" + name;
}
@Override
public String toParamName(String name) {
// should be the same as variable name
return toVarName(name);
}
@Override
public String toVarName(String name) {
// sanitize name
name = sanitizeName(name);
if ("_".equals(name)) {
name = "_u";
}
// if it's all uppper case, do nothing
if (name.matches("^[A-Z_]*$")) {
return name;
}
name = getNameUsingModelPropertyNaming(name);
// for reserved word or word starting with number, append _
if (isReservedWord(name) || name.matches("^\\d.*")) {
name = escapeReservedWord(name);
}
return name;
}
@Override
public String toModelName(String name) {
name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
if (!StringUtils.isEmpty(modelNamePrefix)) {
name = modelNamePrefix + "_" + name;
}
if (!StringUtils.isEmpty(modelNameSuffix)) {
name = name + "_" + modelNameSuffix;
}
// model name cannot use reserved keyword, e.g. return
if (isReservedWord(name)) {
String modelName = camelize("model_" + name);
LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + modelName);
return modelName;
}
// model name starts with number
if (name.matches("^\\d.*")) {
String modelName = camelize("model_" + name); // e.g. 200Response => Model200Response (after camelize)
LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + modelName);
return modelName;
}
if (languageSpecificPrimitives.contains(name)) {
String modelName = camelize("model_" + name);
LOGGER.warn(name + " (model name matches existing language type) cannot be used as a model name. Renamed to " + modelName);
return modelName;
}
// camelize the model name
// phone_number => PhoneNumber
return camelize(name);
}
@Override
public String toModelFilename(String name) {
// should be the same as the model name
return toModelName(name);
}
@Override
protected String getParameterDataType(Parameter parameter, Schema p) {
// handle enums of various data types
Schema inner;
if (ModelUtils.isArraySchema(p)) {
ArraySchema mp1 = (ArraySchema) p;
inner = mp1.getItems();
return this.getSchemaType(p) + "<" + this.getParameterDataType(parameter, inner) + ">";
} else if (ModelUtils.isMapSchema(p)) {
inner = (Schema) p.getAdditionalProperties();
return "{ [key: string]: " + this.getParameterDataType(parameter, inner) + "; }";
} else if (ModelUtils.isStringSchema(p)) {
// Handle string enums
if (p.getEnum() != null) {
return enumValuesToEnumTypeUnion(p.getEnum(), "string");
}
} else if (ModelUtils.isIntegerSchema(p)) {
// Handle integer enums
if (p.getEnum() != null) {
return numericEnumValuesToEnumTypeUnion(new ArrayList<Number>(p.getEnum()));
}
} else if (ModelUtils.isNumberSchema(p)) {
// Handle double enums
if (p.getEnum() != null) {
return numericEnumValuesToEnumTypeUnion(new ArrayList<Number>(p.getEnum()));
}
}
/* TODO revise the logic below
else if (ModelUtils.isDateSchema(p)) {
// Handle date enums
DateSchema sp = (DateSchema) p;
if (sp.getEnum() != null) {
return enumValuesToEnumTypeUnion(sp.getEnum(), "string");
}
} else if (ModelUtils.isDateTimeSchema(p)) {
// Handle datetime enums
DateTimeSchema sp = (DateTimeSchema) p;
if (sp.getEnum() != null) {
return enumValuesToEnumTypeUnion(sp.getEnum(), "string");
}
}*/
return this.getTypeDeclaration(p);
}
/**
* Converts a list of strings to a literal union for representing enum values as a type.
* Example output: 'available' | 'pending' | 'sold'
*
* @param values list of allowed enum values
* @param dataType either "string" or "number"
* @return a literal union for representing enum values as a type
*/
protected String enumValuesToEnumTypeUnion(List<String> values, String dataType) {
StringBuilder b = new StringBuilder();
boolean isFirst = true;
for (String value : values) {
if (!isFirst) {
b.append(" | ");
}
b.append(toEnumValue(value.toString(), dataType));
isFirst = false;
}
return b.toString();
}
/**
* Converts a list of numbers to a literal union for representing enum values as a type.
* Example output: 3 | 9 | 55
*
* @param values a list of numbers
* @return a literal union for representing enum values as a type
*/
protected String numericEnumValuesToEnumTypeUnion(List<Number> values) {
List<String> stringValues = new ArrayList<>();
for (Number value : values) {
stringValues.add(value.toString());
}
return enumValuesToEnumTypeUnion(stringValues, "number");
}
@Override
public String toDefaultValue(Schema p) {
if (ModelUtils.isBooleanSchema(p)) {
return UNDEFINED_VALUE;
} else if (ModelUtils.isDateSchema(p)) {
return UNDEFINED_VALUE;
} else if (ModelUtils.isDateTimeSchema(p)) {
return UNDEFINED_VALUE;
} else if (ModelUtils.isNumberSchema(p)) {
if (p.getDefault() != null) {
return p.getDefault().toString();
}
return UNDEFINED_VALUE;
} else if (ModelUtils.isIntegerSchema(p)) {
if (p.getDefault() != null) {
return p.getDefault().toString();
}
return UNDEFINED_VALUE;
} else if (ModelUtils.isStringSchema(p)) {
if (p.getDefault() != null) {
return "'" + (String) p.getDefault() + "'";
}
return UNDEFINED_VALUE;
} else {
return UNDEFINED_VALUE;
}
}
@Override
protected boolean isReservedWord(String word) {
// NOTE: This differs from super's implementation in that TypeScript does _not_ want case insensitive matching.
return reservedWords.contains(word);
}
@Override
public String getSchemaType(Schema p) {
String openAPIType = super.getSchemaType(p);
String type = null;
if (typeMapping.containsKey(openAPIType)) {
type = typeMapping.get(openAPIType);
if (languageSpecificPrimitives.contains(type))
return type;
} else
type = openAPIType;
return toModelName(type);
}
@Override
public String toOperationId(String operationId) {
// throw exception if method name is empty
if (StringUtils.isEmpty(operationId)) {
throw new RuntimeException("Empty method name (operationId) not allowed");
}
// method name cannot use reserved keyword, e.g. return
// append _ at the beginning, e.g. _return
if (isReservedWord(operationId)) {
return escapeReservedWord(camelize(sanitizeName(operationId), true));
}
return camelize(sanitizeName(operationId), true);
}
public void setModelPropertyNaming(String naming) {
if ("original".equals(naming) || "camelCase".equals(naming) ||
"PascalCase".equals(naming) || "snake_case".equals(naming)) {
this.modelPropertyNaming = naming;
} else {
throw new IllegalArgumentException("Invalid model property naming '" +
naming + "'. Must be 'original', 'camelCase', " +
"'PascalCase' or 'snake_case'");
}
}
public String getModelPropertyNaming() {
return this.modelPropertyNaming;
}
public String getNameUsingModelPropertyNaming(String name) {
switch (CodegenConstants.MODEL_PROPERTY_NAMING_TYPE.valueOf(getModelPropertyNaming())) {
case original:
return name;
case camelCase:
return camelize(name, true);
case PascalCase:
return camelize(name);
case snake_case:
return underscore(name);
default:
throw new IllegalArgumentException("Invalid model property naming '" +
name + "'. Must be 'original', 'camelCase', " +
"'PascalCase' or 'snake_case'");
}
}
@Override
public String toEnumValue(String value, String datatype) {
if ("number".equals(datatype)) {
return value;
} else {
return "\'" + escapeText(value) + "\'";
}
}
@Override
public String toEnumDefaultValue(String value, String datatype) {
return datatype + "_" + value;
}
@Override
public String toEnumVarName(String name, String datatype) {
if (name.length() == 0) {
return "Empty";
}
// for symbol, e.g. $, #
if (getSymbolName(name) != null) {
return camelize(getSymbolName(name));
}
// number
if ("number".equals(datatype)) {
String varName = "NUMBER_" + name;
varName = varName.replaceAll("-", "MINUS_");
varName = varName.replaceAll("\\+", "PLUS_");
varName = varName.replaceAll("\\.", "_DOT_");
return varName;
}
// string
String enumName = sanitizeName(name);
enumName = enumName.replaceFirst("^_", "");
enumName = enumName.replaceFirst("_$", "");
// camelize the enum variable name
// ref: https://basarat.gitbooks.io/typescript/content/docs/enums.html
enumName = camelize(enumName);
if (enumName.matches("\\d.*")) { // starts with number
return "_" + enumName;
} else {
return enumName;
}
}
@Override
public String toEnumName(CodegenProperty property) {
String enumName = toModelName(property.name) + "Enum";
if (enumName.matches("\\d.*")) { // starts with number
return "_" + enumName;
} else {
return enumName;
}
}
@Override
public Map<String, Object> postProcessModels(Map<String, Object> objs) {
// process enum in models
List<Map<String, Object>> models = (List<Map<String, Object>>) postProcessModelsEnum(objs).get("models");
for (Object _mo : models) {
Map<String, Object> mo = (Map<String, Object>) _mo;
CodegenModel cm = (CodegenModel) mo.get("model");
cm.imports = new TreeSet(cm.imports);
// name enum with model name, e.g. StatusEnum => Pet.StatusEnum
for (CodegenProperty var : cm.vars) {
if (Boolean.TRUE.equals(var.isEnum)) {
var.datatypeWithEnum = var.datatypeWithEnum.replace(var.enumName, cm.classname + var.enumName);
}
}
if (cm.parent != null) {
for (CodegenProperty var : cm.allVars) {
if (Boolean.TRUE.equals(var.isEnum)) {
var.datatypeWithEnum = var.datatypeWithEnum
.replace(var.enumName, cm.classname + var.enumName);
}
}
}
}
for (Map<String, Object> mo : models) {
CodegenModel cm = (CodegenModel) mo.get("model");
// Add additional filename information for imports
mo.put("tsImports", toTsImports(cm, cm.imports));
}
return objs;
}
private List<Map<String, String>> toTsImports(CodegenModel cm, Set<String> imports) {
List<Map<String, String>> tsImports = new ArrayList<>();
for (String im : imports) {
if (!im.equals(cm.classname)) {
HashMap<String, String> tsImport = new HashMap<>();
// TVG: This is used as class name in the import statements of the model file
tsImport.put("classname", im);
tsImport.put("filename", toModelFilename(im));
tsImports.add(tsImport);
}
}
return tsImports;
}
@Override
public Map<String, Object> postProcessAllModels(Map<String, Object> objs) {
Map<String, Object> result = super.postProcessAllModels(objs);
for (Map.Entry<String, Object> entry : result.entrySet()) {
Map<String, Object> inner = (Map<String, Object>) entry.getValue();
List<Map<String, Object>> models = (List<Map<String, Object>>) inner.get("models");
for (Map<String, Object> mo : models) {
CodegenModel cm = (CodegenModel) mo.get("model");
if (cm.discriminator != null && cm.children != null) {
for (CodegenModel child : cm.children) {
this.setDiscriminatorValue(child, cm.discriminator.getPropertyName(), this.getDiscriminatorValue(child));
}
}
}
}
return result;
}
private void setDiscriminatorValue(CodegenModel model, String baseName, String value) {
for (CodegenProperty prop : model.allVars) {
if (prop.baseName.equals(baseName)) {
prop.discriminatorValue = value;
}
}
if (model.children != null) {
final boolean newDiscriminator = model.discriminator != null;
for (CodegenModel child : model.children) {
this.setDiscriminatorValue(child, baseName, newDiscriminator ? value : this.getDiscriminatorValue(child));
}
}
}
private String getDiscriminatorValue(CodegenModel model) {
return model.vendorExtensions.containsKey(X_DISCRIMINATOR_TYPE) ?
(String) model.vendorExtensions.get(X_DISCRIMINATOR_TYPE) : model.classname;
}
@Override
public String escapeQuotationMark(String input) {
// remove ', " to avoid code injection
return input.replace("\"", "").replace("'", "");
}
@Override
public String escapeUnsafeCharacters(String input) {
return input.replace("*/", "*_/").replace("/*", "/_*");
}
@Override
public String getName() {
return "typescript";
}
@Override
public String getHelp() {
return "Generates a TypeScript client library using Fetch API (beta).";
}
@Override
public void processOpts() {
super.processOpts();
if (additionalProperties.containsKey(CodegenConstants.MODEL_PROPERTY_NAMING)) {
setModelPropertyNaming((String) additionalProperties.get(CodegenConstants.MODEL_PROPERTY_NAMING));
}
convertPropertyToBooleanAndWriteBack(CodegenConstants.SUPPORTS_ES6);
// change package names
apiPackage = this.apiPackage + ".apis";
modelPackage = this.modelPackage + ".models";
testPackage = this.testPackage + ".tests";
additionalProperties.putIfAbsent(FRAMEWORK_SWITCH, FRAMEWORKS[0]);
supportingFiles.add(new SupportingFile(
"generators" + File.separator + additionalProperties.get(FRAMEWORK_SWITCH) + ".mustache",
"index.ts"
));
String httpLibName = this.getHttpLibForFramework(additionalProperties.get(FRAMEWORK_SWITCH).toString());
supportingFiles.add(new SupportingFile(
"http" + File.separator + httpLibName + ".mustache",
"http", httpLibName + ".ts"
));
Object propPlatform = additionalProperties.get(PLATFORM_SWITCH);
if (propPlatform == null) {
propPlatform = "browser";
additionalProperties.put("platform", propPlatform);
}
Map<String, Boolean> platforms = new HashMap<>();
for (String platform: PLATFORMS) {
platforms.put(platform, platform.equals(propPlatform));
}
additionalProperties.put("platforms", platforms);
additionalProperties.putIfAbsent(FILE_CONTENT_DATA_TYPE, propPlatform.equals("node") ? "Buffer" : "Blob");
final boolean useRxJS = convertPropertyToBooleanAndWriteBack(USE_RXJS_SWITCH);
if (!useRxJS) {
supportingFiles.add(new SupportingFile("rxjsStub.mustache", "", "rxjsStub.ts"));
}
}
private String getHttpLibForFramework(String object) {
return this.frameworkToHttpLibMap.get(object);
}
@Override
public String getTypeDeclaration(Schema p) {
Schema inner;
if (ModelUtils.isArraySchema(p)) {
inner = ((ArraySchema) p).getItems();
return this.getSchemaType(p) + "<" + this.getTypeDeclaration(inner) + ">";
} else if (ModelUtils.isMapSchema(p)) {
inner = (Schema) p.getAdditionalProperties();
return "{ [key: string]: " + this.getTypeDeclaration(inner) + "; }";
} else if (ModelUtils.isFileSchema(p)) {
// TODO: Change type declaration
return "HttpFile";
} else if (ModelUtils.isBinarySchema(p)) {
return "any";
} else {
return super.getTypeDeclaration(p);
}
}
@Override
protected void addAdditionPropertiesToCodeGenModel(CodegenModel codegenModel, Schema schema) {
codegenModel.additionalPropertiesType = getTypeDeclaration((Schema) schema.getAdditionalProperties());
addImport(codegenModel, codegenModel.additionalPropertiesType);
}
}

View File

@@ -1,7 +1,5 @@
# {{classname}}
{{#description}}{{&description}}
{{/description}}
## Properties
Name | Type | Description | Notes

View File

@@ -109,6 +109,7 @@ org.openapitools.codegen.languages.StaticHtml2Generator
org.openapitools.codegen.languages.SwiftClientCodegen
org.openapitools.codegen.languages.Swift3Codegen
org.openapitools.codegen.languages.Swift4Codegen
org.openapitools.codegen.languages.TypeScriptClientCodegen
org.openapitools.codegen.languages.TypeScriptAngularClientCodegen
org.openapitools.codegen.languages.TypeScriptAngularJsClientCodegen
org.openapitools.codegen.languages.TypeScriptAureliaClientCodegen

View File

@@ -1,8 +1,6 @@
{{#models}}
{{#model}}
# {{{packageName}}}.{{modelPackage}}.{{{classname}}}
{{#description}}{{&description}}
{{/description}}
## Properties
Name | Type | Description | Notes

View File

@@ -19,7 +19,6 @@ module {{title}}.API
, {{title}}Backend(..)
, create{{title}}Client
, run{{title}}Server
, run{{title}}MiddlewareServer
, run{{title}}Client
, run{{title}}ClientWithManager
, call{{title}}
@@ -52,7 +51,6 @@ import GHC.Generics (Generic)
import Network.HTTP.Client (Manager, newManager)
import Network.HTTP.Client.TLS (tlsManagerSettings)
import Network.HTTP.Types.Method (methodOptions)
import Network.Wai (Middleware)
import qualified Network.Wai.Handler.Warp as Warp
import Servant (ServerError, serve)
import Servant.API
@@ -61,8 +59,7 @@ import Servant.Client (ClientEnv, Scheme (Http), C
mkClientEnv, parseBaseUrl)
import Servant.Client.Core (baseUrlPort, baseUrlHost)
import Servant.Client.Internal.HttpClient (ClientM (..))
import Servant.Server (Handler (..)){{#serveStatic}}
import Servant.Server.StaticFiles (serveDirectoryFileServer){{/serveStatic}}
import Servant.Server (Handler (..))
import Web.FormUrlEncoded
import Web.HttpApiData
@@ -132,8 +129,7 @@ formatSeparatedQueryList char = T.intercalate (T.singleton char) . map toQueryPa
type {{title}}API
= {{#apis}}{{#operations}}{{#operation}}{{& vendorExtensions.x-routeType}} -- '{{operationId}}' route{{#hasMore}}
:<|> {{/hasMore}}{{/operation}}{{/operations}}{{#hasMore}}
:<|> {{/hasMore}}{{/apis}}{{#serveStatic}}
:<|> Raw {{/serveStatic}}
:<|> {{/hasMore}}{{/apis}}
{{/apiInfo}}
@@ -153,7 +149,7 @@ newtype {{title}}ClientError = {{title}}ClientError ClientError
-- | Backend for {{title}}.
-- The backend can be used both for the client and the server. The client generated from the {{title}} OpenAPI spec
-- is a backend that executes actions by sending HTTP requests (see @create{{title}}Client@). Alternatively, provided
-- a backend, the API can be served using @run{{title}}MiddlewareServer@.
-- a backend, the API can be served using @run{{title}}Server@.
data {{title}}Backend m = {{title}}Backend
{ {{#apis}}{{#operations}}{{#operation}}{{operationId}} :: {{& vendorExtensions.x-clientType}}{- ^ {{& notes}} -}{{#hasMore}}
, {{/hasMore}}{{/operation}}{{/operations}}{{#hasMore}}
@@ -185,8 +181,7 @@ create{{title}}Client = {{title}}Backend{..}
where
({{#apis}}{{#operations}}{{#operation}}(coerce -> {{operationId}}){{#hasMore}} :<|>
{{/hasMore}}{{/operation}}{{/operations}}{{#hasMore}} :<|>
{{/hasMore}}{{/apis}}{{#serveStatic}} :<|>
_{{/serveStatic}}) = client (Proxy :: Proxy {{title}}API)
{{/hasMore}}{{/apis}}) = client (Proxy :: Proxy {{title}}API)
-- | Run requests in the {{title}}Client monad.
run{{title}}Client :: Config -> {{title}}Client a -> ExceptT ClientError IO a
@@ -212,31 +207,20 @@ call{{title}} env f = do
Right response -> pure response
{{/apiInfo}}
{{#apiInfo}}
requestMiddlewareId :: Application -> Application
requestMiddlewareId a = a
-- | Run the {{title}} server at the provided host and port.
run{{title}}Server
:: (MonadIO m, MonadThrow m)
=> Config -> {{title}}Backend (ExceptT ServerError IO) -> m ()
run{{title}}Server config backend = run{{title}}MiddlewareServer config requestMiddlewareId backend
-- | Run the {{title}} server at the provided host and port.
run{{title}}MiddlewareServer
:: (MonadIO m, MonadThrow m)
=> Config -> Middleware -> {{title}}Backend (ExceptT ServerError IO) -> m ()
run{{title}}MiddlewareServer Config{..} middleware backend = do
=> Config -> {{title}}Backend (ExceptT ServerError IO) -> m ()
run{{title}}Server Config{..} backend = do
url <- parseBaseUrl configUrl
let warpSettings = Warp.defaultSettings
& Warp.setPort (baseUrlPort url)
& Warp.setHost (fromString $ baseUrlHost url)
liftIO $ Warp.runSettings warpSettings $ middleware $ serve (Proxy :: Proxy {{title}}API) (serverFromBackend backend)
liftIO $ Warp.runSettings warpSettings $ serve (Proxy :: Proxy {{title}}API) (serverFromBackend backend)
where
serverFromBackend {{title}}Backend{..} =
({{#apis}}{{#operations}}{{#operation}}coerce {{operationId}}{{#hasMore}} :<|>
{{/hasMore}}{{/operation}}{{/operations}}{{#hasMore}} :<|>
{{/hasMore}}{{/apis}}{{#serveStatic}} :<|>
serveDirectoryFileServer "static"{{/serveStatic}})
{{/hasMore}}{{/apis}})
{{/apiInfo}}

View File

@@ -58,7 +58,7 @@ main = do
## Creating a Server
In order to create a server, you must use the `run{{title}}MiddlewareServer` function. However, you unlike the client, in which case you *got* a `{{title}}Backend`
In order to create a server, you must use the `run{{title}}Server` function. However, you unlike the client, in which case you *got* a `{{title}}Backend`
from the library, you must instead *provide* a `{{title}}Backend`. For example, if you have defined handler functions for all the
functions in `{{title}}.Handlers`, you can write:
@@ -66,24 +66,14 @@ functions in `{{title}}.Handlers`, you can write:
{-# LANGUAGE RecordWildCards #-}
import {{title}}.API
-- required dependency: wai
import Network.Wai (Middleware)
-- required dependency: wai-extra
import Network.Wai.Middleware.RequestLogger (logStdout)
-- A module you wrote yourself, containing all handlers needed for the {{title}}Backend type.
import {{title}}.Handlers
-- If you would like to not use any middlewares you could use run{{title}}Server instead
-- Combined middlewares
requestMiddlewares :: Middleware
requestMiddlewares = logStdout
-- Run a {{title}} server on localhost:8080
main :: IO ()
main = do
let server = {{title}}Backend{..}
config = Config "http://localhost:8080/"
run{{title}}MiddlewareServer config requestMiddlewares server
run{{title}}Server config server
```

View File

@@ -28,7 +28,6 @@ library
, servant-client-core
, servant-server
, servant
, wai
, warp
, transformers
, mtl

View File

@@ -347,19 +347,18 @@ class ApiClient(object):
response_type, auth_settings,
_return_http_data_only, collection_formats,
_preload_content, _request_timeout, _host)
return self.pool.apply_async(self.__call_api, (resource_path,
method, path_params,
query_params,
header_params, body,
post_params, files,
response_type,
auth_settings,
_return_http_data_only,
collection_formats,
_preload_content,
_request_timeout,
_host))
else:
thread = self.pool.apply_async(self.__call_api, (resource_path,
method, path_params, query_params,
header_params, body,
post_params, files,
response_type, auth_settings,
_return_http_data_only,
collection_formats,
_preload_content,
_request_timeout,
_host))
return thread
def request(self, method, url, query_params=None, headers=None,
post_params=None, body=None, _preload_content=True,

View File

@@ -1,7 +1,5 @@
{{#models}}{{#model}}# {{classname}}
{{#description}}{{&description}}
{{/description}}
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------

View File

@@ -1,7 +1,5 @@
{{#models}}{{#model}}# {{classname}}
{{#description}}{{&description}}
{{/description}}
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------

View File

@@ -1,11 +1,11 @@
Package: {{{packageName}}}
Title: R Package Client for {{{appName}}}
Version: {{packageVersion}}
Authors@R: person("{{#infoName}}{{infoName}}{{/infoName}}{{^infoName}}OpenAPI Generator community{{/infoName}}", email = "{{#infoEmail}}{{infoEmail}}{{/infoEmail}}{{^infoEmail}}team@openapitools.org{{/infoEmail}}", role = c("aut", "cre"))
Authors@R: person("OpenAPI Generator community", email = "team@openapitools.org", role = c("aut", "cre"))
Description: {{{appDescription}}}{{^appDescription}}R Package Client for {{{appName}}}{{/appDescription}}
Depends: R (>= 3.3.3)
Encoding: UTF-8
License: {{#licenseInfo}}{{licenseInfo}}{{/licenseInfo}}{{^licenseInfo}}Unlicense{{/licenseInfo}}
License: Unlicense
LazyData: true
Suggests: testthat
Imports: jsonlite, httr, R6, caTools{{#useRlangExceptionHandling}}, rlang{{/useRlangExceptionHandling}}

View File

@@ -1,7 +1,5 @@
{{#models}}{{#model}}# {{packageName}}::{{classname}}
{{#description}}{{&description}}
{{/description}}
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------

View File

@@ -1,4 +1,5 @@
// tslint:disable
/// <reference path="./custom.d.ts" />
{{>licenseInfo}}
{{^withSeparateModelsAndApi}}

View File

@@ -1,5 +1,6 @@
{{#withSeparateModelsAndApi}}
// tslint:disable
/// <reference path="{{apiRelativeToRoot}}custom.d.ts" />
{{>licenseInfo}}
import * as globalImportUrl from 'url';

View File

@@ -1,4 +1,5 @@
// tslint:disable
/// <reference path="./custom.d.ts" />
{{>licenseInfo}}
import { Configuration } from "./configuration";

View File

@@ -0,0 +1 @@
declare module 'url';

View File

@@ -1,4 +1,5 @@
// tslint:disable
/// <reference path="{{modelRelativeToRoot}}custom.d.ts" />
{{>licenseInfo}}
{{#withSeparateModelsAndApi}}{{#imports}}
import { {{class}} } from './{{filename}}';{{/imports}}{{/withSeparateModelsAndApi}}

View File

@@ -21,8 +21,8 @@
"axios": "^0.18.0"
},
"devDependencies": {
"@types/node": "^12.11.5",
"typescript": "^3.6.4"
"@types/node": "^8.0.9",
"typescript": "^2.4"
}{{#npmRepository}},{{/npmRepository}}
{{#npmRepository}}
"publishConfig": {

View File

@@ -0,0 +1 @@
dist

View File

@@ -0,0 +1 @@
readme

View File

@@ -0,0 +1,190 @@
// TODO: better import syntax?
import { BaseAPIRequestFactory, RequiredError } from './baseapi';
import {Configuration} from '../configuration';
import { RequestContext, HttpMethod, ResponseContext, HttpFile} from '../http/http';
{{#platforms}}
{{#node}}
import * as FormData from "form-data";
{{/node}}
{{/platforms}}
import {ObjectSerializer} from '../models/ObjectSerializer';
import {ApiException} from './exception';
import {isCodeInRange} from '../util';
{{#imports}}
import { {{classname}} } from '..{{filename}}';
{{/imports}}
{{#operations}}
/**
* {{#description}}{{{description}}}{{/description}}{{^description}}no description{{/description}}
*/
export class {{classname}}RequestFactory extends BaseAPIRequestFactory {
{{#operation}}
/**
{{#notes}}
* {{&notes}}
{{/notes}}
{{#summary}}
* {{&summary}}
{{/summary}}
{{#allParams}}
* @param {{paramName}} {{description}}
{{/allParams}}
*/
public {{nickname}}({{#allParams}}{{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, {{/allParams}}options?: Configuration): RequestContext {
let config = options || this.configuration;
{{#allParams}}
{{#required}}
// verify required parameter '{{paramName}}' is not null or undefined
if ({{paramName}} === null || {{paramName}} === undefined) {
throw new RequiredError('Required parameter {{paramName}} was null or undefined when calling {{nickname}}.');
}
{{/required}}
{{/allParams}}
// Path Params
const localVarPath = '{{{path}}}'{{#pathParams}}
.replace('{' + '{{baseName}}' + '}', encodeURIComponent(String({{paramName}}))){{/pathParams}};
// Make Request Context
const requestContext = config.baseServer.makeRequestContext(localVarPath, HttpMethod.{{httpMethod}});
requestContext.setHeaderParam("Accept", "application/json")
// Query Params
{{#queryParams}}
if ({{paramName}} !== undefined) {
requestContext.setQueryParam("{{baseName}}", ObjectSerializer.serialize({{paramName}}, "{{{dataType}}}", "{{dataFormat}}"));
}
{{/queryParams}}
// Header Params
{{#headerParams}}
requestContext.setHeaderParam("{{baseName}}", ObjectSerializer.serialize({{paramName}}, "{{{dataType}}}", "{{dataFormat}}"));
{{/headerParams}}
// Form Params
{{#hasFormParams}}
let localVarFormParams = new FormData();
{{/hasFormParams}}
{{#formParams}}
{{#isListContainer}}
if ({{paramName}}) {
{{#isCollectionFormatMulti}}
{{paramName}}.forEach((element) => {
localVarFormParams.append('{{baseName}}', element as any);
})
{{/isCollectionFormatMulti}}
{{^isCollectionFormatMulti}}
// TODO: replace .append with .set
localVarFormParams.append('{{baseName}}', {{paramName}}.join(COLLECTION_FORMATS["{{collectionFormat}}"]));
{{/isCollectionFormatMulti}}
}
{{/isListContainer}}
{{^isListContainer}}
if ({{paramName}} !== undefined) {
// TODO: replace .append with .set
{{^isFile}}
localVarFormParams.append('{{baseName}}', {{paramName}} as any);
{{/isFile}}
{{#isFile}}
localVarFormParams.append('{{baseName}}', {{paramName}}.data, {{paramName}}.name);
{{/isFile}}
}
{{/isListContainer}}
{{/formParams}}
{{#hasFormParams}}
requestContext.setBody(localVarFormParams);
{{/hasFormParams}}
// Body Params
{{#bodyParam}}
{{^consumes}}
requestContext.setHeaderParam("Content-Type", "application/json");
{{/consumes}}
{{#consumes.0}}
requestContext.setHeaderParam("Content-Type", "{{{mediaType}}}");
{{/consumes.0}}
// TODO: Should this be handled by ObjectSerializer? imo yes => confidential information included in local object should not be sent
const needsSerialization = (<any>"{{dataType}}" !== "string") || requestContext.getHeaders()['Content-Type'] === 'application/json';
const serializedBody = needsSerialization ? JSON.stringify({{paramName}} || {}) : ({{paramName}}.toString() || ""); // TODO: `toString` call is unnecessary
requestContext.setBody(serializedBody);
{{/bodyParam}}
{{#hasAuthMethods}}
let authMethod = null;
{{/hasAuthMethods}}
// Apply auth methods
{{#authMethods}}
authMethod = config.authMethods["{{name}}"]
if (authMethod) {
authMethod.applySecurityAuthentication(requestContext);
}
{{/authMethods}}
return requestContext;
}
{{/operation}}
}
{{/operations}}
{{#operations}}
export class {{classname}}ResponseProcessor {
{{#operation}}
/**
* Unwraps the actual response sent by the server from the response context and deserializes the response content
* to the expected objects
*
* @params response Response returned by the server for a request to {{nicknam}}
* @throws ApiException if the response code was not in [200, 299]
*/
public {{nickname}}(response: ResponseContext): {{#returnType}} {{{returnType}}}{{/returnType}} {{^returnType}} void {{/returnType}} {
{{#responses}}
if (isCodeInRange("{{code}}", response.httpStatusCode)) {
{{#dataType}}
const jsonBody = JSON.parse(response.body);
const body: {{{dataType}}} = ObjectSerializer.deserialize(jsonBody, "{{{dataType}}}", "{{returnFormat}}") as {{{dataType}}};
{{#isSuccessCode}}
return body;
{{/isSuccessCode}}
{{^isSuccessCode}}
throw new ApiException<{{{dataType}}}>({{code}}, body);
{{/isSuccessCode}}
{{/dataType}}
{{^dataType}}
{{#isSuccessCode}}
return;
{{/isSuccessCode}}
{{^isSuccessCode}}
throw new ApiException<string>(response.httpStatusCode, "{{message}}");
{{/isSuccessCode}}
{{/dataType}}
}
{{/responses}}
// Work around for incorrect api specification in petstore.yaml
if (response.httpStatusCode >= 200 && response.httpStatusCode <= 299) {
{{#returnType}}
const jsonBody = JSON.parse(response.body);
const body: {{{returnType}}} = ObjectSerializer.deserialize(jsonBody, "{{{returnType}}}", "{{returnFormat}}") as {{{returnType}}};
return body;
{{/returnType}}
{{^returnType}}
return;
{{/returnType}}
}
let body = response.body || "";
throw new ApiException<string>(response.httpStatusCode, "Unknown API Status Code!\nBody: \"" + body + "\"");
}
{{/operation}}
}
{{/operations}}

View File

@@ -0,0 +1,37 @@
import { Configuration } from '../configuration'
/**
*
* @export
*/
export const COLLECTION_FORMATS = {
csv: ",",
ssv: " ",
tsv: "\t",
pipes: "|",
};
/**
*
* @export
* @class BaseAPI
*/
export class BaseAPIRequestFactory {
constructor(protected configuration: Configuration) {
}
};
/**
*
* @export
* @class RequiredError
* @extends {Error}
*/
export class RequiredError extends Error {
name: "RequiredError" = "RequiredError";
constructor(public field: string, msg?: string) {
super(msg);
}
}

View File

@@ -0,0 +1,14 @@
/**
* Represents an error caused by an api call i.e. it has attributes for a HTTP status code
* and the returned body object.
*
* Example
* API returns a ErrorMessageObject whenever HTTP status code is not in [200, 299]
* => ApiException(404, someErrorMessageObject)
*
*/
export class ApiException<T> extends Error {
public constructor(public code: number, public body: T) {
super("HTTP-Code: " + code + "\nMessage: " + JSON.stringify(body))
}
}

View File

@@ -0,0 +1,66 @@
import {RequestContext, ResponseContext} from './http/http';
import { Observable, from } from {{#useRxJS}}'rxjs'{{/useRxJS}}{{^useRxJS}}'./rxjsStub'{{/useRxJS}};
/**
* Defines the contract for a middleware intercepting requests before
* they are sent (but after the RequestContext was created)
* and before the ResponseContext is unwrapped.
*
*/
export interface Middleware {
/**
* Modifies the request before the request is sent.
*
* @param context RequestContext of a request which is about to be sent to the server
* @returns an observable of the updated request context
*
*/
pre(context: RequestContext): Observable<RequestContext>;
/**
* Modifies the returned response before it is deserialized.
*
* @param context ResponseContext of a sent request
* @returns an observable of the modified response context
*/
post(context: ResponseContext): Observable<ResponseContext>;
}
export class PromiseMiddlewareWrapper implements Middleware {
public constructor(private middleware: PromiseMiddleware) {
}
pre(context: RequestContext): Observable<RequestContext> {
return from(this.middleware.pre(context));
}
post(context: ResponseContext): Observable<ResponseContext> {
return from(this.middleware.post(context));
}
}
/**
* Defines the contract for a middleware intercepting requests before
* they are sent (but after the RequestContext was created)
* and before the ResponseContext is unwrapped.
*
*/
export interface PromiseMiddleware {
/**
* Modifies the request before the request is sent.
*
* @param context RequestContext of a request which is about to be sent to the server
* @returns an observable of the updated request context
*
*/
pre(context: RequestContext): Promise<RequestContext>;
/**
* Modifies the returned response before it is deserialized.
*
* @param context ResponseContext of a sent request
* @returns an observable of the modified response context
*/
post(context: ResponseContext): Promise<ResponseContext>;
}

View File

@@ -0,0 +1,152 @@
import {RequestContext} from '../http/http';
// typings for btoa are incorrect
//@ts-ignore
import * as btoa from "btoa";
/**
* Base class for all authentication schemes.
*
*/
export abstract class SecurityAuthentication {
public constructor(private name: string) {
}
/*
*
* @return returns the name of the security authentication as specified in OAI
*/
public getName(): string {
return this.name;
}
/**
* Applies the authentication scheme to the request context
*
* @params context the request context which should use this authentication scheme
*/
public abstract applySecurityAuthentication(context: RequestContext): void;
}
/**
* Applies no authentication.
*
*/
export class NoAuthentication extends SecurityAuthentication {
public constructor() {
super("_no_auth");
}
public applySecurityAuthentication(_context: RequestContext) {
}
}
/**
* Applies an api key to the request context.
*
*/
export class APIKeyAuthentication extends SecurityAuthentication {
/**
* Configures this api key authentication with the necessary properties
*
* @param authName: name of this authentication scheme as specified in the swagger.json
* @param paramName: Parameter name used for the api key
* @param keyLocation: Parameter location, either query, header or cookie.
* @param apiKey: The api key to be used for every request
*/
public constructor(authName: string, private paramName: string, private keyLocation: "query" | "header" | "cookie", private apiKey: string) {
super(authName);
}
public applySecurityAuthentication(context: RequestContext) {
if (this.keyLocation === "header") {
context.setHeaderParam(this.paramName, this.apiKey);
} else if (this.keyLocation === "cookie") {
context.addCookie(this.paramName, this.apiKey);
} else if (this.keyLocation === "query") {
context.setQueryParam(this.paramName, this.apiKey);
}
}
}
/**
* Applies basic http authentication to a request.
*
*/
export class HttpBasicAuthentication extends SecurityAuthentication {
/**
* Configures the http authentication with the required details.
*
*
* @param authName name of the authentication scheme as defined in swagger json
* @param username username for http basic authentication
* @param password password for http basic authentication
*/
public constructor(authName: string, private username: string, private password: string) {
super(authName);
}
public applySecurityAuthentication(context: RequestContext) {
let comb = this.username + ":" + this.password;
context.setHeaderParam("Authentication", "Basic " + btoa(comb));
}
}
// TODO: How to handle oauth2 authentication!
export class OAuth2Authentication extends SecurityAuthentication {
public constructor(authName: string) {
super(authName);
}
public applySecurityAuthentication(context: RequestContext) {
// TODO
}
}
export type AuthMethods = {
{{#authMethods}}
"{{name}}"?: {{#isApiKey}}APIKeyAuthentication{{/isApiKey}}{{#isHttp}}HttpBasicAuthentication{{/isHttp}}{{#isOAuth}}OAuth2Authentication{{/isOAuth}},
{{/authMethods}}
}
export type ApiKeyConfiguration = string;
export type HttpBasicConfiguration = { "username": string, "password": string };
export type OAuth2Configuration = string;
export type AuthMethodsConfiguration = { {{#authMethods}}"{{name}}"?:{{#isApiKey}}ApiKeyConfiguration{{/isApiKey}}{{#isHttp}}HttpBasicConfiguration{{/isHttp}}{{#isOAuth}}OAuth2Configuration{{/isOAuth}}, {{/authMethods}} }
/**
* Creates the authentication methods from a swagger description.
*
*/
export function configureAuthMethods(conf: AuthMethodsConfiguration | undefined): AuthMethods {
let authMethods: AuthMethods = {
}
if (!conf) {
return authMethods;
}
{{#authMethods}}
if (conf["{{name}}"]) {
{{#isApiKey}}
authMethods["{{name}}"] = new APIKeyAuthentication("{{name}}", "{{keyParamName}}", {{#isKeyInQuery}}"query"{{/isKeyInQuery}}{{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{#isKeyInCookie}}"cookie"{{/isKeyInCookie}}, <string> conf["{{name}}"]);
{{/isApiKey}}
{{#isBasic}}
authMethods["{{name}}"] = new HttpBasicAuthentication("{{name}}", config["{{name}}"]["username"], config["{{name}}"]["password"]);
{{/isBasic}}
{{#isOAuth}}
authMethods["{{name}}"] = new OAuth2Authentication("{{name}}");
{{/isOAuth}}
}
{{/authMethods}}
return authMethods;
}

View File

@@ -0,0 +1,67 @@
import {HttpLibrary} from './http/http';
import {Middleware, PromiseMiddleware, PromiseMiddlewareWrapper} from './middleware';
{{#frameworks}}
{{#fetch-api}}
import {IsomorphicFetchHttpLibrary} from "./http/isomorphic-fetch";
{{/fetch-api}}
{{#jquery}}
import {JQueryHttpLibrary} from "./http/jquery";
{{/jquery}}
{{/frameworks}}
import {ServerConfiguration, server1} from './servers';
import {configureAuthMethods, AuthMethods, AuthMethodsConfiguration} from './auth/auth';
/**
* Inetrface with which a configuration object can be configured.
*
*/
export interface ConfigurationParameters {
/**
* Default server to use
*/
baseServer?: ServerConfiguration<any>;
/**
* HTTP library to use e.g. IsomorphicFetch
*/
httpApi?: HttpLibrary;
/**
* The middlewares which will be applied to requests and responses
*/
middleware?: Middleware[]; // middleware to apply before/after fetch requests
/**
* configures all middlewares using the promise api instead of observables (which Middleware uses)
*/
promiseMiddleware?: PromiseMiddleware[];
/**
* Configuration for the available authentication methods
*/
authMethods?: AuthMethodsConfiguration
}
export class Configuration {
baseServer: ServerConfiguration<any>;
httpApi: HttpLibrary;
middleware: Middleware[];
authMethods: AuthMethods;
/**
* Creates a new configuration object based on the given configuration.
* If a property is not included in conf, a default is used:
* - baseServer: server1
* - httpApi: IsomorphicFetchHttpLibrary
* - middleware: []
* - promiseMiddleware: []
* - authMethods: {}
* @param conf particial configuration
*/
constructor(conf: ConfigurationParameters = {}) {
this.baseServer = conf.baseServer !== undefined ? conf.baseServer : server1;
this.httpApi = conf.httpApi || {{#frameworks}}{{#fetch-api}}new IsomorphicFetchHttpLibrary(){{/fetch-api}}{{#jquery}}new JQueryHttpLibrary{{/jquery}}{{/frameworks}}; // TODO: replace with window.fetch if available?
this.middleware = conf.middleware || [];
this.authMethods = configureAuthMethods(conf.authMethods);
if (conf.promiseMiddleware) {
conf.promiseMiddleware.forEach(m => this.middleware.push(new PromiseMiddlewareWrapper(m)));
}
}
}

View File

@@ -0,0 +1,19 @@
import * as http from './http/http';
import * as auth from './auth/auth';
import {Middleware, PromiseMiddleware} from './middleware';
import * as models from './models/all';
import { Configuration} from './configuration'
import * as apis from './types/PromiseAPI';
import * as exceptions from './apis/exception';
export {
http,
auth,
Middleware,
PromiseMiddleware,
models,
Configuration,
apis,
exceptions
};

View File

@@ -0,0 +1,19 @@
import * as http from './http/http';
import * as auth from './auth/auth';
import {Middleware, PromiseMiddleware} from './middleware';
import * as models from './models/all';
import { Configuration} from './configuration'
import * as apis from './types/PromiseAPI';
import * as exceptions from './apis/exception';
export {
http,
auth,
Middleware,
PromiseMiddleware,
models,
Configuration,
apis,
exceptions
};

View File

@@ -0,0 +1,67 @@
import { ResponseContext, RequestContext, HttpFile } from '../http/http';
import * as models from '../models/all';
import { Configuration} from '../configuration'
import { Observable, of } from {{#useRxJS}}'rxjs'{{/useRxJS}}{{^useRxJS}}'../rxjsStub'{{/useRxJS}};
import {mergeMap, map} from {{#useRxJS}}'rxjs/operators'{{/useRxJS}}{{^useRxJS}}'../rxjsStub'{{/useRxJS}};
{{#models}}
{{#model}}
import { {{name}} } from '../models/{{name}}';
{{/model}}
{{/models}}
{{#apiInfo}}
{{#apis}}
{{#operations}}
import { {{classname}}RequestFactory, {{classname}}ResponseProcessor} from "../apis/{{classname}}";
export class Observable{{classname}} {
private requestFactory: {{classname}}RequestFactory;
private responseProcessor: {{classname}}ResponseProcessor;
private configuration: Configuration;
public constructor(configuration: Configuration, requestFactory?: {{classname}}RequestFactory, responseProcessor?: {{classname}}ResponseProcessor) {
this.configuration = configuration;
this.requestFactory = requestFactory || new {{classname}}RequestFactory(configuration);
this.responseProcessor = responseProcessor || new {{classname}}ResponseProcessor();
}
{{#operation}}
/**
{{#notes}}
* {{&notes}}
{{/notes}}
{{#summary}}
* {{&summary}}
{{/summary}}
{{#allParams}}
* @param {{paramName}} {{description}}
{{/allParams}}
*/
public {{nickname}}({{#allParams}}{{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, {{/allParams}}options?: Configuration): Observable<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}}> {
const requestContext = this.requestFactory.{{nickname}}({{#allParams}}{{paramName}}, {{/allParams}}options);
// build promise chain
let middlewarePreObservable = of(requestContext);
for (let middleware of this.configuration.middleware) {
middlewarePreObservable = middlewarePreObservable.pipe(mergeMap((ctx: RequestContext) => middleware.pre(ctx)));
}
return middlewarePreObservable.pipe(mergeMap((ctx: RequestContext) => this.configuration.httpApi.send(ctx))).
pipe(mergeMap((response: ResponseContext) => {
let middlewarePostObservable = of(response);
for (let middleware of this.configuration.middleware) {
middlewarePostObservable = middlewarePostObservable.pipe(mergeMap((rsp: ResponseContext) => middleware.post(rsp)));
}
return middlewarePostObservable.pipe(map((rsp: ResponseContext) => this.responseProcessor.{{nickname}}(rsp)));
}));
}
{{/operation}}
}
{{/operations}}
{{/apis}}
{{/apiInfo}}

View File

@@ -0,0 +1,49 @@
import { ResponseContext, RequestContext, HttpFile } from '../http/http';
import * as models from '../models/all';
import { Configuration} from '../configuration'
{{#models}}
{{#model}}
import { {{name}} } from '../models/{{name}}';
{{/model}}
{{/models}}
{{#apiInfo}}
{{#apis}}
import { Observable{{classname}} } from './ObservableAPI';
{{#operations}}
import { {{classname}}RequestFactory, {{classname}}ResponseProcessor} from "../apis/{{classname}}";
export class Promise{{classname}} {
private api: Observable{{classname}}
public constructor(configuration: Configuration, requestFactory?: {{classname}}RequestFactory, responseProcessor?: {{classname}}ResponseProcessor) {
this.api = new Observable{{classname}}(configuration, requestFactory, responseProcessor);
}
{{#operation}}
/**
{{#notes}}
* {{&notes}}
{{/notes}}
{{#summary}}
* {{&summary}}
{{/summary}}
{{#allParams}}
* @param {{paramName}} {{description}}
{{/allParams}}
*/
public {{nickname}}({{#allParams}}{{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, {{/allParams}}options?: Configuration): Promise<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}}> {
const result = this.api.{{nickname}}({{#allParams}}{{paramName}}, {{/allParams}}options);
return result.toPromise();
}
{{/operation}}
}
{{/operations}}
{{/apis}}
{{/apiInfo}}

View File

@@ -0,0 +1,52 @@
#!/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"
git_user_id=$1
git_repo_id=$2
release_note=$3
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://github.com/${git_user_id}/${git_repo_id}.git
else
git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${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://github.com/${git_user_id}/${git_repo_id}.git"
git push origin master 2>&1 | grep -v 'To https'

View File

@@ -0,0 +1,151 @@
{{#platforms}}
{{#node}}
// TODO: evaluate if we can easily get rid of this library
import * as FormData from "form-data";
{{/node}}
{{/platforms}}
// typings of url-parse are incorrect...
// @ts-ignore
import * as URLParse from "url-parse";
import { Observable } from {{#useRxJS}}'rxjs'{{/useRxJS}}{{^useRxJS}}'../rxjsStub'{{/useRxJS}};
{{#frameworks}}
{{#fetch-api}}
export * from './isomorphic-fetch';
{{/fetch-api}}
{{#jquery}}
export * from './jquery';
{{/jquery}}
{{/frameworks}}
/**
* Represents a HTTP Method.
*/
export enum HttpMethod {
GET = "GET",
HEAD = "HEAD",
POST = "POST",
PUT = "PUT",
DELETE = "DELETE",
CONNECT = "CONNECT",
OPTIONS = "OPTIONS",
TRACE = "TRACE",
PATCH = "PATCH"
}
/**
* Represents a http file which will be uploaded to a server.
*/
export interface HttpFile {
data: {{{fileContentDataType}}};
name: string;
}
export class HttpException extends Error {
public constructor(msg: string) {
super(msg);
}
}
/**
* Represents a HTTP request context
*
*/
export class RequestContext {
private headers: { [key: string]: string } = {};
private body: string | FormData = "";
private url: URLParse;
/**
* Creates the request context using a http method and request resource url
*
* @param url url of the requested resource
* @param httpMethod http method
*/
public constructor(url: string, private httpMethod: HttpMethod) {
this.url = URLParse(url, true);
}
/*
* Returns the url set in the constructor including the query string
*
*/
public getUrl(): string {
return this.url.toString();
}
/**
* Replaces the url set in the constructor with this url.
*
*/
public setUrl(url: string) {
this.url = URLParse(url, true);
}
/**
* Sets the body of the http request either as a string or FormData
* Setting a body on a HTTP GET request is disallowed under HTTP-Spec 1.1. Section
* 4.3 and this method throws an HttpException accordingly.
*
* @param body the body of the request
*/
public setBody(body: string | FormData) {
// HTTP-Spec 1.1 Section 4.3
if (this.httpMethod === HttpMethod.GET) {
throw new HttpException("Body should not be included in GET-Requests!");
}
// TODO: other http methods
// post is fine either formData or string
this.body = body;
}
public getHttpMethod(): HttpMethod {
return this.httpMethod;
}
public getHeaders(): { [key: string]: string } {
return this.headers;
}
public getBody(): string | FormData {
return this.body;
}
public setQueryParam(name: string, value: string) {
let queryObj = this.url.query;
queryObj[name] = value;
this.url.set("query", queryObj);
}
/**
* Sets a cookie with the name and value. NO check for duplicate cookies is performed
*
*/
public addCookie(name: string, value: string): void {
if (!this.headers["Cookie"]) {
this.headers["Cookie"] = "";
}
this.headers["Cookie"] += name + "=" + value + "; ";
}
public setHeaderParam(key: string, value: string): void {
this.headers[key] = value;
}
}
export class ResponseContext {
public constructor(public httpStatusCode: number,
public headers: { [key: string]: string }, public body: string) {
}
}
export interface HttpLibrary {
send(request: RequestContext): Observable<ResponseContext>;
}

View File

@@ -0,0 +1,35 @@
declare var fetch: any;
import {HttpLibrary, RequestContext, ResponseContext} from './http';
import * as e6p from 'es6-promise'
import { from, Observable } from {{#useRxJS}}'rxjs'{{/useRxJS}}{{^useRxJS}}'../rxjsStub'{{/useRxJS}};
e6p.polyfill();
import 'isomorphic-fetch';
export class IsomorphicFetchHttpLibrary implements HttpLibrary {
public send(request: RequestContext): Observable<ResponseContext> {
let method = request.getHttpMethod().toString();
let body = request.getBody();
const resultPromise = fetch(request.getUrl(), {
method: method,
body: body as any,
headers: request.getHeaders(),
credentials: "same-origin"
}).then((resp: any) => {
// hack
let headers = (resp.headers as any)._headers;
for (let key in headers) {
headers[key] = (headers[key] as Array<string>).join("; ");
}
return resp.text().then((body: string) => {
return new ResponseContext(resp.status, headers, body)
});
});
return from<Promise<ResponseContext>>(resultPromise);
}
}

View File

@@ -0,0 +1,79 @@
import {HttpLibrary, RequestContext, ResponseContext, HttpException} from './http';
import * as e6p from 'es6-promise'
import { from, Observable } from {{#useRxJS}}'rxjs'{{/useRxJS}}{{^useRxJS}}'../rxjsStub'{{/useRxJS}};
e6p.polyfill();
import * as $ from 'jquery';
{{#platforms}}
{{#node}}
import * as FormData from "form-data";
{{/node}}
{{/platforms}}
export class JQueryHttpLibrary implements HttpLibrary {
public send(request: RequestContext): Observable<ResponseContext> {
let method = request.getHttpMethod().toString();
let body = request.getBody();
let headerParams = request.getHeaders()
let requestOptions: any = {
url: request.getUrl(),
type: method,
headers: request.getHeaders(),
processData: false,
xhrFields: { withCredentials: true },
data: body
};
if (request.getHeaders()['Content-Type']) {
requestOptions.contentType = headerParams['Content-Type'];
}
requestOptions.dataFilter = ((headerParams: { [key:string]: string}) => {
return (data: string, type: string) => {
if (headerParams["Accept"] == "application/json" && data == "") {
return "{}"
} else {
return data
}
}
})(headerParams);
if (request.getHeaders()["Cookie"]) {
throw new HttpException("Setting the \"Cookie\"-Header field is blocked by every major browser when using jquery.ajax requests. Please switch to another library like fetch to enable this option");
}
if (body.constructor.name == "FormData") {
requestOptions.contentType = false;
}
const sentRequest = $.ajax(requestOptions);
const resultPromise = new Promise<ResponseContext>((resolve, reject) => {
sentRequest.done((resp, _, jqXHR) => {
const headers = this.getResponseHeaders(jqXHR)
const result = new ResponseContext(jqXHR.status, headers, JSON.stringify(resp));
resolve(result);
})
sentRequest.fail((jqXHR: any) => {
const headers = this.getResponseHeaders(jqXHR)
const result = new ResponseContext(jqXHR.status, headers, jqXHR.responseText);
resolve(result);
})
})
return from(resultPromise);
}
private getResponseHeaders(jqXHR: any): { [key: string]: string } {
const responseHeaders: { [key: string]: string } = {};
var headers = jqXHR.getAllResponseHeaders();
headers = headers.split("\n");
headers.forEach(function (header: any) {
header = header.split(": ");
var key = header.shift();
if (key.length == 0) return
// chrome60+ force lowercase, other browsers can be different
key = key.toLowerCase();
responseHeaders[key] = header.join(": ");
});
return responseHeaders
}
}

View File

@@ -0,0 +1,57 @@
import {RequestContext, HttpMethod} from './http/http';
/**
*
* Represents the configuration of a server including its
* url template and variable configuration based on the url.
*
*/
export class ServerConfiguration<T> {
public constructor(private url: string, private variableConfiguration: T) {
}
/**
* Sets the value of the variables of this server.
*
* @param variableConfiguration a partial variable configuration for the variables contained in the url
*/
public setVariables(variableConfiguration: Partial<T>) {
for (const key in variableConfiguration) {
const val = variableConfiguration[key]
// We know that val isn't undefined here - hopefully
if (val !== undefined) {
this.variableConfiguration[key] = val as T[Extract<keyof T, string>];
}
}
}
public getConfiguration(): T {
return this.variableConfiguration
}
private getUrl() {
let replacedUrl = this.url;
for (const key in this.variableConfiguration) {
var re = new RegExp("{" + key + "}","g");
replacedUrl = replacedUrl.replace(re, this.variableConfiguration[key].toString());
}
return replacedUrl
}
/**
* Creates a new request context for this server using the url with variables
* replaced with their respective values and the endpoint of the request appended.
*
* @param endpoint the endpoint to be queried on the server
* @param httpMethod httpMethod to be used
*
*/
public makeRequestContext(endpoint: string, httpMethod: HttpMethod): RequestContext {
return new RequestContext(this.getUrl() + endpoint, httpMethod);
}
}
{{#servers}}
export const server{{-index}} = new ServerConfiguration<{ {{#variables}} "{{name}}": {{#enumValues}}"{{.}}"{{^-last}} | {{/-last}}{{/enumValues}}{{^enumValues}}string{{/enumValues}}{{^-last}},{{/-last}} {{/variables}} }>("{{url}}", { {{#variables}} "{{name}}": "{{defaultValue}}" {{^-last}},{{/-last}}{{/variables}} })
{{/servers}}

View File

@@ -0,0 +1,11 @@
/**
* {{{appName}}}
* {{{appDescription}}}
*
* {{#version}}OpenAPI spec version: {{{version}}}{{/version}}
* {{#infoEmail}}Contact: {{{infoEmail}}}{{/infoEmail}}
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/

View File

@@ -0,0 +1,165 @@
{{#models}}
{{#model}}
export * from './{{{ classFilename }}}';
{{/model}}
{{/models}}
{{#models}}
{{#model}}
import { {{classname}}{{#hasEnums}}{{#vars}}{{#isEnum}}, {{classname}}{{enumName}} {{/isEnum}} {{/vars}}{{/hasEnums}} } from './{{{ classFilename }}}';
{{/model}}
{{/models}}
/* tslint:disable:no-unused-variable */
let primitives = [
"string",
"boolean",
"double",
"integer",
"long",
"float",
"number",
"any"
];
let enumsMap: Set<string> = new Set<string>([
{{#models}}
{{#model}}
{{#hasEnums}}
{{#vars}}
{{#isEnum}}
"{{classname}}{{enumName}}",
{{/isEnum}}
{{/vars}}
{{/hasEnums}}
{{/model}}
{{/models}}
]);
let typeMap: {[index: string]: any} = {
{{#models}}
{{#model}}
"{{classname}}": {{classname}},
{{/model}}
{{/models}}
}
export class ObjectSerializer {
public static findCorrectType(data: any, expectedType: string) {
if (data == undefined) {
return expectedType;
} else if (primitives.indexOf(expectedType.toLowerCase()) !== -1) {
return expectedType;
} else if (expectedType === "Date") {
return expectedType;
} else {
if (enumsMap.has(expectedType)) {
return expectedType;
}
if (!typeMap[expectedType]) {
return expectedType; // w/e we don't know the type
}
// Check the discriminator
let discriminatorProperty = typeMap[expectedType].discriminator;
if (discriminatorProperty == null) {
return expectedType; // the type does not have a discriminator. use it.
} else {
if (data[discriminatorProperty]) {
var discriminatorType = data[discriminatorProperty];
if(typeMap[discriminatorType]){
return discriminatorType; // use the type given in the discriminator
} else {
return expectedType; // discriminator did not map to a type
}
} else {
return expectedType; // discriminator was not present (or an empty string)
}
}
}
}
public static serialize(data: any, type: string, format: string) {
if (data == undefined) {
return data;
} else if (primitives.indexOf(type.toLowerCase()) !== -1) {
return data;
} else if (type.lastIndexOf("Array<", 0) === 0) { // string.startsWith pre es6
let subType: string = type.replace("Array<", ""); // Array<Type> => Type>
subType = subType.substring(0, subType.length - 1); // Type> => Type
let transformedData: any[] = [];
for (let index in data) {
let date = data[index];
transformedData.push(ObjectSerializer.serialize(date, subType, format));
}
return transformedData;
} else if (type === "Date") {
if (format == "date") {
let month = data.getMonth()+1
month = month < 10 ? "0" + month.toString() : month.toString()
let day = data.getDate();
day = day < 10 ? "0" + day.toString() : day.toString();
return data.getFullYear() + "-" + month + "-" + day;
} else {
return data.toISOString();
}
} else {
if (enumsMap.has(type)) {
return data;
}
if (!typeMap[type]) { // in case we dont know the type
return data;
}
// Get the actual type of this object
type = this.findCorrectType(data, type);
// get the map for the correct type.
let attributeTypes = typeMap[type].getAttributeTypeMap();
let instance: {[index: string]: any} = {};
for (let index in attributeTypes) {
let attributeType = attributeTypes[index];
instance[attributeType.baseName] = ObjectSerializer.serialize(data[attributeType.name], attributeType.type, attributeType.format);
}
return instance;
}
}
public static deserialize(data: any, type: string, format: string) {
// polymorphism may change the actual type.
type = ObjectSerializer.findCorrectType(data, type);
if (data == undefined) {
return data;
} else if (primitives.indexOf(type.toLowerCase()) !== -1) {
return data;
} else if (type.lastIndexOf("Array<", 0) === 0) { // string.startsWith pre es6
let subType: string = type.replace("Array<", ""); // Array<Type> => Type>
subType = subType.substring(0, subType.length - 1); // Type> => Type
let transformedData: any[] = [];
for (let index in data) {
let date = data[index];
transformedData.push(ObjectSerializer.deserialize(date, subType, format));
}
return transformedData;
} else if (type === "Date") {
return new Date(data);
} else {
if (enumsMap.has(type)) {// is Enum
return data;
}
if (!typeMap[type]) { // dont know the type
return data;
}
let instance = new typeMap[type]();
let attributeTypes = typeMap[type].getAttributeTypeMap();
for (let index in attributeTypes) {
let attributeType = attributeTypes[index];
instance[attributeType.name] = ObjectSerializer.deserialize(data[attributeType.baseName], attributeType.type, attributeType.format);
}
return instance;
}
}
}

View File

@@ -0,0 +1,78 @@
{{>licenseInfo}}
{{#models}}
{{#model}}
{{#tsImports}}
import { {{classname}} } from './{{filename}}';
{{/tsImports}}
{{#description}}
/**
* {{{description}}}
*/
{{/description}}
export class {{classname}} {{#parent}}extends {{{parent}}} {{/parent}}{
{{#vars}}
{{#description}}
/**
* {{{description}}}
*/
{{/description}}
'{{name}}'{{^required}}?{{/required}}: {{#isEnum}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}};
{{/vars}}
{{#discriminator}}
static readonly discriminator: string | undefined = "{{discriminatorName}}";
{{/discriminator}}
{{^discriminator}}
static readonly discriminator: string | undefined = undefined;
{{/discriminator}}
{{^isArrayModel}}
static readonly attributeTypeMap: Array<{name: string, baseName: string, type: string, format: string}> = [
{{#vars}}
{
"name": "{{name}}",
"baseName": "{{baseName}}",
"type": "{{#isEnum}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}",
"format": "{{dataFormat}}"
}{{#hasMore}},
{{/hasMore}}
{{/vars}}
];
static getAttributeTypeMap() {
{{#parent}}
return super.getAttributeTypeMap().concat({{classname}}.attributeTypeMap);
{{/parent}}
{{^parent}}
return {{classname}}.attributeTypeMap;
{{/parent}}
}
{{/isArrayModel}}
public constructor() {
{{#parent}}
super();
{{/parent}}
{{#allVars}}
{{#discriminatorValue}}
this.{{name}} = "{{discriminatorValue}}";
{{/discriminatorValue}}
{{/allVars}}
{{#discriminatorName}}
this.{{discriminatorName}} = "{{classname}}";
{{/discriminatorName}}
}
}
{{#hasEnums}}
{{#vars}}
{{#isEnum}}
export type {{classname}}{{enumName}} ={{#allowableValues}}{{#values}} "{{.}}" {{^-last}}|{{/-last}}{{/values}}{{/allowableValues}};
{{/isEnum}}
{{/vars}}
{{/hasEnums}}
{{/model}}
{{/models}}

View File

@@ -0,0 +1,5 @@
{{#models}}
{{#model}}
export * from './{{name}}'
{{/model}}
{{/models}}

View File

@@ -0,0 +1,51 @@
{
"name": "{{npmName}}",
"version": "1.0.0",
"description": "OpenAPI client for {{npmName}}",
"author": "OpenAPI-Generator Contributors",
"keywords": [
"fetch",
"typescript",
"openapi-client",
"openapi-generator"
],
"license": "Unlicense",
"main": "./dist/index.js",
"typings": "./dist/index.d.ts",
"scripts": {
"build": "tsc",
"prepublishOnly": "npm run build"
},
"dependencies": {
{{#frameworks}}
{{#fetch-api}}
"isomorphic-fetch": "^2.2.1",
"@types/isomorphic-fetch": "0.0.34",
{{/fetch-api}}
{{#jquery}}
"@types/jquery": "^3.3.29",
"jquery": "^3.4.1",
{{/jquery}}
{{/frameworks}}
{{#platforms}}
{{#node}}
"@types/node": "*",
"form-data": "^2.5.0",
{{/node}}
{{/platforms}}
{{#useRxJS}}
"rxjs": "^6.4.0",
{{/useRxJS}}
"btoa": "^1.2.1",
"es6-promise": "^4.2.4",
"url-parse": "^1.4.3"
},
"devDependencies": {
"typescript": "^2.9.2"
}{{#npmRepository}},{{/npmRepository}}
{{#npmRepository}}
"publishConfig":{
"registry":"{{npmRepository}}"
}
{{/npmRepository}}
}

View File

@@ -0,0 +1,27 @@
export class Observable<T> {
constructor(private promise: Promise<T>) {}
toPromise() {
return this.promise;
}
pipe<S>(callback: (value: T) => S | Promise<S>): Observable<S> {
return new Observable(this.promise.then(callback));
}
}
export function from<T>(promise: Promise<any>) {
return new Observable(promise);
}
export function of<T>(value: T) {
return new Observable<T>(Promise.resolve(value));
}
export function mergeMap<T, S>(callback: (value: T) => Observable<S>) {
return (value: T) => callback(value).toPromise();
}
export function map(callback: any) {
return callback;
}

View File

@@ -0,0 +1,29 @@
{
"compilerOptions": {
"strict": true,
/* Basic Options */
"target": "{{#supportsES6}}es6{{/supportsES6}}{{^supportsES6}}es5{{/supportsES6}}",
"module": "{{#supportsES6}}es6{{/supportsES6}}{{^supportsES6}}commonjs{{/supportsES6}}",
"declaration": true,
/* Additional Checks */
"noUnusedLocals": false, /* Report errors on unused locals. */ // TODO: reenable (unused imports!)
"noUnusedParameters": false, /* Report errors on unused parameters. */ // TODO: set to true again
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
"noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
"removeComments": true,
"sourceMap": true,
"outDir": "./dist",
"noLib": false,
"lib": [ "es6", "dom" ]
},
"exclude": [
"dist",
"node_modules"
],
"filesGlob": [
"./**/*.ts",
]
}

View File

@@ -0,0 +1,28 @@
/**
* Returns if a specific http code is in a given code range
* where the code range is defined as a combination of digits
* and "X" (the letter X) with a length of 3
*
* @param codeRange string with length 3 consisting of digits and "X" (the letter X)
* @param code the http status code to be checked against the code range
*/
export function isCodeInRange(codeRange: string, code: number): boolean {
// This is how the default value is encoded in OAG
if (codeRange === "0") {
return true;
}
if (codeRange == code.toString()) {
return true;
} else {
const codeString = code.toString();
if (codeString.length != codeRange.length) {
return false;
}
for (let i = 0; i < codeString.length; i++) {
if (codeRange.charAt(i) != "X" && codeRange.charAt(i) != codeString.charAt(i)) {
return false;
}
}
return true;
}
}

View File

@@ -19,7 +19,6 @@ package org.openapitools.codegen.options;
import com.google.common.collect.ImmutableMap;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.languages.HaskellServantCodegen;
import java.util.Map;
@@ -45,7 +44,6 @@ public class HaskellServantOptionsProvider implements OptionsProvider {
.put(CodegenConstants.ENSURE_UNIQUE_PARAMS, ENSURE_UNIQUE_PARAMS_VALUE)
.put(CodegenConstants.ALLOW_UNICODE_IDENTIFIERS, ALLOW_UNICODE_IDENTIFIERS_VALUE)
.put(CodegenConstants.PREPEND_FORM_OR_BODY_PARAMETERS, PREPEND_FORM_OR_BODY_PARAMETERS_VALUE)
.put(HaskellServantCodegen.PROP_SERVE_STATIC, HaskellServantCodegen.PROP_SERVE_STATIC_DEFAULT.toString())
.build();
}

16
pom.xml
View File

@@ -10,7 +10,7 @@
<packaging>pom</packaging>
<name>openapi-generator-project</name>
<!-- RELEASE_VERSION -->
<version>4.2.0</version>
<version>4.2.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION -->
<url>https://github.com/openapitools/openapi-generator</url>
<scm>
@@ -798,6 +798,18 @@
<module>samples/server/petstore/jaxrs-spec-interface-response</module>
</modules>
</profile>
<profile>
<id>typescript-client-tests-default</id>
<activation>
<property>
<name>env</name>
<value>java</value>
</property>
</activation>
<modules>
<module>samples/client/petstore/typescript/tests/default</module>
</modules>
</profile>
<profile>
<id>typescript-fetch-client-tests-default</id>
<activation>
@@ -1059,6 +1071,8 @@
<module>samples/client/petstore/python-asyncio</module>
<module>samples/client/petstore/python-tornado</module>
<module>samples/openapi3/client/petstore/python</module>
<module>samples/client/petstore/typescript/builds/default</module>
<module>samples/client/petstore/typescript/tests/default</module>
<module>samples/client/petstore/typescript-fetch/builds/default</module>
<module>samples/client/petstore/typescript-fetch/builds/es6-target</module>
<module>samples/client/petstore/typescript-fetch/builds/with-npm-version</module>

View File

@@ -5,7 +5,7 @@ Authors@R: person("OpenAPI Generator community", email = "team@openapitools.org"
Description: This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
Depends: R (>= 3.3.3)
Encoding: UTF-8
License: Apache-2.0
License: Unlicense
LazyData: true
Suggests: testthat
Imports: jsonlite, httr, R6, caTools

View File

@@ -1,6 +1,5 @@
# petstore::Category
A category for a pet
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------

View File

@@ -1,6 +1,5 @@
# petstore::ModelApiResponse
Describes the result of uploading an image resource
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------

View File

@@ -1,6 +1,5 @@
# petstore::Order
An order for a pets from the pet store
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------

View File

@@ -1,6 +1,5 @@
# petstore::Pet
A pet for sale in the pet store
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------

View File

@@ -1,6 +1,5 @@
# petstore::Tag
A tag for a pet
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------

View File

@@ -1,6 +1,5 @@
# petstore::User
A User who is purchasing from the pet store
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------

View File

@@ -1,5 +1,4 @@
# Org.OpenAPITools.Model.ClassModel
Model for testing model with \"_class\" property
## Properties
Name | Type | Description | Notes

View File

@@ -1,5 +1,4 @@
# Org.OpenAPITools.Model.File
Must be named `File` for test.
## Properties
Name | Type | Description | Notes

View File

@@ -1,5 +1,4 @@
# Org.OpenAPITools.Model.Model200Response
Model for testing model name starting with number
## Properties
Name | Type | Description | Notes

View File

@@ -1,5 +1,4 @@
# Org.OpenAPITools.Model.Name
Model for testing model name same as property name
## Properties
Name | Type | Description | Notes

View File

@@ -1,5 +1,4 @@
# Org.OpenAPITools.Model.Return
Model for testing reserved words
## Properties
Name | Type | Description | Notes

View File

@@ -1,5 +1,4 @@
# Org.OpenAPITools.Model.ClassModel
Model for testing model with \"_class\" property
## Properties
Name | Type | Description | Notes

View File

@@ -1,5 +1,4 @@
# Org.OpenAPITools.Model.File
Must be named `File` for test.
## Properties
Name | Type | Description | Notes

View File

@@ -1,5 +1,4 @@
# Org.OpenAPITools.Model.Model200Response
Model for testing model name starting with number
## Properties
Name | Type | Description | Notes

View File

@@ -1,5 +1,4 @@
# Org.OpenAPITools.Model.Name
Model for testing model name same as property name
## Properties
Name | Type | Description | Notes

View File

@@ -1,5 +1,4 @@
# Org.OpenAPITools.Model.Return
Model for testing reserved words
## Properties
Name | Type | Description | Notes

View File

@@ -2,7 +2,6 @@
# ClassModel
Model for testing model with \"_class\" property
## Properties
Name | Type | Description | Notes

View File

@@ -2,7 +2,6 @@
# Model200Response
Model for testing model name starting with number
## Properties
Name | Type | Description | Notes

View File

@@ -2,7 +2,6 @@
# ModelReturn
Model for testing reserved words
## Properties
Name | Type | Description | Notes

View File

@@ -2,7 +2,6 @@
# Name
Model for testing model name same as property name
## Properties
Name | Type | Description | Notes

View File

@@ -2,7 +2,6 @@
# ClassModel
Model for testing model with \"_class\" property
## Properties
Name | Type | Description | Notes

View File

@@ -2,7 +2,6 @@
# Model200Response
Model for testing model name starting with number
## Properties
Name | Type | Description | Notes

View File

@@ -2,7 +2,6 @@
# ModelReturn
Model for testing reserved words
## Properties
Name | Type | Description | Notes

View File

@@ -2,7 +2,6 @@
# Name
Model for testing model name same as property name
## Properties
Name | Type | Description | Notes

View File

@@ -2,7 +2,6 @@
# ClassModel
Model for testing model with \"_class\" property
## Properties
Name | Type | Description | Notes

View File

@@ -2,7 +2,6 @@
# Model200Response
Model for testing model name starting with number
## Properties
Name | Type | Description | Notes

View File

@@ -2,7 +2,6 @@
# ModelReturn
Model for testing reserved words
## Properties
Name | Type | Description | Notes

View File

@@ -2,7 +2,6 @@
# Name
Model for testing model name same as property name
## Properties
Name | Type | Description | Notes

View File

@@ -2,7 +2,6 @@
# ClassModel
Model for testing model with \"_class\" property
## Properties
Name | Type | Description | Notes

View File

@@ -2,7 +2,6 @@
# Model200Response
Model for testing model name starting with number
## Properties
Name | Type | Description | Notes

View File

@@ -2,7 +2,6 @@
# ModelReturn
Model for testing reserved words
## Properties
Name | Type | Description | Notes

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