diff --git a/modules/openapi-generator-cli/~/ts-fetch-client/.openapi-generator-ignore b/modules/openapi-generator-cli/~/ts-fetch-client/.openapi-generator-ignore new file mode 100644 index 00000000000..7484ee590a3 --- /dev/null +++ b/modules/openapi-generator-cli/~/ts-fetch-client/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/modules/openapi-generator-cli/~/ts-fetch-client/.openapi-generator/VERSION b/modules/openapi-generator-cli/~/ts-fetch-client/.openapi-generator/VERSION new file mode 100644 index 00000000000..717311e32e3 --- /dev/null +++ b/modules/openapi-generator-cli/~/ts-fetch-client/.openapi-generator/VERSION @@ -0,0 +1 @@ +unset \ No newline at end of file diff --git a/modules/openapi-generator-cli/~/ts-fetch-client/README.md b/modules/openapi-generator-cli/~/ts-fetch-client/README.md new file mode 100644 index 00000000000..ea786ff2cf6 --- /dev/null +++ b/modules/openapi-generator-cli/~/ts-fetch-client/README.md @@ -0,0 +1 @@ +readme \ No newline at end of file diff --git a/modules/openapi-generator-cli/~/ts-fetch-client/configuration.ts b/modules/openapi-generator-cli/~/ts-fetch-client/configuration.ts new file mode 100644 index 00000000000..06cc0f09bdd --- /dev/null +++ b/modules/openapi-generator-cli/~/ts-fetch-client/configuration.ts @@ -0,0 +1,38 @@ +import {HttpLibrary} from './http/http'; +import {Middleware} from './middleware'; + +export interface ConfigurationParameters { + basePath?: string; // override base path + httpApi?: HttpLibrary; // override for fetch implementation + middleware?: Middleware[]; // middleware to apply before/after fetch requests + username?: string; // parameter for basic security + password?: string; // parameter for basic security + apiKey?: string | ((name: string) => string); // parameter for apiKey security + accessToken?: string | ((name: string, scopes?: string[]) => string); // parameter for oauth2 security +} + +export class Configuration { + + basePath: string; + httpApi: HttpLibrary; + middleware: Middleware[]; + username?: string; + password?: string; + apiKey?: (name: string) => string; + accessToken?: (name: string, scopes?: string[]) => string; + + constructor(conf: ConfigurationParameters = {}) { + this.basePath = conf.basePath !== undefined ? conf.basePath : BASE_PATH; + this.fetchApi = conf.fetchApi || window.fetch.bind(window); + this.middleware = conf.middleware || []; + this.username = conf.username; + this.password = conf.password; + const { apiKey, accessToken } = conf; + if (apiKey) { + this.apiKey = typeof apiKey === 'function' ? apiKey : () => apiKey; + } + if (accessToken) { + this.accessToken = typeof accessToken === 'function' ? accessToken : () => accessToken; + } + } +} \ No newline at end of file diff --git a/modules/openapi-generator-cli/~/ts-fetch-client/http/http.ts b/modules/openapi-generator-cli/~/ts-fetch-client/http/http.ts new file mode 100644 index 00000000000..79391f8588c --- /dev/null +++ b/modules/openapi-generator-cli/~/ts-fetch-client/http/http.ts @@ -0,0 +1,51 @@ +export enum HttpMethod { + GET = "GET", + HEAD = "HEAD", + POST = "POST", + PUT = "PUT", + DELETE = "DELETE", + CONNECT = "CONNECT", + OPTIONS = "OPTIONS", + TRACE = "TRACE", + PATCH = "PATCH" +} + +export interface FormEntry { + contentType: string; + value: string | Blob; +} + +export type FormData = { [key: string]: FormEntry }; + + +export class RequestContext { + public headers: { [key: string]: string } = {}; + public body: string | FormData = ""; + + public constructor(public url: string, public httpMethod: HttpMethod) { + + } + + public addCookie(name: string, value: string): void { + if (!this.headers["Cookie"]) { + this.headers["Cookie"] = ""; + } + this.headers["Cookie"] += name + "=" + value + "; "; + } + + public setHeader(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): Promise; +} \ No newline at end of file diff --git a/modules/openapi-generator-cli/~/ts-fetch-client/http/isomorphic-fetch.ts b/modules/openapi-generator-cli/~/ts-fetch-client/http/isomorphic-fetch.ts new file mode 100644 index 00000000000..47fb11c86e5 --- /dev/null +++ b/modules/openapi-generator-cli/~/ts-fetch-client/http/isomorphic-fetch.ts @@ -0,0 +1,38 @@ +import {HttpLibrary, RequestContext, ResponseContext} from './http'; +import * as e6p from 'es6-promise' +e6p.polyfill(); +import 'isomorphic-fetch'; + +export class IsomorphicFetchHttpLibrary implements HttpLibrary { + + public send(request: RequestContext): Promise { + let method = request.httpMethod.toString(); + let body: string | FormData = ""; + if (typeof request.body === "string") { + body = request.body; + } else { + body = new FormData(); + for (const key in request.body) { + body.append(key, request.body[key].value); + } + } + + return fetch(request.url, { + method: method, + body: body, + headers: request.headers, + credentials: "same-origin" + }).then((resp) => { + // hack + let headers = (resp.headers as any)._headers; + for (let key in headers) { + headers[key] = (headers[key] as Array).join("; "); + } + + return resp.text().then((body) => { + return new ResponseContext(resp.status, headers, body) + }); + }); + + } +} diff --git a/modules/openapi-generator-cli/~/ts-fetch-client/middleware.ts b/modules/openapi-generator-cli/~/ts-fetch-client/middleware.ts new file mode 100644 index 00000000000..17fdcc8ea6f --- /dev/null +++ b/modules/openapi-generator-cli/~/ts-fetch-client/middleware.ts @@ -0,0 +1,6 @@ +import {RequestContext, ResponseContext} from './http/http'; + +export interface Middleware { + pre?(context: RequestContext): Promise; + post?(context: ResponseContext): Promise; +} \ No newline at end of file diff --git a/modules/openapi-generator-cli/~/ts-fetch-client/package.json b/modules/openapi-generator-cli/~/ts-fetch-client/package.json new file mode 100644 index 00000000000..4b73dd96ff2 --- /dev/null +++ b/modules/openapi-generator-cli/~/ts-fetch-client/package.json @@ -0,0 +1,28 @@ +{ + "name": "", + "version": "", + "description": "OpenAPI client for ", + "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": { + "es6-promise": "^4.2.4", + "isomorphic-fetch": "^2.2.1", + "@types/isomorphic-fetch": "0.0.34" + }, + "devDependencies": { + "typescript": "^2.9.2" + } +} diff --git a/modules/openapi-generator-cli/~/ts-fetch-client/tsconfig.json b/modules/openapi-generator-cli/~/ts-fetch-client/tsconfig.json new file mode 100644 index 00000000000..4ef0a027802 --- /dev/null +++ b/modules/openapi-generator-cli/~/ts-fetch-client/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "strict": true, + /* Basic Options */ + "target": "es5", + "module": "commonjs", + "declaration": true, + + /* Additional Checks */ + "noUnusedLocals": true, /* Report errors on unused locals. */ + "noUnusedParameters": true, /* Report errors on unused parameters. */ + "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, + "declaration": true, + "lib": [ "es6", "dom" ] + }, + "exclude": [ + "node_modules" + ], + "filesGlob": [ + "./**/*.ts", + ] + +} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java index 76df02a6cae..d7e9613bf50 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java @@ -116,8 +116,14 @@ public class TypeScriptClientCodegen extends DefaultCodegen implements CodegenCo supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); supportingFiles.add(new SupportingFile("package.mustache", "", "package.json")); supportingFiles.add(new SupportingFile("tsconfig.mustache", "", "tsconfig.json")); + + // http supportingFiles.add(new SupportingFile("http" + File.separator + "http.mustache", "http", "http.ts")); supportingFiles.add(new SupportingFile("http" + File.separator + "isomorphic-fetch.mustache", "http", "isomorphic-fetch.ts")); + + supportingFiles.add(new SupportingFile("configuration.mustache", "", "configuration.ts")); + supportingFiles.add(new SupportingFile("middleware.mustache", "", "middleware.ts")); + } diff --git a/modules/openapi-generator/src/main/resources/typescript/configuration.mustache b/modules/openapi-generator/src/main/resources/typescript/configuration.mustache new file mode 100644 index 00000000000..2a7e7da234d --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript/configuration.mustache @@ -0,0 +1,41 @@ +import {HttpLibrary} from './http/http'; +import {Middleware} from './middleware'; +import {IsomorphicFetchHttpLibrary} from "./http/isomorphic-fetch"; + +export const BASE_PATH = "{{{basePath}}}".replace(/\/+$/, ""); + +export interface ConfigurationParameters { + basePath?: string; // override base path + httpApi?: HttpLibrary; // override for fetch implementation + middleware?: Middleware[]; // middleware to apply before/after fetch requests + username?: string; // parameter for basic security + password?: string; // parameter for basic security + apiKey?: string | ((name: string) => string); // parameter for apiKey security + accessToken?: string | ((name: string, scopes?: string[]) => string); // parameter for oauth2 security +} + +export class Configuration { + + basePath: string; + httpApi: HttpLibrary; + middleware: Middleware[]; + username?: string; + password?: string; + apiKey?: (name: string) => string; + accessToken?: (name: string, scopes?: string[]) => string; + + constructor(conf: ConfigurationParameters = {}) { + this.basePath = conf.basePath !== undefined ? conf.basePath : BASE_PATH; + this.httpApi = conf.httpApi || new IsomorphicFetchHttpLibrary(); // TODO: replace with window.fetch? + this.middleware = conf.middleware || []; + this.username = conf.username; + this.password = conf.password; + const { apiKey, accessToken } = conf; + if (apiKey) { + this.apiKey = typeof apiKey === 'function' ? apiKey : () => apiKey; + } + if (accessToken) { + this.accessToken = typeof accessToken === 'function' ? accessToken : () => accessToken; + } + } +} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/typescript/http/http.mustache b/modules/openapi-generator/src/main/resources/typescript/http/http.mustache index f41e109fef6..4bd5bdcfefb 100644 --- a/modules/openapi-generator/src/main/resources/typescript/http/http.mustache +++ b/modules/openapi-generator/src/main/resources/typescript/http/http.mustache @@ -1,3 +1,6 @@ +// TODO: evaluate if we can easily get rid of this library +import * as FormData from "form-data"; + export enum HttpMethod { GET = "GET", HEAD = "HEAD", @@ -11,20 +14,57 @@ export enum HttpMethod { } export interface FormEntry { - contentType: string; + contentDisposition: string; value: string | Blob; } -export type FormData = { [key: string]: FormEntry }; +export class HttpException extends Error { + public constructor(msg: string) { + super(msg); + } +} -export class Request { - public headers: { [key: string]: string } = {}; - public body: string | FormData = ""; +export class RequestContext { + private headers: { [key: string]: string } = {}; + private body: string | FormData = ""; - public constructor(public url: string, public httpMethod: HttpMethod) { + public constructor(private url: string, private httpMethod: HttpMethod) { } + + public getUrl(): string { + return this.url; + } + + public setUrl(url: string) { + this.url = url; + } + + 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 addCookie(name: string, value: string): void { if (!this.headers["Cookie"]) { @@ -38,7 +78,7 @@ export class Request { } } -export class Response { +export class ResponseContext { public constructor(public httpStatusCode: number, public headers: { [key: string]: string }, public body: string) { @@ -47,5 +87,5 @@ export class Response { } export interface HttpLibrary { - send(request: Request): Promise; + send(request: RequestContext): Promise; } \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/typescript/http/isomorphic-fetch.mustache b/modules/openapi-generator/src/main/resources/typescript/http/isomorphic-fetch.mustache index 25bef19fa9e..dd200043238 100644 --- a/modules/openapi-generator/src/main/resources/typescript/http/isomorphic-fetch.mustache +++ b/modules/openapi-generator/src/main/resources/typescript/http/isomorphic-fetch.mustache @@ -1,26 +1,18 @@ -import {HttpLibrary, Request, Response} from './http'; +import {HttpLibrary, RequestContext, ResponseContext} from './http'; import * as e6p from 'es6-promise' e6p.polyfill(); import 'isomorphic-fetch'; export class IsomorphicFetchHttpLibrary implements HttpLibrary { - public send(request: Request): Promise { - let method = request.httpMethod.toString(); - let body: string | FormData = ""; - if (typeof request.body === "string") { - body = request.body; - } else { - body = new FormData(); - for (const key in request.body) { - body.append(key, request.body[key].value); - } - } + public send(request: RequestContext): Promise { + let method = request.getHttpMethod().toString(); + let body = request.getBody(); - return fetch(request.url, { + return fetch(request.getUrl(), { method: method, - body: body, - headers: request.headers, + body: body as any, + headers: request.getHeaders(), credentials: "same-origin" }).then((resp) => { // hack @@ -30,7 +22,7 @@ export class IsomorphicFetchHttpLibrary implements HttpLibrary { } return resp.text().then((body) => { - return new Response(resp.status, headers, body) + return new ResponseContext(resp.status, headers, body) }); }); diff --git a/modules/openapi-generator/src/main/resources/typescript/middleware.mustache b/modules/openapi-generator/src/main/resources/typescript/middleware.mustache new file mode 100644 index 00000000000..17fdcc8ea6f --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript/middleware.mustache @@ -0,0 +1,6 @@ +import {RequestContext, ResponseContext} from './http/http'; + +export interface Middleware { + pre?(context: RequestContext): Promise; + post?(context: ResponseContext): Promise; +} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/typescript/package.mustache b/modules/openapi-generator/src/main/resources/typescript/package.mustache index 327f133bceb..cb3ab771c69 100644 --- a/modules/openapi-generator/src/main/resources/typescript/package.mustache +++ b/modules/openapi-generator/src/main/resources/typescript/package.mustache @@ -21,9 +21,16 @@ "es6-promise": "^4.2.4", "isomorphic-fetch": "^2.2.1", "@types/isomorphic-fetch": "0.0.34" + "form-data": "^2.3.2", + "@types/form-data": "^2.2.1", }, "devDependencies": { - "typescript": "^2.9.2" + "ts-node": "^7.0.0", + "typescript": "^2.9.2", + "@types/chai": "^4.1.4", + "@types/mocha": "^5.2.5", + "chai": "^4.1.2", + "mocha": "^5.2.0" }{{#npmRepository}},{{/npmRepository}} {{#npmRepository}} "publishConfig":{