mirror of
https://github.com/ferdikoomen/openapi-typescript-codegen.git
synced 2025-12-08 20:16:21 +00:00
- Removed javascript generation
This commit is contained in:
parent
e0b68a3326
commit
b110b22921
12
README.md
12
README.md
@ -5,12 +5,12 @@
|
||||
[](https://travis-ci.org/ferdikoomen/openapi-typescript-codegen)
|
||||
[](https://lgtm.com/projects/g/ferdikoomen/openapi-typescript-codegen)
|
||||
|
||||
> NodeJS library that generates Typescript or Javascript clients based on the OpenAPI specification.
|
||||
> NodeJS library that generates Typescript clients based on the OpenAPI specification.
|
||||
|
||||
#### Why?
|
||||
- Frontend ❤️ OpenAPI, but we do not want to use JAVA codegen in our builds.
|
||||
- Quick, lightweight, robust and framework agnostic.
|
||||
- Supports generation of Typescript and Javascript clients.
|
||||
- Supports generation of Typescript clients.
|
||||
- Supports generations of fetch and XHR http clients.
|
||||
- Supports OpenAPI specification v2.0 and v3.0.
|
||||
- Supports JSON and YAML files for input.
|
||||
@ -20,7 +20,7 @@
|
||||
- If you use enums inside your models / definitions then those enums are now
|
||||
inside a namespace with the same name as your model. This is called declaration
|
||||
merging. However Babel 7 now support compiling of Typescript and right now they
|
||||
do not support namespaces.
|
||||
do not support namespaces.
|
||||
|
||||
|
||||
## Installation
|
||||
@ -41,7 +41,7 @@ npm install openapi-typescript-codegen --save-dev
|
||||
}
|
||||
```
|
||||
|
||||
Command line
|
||||
Command line
|
||||
|
||||
```
|
||||
npm install openapi-typescript-codegen -g
|
||||
@ -54,10 +54,8 @@ NodeJS API:
|
||||
```
|
||||
const OpenAPI = require('openapi-typescript-codegen');
|
||||
|
||||
const result = OpenAPI.generate(
|
||||
OpenAPI.generate(
|
||||
'./api/openapi.json',
|
||||
'./dist'
|
||||
);
|
||||
|
||||
console.log(result);
|
||||
```
|
||||
|
||||
@ -10,7 +10,6 @@ program
|
||||
.version(pkg.version)
|
||||
.option('--input [value]', 'Path to swagger specification', './spec.json')
|
||||
.option('--output [value]', 'Output directory', './generated')
|
||||
.option('--language [value]', 'Language to generate [typescript, javascript]', 'typescript')
|
||||
.option('--http-client [value]', 'HTTP client to generate [fetch, xhr]', 'fetch')
|
||||
.parse(process.argv);
|
||||
|
||||
@ -20,7 +19,6 @@ if (SwaggerCodegen) {
|
||||
SwaggerCodegen.generate(
|
||||
program.input,
|
||||
program.output,
|
||||
program.language,
|
||||
program.httpClient
|
||||
);
|
||||
}
|
||||
|
||||
@ -43,10 +43,8 @@
|
||||
"dist/index.d.ts",
|
||||
"dist/**/*.js",
|
||||
"dist/**/*.d.ts",
|
||||
"src/templates/javascript/**/*.hbs",
|
||||
"src/templates/javascript/**/*.js",
|
||||
"src/templates/typescript/**/*.hbs",
|
||||
"src/templates/typescript/**/*.ts"
|
||||
"src/templates/**/*.hbs",
|
||||
"src/templates/**/*.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "rimraf \"./dist\" \"./coverage\" \"./test/result\"",
|
||||
|
||||
32
src/index.ts
32
src/index.ts
@ -7,11 +7,6 @@ import { parse as parseV3 } from './openApi/v3';
|
||||
import { readHandlebarsTemplates } from './utils/readHandlebarsTemplates';
|
||||
import { writeClient } from './utils/writeClient';
|
||||
|
||||
export enum Language {
|
||||
TYPESCRIPT = 'typescript',
|
||||
JAVASCRIPT = 'javascript',
|
||||
}
|
||||
|
||||
export enum HttpClient {
|
||||
FETCH = 'fetch',
|
||||
XHR = 'xhr',
|
||||
@ -23,10 +18,9 @@ export enum HttpClient {
|
||||
* service layer, etc.
|
||||
* @param input The relative location of the OpenAPI spec.
|
||||
* @param output The relative location of the output directory.
|
||||
* @param language: The language that should be generated (Typescript or Javascript).
|
||||
* @param httpClient: The selected httpClient (fetch or XHR).
|
||||
*/
|
||||
export function generate(input: string, output: string, language: Language = Language.TYPESCRIPT, httpClient: HttpClient = HttpClient.FETCH): void {
|
||||
export function generate(input: string, output: string, httpClient: HttpClient = HttpClient.FETCH): void {
|
||||
const inputPath = path.resolve(process.cwd(), input);
|
||||
const outputPath = path.resolve(process.cwd(), output);
|
||||
|
||||
@ -35,22 +29,18 @@ export function generate(input: string, output: string, language: Language = Lan
|
||||
// handlebar templates for the given language
|
||||
const openApi = getOpenApiSpec(inputPath);
|
||||
const openApiVersion = getOpenApiVersion(openApi);
|
||||
const templates = readHandlebarsTemplates(language);
|
||||
const templates = readHandlebarsTemplates();
|
||||
|
||||
switch (language) {
|
||||
case Language.JAVASCRIPT:
|
||||
case Language.TYPESCRIPT:
|
||||
// Generate and write version 2 client
|
||||
if (openApiVersion === OpenApiVersion.V2) {
|
||||
const clientV2 = parseV2(openApi);
|
||||
writeClient(clientV2, language, httpClient, templates, outputPath);
|
||||
}
|
||||
switch (openApiVersion) {
|
||||
case OpenApiVersion.V2:
|
||||
const clientV2 = parseV2(openApi);
|
||||
writeClient(clientV2, httpClient, templates, outputPath);
|
||||
break;
|
||||
|
||||
// Generate and write version 3 client
|
||||
if (openApiVersion === OpenApiVersion.V3) {
|
||||
const clientV3 = parseV3(openApi);
|
||||
writeClient(clientV3, language, httpClient, templates, outputPath);
|
||||
}
|
||||
case OpenApiVersion.V3:
|
||||
const clientV3 = parseV3(openApi);
|
||||
writeClient(clientV3, httpClient, templates, outputPath);
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
17
src/templates/core/getSchema.ts
Normal file
17
src/templates/core/getSchema.ts
Normal file
@ -0,0 +1,17 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
import * as schemas from '../schemas';
|
||||
|
||||
/**
|
||||
* Get a schema object for a given model name.
|
||||
* @param model The model name to return the schema from.
|
||||
*/
|
||||
export function getSchema<K extends keyof typeof schemas>(model: K) {
|
||||
if (schemas.hasOwnProperty(model)) {
|
||||
return schemas[model];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
11
src/templates/index.ts
Normal file
11
src/templates/index.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
export { ApiError } from './core/ApiError';
|
||||
export { getSchema } from './core/getSchema';
|
||||
export { isSuccess } from './core/isSuccess';
|
||||
export { OpenAPI } from './core/OpenAPI';
|
||||
export * from './models/';
|
||||
export * from './services/';
|
||||
@ -1,54 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
import { isSuccess } from "./isSuccess";
|
||||
|
||||
export class ApiError extends Error {
|
||||
|
||||
constructor(result, message) {
|
||||
super(message);
|
||||
|
||||
this.url = result.url;
|
||||
this.status = result.status;
|
||||
this.statusText = result.statusText;
|
||||
this.body = result.body;
|
||||
}
|
||||
}
|
||||
|
||||
(function (ApiError) {
|
||||
let Message;
|
||||
(function (Message) {
|
||||
Message.BAD_REQUEST = 'Bad Request';
|
||||
Message.UNAUTHORIZED = 'Unauthorized';
|
||||
Message.FORBIDDEN = 'Forbidden';
|
||||
Message.NOT_FOUND = 'Not Found';
|
||||
Message.INTERNAL_SERVER_ERROR = 'Internal Server Error';
|
||||
Message.BAD_GATEWAY = 'Bad Gateway';
|
||||
Message.SERVICE_UNAVAILABLE = 'Service Unavailable';
|
||||
Message.GENERIC_ERROR = 'Generic Error';
|
||||
})(Message = ApiError.Message || (ApiError.Message = {}));
|
||||
})(ApiError || (ApiError = {}));
|
||||
|
||||
/**
|
||||
* Catch common errors (based on status code).
|
||||
* @param result
|
||||
*/
|
||||
export function catchGenericError(result) {
|
||||
|
||||
switch (result.status) {
|
||||
case 400: throw new ApiError(result, ApiError.Message.BAD_REQUEST);
|
||||
case 401: throw new ApiError(result, ApiError.Message.UNAUTHORIZED);
|
||||
case 403: throw new ApiError(result, ApiError.Message.FORBIDDEN);
|
||||
case 404: throw new ApiError(result, ApiError.Message.NOT_FOUND);
|
||||
case 500: throw new ApiError(result, ApiError.Message.INTERNAL_SERVER_ERROR);
|
||||
case 502: throw new ApiError(result, ApiError.Message.BAD_GATEWAY);
|
||||
case 503: throw new ApiError(result, ApiError.Message.SERVICE_UNAVAILABLE);
|
||||
}
|
||||
|
||||
if (!isSuccess(result.status)) {
|
||||
throw new ApiError(result, ApiError.Message.GENERIC_ERROR);
|
||||
}
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
export let OpenAPI;
|
||||
(function (OpenAPI) {
|
||||
OpenAPI.BASE = '{{{server}}}';
|
||||
OpenAPI.VERSION = '{{{version}}}';
|
||||
OpenAPI.CLIENT = '{{{httpClient}}}';
|
||||
OpenAPI.TOKEN = '';
|
||||
})(OpenAPI || (OpenAPI = {}));
|
||||
@ -1,23 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
/**
|
||||
* Get FormData from object. This method is needed to upload
|
||||
* multipart form data to the REST API.
|
||||
* @param params Key value based object.
|
||||
*/
|
||||
export function getFormData(params) {
|
||||
const formData = new FormData();
|
||||
for (const key in params) {
|
||||
if (typeof params[key] !== 'undefined') {
|
||||
const value = params[key];
|
||||
if (value !== undefined && value !== null) {
|
||||
formData.append(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return formData;
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
/**
|
||||
* Get query string from query parameters object. This method also
|
||||
* supports multi-value items by creating a key for each item.
|
||||
* @param params Key value based object.
|
||||
*/
|
||||
export function getQueryString(params) {
|
||||
const qs = [];
|
||||
for (const key in params) {
|
||||
if (typeof params[key] !== 'undefined') {
|
||||
const value = params[key];
|
||||
if (value !== undefined && value !== null) {
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach(value => {
|
||||
qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
|
||||
});
|
||||
} else {
|
||||
qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (qs.length > 0) {
|
||||
return `?${qs.join('&')}`;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
/**
|
||||
* Check success response code.
|
||||
* @param status Status code
|
||||
*/
|
||||
export function isSuccess(status) {
|
||||
return status >= 200 && status < 300;
|
||||
}
|
||||
@ -1,80 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
import { getFormData } from './getFormData';
|
||||
import { getQueryString } from './getQueryString';
|
||||
import { OpenAPI } from './OpenAPI';
|
||||
import { requestUsingFetch } from './requestUsingFetch';
|
||||
import { requestUsingXHR } from './requestUsingXHR';
|
||||
|
||||
/**
|
||||
* Create the request.
|
||||
* @param options Request method options.
|
||||
* @returns Result object (see above)
|
||||
*/
|
||||
export async function request(options) {
|
||||
|
||||
// Create the request URL
|
||||
let url = `${OpenAPI.BASE}${options.path}`;
|
||||
|
||||
// Create request headers
|
||||
const headers = new Headers({
|
||||
...options.headers,
|
||||
Accept: 'application/json',
|
||||
});
|
||||
|
||||
// Create request settings
|
||||
const request = {
|
||||
headers,
|
||||
method: options.method,
|
||||
credentials: 'same-origin',
|
||||
};
|
||||
|
||||
// If we have a bearer token then we set the authentication header.
|
||||
if (OpenAPI.TOKEN !== null && OpenAPI.TOKEN !== '') {
|
||||
headers.append('Authorization', `Bearer ${OpenAPI.TOKEN}`);
|
||||
}
|
||||
|
||||
// Add the query parameters (if defined).
|
||||
if (options.query) {
|
||||
url += getQueryString(options.query);
|
||||
}
|
||||
|
||||
// Append formData as body
|
||||
if (options.formData) {
|
||||
request.body = getFormData(options.formData);
|
||||
} else if (options.body) {
|
||||
|
||||
// If this is blob data, then pass it directly to the body and set content type.
|
||||
// Otherwise we just convert request data to JSON string (needed for fetch api)
|
||||
if (options.body instanceof Blob) {
|
||||
request.body = options.body;
|
||||
if (options.body.type) {
|
||||
headers.append('Content-Type', options.body.type);
|
||||
}
|
||||
} else {
|
||||
request.body = JSON.stringify(options.body);
|
||||
headers.append('Content-Type', 'application/json');
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
switch (OpenAPI.CLIENT) {
|
||||
case 'xhr':
|
||||
return await requestUsingXHR(url, request);
|
||||
default:
|
||||
return await requestUsingFetch(url, request);
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
url,
|
||||
ok: false,
|
||||
status: 0,
|
||||
statusText: '',
|
||||
body: error
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
/**
|
||||
* Request content using the new Fetch API. This is the default API that is used and
|
||||
* is create for all JSON, XML and text objects. However it is limited to UTF-8.
|
||||
* This is a problem for some of the Docs content, since that requires UTF-16!
|
||||
* @param url The url to request.
|
||||
* @param request The request object, containing method, headers, body, etc.
|
||||
*/
|
||||
export async function requestUsingFetch(url, request) {
|
||||
|
||||
// Fetch response using fetch API.
|
||||
const response = await fetch(url, request);
|
||||
|
||||
// Create result object.
|
||||
const result = {
|
||||
url,
|
||||
ok: response.ok,
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
body: null,
|
||||
};
|
||||
|
||||
// Try to parse the content for any response status code.
|
||||
// We check the "Content-Type" header to see if we need to parse the
|
||||
// content as json or as plain text.
|
||||
const contentType = response.headers.get('Content-Type');
|
||||
if (contentType) {
|
||||
switch (contentType.toLowerCase()) {
|
||||
case 'application/json':
|
||||
case 'application/json; charset=utf-8':
|
||||
result.body = await response.json();
|
||||
break;
|
||||
|
||||
case 'text/plain':
|
||||
case 'text/xml':
|
||||
case 'text/xml; charset=utf-8':
|
||||
case 'text/xml; charset=utf-16':
|
||||
result.body = await response.text();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -1,72 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
import { isSuccess } from './isSuccess';
|
||||
|
||||
/**
|
||||
* Request content using the new legacy XMLHttpRequest API. This method is useful
|
||||
* when we want to request UTF-16 content, since it natively supports loading UTF-16.
|
||||
* We could do the same with the Fetch API, but then we will need to convert the
|
||||
* content using JavaScript... And that is very very slow.
|
||||
* @param url The url to request.
|
||||
* @param request The request object, containing method, headers, body, etc.
|
||||
*/
|
||||
export async function requestUsingXHR(url, request) {
|
||||
return new Promise(resolve => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
// Open the request, remember to do this before adding any headers,
|
||||
// because the request needs to be initialized!
|
||||
xhr.open(request.method, url, true);
|
||||
|
||||
// Add the headers (required when dealing with JSON)
|
||||
const headers = request.headers as Headers;
|
||||
headers.forEach((value, key) => {
|
||||
xhr.setRequestHeader(key, value);
|
||||
});
|
||||
|
||||
// Register the readystate handler, this will fire when the request is done.
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
|
||||
// Create result object.
|
||||
const result = {
|
||||
url,
|
||||
ok: isSuccess(xhr.status),
|
||||
status: xhr.status,
|
||||
statusText: xhr.statusText,
|
||||
body: null,
|
||||
};
|
||||
|
||||
// Try to parse the content for any response status code.
|
||||
// We check the "Content-Type" header to see if we need to parse the
|
||||
// content as json or as plain text.
|
||||
const contentType = xhr.getResponseHeader('Content-Type');
|
||||
if (contentType) {
|
||||
switch (contentType.toLowerCase()) {
|
||||
case 'application/json':
|
||||
case 'application/json; charset=utf-8':
|
||||
result.body = JSON.parse(xhr.responseText);
|
||||
break;
|
||||
|
||||
case 'text/plain':
|
||||
case 'text/xml':
|
||||
case 'text/xml; charset=utf-8':
|
||||
case 'text/xml; charset=utf-16':
|
||||
result.body = xhr.responseText;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Done!
|
||||
resolve(result);
|
||||
}
|
||||
};
|
||||
|
||||
// Start the request!
|
||||
xhr.send(request.body);
|
||||
});
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
export { ApiError } from './core/ApiError';
|
||||
export { isSuccess } from './core/isSuccess';
|
||||
export { OpenAPI } from './core/OpenAPI';
|
||||
{{#if models}}
|
||||
|
||||
{{#each models}}
|
||||
import { {{{this}}} } from './models/{{{this}}}';
|
||||
{{/each}}
|
||||
|
||||
{{#each models}}
|
||||
export { {{{this}}} };
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{#if services}}
|
||||
|
||||
{{#each services}}
|
||||
export { {{{this}}} } from './services/{{{this}}}';
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{#if models}}
|
||||
|
||||
const definitions = {
|
||||
{{#each models}}
|
||||
'{{{this}}}': {{{this}}}.definition,
|
||||
{{/each}}
|
||||
};
|
||||
|
||||
export function getDefinition(definition) {
|
||||
if (definitions.hasOwnProperty(definition)) {
|
||||
return definitions[definition];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
{{/if}}
|
||||
@ -1,13 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
{{#equals export 'interface'}}
|
||||
{{>exportInterface}}
|
||||
{{else equals export 'enum'}}
|
||||
{{>exportEnum}}
|
||||
{{else}}
|
||||
{{>exportGeneric}}
|
||||
{{/equals}}
|
||||
@ -1,14 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
export let Dictionary;
|
||||
(function (Dictionary) {
|
||||
|
||||
Dictionary.definition = {
|
||||
type: 'Dictionary'
|
||||
};
|
||||
|
||||
})(Dictionary || (Dictionary = {}));
|
||||
@ -1,23 +0,0 @@
|
||||
{
|
||||
properties: {
|
||||
{{#if extends}}
|
||||
{{#each extends}}
|
||||
...{{{this}}}.definition.properties,
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{#if properties}}
|
||||
{{#each properties}}
|
||||
{{{name}}}: {{>definition}},
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
},
|
||||
{{#if isReadOnly~}}
|
||||
isReadOnly: {{{isReadOnly}}},
|
||||
{{/if}}
|
||||
{{#if isRequired~}}
|
||||
isRequired: {{{isRequired}}},
|
||||
{{/if}}
|
||||
{{#if isNullable~}}
|
||||
isNullable: {{{isNullable}}},
|
||||
{{/if}}
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
{{#if description}}
|
||||
/**
|
||||
* {{{description}}}
|
||||
*/
|
||||
{{/if}}
|
||||
export let {{{name}}};
|
||||
(function ({{{name}}}) {
|
||||
|
||||
{{#if enum}}
|
||||
{{#each enum}}
|
||||
{{{../name}}}.{{{name}}} = {{{value}}};
|
||||
{{/each}}
|
||||
|
||||
{{/if}}
|
||||
{{{name}}}.definition = {{>definition}};
|
||||
|
||||
})({{{name}}} || ({{{name}}} = {}));
|
||||
@ -1,11 +0,0 @@
|
||||
{{#if description}}
|
||||
/**
|
||||
* {{{description}}}
|
||||
*/
|
||||
{{/if}}
|
||||
export let {{{name}}};
|
||||
(function ({{{name}}}) {
|
||||
|
||||
{{{name}}}.definition = {{>definition}};
|
||||
|
||||
})({{{name}}} || ({{{name}}} = {}));
|
||||
@ -1,26 +0,0 @@
|
||||
{{#if description}}
|
||||
/**
|
||||
* {{{description}}}
|
||||
*/
|
||||
{{/if}}
|
||||
export let {{{name}}};
|
||||
(function ({{{name}}}) {
|
||||
|
||||
{{#if enums}}
|
||||
{{#each enums}}
|
||||
{{#if description}}
|
||||
/**
|
||||
* {{{description}}}
|
||||
*/
|
||||
{{/if}}
|
||||
{{{../name}}}.{{{name}}} = {
|
||||
{{#each enum}}
|
||||
{{{name}}}: {{{value}}},
|
||||
{{/each}}
|
||||
};
|
||||
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{{name}}}.definition = {{>definition}};
|
||||
|
||||
})({{{name}}} || ({{{name}}} = {}));
|
||||
@ -1,92 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
import { ApiError, catchGenericError } from '../core/ApiError';
|
||||
import { request as $request } from '../core/request';
|
||||
import { OpenAPI } from '../core/OpenAPI';
|
||||
|
||||
export class {{{name}}} {
|
||||
|
||||
{{#each operations}}
|
||||
/**
|
||||
{{#if deprecated}}
|
||||
* @deprecated
|
||||
{{/if}}
|
||||
{{#if summary}}
|
||||
* {{{summary}}}
|
||||
{{/if}}
|
||||
{{#if description}}
|
||||
* {{{description}}}
|
||||
{{/if}}
|
||||
{{#if parameters}}
|
||||
{{#each parameters}}
|
||||
* @param {{{name}}} {{{description}}}
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{#each results}}
|
||||
* @result {{{type}}} {{{description}}}
|
||||
{{/each}}
|
||||
* @throws ApiError
|
||||
*/
|
||||
static async {{{name}}}({{#if parameters}}
|
||||
{{#each parameters}}
|
||||
{{{name}}}{{#if default}} = {{{default}}}{{/if}},
|
||||
{{/each}}
|
||||
{{/if}}) {
|
||||
|
||||
const result = await $request({
|
||||
method: '{{{method}}}',
|
||||
path: `{{{path}}}`,
|
||||
{{#if parametersCookie~}}
|
||||
cookies: {
|
||||
{{#each parametersCookie}}
|
||||
'{{{prop}}}': {{{name}}},
|
||||
{{/each}}
|
||||
},
|
||||
{{/if}}
|
||||
{{#if parametersHeader~}}
|
||||
headers: {
|
||||
{{#each parametersHeader}}
|
||||
'{{{prop}}}': {{{name}}},
|
||||
{{/each}}
|
||||
},
|
||||
{{/if}}
|
||||
{{#if parametersQuery~}}
|
||||
query: {
|
||||
{{#each parametersQuery}}
|
||||
'{{{prop}}}': {{{name}}},
|
||||
{{/each}}
|
||||
},
|
||||
{{/if}}
|
||||
{{#if parametersForm~}}
|
||||
formData: {
|
||||
{{#each parametersForm}}
|
||||
'{{{prop}}}': {{{name}}},
|
||||
{{/each}}
|
||||
},
|
||||
{{/if}}
|
||||
{{#if parametersBody~}}
|
||||
body: {{{parametersBody.name}}},
|
||||
{{/if}}
|
||||
});
|
||||
{{#if errors}}
|
||||
|
||||
if (!result.ok) {
|
||||
switch (result.status) {
|
||||
{{#each errors}}
|
||||
case {{{code}}}: throw new ApiError(result, `{{{description}}}`);
|
||||
{{/each}}
|
||||
}
|
||||
}
|
||||
{{/if}}
|
||||
|
||||
catchGenericError(result);
|
||||
|
||||
return result.body;
|
||||
}
|
||||
|
||||
{{/each}}
|
||||
}
|
||||
@ -6,11 +6,3 @@
|
||||
export type Dictionary<T> = {
|
||||
[key: string]: T;
|
||||
}
|
||||
|
||||
export namespace Dictionary {
|
||||
|
||||
export const definition = {
|
||||
type: 'Dictionary'
|
||||
};
|
||||
|
||||
}
|
||||
8
src/templates/models/index.hbs
Normal file
8
src/templates/models/index.hbs
Normal file
@ -0,0 +1,8 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
{{#each models}}
|
||||
export { {{{this}}} } from './{{{this}}}';
|
||||
{{/each}}
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
{{#if imports}}
|
||||
{{#each imports}}
|
||||
import { {{{this}}} } from '../models/{{{this}}}';
|
||||
import { {{{this}}} } from './{{{this}}}';
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
@ -8,9 +8,3 @@ export enum {{{name}}} {
|
||||
{{{name}}} = {{{value}}},
|
||||
{{/each}}
|
||||
}
|
||||
|
||||
export namespace {{{name}}} {
|
||||
|
||||
export const definition = {{>definition}};
|
||||
|
||||
}
|
||||
@ -4,9 +4,3 @@
|
||||
*/
|
||||
{{/if}}
|
||||
export type {{{name}}} = {{>type}};
|
||||
|
||||
export namespace {{{name}}} {
|
||||
|
||||
export const definition = {{>definition}};
|
||||
|
||||
}
|
||||
@ -13,10 +13,10 @@ export interface {{{name}}}{{>extends}} {
|
||||
{{>isReadOnly}}{{{name}}}{{>isRequired}}: {{>type parent=../name}};
|
||||
{{/each}}
|
||||
}
|
||||
{{#if enums}}
|
||||
|
||||
export namespace {{{name}}} {
|
||||
|
||||
{{#if enums}}
|
||||
{{#each enums}}
|
||||
{{#if description}}
|
||||
/**
|
||||
@ -30,7 +30,6 @@ export namespace {{{name}}} {
|
||||
}
|
||||
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
export const definition = {{>definition}};
|
||||
|
||||
}
|
||||
{{/if}}
|
||||
@ -1,11 +1,11 @@
|
||||
{{#equals export 'interface'}}
|
||||
{{>definitionInterface}}
|
||||
{{>schemaInterface}}
|
||||
{{else equals export 'enum'}}
|
||||
{{>definitionEnum}}
|
||||
{{>schemaEnum}}
|
||||
{{else equals export 'array'}}
|
||||
{{>definitionArray}}
|
||||
{{>schemaArray}}
|
||||
{{else equals export 'dictionary'}}
|
||||
{{>definitionDictionary}}
|
||||
{{>schemaDictionary}}
|
||||
{{else}}
|
||||
{{>definitionGeneric}}
|
||||
{{>schemaGeneric}}
|
||||
{{/equals}}
|
||||
@ -2,12 +2,12 @@
|
||||
properties: {
|
||||
{{#if extends}}
|
||||
{{#each extends}}
|
||||
...{{{this}}}.definition.properties,
|
||||
...${{{this}}}.properties,
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{#if properties}}
|
||||
{{#each properties}}
|
||||
{{{name}}}: {{>definition}},
|
||||
{{{name}}}: {{>schema}},
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
},
|
||||
8
src/templates/schemas/$Dictionary.ts
Normal file
8
src/templates/schemas/$Dictionary.ts
Normal file
@ -0,0 +1,8 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
export const $Dictionary = {
|
||||
type: 'Dictionary'
|
||||
};
|
||||
8
src/templates/schemas/index.hbs
Normal file
8
src/templates/schemas/index.hbs
Normal file
@ -0,0 +1,8 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
{{#each schemas}}
|
||||
export { ${{{this}}} as {{{this}}} } from './${{{this}}}';
|
||||
{{/each}}
|
||||
12
src/templates/schemas/schema.hbs
Normal file
12
src/templates/schemas/schema.hbs
Normal file
@ -0,0 +1,12 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
{{#if extends}}
|
||||
{{#each extends}}
|
||||
import { ${{{this}}} } from './${{{this}}}';
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
export const ${{{name}}} = {{>schema}};
|
||||
8
src/templates/services/index.hbs
Normal file
8
src/templates/services/index.hbs
Normal file
@ -0,0 +1,8 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
{{#each services}}
|
||||
export { {{{this}}} } from './{{{this}}}';
|
||||
{{/each}}
|
||||
@ -1,42 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
export { ApiError } from './core/ApiError';
|
||||
export { isSuccess } from './core/isSuccess';
|
||||
export { OpenAPI } from './core/OpenAPI';
|
||||
{{#if models}}
|
||||
|
||||
{{#each models}}
|
||||
import { {{{this}}} } from './models/{{{this}}}';
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{#if models}}
|
||||
|
||||
{{#each models}}
|
||||
export { {{{this}}} };
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{#if services}}
|
||||
|
||||
{{#each services}}
|
||||
export { {{{this}}} } from './services/{{{this}}}';
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{#if models}}
|
||||
|
||||
const definitions = {
|
||||
{{#each models}}
|
||||
'{{{this}}}': {{{this}}}.definition,
|
||||
{{/each}}
|
||||
};
|
||||
|
||||
export function getDefinition<K extends keyof typeof definitions>(definition: K) {
|
||||
if (definitions.hasOwnProperty(definition)) {
|
||||
return definitions[definition];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
{{/if}}
|
||||
@ -1,11 +0,0 @@
|
||||
{{#equals export 'interface'}}
|
||||
{{>definitionInterface}}
|
||||
{{else equals export 'enum'}}
|
||||
{{>definitionEnum}}
|
||||
{{else equals export 'array'}}
|
||||
{{>definitionArray}}
|
||||
{{else equals export 'dictionary'}}
|
||||
{{>definitionDictionary}}
|
||||
{{else}}
|
||||
{{>definitionGeneric}}
|
||||
{{/equals}}
|
||||
@ -1,12 +0,0 @@
|
||||
{
|
||||
type: 'Array',
|
||||
{{#if isReadOnly~}}
|
||||
isReadOnly: {{{isReadOnly}}},
|
||||
{{/if}}
|
||||
{{#if isRequired~}}
|
||||
isRequired: {{{isRequired}}},
|
||||
{{/if}}
|
||||
{{#if isNullable~}}
|
||||
isNullable: {{{isNullable}}},
|
||||
{{/if}}
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
{
|
||||
type: 'Dictionary',
|
||||
{{#if isReadOnly~}}
|
||||
isReadOnly: {{{isReadOnly}}},
|
||||
{{/if}}
|
||||
{{#if isRequired~}}
|
||||
isRequired: {{{isRequired}}},
|
||||
{{/if}}
|
||||
{{#if isNullable~}}
|
||||
isNullable: {{{isNullable}}},
|
||||
{{/if}}
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
{
|
||||
type: 'Enum',
|
||||
{{#if isReadOnly~}}
|
||||
isReadOnly: {{{isReadOnly}}},
|
||||
{{/if}}
|
||||
{{#if isRequired~}}
|
||||
isRequired: {{{isRequired}}},
|
||||
{{/if}}
|
||||
{{#if isNullable~}}
|
||||
isNullable: {{{isNullable}}},
|
||||
{{/if}}
|
||||
}
|
||||
@ -1,56 +0,0 @@
|
||||
{
|
||||
{{#if type~}}
|
||||
type: '{{{base}}}',
|
||||
{{/if}}
|
||||
{{#if isReadOnly~}}
|
||||
isReadOnly: {{{isReadOnly}}},
|
||||
{{/if}}
|
||||
{{#if isRequired~}}
|
||||
isRequired: {{{isRequired}}},
|
||||
{{/if}}
|
||||
{{#if isNullable~}}
|
||||
isNullable: {{{isNullable}}},
|
||||
{{/if}}
|
||||
{{#if format~}}
|
||||
format: '{{{format}}}',
|
||||
{{/if}}
|
||||
{{#if maximum~}}
|
||||
maximum: {{{maximum}}},
|
||||
{{/if}}
|
||||
{{#if exclusiveMaximum~}}
|
||||
exclusiveMaximum: {{{exclusiveMaximum}}},
|
||||
{{/if}}
|
||||
{{#if minimum~}}
|
||||
minimum: {{{minimum}}},
|
||||
{{/if}}
|
||||
{{#if exclusiveMinimum~}}
|
||||
exclusiveMinimum: {{{exclusiveMinimum}}},
|
||||
{{/if}}
|
||||
{{#if multipleOf~}}
|
||||
multipleOf: {{{multipleOf}}},
|
||||
{{/if}}
|
||||
{{#if maxLength~}}
|
||||
maxLength: {{{maxLength}}},
|
||||
{{/if}}
|
||||
{{#if minLength~}}
|
||||
minLength: {{{minLength}}},
|
||||
{{/if}}
|
||||
{{#if pattern~}}
|
||||
pattern: '{{{pattern}}}',
|
||||
{{/if}}
|
||||
{{#if maxItems~}}
|
||||
maxItems: {{{maxItems}}},
|
||||
{{/if}}
|
||||
{{#if minItems~}}
|
||||
minItems: {{{minItems}}},
|
||||
{{/if}}
|
||||
{{#if uniqueItems~}}
|
||||
uniqueItems: {{{uniqueItems}}},
|
||||
{{/if}}
|
||||
{{#if maxProperties~}}
|
||||
maxProperties: {{{maxProperties}}},
|
||||
{{/if}}
|
||||
{{#if minProperties~}}
|
||||
minProperties: {{{minProperties}}},
|
||||
{{/if}}
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
import { Language } from '../index';
|
||||
import { getFileName } from './getFileName';
|
||||
|
||||
describe('getFileName', () => {
|
||||
it('should convert to correct file name', () => {
|
||||
expect(getFileName('file', Language.TYPESCRIPT)).toEqual('file.ts');
|
||||
expect(getFileName('file', Language.JAVASCRIPT)).toEqual('file.js');
|
||||
});
|
||||
});
|
||||
@ -1,16 +0,0 @@
|
||||
import { Language } from '../index';
|
||||
|
||||
/**
|
||||
* Get the correct file name and extension for a given language.
|
||||
* @param fileName Any file name.
|
||||
* @param language Typescript or Javascript.
|
||||
*/
|
||||
export function getFileName(fileName: string, language: Language): string {
|
||||
switch (language) {
|
||||
case Language.TYPESCRIPT:
|
||||
return `${fileName}.ts`;
|
||||
case Language.JAVASCRIPT:
|
||||
return `${fileName}.js`;
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
@ -59,7 +59,7 @@ describe('getModelNames', () => {
|
||||
properties: [],
|
||||
});
|
||||
|
||||
expect(getModelNames([])).toEqual(['Dictionary']);
|
||||
expect(getModelNames(models)).toEqual(['Dictionary', 'Doe', 'Jane', 'John']);
|
||||
expect(getModelNames([])).toEqual([]);
|
||||
expect(getModelNames(models)).toEqual(['Doe', 'Jane', 'John']);
|
||||
});
|
||||
});
|
||||
|
||||
@ -3,7 +3,6 @@ import { Model } from '../client/interfaces/Model';
|
||||
export function getModelNames(models: Model[]): string[] {
|
||||
return models
|
||||
.map(model => model.name)
|
||||
.concat('Dictionary')
|
||||
.sort((a, b) => {
|
||||
const nameA = a.toLowerCase();
|
||||
const nameB = b.toLowerCase();
|
||||
|
||||
@ -16,16 +16,18 @@ describe('readHandlebarsTemplates', () => {
|
||||
fsReadFileSync.mockReturnValue('{{{message}}}');
|
||||
globSync.mockReturnValue([]);
|
||||
|
||||
const template = readHandlebarsTemplates(Language.TYPESCRIPT);
|
||||
const template = readHandlebarsTemplates();
|
||||
|
||||
expect(template).toBeDefined();
|
||||
expect(template.index).toBeDefined();
|
||||
expect(template.model).toBeDefined();
|
||||
expect(template.models).toBeDefined();
|
||||
expect(template.service).toBeDefined();
|
||||
expect(template.services).toBeDefined();
|
||||
expect(template.settings).toBeDefined();
|
||||
expect(template.index({ message: 'Hello World!' })).toEqual('Hello World!');
|
||||
expect(template.model({ message: 'Hello World!' })).toEqual('Hello World!');
|
||||
expect(template.models({ message: 'Hello World!' })).toEqual('Hello World!');
|
||||
expect(template.service({ message: 'Hello World!' })).toEqual('Hello World!');
|
||||
expect(template.services({ message: 'Hello World!' })).toEqual('Hello World!');
|
||||
expect(template.settings({ message: 'Hello World!' })).toEqual('Hello World!');
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
import * as Handlebars from 'handlebars';
|
||||
import * as glob from 'glob';
|
||||
import * as path from 'path';
|
||||
import { Language } from '../index';
|
||||
import { readHandlebarsTemplate } from './readHandlebarsTemplate';
|
||||
import { registerHandlebarHelpers } from './registerHandlebarHelpers';
|
||||
|
||||
export interface Templates {
|
||||
index: Handlebars.TemplateDelegate;
|
||||
models: Handlebars.TemplateDelegate;
|
||||
model: Handlebars.TemplateDelegate;
|
||||
schemas: Handlebars.TemplateDelegate;
|
||||
schema: Handlebars.TemplateDelegate;
|
||||
services: Handlebars.TemplateDelegate;
|
||||
service: Handlebars.TemplateDelegate;
|
||||
settings: Handlebars.TemplateDelegate;
|
||||
}
|
||||
@ -15,20 +17,22 @@ export interface Templates {
|
||||
/**
|
||||
* Read all the Handlebar templates that we need and return on wrapper object
|
||||
* so we can easily access the templates in out generator / write functions.
|
||||
* @param language The language we need to generate (Typescript or Javascript).
|
||||
*/
|
||||
export function readHandlebarsTemplates(language: Language): Templates {
|
||||
export function readHandlebarsTemplates(): Templates {
|
||||
try {
|
||||
registerHandlebarHelpers();
|
||||
|
||||
const templates: Templates = {
|
||||
index: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/index.hbs`)),
|
||||
model: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/model.hbs`)),
|
||||
service: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/service.hbs`)),
|
||||
settings: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/core/OpenAPI.hbs`)),
|
||||
models: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/models/index.hbs`)),
|
||||
model: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/models/model.hbs`)),
|
||||
schemas: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/schemas/index.hbs`)),
|
||||
schema: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/schemas/schema.hbs`)),
|
||||
services: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/services/index.hbs`)),
|
||||
service: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/services/service.hbs`)),
|
||||
settings: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/core/OpenAPI.hbs`)),
|
||||
};
|
||||
|
||||
const partials = path.resolve(__dirname, `../../src/templates/${language}/partials`);
|
||||
const partials = path.resolve(__dirname, `../../src/templates//partials`);
|
||||
const partialsFiles = glob.sync('*.hbs', { cwd: partials });
|
||||
partialsFiles.forEach(partial => {
|
||||
Handlebars.registerPartial(path.basename(partial, '.hbs'), readHandlebarsTemplate(path.resolve(partials, partial)));
|
||||
|
||||
@ -3,7 +3,7 @@ import * as glob from 'glob';
|
||||
import * as mkdirp from 'mkdirp';
|
||||
import * as rimraf from 'rimraf';
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { HttpClient, Language } from '../index';
|
||||
import { HttpClient } from '../index';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { writeClient } from './writeClient';
|
||||
|
||||
@ -27,15 +27,18 @@ describe('writeClient', () => {
|
||||
};
|
||||
|
||||
const templates: Templates = {
|
||||
index: () => 'dummy',
|
||||
model: () => 'dummy',
|
||||
models: () => 'dummy',
|
||||
schema: () => 'dummy',
|
||||
schemas: () => 'dummy',
|
||||
service: () => 'dummy',
|
||||
services: () => 'dummy',
|
||||
settings: () => 'dummy',
|
||||
};
|
||||
|
||||
globSync.mockReturnValue([]);
|
||||
|
||||
writeClient(client, Language.TYPESCRIPT, HttpClient.FETCH, templates, '/');
|
||||
writeClient(client, HttpClient.FETCH, templates, '/');
|
||||
|
||||
expect(rimrafSync).toBeCalled();
|
||||
expect(mkdirpSync).toBeCalled();
|
||||
|
||||
@ -4,24 +4,24 @@ import * as mkdirp from 'mkdirp';
|
||||
import * as path from 'path';
|
||||
import * as rimraf from 'rimraf';
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { HttpClient, Language } from '../index';
|
||||
import { HttpClient } from '../index';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { writeClientIndex } from './writeClientIndex';
|
||||
import { writeClientModels } from './writeClientModels';
|
||||
import { writeClientSchemas } from './writeClientSchemas';
|
||||
import { writeClientServices } from './writeClientServices';
|
||||
import { writeClientSettings } from './writeClientSettings';
|
||||
|
||||
/**
|
||||
* Write our OpenAPI client, using the given templates at the given output path.
|
||||
* @param client Client object with all the models, services, etc.
|
||||
* @param language The language that should be generated (Typescript or Javascript).
|
||||
* @param httpClient The selected httpClient (fetch or XHR).
|
||||
* @param templates Templates wrapper with all loaded Handlebars templates.
|
||||
* @param outputPath
|
||||
*/
|
||||
export function writeClient(client: Client, language: Language, httpClient: HttpClient, templates: Templates, outputPath: string): void {
|
||||
export function writeClient(client: Client, httpClient: HttpClient, templates: Templates, outputPath: string): void {
|
||||
const outputPathCore = path.resolve(outputPath, 'core');
|
||||
const outputPathModels = path.resolve(outputPath, 'models');
|
||||
const outputPathSchemas = path.resolve(outputPath, 'schemas');
|
||||
const outputPathServices = path.resolve(outputPath, 'services');
|
||||
|
||||
// Clean output directory
|
||||
@ -36,14 +36,15 @@ export function writeClient(client: Client, language: Language, httpClient: Http
|
||||
mkdirp.sync(outputPath);
|
||||
mkdirp.sync(outputPathCore);
|
||||
mkdirp.sync(outputPathModels);
|
||||
mkdirp.sync(outputPathSchemas);
|
||||
mkdirp.sync(outputPathServices);
|
||||
} catch (e) {
|
||||
throw new Error(`Could not create output directories`);
|
||||
}
|
||||
|
||||
// Copy all support files
|
||||
const supportFiles = path.resolve(__dirname, `../../src/templates/${language}/`);
|
||||
const supportFilesList = glob.sync('**/*.{ts,js}', { cwd: supportFiles });
|
||||
const supportFiles = path.resolve(__dirname, `../../src/templates/`);
|
||||
const supportFilesList = glob.sync('**/*.ts', { cwd: supportFiles });
|
||||
supportFilesList.forEach(file => {
|
||||
fs.copyFileSync(
|
||||
path.resolve(supportFiles, file), // From input path
|
||||
@ -52,12 +53,8 @@ export function writeClient(client: Client, language: Language, httpClient: Http
|
||||
});
|
||||
|
||||
// Write the client files
|
||||
try {
|
||||
writeClientSettings(client, language, httpClient, templates, outputPathCore);
|
||||
writeClientModels(client.models, language, templates, outputPathModels);
|
||||
writeClientServices(client.services, language, templates, outputPathServices);
|
||||
writeClientIndex(client, language, templates, outputPath);
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
writeClientSettings(client, httpClient, templates, outputPathCore);
|
||||
writeClientModels(client.models, templates, outputPathModels);
|
||||
writeClientSchemas(client.models, templates, outputPathSchemas);
|
||||
writeClientServices(client.services, templates, outputPathServices);
|
||||
}
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
import * as fs from 'fs';
|
||||
import * as glob from 'glob';
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { Language } from '../index';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { writeClientIndex } from './writeClientIndex';
|
||||
|
||||
jest.mock('fs');
|
||||
jest.mock('glob');
|
||||
|
||||
const fsWriteFileSync = fs.writeFileSync as jest.MockedFunction<typeof fs.writeFileSync>;
|
||||
const globSync = glob.sync as jest.MockedFunction<typeof glob.sync>;
|
||||
|
||||
describe('writeClientIndex', () => {
|
||||
it('should write to filesystem', () => {
|
||||
const client: Client = {
|
||||
server: 'http://localhost:8080',
|
||||
version: '1.0',
|
||||
models: [],
|
||||
services: [],
|
||||
};
|
||||
|
||||
const templates: Templates = {
|
||||
index: () => 'dummy',
|
||||
model: () => 'dummy',
|
||||
service: () => 'dummy',
|
||||
settings: () => 'dummy',
|
||||
};
|
||||
|
||||
globSync.mockReturnValue([]);
|
||||
|
||||
writeClientIndex(client, Language.TYPESCRIPT, templates, '/');
|
||||
|
||||
expect(fsWriteFileSync).toBeCalledWith('/index.ts', 'dummy');
|
||||
});
|
||||
});
|
||||
@ -1,34 +0,0 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { Language } from '../index';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { getFileName } from './getFileName';
|
||||
import { getModelNames } from './getModelNames';
|
||||
import { getServiceNames } from './getServiceNames';
|
||||
|
||||
/**
|
||||
* Generate the OpenAPI client index file using the Handlebar template and write it to disk.
|
||||
* The index file just contains all the exports you need to use the client as a standalone
|
||||
* library. But yuo can also import individual models and services directly.
|
||||
* @param client Client object, containing, models, schemas and services.
|
||||
* @param language The output language (Typescript or javascript).
|
||||
* @param templates The loaded handlebar templates.
|
||||
* @param outputPath
|
||||
*/
|
||||
export function writeClientIndex(client: Client, language: Language, templates: Templates, outputPath: string): void {
|
||||
const fileName = getFileName('index', language);
|
||||
try {
|
||||
fs.writeFileSync(
|
||||
path.resolve(outputPath, fileName),
|
||||
templates.index({
|
||||
server: client.server,
|
||||
version: client.version,
|
||||
models: getModelNames(client.models),
|
||||
services: getServiceNames(client.services),
|
||||
})
|
||||
);
|
||||
} catch (e) {
|
||||
throw new Error(`Could not write index: "${fileName}"`);
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
import * as fs from 'fs';
|
||||
import { Language } from '../index';
|
||||
import { Model } from '../client/interfaces/Model';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { writeClientModels } from './writeClientModels';
|
||||
@ -31,13 +30,16 @@ describe('writeClientModels', () => {
|
||||
});
|
||||
|
||||
const templates: Templates = {
|
||||
index: () => 'dummy',
|
||||
model: () => 'dummy',
|
||||
models: () => 'dummy',
|
||||
schema: () => 'dummy',
|
||||
schemas: () => 'dummy',
|
||||
service: () => 'dummy',
|
||||
services: () => 'dummy',
|
||||
settings: () => 'dummy',
|
||||
};
|
||||
|
||||
writeClientModels(models, Language.TYPESCRIPT, templates, '/');
|
||||
writeClientModels(models, templates, '/');
|
||||
|
||||
expect(fsWriteFileSync).toBeCalledWith('/Item.ts', 'dummy');
|
||||
});
|
||||
|
||||
@ -1,28 +1,28 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { Language } from '../index';
|
||||
import { Model } from '../client/interfaces/Model';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { exportModel } from './exportModel';
|
||||
import { format } from './format';
|
||||
import { getFileName } from './getFileName';
|
||||
import { getModelNames } from './getModelNames';
|
||||
|
||||
/**
|
||||
* Generate Models using the Handlebar template and write to disk.
|
||||
* @param models Array of Models to write.
|
||||
* @param language The output language (Typescript or javascript).
|
||||
* @param templates The loaded handlebar templates.
|
||||
* @param outputPath
|
||||
*/
|
||||
export function writeClientModels(models: Model[], language: Language, templates: Templates, outputPath: string): void {
|
||||
export function writeClientModels(models: Model[], templates: Templates, outputPath: string): void {
|
||||
models.forEach(model => {
|
||||
const fileName = getFileName(model.name, language);
|
||||
try {
|
||||
const templateData = exportModel(model);
|
||||
const templateResult = templates.model(templateData);
|
||||
fs.writeFileSync(path.resolve(outputPath, fileName), format(templateResult));
|
||||
} catch (e) {
|
||||
throw new Error(`Could not write model: "${fileName}"`);
|
||||
}
|
||||
const file = path.resolve(outputPath, `${model.name}.ts`);
|
||||
const templateData = exportModel(model);
|
||||
const templateResult = templates.model(templateData);
|
||||
fs.writeFileSync(file, format(templateResult));
|
||||
});
|
||||
|
||||
const file = path.resolve(outputPath, 'index.ts');
|
||||
const templateResult = templates.models({
|
||||
models: getModelNames(models),
|
||||
});
|
||||
fs.writeFileSync(file, format(templateResult));
|
||||
}
|
||||
|
||||
46
src/utils/writeClientSchemas.spec.ts
Normal file
46
src/utils/writeClientSchemas.spec.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import * as fs from 'fs';
|
||||
import { Model } from '../client/interfaces/Model';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { writeClientModels } from './writeClientModels';
|
||||
|
||||
jest.mock('fs');
|
||||
|
||||
const fsWriteFileSync = fs.writeFileSync as jest.MockedFunction<typeof fs.writeFileSync>;
|
||||
|
||||
describe('writeClientModels', () => {
|
||||
it('should write to filesystem', () => {
|
||||
const models: Model[] = [];
|
||||
models.push({
|
||||
export: 'interface',
|
||||
name: 'Item',
|
||||
type: 'Item',
|
||||
base: 'Item',
|
||||
template: null,
|
||||
link: null,
|
||||
description: null,
|
||||
isProperty: false,
|
||||
isReadOnly: false,
|
||||
isRequired: false,
|
||||
isNullable: false,
|
||||
imports: [],
|
||||
extends: [],
|
||||
enum: [],
|
||||
enums: [],
|
||||
properties: [],
|
||||
});
|
||||
|
||||
const templates: Templates = {
|
||||
model: () => 'dummy',
|
||||
models: () => 'dummy',
|
||||
schema: () => 'dummy',
|
||||
schemas: () => 'dummy',
|
||||
service: () => 'dummy',
|
||||
services: () => 'dummy',
|
||||
settings: () => 'dummy',
|
||||
};
|
||||
|
||||
writeClientModels(models, templates, '/');
|
||||
|
||||
expect(fsWriteFileSync).toBeCalledWith('/Item.ts', 'dummy');
|
||||
});
|
||||
});
|
||||
28
src/utils/writeClientSchemas.ts
Normal file
28
src/utils/writeClientSchemas.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { Model } from '../client/interfaces/Model';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { exportModel } from './exportModel';
|
||||
import { format } from './format';
|
||||
import { getModelNames } from './getModelNames';
|
||||
|
||||
/**
|
||||
* Generate Schemas using the Handlebar template and write to disk.
|
||||
* @param models Array of Models to write.
|
||||
* @param templates The loaded handlebar templates.
|
||||
* @param outputPath
|
||||
*/
|
||||
export function writeClientSchemas(models: Model[], templates: Templates, outputPath: string): void {
|
||||
models.forEach(model => {
|
||||
const file = path.resolve(outputPath, `$${model.name}.ts`);
|
||||
const templateData = exportModel(model);
|
||||
const templateResult = templates.schema(templateData);
|
||||
fs.writeFileSync(file, format(templateResult));
|
||||
});
|
||||
|
||||
const file = path.resolve(outputPath, 'index.ts');
|
||||
const templateResult = templates.schemas({
|
||||
schemas: getModelNames(models),
|
||||
});
|
||||
fs.writeFileSync(file, format(templateResult));
|
||||
}
|
||||
@ -18,13 +18,16 @@ describe('writeClientServices', () => {
|
||||
});
|
||||
|
||||
const templates: Templates = {
|
||||
index: () => 'dummy',
|
||||
model: () => 'dummy',
|
||||
models: () => 'dummy',
|
||||
schema: () => 'dummy',
|
||||
schemas: () => 'dummy',
|
||||
service: () => 'dummy',
|
||||
services: () => 'dummy',
|
||||
settings: () => 'dummy',
|
||||
};
|
||||
|
||||
writeClientServices(services, Language.TYPESCRIPT, templates, '/');
|
||||
writeClientServices(services, templates, '/');
|
||||
|
||||
expect(fsWriteFileSync).toBeCalledWith('/Item.ts', 'dummy');
|
||||
});
|
||||
|
||||
@ -1,28 +1,28 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { Language } from '../index';
|
||||
import { Service } from '../client/interfaces/Service';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { exportService } from './exportService';
|
||||
import { format } from './format';
|
||||
import { getFileName } from './getFileName';
|
||||
import { getServiceNames } from './getServiceNames';
|
||||
|
||||
/**
|
||||
* Generate Services using the Handlebar template and write to disk.
|
||||
* @param services Array of Services to write.
|
||||
* @param language The output language (Typescript or javascript).
|
||||
* @param templates The loaded handlebar templates.
|
||||
* @param outputPath
|
||||
*/
|
||||
export function writeClientServices(services: Service[], language: Language, templates: Templates, outputPath: string): void {
|
||||
export function writeClientServices(services: Service[], templates: Templates, outputPath: string): void {
|
||||
services.forEach(service => {
|
||||
const fileName = getFileName(service.name, language);
|
||||
try {
|
||||
const templateData = exportService(service);
|
||||
const templateResult = templates.service(templateData);
|
||||
fs.writeFileSync(path.resolve(outputPath, fileName), format(templateResult));
|
||||
} catch (e) {
|
||||
throw new Error(`Could not write service: "${fileName}"`);
|
||||
}
|
||||
const file = path.resolve(outputPath, `${service.name}.ts`);
|
||||
const templateData = exportService(service);
|
||||
const templateResult = templates.service(templateData);
|
||||
fs.writeFileSync(file, format(templateResult));
|
||||
});
|
||||
|
||||
const file = path.resolve(outputPath, 'index.ts');
|
||||
const templateResult = templates.services({
|
||||
services: getServiceNames(services),
|
||||
});
|
||||
fs.writeFileSync(file, format(templateResult));
|
||||
}
|
||||
|
||||
@ -1,23 +1,16 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { HttpClient, Language } from '../index';
|
||||
import { HttpClient } from '../index';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { getFileName } from './getFileName';
|
||||
|
||||
export function writeClientSettings(client: Client, language: Language, httpClient: HttpClient, templates: Templates, outputPath: string): void {
|
||||
const fileName = getFileName('OpenAPI', language);
|
||||
try {
|
||||
fs.writeFileSync(
|
||||
path.resolve(outputPath, fileName),
|
||||
templates.settings({
|
||||
language,
|
||||
httpClient,
|
||||
server: client.server,
|
||||
version: client.version,
|
||||
})
|
||||
);
|
||||
} catch (e) {
|
||||
throw new Error(`Could not write settings: "${fileName}"`);
|
||||
}
|
||||
export function writeClientSettings(client: Client, httpClient: HttpClient, templates: Templates, outputPath: string): void {
|
||||
fs.writeFileSync(
|
||||
path.resolve(outputPath, 'OpenAPI.ts'),
|
||||
templates.settings({
|
||||
httpClient,
|
||||
server: client.server,
|
||||
version: client.version,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,32 +1,16 @@
|
||||
const OpenAPI = require('../dist');
|
||||
|
||||
OpenAPI.generate(
|
||||
'./test/mock/spec-v2.json',
|
||||
'./test/result/v2/typescript/',
|
||||
OpenAPI.Language.TYPESCRIPT,
|
||||
'./test/mock/v2/spec.json',
|
||||
'./test/result/v2/',
|
||||
OpenAPI.HttpClient.FETCH,
|
||||
);
|
||||
|
||||
OpenAPI.generate(
|
||||
'./test/mock/spec-v2.json',
|
||||
'./test/result/v2/javascript/',
|
||||
OpenAPI.Language.JAVASCRIPT,
|
||||
OpenAPI.HttpClient.XHR,
|
||||
);
|
||||
|
||||
OpenAPI.generate(
|
||||
'./test/mock/spec-v3.json',
|
||||
'./test/result/v3/typescript/',
|
||||
OpenAPI.Language.TYPESCRIPT,
|
||||
'./test/mock/v3/spec.json',
|
||||
'./test/result/v3/',
|
||||
OpenAPI.HttpClient.FETCH,
|
||||
);
|
||||
|
||||
OpenAPI.generate(
|
||||
'./test/mock/spec-v3.json',
|
||||
'./test/result/v3/javascript/',
|
||||
OpenAPI.Language.JAVASCRIPT,
|
||||
OpenAPI.HttpClient.XHR,
|
||||
);
|
||||
|
||||
OpenAPI.compile('./test/result/v2/typescript/');
|
||||
OpenAPI.compile('./test/result/v3/typescript/');
|
||||
OpenAPI.compile('./test/result/v2/');
|
||||
OpenAPI.compile('./test/result/v3/');
|
||||
|
||||
@ -6,79 +6,35 @@ describe('generation', () => {
|
||||
|
||||
describe('v2', () => {
|
||||
|
||||
describe('typescript', () => {
|
||||
OpenAPI.generate(
|
||||
'./test/mock/v2/spec.json',
|
||||
'./test/result/v2/',
|
||||
OpenAPI.HttpClient.FETCH,
|
||||
);
|
||||
|
||||
OpenAPI.generate(
|
||||
'./test/mock/spec-v2.json',
|
||||
'./test/result/v2/typescript/',
|
||||
OpenAPI.Language.TYPESCRIPT,
|
||||
OpenAPI.HttpClient.FETCH,
|
||||
);
|
||||
|
||||
test.each(glob
|
||||
.sync('./test/result/v2/typescript/**/*.ts')
|
||||
.map(file => [file])
|
||||
)('file(%s)', file => {
|
||||
const content = fs.readFileSync(file, 'utf8').toString();
|
||||
expect(content).toMatchSnapshot(file);
|
||||
});
|
||||
});
|
||||
|
||||
describe('javascript', () => {
|
||||
|
||||
OpenAPI.generate(
|
||||
'./test/mock/spec-v2.json',
|
||||
'./test/result/v2/javascript/',
|
||||
OpenAPI.Language.JAVASCRIPT,
|
||||
OpenAPI.HttpClient.XHR,
|
||||
);
|
||||
|
||||
test.each(glob
|
||||
.sync('./test/result/v2/javascript/**/*.js')
|
||||
.map(file => [file])
|
||||
)('file(%s)', file => {
|
||||
const content = fs.readFileSync(file, 'utf8').toString();
|
||||
expect(content).toMatchSnapshot(file);
|
||||
});
|
||||
test.each(glob
|
||||
.sync('./test/result/v2/**/*.ts')
|
||||
.map(file => [file])
|
||||
)('file(%s)', file => {
|
||||
const content = fs.readFileSync(file, 'utf8').toString();
|
||||
expect(content).toMatchSnapshot(file);
|
||||
});
|
||||
});
|
||||
|
||||
describe('v3', () => {
|
||||
|
||||
describe('typescript', () => {
|
||||
OpenAPI.generate(
|
||||
'./test/mock/v3/spec.json',
|
||||
'./test/result/v3/',
|
||||
OpenAPI.HttpClient.FETCH,
|
||||
);
|
||||
|
||||
OpenAPI.generate(
|
||||
'./test/mock/spec-v3.json',
|
||||
'./test/result/v3/typescript/',
|
||||
OpenAPI.Language.TYPESCRIPT,
|
||||
OpenAPI.HttpClient.FETCH,
|
||||
);
|
||||
|
||||
test.each(glob
|
||||
.sync('./test/result/v3/typescript/**/*.ts')
|
||||
.map(file => [file])
|
||||
)('file(%s)', file => {
|
||||
const content = fs.readFileSync(file, 'utf8').toString();
|
||||
expect(content).toMatchSnapshot(file);
|
||||
});
|
||||
});
|
||||
|
||||
describe('javascript', () => {
|
||||
|
||||
OpenAPI.generate(
|
||||
'./test/mock/spec-v3.json',
|
||||
'./test/result/v3/javascript/',
|
||||
OpenAPI.Language.JAVASCRIPT,
|
||||
OpenAPI.HttpClient.XHR,
|
||||
);
|
||||
|
||||
test.each(glob
|
||||
.sync('./test/result/v3/javascript/**/*.js')
|
||||
.map(file => [file])
|
||||
)('file(%s)', file => {
|
||||
const content = fs.readFileSync(file, 'utf8').toString();
|
||||
expect(content).toMatchSnapshot(file);
|
||||
});
|
||||
test.each(glob
|
||||
.sync('./test/result/v3/**/*.ts')
|
||||
.map(file => [file])
|
||||
)('file(%s)', file => {
|
||||
const content = fs.readFileSync(file, 'utf8').toString();
|
||||
expect(content).toMatchSnapshot(file);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user