mirror of
https://github.com/ferdikoomen/openapi-typescript-codegen.git
synced 2025-12-08 20:16:21 +00:00
Merge pull request #243 from ferdikoomen/feature/async-await
- Creating async await compatible version
This commit is contained in:
commit
760e1bd72c
13
.babelrc.js
13
.babelrc.js
@ -2,7 +2,14 @@
|
||||
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@babel/preset-env',
|
||||
'@babel/preset-typescript'
|
||||
]
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
targets: {
|
||||
esmodules: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
'@babel/preset-typescript',
|
||||
],
|
||||
};
|
||||
|
||||
@ -32,5 +32,12 @@ if (OpenAPI) {
|
||||
exportServices: program.exportServices,
|
||||
exportModels: program.exportModels,
|
||||
exportSchemas: program.exportSchemas,
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
process.exit(0);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openapi-typescript-codegen",
|
||||
"version": "0.3.1",
|
||||
"version": "0.4.0",
|
||||
"description": "NodeJS library that generates Typescript or Javascript clients based on the OpenAPI specification.",
|
||||
"author": "Ferdi Koomen",
|
||||
"homepage": "https://github.com/ferdikoomen/openapi-typescript-codegen",
|
||||
|
||||
@ -50,7 +50,7 @@ export default {
|
||||
file: './dist/index.js',
|
||||
format: 'cjs',
|
||||
},
|
||||
external: ['fs', 'os', ...external],
|
||||
external: ['fs', 'os', 'util', ...external],
|
||||
plugins: [
|
||||
handlebarsPlugin(),
|
||||
typescript({
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import * as OpenAPI from '.';
|
||||
|
||||
describe('index', () => {
|
||||
it('parses v2 without issues', () => {
|
||||
OpenAPI.generate({
|
||||
it('parses v2 without issues', async () => {
|
||||
await OpenAPI.generate({
|
||||
input: './test/mock/v2/spec.json',
|
||||
output: './test/result/v2/',
|
||||
useOptions: true,
|
||||
@ -11,8 +11,8 @@ describe('index', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('parses v3 without issues', () => {
|
||||
OpenAPI.generate({
|
||||
it('parses v3 without issues', async () => {
|
||||
await OpenAPI.generate({
|
||||
input: './test/mock/v3/spec.json',
|
||||
output: './test/result/v3/',
|
||||
useOptions: true,
|
||||
|
||||
53
src/index.ts
53
src/index.ts
@ -4,7 +4,7 @@ import { getOpenApiSpec } from './utils/getOpenApiSpec';
|
||||
import { getOpenApiVersion, OpenApiVersion } from './utils/getOpenApiVersion';
|
||||
import { isString } from './utils/isString';
|
||||
import { postProcessClient } from './utils/postProcessClient';
|
||||
import { readHandlebarsTemplates } from './utils/readHandlebarsTemplates';
|
||||
import { registerHandlebarsTemplates } from './utils/registerHandlebarsTemplates';
|
||||
import { writeClient } from './utils/writeClient';
|
||||
|
||||
export enum HttpClient {
|
||||
@ -40,7 +40,7 @@ export interface Options {
|
||||
* @param exportSchemas: Generate schemas.
|
||||
* @param write Write the files to disk (true or false).
|
||||
*/
|
||||
export function generate({
|
||||
export async function generate({
|
||||
input,
|
||||
output,
|
||||
httpClient = HttpClient.FETCH,
|
||||
@ -51,35 +51,30 @@ export function generate({
|
||||
exportModels = true,
|
||||
exportSchemas = false,
|
||||
write = true,
|
||||
}: Options): void {
|
||||
try {
|
||||
// Load the specification, read the OpenAPI version and load the
|
||||
// handlebar templates for the given language
|
||||
const openApi = isString(input) ? getOpenApiSpec(input) : input;
|
||||
const openApiVersion = getOpenApiVersion(openApi);
|
||||
const templates = readHandlebarsTemplates();
|
||||
}: Options): Promise<void> {
|
||||
// Load the specification, read the OpenAPI version and load the
|
||||
// handlebar templates for the given language
|
||||
const openApi = isString(input) ? await getOpenApiSpec(input) : input;
|
||||
const openApiVersion = getOpenApiVersion(openApi);
|
||||
const templates = registerHandlebarsTemplates();
|
||||
|
||||
switch (openApiVersion) {
|
||||
case OpenApiVersion.V2: {
|
||||
const client = parseV2(openApi);
|
||||
const clientFinal = postProcessClient(client, useUnionTypes);
|
||||
if (write) {
|
||||
writeClient(clientFinal, templates, output, httpClient, useOptions, exportCore, exportServices, exportModels, exportSchemas);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OpenApiVersion.V3: {
|
||||
const client = parseV3(openApi);
|
||||
const clientFinal = postProcessClient(client, useUnionTypes);
|
||||
if (write) {
|
||||
writeClient(clientFinal, templates, output, httpClient, useOptions, exportCore, exportServices, exportModels, exportSchemas);
|
||||
}
|
||||
break;
|
||||
switch (openApiVersion) {
|
||||
case OpenApiVersion.V2: {
|
||||
const client = parseV2(openApi);
|
||||
const clientFinal = postProcessClient(client, useUnionTypes);
|
||||
if (write) {
|
||||
await writeClient(clientFinal, templates, output, httpClient, useOptions, exportCore, exportServices, exportModels, exportSchemas);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OpenApiVersion.V3: {
|
||||
const client = parseV3(openApi);
|
||||
const clientFinal = postProcessClient(client, useUnionTypes);
|
||||
if (write) {
|
||||
await writeClient(clientFinal, templates, output, httpClient, useOptions, exportCore, exportServices, exportModels, exportSchemas);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
33
src/openApi/v2/parser/getRef.spec.ts
Normal file
33
src/openApi/v2/parser/getRef.spec.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { getRef } from './getRef';
|
||||
|
||||
describe('getRef', () => {
|
||||
it('should produce correct result', () => {
|
||||
expect(
|
||||
getRef(
|
||||
{
|
||||
swagger: '2.0',
|
||||
info: {
|
||||
title: 'dummy',
|
||||
version: '1.0',
|
||||
},
|
||||
host: 'localhost:8080',
|
||||
basePath: '/api',
|
||||
schemes: ['http', 'https'],
|
||||
paths: {},
|
||||
definitions: {
|
||||
Example: {
|
||||
description: 'This is an Example model ',
|
||||
type: 'integer',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
$ref: '#/definitions/Example',
|
||||
}
|
||||
)
|
||||
).toEqual({
|
||||
description: 'This is an Example model ',
|
||||
type: 'integer',
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -19,7 +19,7 @@ export interface OpenApiComponents {
|
||||
examples?: Dictionary<OpenApiExample>;
|
||||
requestBodies?: Dictionary<OpenApiRequestBody>;
|
||||
headers?: Dictionary<OpenApiHeader>;
|
||||
securitySchemes: Dictionary<OpenApiSecurityScheme>;
|
||||
securitySchemes?: Dictionary<OpenApiSecurityScheme>;
|
||||
links?: Dictionary<OpenApiLink>;
|
||||
callbacks?: Dictionary<OpenApiCallback>;
|
||||
}
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
import { Enum } from '../../../client/interfaces/Enum';
|
||||
|
||||
export function getEnumValues(enumerators: Enum[]): string[] {
|
||||
// Fetch values from the symbols, just to be sure we filter out
|
||||
// any double values and finally we sort them to make them easier
|
||||
// to read when we use them in our generated code.
|
||||
return enumerators
|
||||
.map(enumerator => enumerator.value)
|
||||
.filter((enumerator, index, arr) => {
|
||||
return arr.indexOf(enumerator) === index;
|
||||
})
|
||||
.sort();
|
||||
}
|
||||
37
src/openApi/v3/parser/getRef.spec.ts
Normal file
37
src/openApi/v3/parser/getRef.spec.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { getRef } from './getRef';
|
||||
|
||||
describe('getRef', () => {
|
||||
it('should produce correct result', () => {
|
||||
expect(
|
||||
getRef(
|
||||
{
|
||||
openapi: '3.0',
|
||||
info: {
|
||||
title: 'dummy',
|
||||
version: '1.0',
|
||||
},
|
||||
paths: {},
|
||||
servers: [
|
||||
{
|
||||
url: 'https://localhost:8080/api',
|
||||
},
|
||||
],
|
||||
components: {
|
||||
schemas: {
|
||||
Example: {
|
||||
description: 'This is an Example model ',
|
||||
type: 'integer',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
$ref: '#/components/schemas/Example',
|
||||
}
|
||||
)
|
||||
).toEqual({
|
||||
description: 'This is an Example model ',
|
||||
type: 'integer',
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -4,7 +4,7 @@ import { OpenApiReference } from '../interfaces/OpenApiReference';
|
||||
export function getRef<T>(openApi: OpenApi, item: T & OpenApiReference): T {
|
||||
if (item.$ref) {
|
||||
// Fetch the paths to the definitions, this converts:
|
||||
// "#/definitions/Form" to ["definitions", "Form"]
|
||||
// "#/components/schemas/Form" to ["components", "schemas", "Form"]
|
||||
const paths = item.$ref
|
||||
.replace(/^#/g, '')
|
||||
.split('/')
|
||||
|
||||
6
src/utils/__mocks__/fileSystem.ts
Normal file
6
src/utils/__mocks__/fileSystem.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export const readFile = jest.fn();
|
||||
export const writeFile = jest.fn();
|
||||
export const copyFile = jest.fn();
|
||||
export const exists = jest.fn();
|
||||
export const rmdir = jest.fn();
|
||||
export const mkdir = jest.fn();
|
||||
25
src/utils/fileSystem.ts
Normal file
25
src/utils/fileSystem.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import * as fs from 'fs';
|
||||
import * as mkdirp from 'mkdirp';
|
||||
import rimraf from 'rimraf';
|
||||
import * as util from 'util';
|
||||
|
||||
// Wrapped file system calls
|
||||
export const readFile = util.promisify(fs.readFile);
|
||||
export const writeFile = util.promisify(fs.writeFile);
|
||||
export const copyFile = util.promisify(fs.copyFile);
|
||||
export const exists = util.promisify(fs.exists);
|
||||
|
||||
// Re-export from mkdirp to make mocking easier
|
||||
export const mkdir = mkdirp;
|
||||
|
||||
// Promisified version of rimraf
|
||||
export const rmdir = (path: string) =>
|
||||
new Promise((resolve, reject) => {
|
||||
rimraf(path, (error: Error) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
9
src/utils/flatMap.spec.ts
Normal file
9
src/utils/flatMap.spec.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { flatMap } from './flatMap';
|
||||
|
||||
describe('flatMap', () => {
|
||||
it('should produce correct result', () => {
|
||||
expect(flatMap([1, 2, 3], i => [i])).toEqual([1, 2, 3]);
|
||||
expect(flatMap([1, 2, 3], i => [i + 1])).toEqual([2, 3, 4]);
|
||||
expect(flatMap([1, 2, 3], () => [1])).toEqual([1, 1, 1]);
|
||||
});
|
||||
});
|
||||
@ -4,7 +4,7 @@
|
||||
*/
|
||||
export function flatMap<U, T>(array: T[], callback: (value: T, index: number, array: T[]) => U[]): U[] {
|
||||
const result: U[] = [];
|
||||
array.map(callback).forEach(arr => {
|
||||
array.map<U[]>(callback).forEach(arr => {
|
||||
result.push(...arr);
|
||||
});
|
||||
return result;
|
||||
|
||||
40
src/utils/format.spec.ts
Normal file
40
src/utils/format.spec.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { format } from './format';
|
||||
|
||||
const input1 = `{ foo: true }`;
|
||||
|
||||
const output1 = `{ foo: true }`;
|
||||
|
||||
const input2 = `{ foo: true, bar: 123 }`;
|
||||
|
||||
const output2 = `{ foo: true, bar: 123 }`;
|
||||
|
||||
const input3 = `{
|
||||
foo: true,
|
||||
bar: 123
|
||||
}`;
|
||||
|
||||
const output3 = `{
|
||||
foo: true,
|
||||
bar: 123
|
||||
}`;
|
||||
|
||||
const input4 = `{
|
||||
\t\t\t\tfoo: true,
|
||||
\t\t\t\tbar: 123
|
||||
}`;
|
||||
|
||||
const output4 = `{
|
||||
foo: true,
|
||||
bar: 123
|
||||
}`;
|
||||
|
||||
describe('format', () => {
|
||||
it('should produce correct result', () => {
|
||||
expect(format(``)).toEqual('');
|
||||
expect(format(`{}`)).toEqual('{}');
|
||||
expect(format(input1)).toEqual(output1);
|
||||
expect(format(input2)).toEqual(output2);
|
||||
expect(format(input3)).toEqual(output3);
|
||||
expect(format(input4)).toEqual(output4);
|
||||
});
|
||||
});
|
||||
@ -1,24 +1,27 @@
|
||||
import * as fs from 'fs';
|
||||
|
||||
import { exists, readFile } from './fileSystem';
|
||||
import { getOpenApiSpec } from './getOpenApiSpec';
|
||||
|
||||
jest.mock('fs');
|
||||
jest.mock('./fileSystem');
|
||||
|
||||
const fsExistsSync = fs.existsSync as jest.MockedFunction<typeof fs.existsSync>;
|
||||
const fsReadFileSync = fs.readFileSync as jest.MockedFunction<typeof fs.readFileSync>;
|
||||
const existsMocked = exists as jest.MockedFunction<typeof exists>;
|
||||
const readFileMocked = readFile as jest.MockedFunction<typeof readFile>;
|
||||
|
||||
function mockPromise<T>(value: T): Promise<T> {
|
||||
return new Promise<T>(resolve => resolve(value));
|
||||
}
|
||||
|
||||
describe('getOpenApiSpec', () => {
|
||||
it('should read the json file', () => {
|
||||
fsExistsSync.mockReturnValue(true);
|
||||
fsReadFileSync.mockReturnValue('{"message": "Hello World!"}');
|
||||
const spec = getOpenApiSpec('spec.json');
|
||||
it('should read the json file', async () => {
|
||||
existsMocked.mockReturnValue(mockPromise(true));
|
||||
readFileMocked.mockReturnValue(mockPromise('{"message": "Hello World!"}'));
|
||||
const spec = await getOpenApiSpec('spec.json');
|
||||
expect(spec.message).toEqual('Hello World!');
|
||||
});
|
||||
|
||||
it('should read the yaml file', () => {
|
||||
fsExistsSync.mockReturnValue(true);
|
||||
fsReadFileSync.mockReturnValue('message: "Hello World!"');
|
||||
const spec = getOpenApiSpec('spec.yaml');
|
||||
it('should read the yaml file', async () => {
|
||||
existsMocked.mockReturnValue(mockPromise(true));
|
||||
readFileMocked.mockReturnValue(mockPromise('message: "Hello World!"'));
|
||||
const spec = await getOpenApiSpec('spec.yaml');
|
||||
expect(spec.message).toEqual('Hello World!');
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,15 +1,18 @@
|
||||
import * as fs from 'fs';
|
||||
import * as yaml from 'js-yaml';
|
||||
import * as path from 'path';
|
||||
|
||||
import { exists, readFile } from './fileSystem';
|
||||
|
||||
/**
|
||||
* Check if given file exists and try to read the content as string.
|
||||
* @param filePath
|
||||
*/
|
||||
function read(filePath: string): string {
|
||||
if (fs.existsSync(filePath)) {
|
||||
async function read(filePath: string): Promise<string> {
|
||||
const fileExists = await exists(filePath);
|
||||
if (fileExists) {
|
||||
try {
|
||||
return fs.readFileSync(filePath, 'utf8').toString();
|
||||
const content = await readFile(filePath, 'utf8');
|
||||
return content.toString();
|
||||
} catch (e) {
|
||||
throw new Error(`Could not read OpenApi spec: "${filePath}"`);
|
||||
}
|
||||
@ -23,10 +26,10 @@ function read(filePath: string): string {
|
||||
* on parsing the file as JSON.
|
||||
* @param input
|
||||
*/
|
||||
export function getOpenApiSpec(input: string): any {
|
||||
export async function getOpenApiSpec(input: string): Promise<any> {
|
||||
const file = path.resolve(process.cwd(), input);
|
||||
const extname = path.extname(file).toLowerCase();
|
||||
const content = read(file);
|
||||
const content = await read(file);
|
||||
switch (extname) {
|
||||
case '.yml':
|
||||
case '.yaml':
|
||||
|
||||
13
src/utils/isString.spec.ts
Normal file
13
src/utils/isString.spec.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { isString } from './isString';
|
||||
|
||||
describe('isString', () => {
|
||||
it('should produce correct result', () => {
|
||||
expect(isString('foo')).toBeTruthy();
|
||||
expect(isString('123')).toBeTruthy();
|
||||
expect(isString('-1')).toBeTruthy();
|
||||
expect(isString('')).toBeTruthy();
|
||||
expect(isString(null)).toBeFalsy();
|
||||
expect(isString(undefined)).toBeFalsy();
|
||||
expect(isString({})).toBeFalsy();
|
||||
});
|
||||
});
|
||||
@ -41,7 +41,7 @@ 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.
|
||||
*/
|
||||
export function readHandlebarsTemplates(): Templates {
|
||||
export function registerHandlebarsTemplates(): Templates {
|
||||
registerHandlebarHelpers();
|
||||
|
||||
const templates: Templates = {
|
||||
@ -1,22 +1,13 @@
|
||||
import * as fs from 'fs';
|
||||
import * as mkdirp from 'mkdirp';
|
||||
import * as rimraf from 'rimraf';
|
||||
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { HttpClient } from '../index';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { mkdir, rmdir, writeFile } from './fileSystem';
|
||||
import { Templates } from './registerHandlebarsTemplates';
|
||||
import { writeClient } from './writeClient';
|
||||
|
||||
jest.mock('rimraf');
|
||||
jest.mock('mkdirp');
|
||||
jest.mock('fs');
|
||||
|
||||
const rimrafSync = mkdirp.sync as jest.MockedFunction<typeof mkdirp.sync>;
|
||||
const mkdirpSync = rimraf.sync as jest.MockedFunction<typeof rimraf.sync>;
|
||||
const fsWriteFileSync = fs.writeFileSync as jest.MockedFunction<typeof fs.writeFileSync>;
|
||||
jest.mock('./fileSystem');
|
||||
|
||||
describe('writeClient', () => {
|
||||
it('should write to filesystem', () => {
|
||||
it('should write to filesystem', async () => {
|
||||
const client: Client = {
|
||||
server: 'http://localhost:8080',
|
||||
version: 'v1',
|
||||
@ -32,10 +23,10 @@ describe('writeClient', () => {
|
||||
settings: () => 'dummy',
|
||||
};
|
||||
|
||||
writeClient(client, templates, '/', HttpClient.FETCH, false, true, true, true, true);
|
||||
await writeClient(client, templates, '/', HttpClient.FETCH, false, true, true, true, true);
|
||||
|
||||
expect(rimrafSync).toBeCalled();
|
||||
expect(mkdirpSync).toBeCalled();
|
||||
expect(fsWriteFileSync).toBeCalled();
|
||||
expect(rmdir).toBeCalled();
|
||||
expect(mkdir).toBeCalled();
|
||||
expect(writeFile).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,19 +1,17 @@
|
||||
import * as fs from 'fs';
|
||||
import * as mkdirp from 'mkdirp';
|
||||
import * as path from 'path';
|
||||
import * as rimraf from 'rimraf';
|
||||
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { HttpClient } from '../index';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { copyFile, mkdir, rmdir } from './fileSystem';
|
||||
import { Templates } from './registerHandlebarsTemplates';
|
||||
import { writeClientIndex } from './writeClientIndex';
|
||||
import { writeClientModels } from './writeClientModels';
|
||||
import { writeClientSchemas } from './writeClientSchemas';
|
||||
import { writeClientServices } from './writeClientServices';
|
||||
import { writeClientSettings } from './writeClientSettings';
|
||||
|
||||
function copySupportFile(filePath: string, outputPath: string): void {
|
||||
fs.copyFileSync(path.resolve(__dirname, `../src/templates/${filePath}`), path.resolve(outputPath, filePath));
|
||||
async function copySupportFile(filePath: string, outputPath: string): Promise<void> {
|
||||
await copyFile(path.resolve(__dirname, `../src/templates/${filePath}`), path.resolve(outputPath, filePath));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -28,7 +26,7 @@ function copySupportFile(filePath: string, outputPath: string): void {
|
||||
* @param exportModels: Generate models.
|
||||
* @param exportSchemas: Generate schemas.
|
||||
*/
|
||||
export function writeClient(
|
||||
export async function writeClient(
|
||||
client: Client,
|
||||
templates: Templates,
|
||||
output: string,
|
||||
@ -38,7 +36,7 @@ export function writeClient(
|
||||
exportServices: boolean,
|
||||
exportModels: boolean,
|
||||
exportSchemas: boolean
|
||||
): void {
|
||||
): Promise<void> {
|
||||
const outputPath = path.resolve(process.cwd(), output);
|
||||
const outputPathCore = path.resolve(outputPath, 'core');
|
||||
const outputPathModels = path.resolve(outputPath, 'models');
|
||||
@ -46,38 +44,38 @@ export function writeClient(
|
||||
const outputPathServices = path.resolve(outputPath, 'services');
|
||||
|
||||
// Clean output directory
|
||||
rimraf.sync(outputPath);
|
||||
mkdirp.sync(outputPath);
|
||||
await rmdir(outputPath);
|
||||
await mkdir(outputPath);
|
||||
|
||||
if (exportCore) {
|
||||
mkdirp.sync(outputPathCore);
|
||||
copySupportFile('core/ApiError.ts', outputPath);
|
||||
copySupportFile('core/getFormData.ts', outputPath);
|
||||
copySupportFile('core/getQueryString.ts', outputPath);
|
||||
copySupportFile('core/isSuccess.ts', outputPath);
|
||||
copySupportFile('core/request.ts', outputPath);
|
||||
copySupportFile('core/RequestOptions.ts', outputPath);
|
||||
copySupportFile('core/requestUsingFetch.ts', outputPath);
|
||||
copySupportFile('core/requestUsingXHR.ts', outputPath);
|
||||
copySupportFile('core/Result.ts', outputPath);
|
||||
await mkdir(outputPathCore);
|
||||
await copySupportFile('core/ApiError.ts', outputPath);
|
||||
await copySupportFile('core/getFormData.ts', outputPath);
|
||||
await copySupportFile('core/getQueryString.ts', outputPath);
|
||||
await copySupportFile('core/isSuccess.ts', outputPath);
|
||||
await copySupportFile('core/request.ts', outputPath);
|
||||
await copySupportFile('core/RequestOptions.ts', outputPath);
|
||||
await copySupportFile('core/requestUsingFetch.ts', outputPath);
|
||||
await copySupportFile('core/requestUsingXHR.ts', outputPath);
|
||||
await copySupportFile('core/Result.ts', outputPath);
|
||||
}
|
||||
|
||||
if (exportServices) {
|
||||
mkdirp.sync(outputPathServices);
|
||||
writeClientSettings(client, templates, outputPathCore, httpClient);
|
||||
writeClientServices(client.services, templates, outputPathServices, useOptions);
|
||||
await mkdir(outputPathServices);
|
||||
await writeClientSettings(client, templates, outputPathCore, httpClient);
|
||||
await writeClientServices(client.services, templates, outputPathServices, useOptions);
|
||||
}
|
||||
|
||||
if (exportSchemas) {
|
||||
mkdirp.sync(outputPathSchemas);
|
||||
writeClientSchemas(client.models, templates, outputPathSchemas);
|
||||
await mkdir(outputPathSchemas);
|
||||
await writeClientSchemas(client.models, templates, outputPathSchemas);
|
||||
}
|
||||
|
||||
if (exportModels) {
|
||||
mkdirp.sync(outputPathModels);
|
||||
copySupportFile('models/Dictionary.ts', outputPath);
|
||||
writeClientModels(client.models, templates, outputPathModels);
|
||||
await mkdir(outputPathModels);
|
||||
await copySupportFile('models/Dictionary.ts', outputPath);
|
||||
await writeClientModels(client.models, templates, outputPathModels);
|
||||
}
|
||||
|
||||
writeClientIndex(client, templates, outputPath, exportCore, exportModels, exportServices, exportSchemas);
|
||||
await writeClientIndex(client, templates, outputPath, exportCore, exportModels, exportServices, exportSchemas);
|
||||
}
|
||||
|
||||
@ -1,15 +1,12 @@
|
||||
import * as fs from 'fs';
|
||||
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { writeFile } from './fileSystem';
|
||||
import { Templates } from './registerHandlebarsTemplates';
|
||||
import { writeClientIndex } from './writeClientIndex';
|
||||
|
||||
jest.mock('fs');
|
||||
|
||||
const fsWriteFileSync = fs.writeFileSync as jest.MockedFunction<typeof fs.writeFileSync>;
|
||||
jest.mock('./fileSystem');
|
||||
|
||||
describe('writeClientIndex', () => {
|
||||
it('should write to filesystem', () => {
|
||||
it('should write to filesystem', async () => {
|
||||
const client: Client = {
|
||||
server: 'http://localhost:8080',
|
||||
version: '1.0',
|
||||
@ -25,8 +22,8 @@ describe('writeClientIndex', () => {
|
||||
settings: () => 'dummy',
|
||||
};
|
||||
|
||||
writeClientIndex(client, templates, '/', true, true, true, true);
|
||||
await writeClientIndex(client, templates, '/', true, true, true, true);
|
||||
|
||||
expect(fsWriteFileSync).toBeCalledWith('/index.ts', 'dummy');
|
||||
expect(writeFile).toBeCalledWith('/index.ts', 'dummy');
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { writeFile } from './fileSystem';
|
||||
import { getModelNames } from './getModelNames';
|
||||
import { getServiceNames } from './getServiceNames';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { Templates } from './registerHandlebarsTemplates';
|
||||
|
||||
/**
|
||||
* Generate the OpenAPI client index file using the Handlebar template and write it to disk.
|
||||
@ -18,8 +18,16 @@ import { Templates } from './readHandlebarsTemplates';
|
||||
* @param exportModels: Generate models.
|
||||
* @param exportSchemas: Generate schemas.
|
||||
*/
|
||||
export function writeClientIndex(client: Client, templates: Templates, outputPath: string, exportCore: boolean, exportServices: boolean, exportModels: boolean, exportSchemas: boolean): void {
|
||||
fs.writeFileSync(
|
||||
export async function writeClientIndex(
|
||||
client: Client,
|
||||
templates: Templates,
|
||||
outputPath: string,
|
||||
exportCore: boolean,
|
||||
exportServices: boolean,
|
||||
exportModels: boolean,
|
||||
exportSchemas: boolean
|
||||
): Promise<void> {
|
||||
await writeFile(
|
||||
path.resolve(outputPath, 'index.ts'),
|
||||
templates.index({
|
||||
exportCore,
|
||||
|
||||
@ -1,15 +1,12 @@
|
||||
import * as fs from 'fs';
|
||||
|
||||
import { Model } from '../client/interfaces/Model';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { writeFile } from './fileSystem';
|
||||
import { Templates } from './registerHandlebarsTemplates';
|
||||
import { writeClientModels } from './writeClientModels';
|
||||
|
||||
jest.mock('fs');
|
||||
|
||||
const fsWriteFileSync = fs.writeFileSync as jest.MockedFunction<typeof fs.writeFileSync>;
|
||||
jest.mock('./fileSystem');
|
||||
|
||||
describe('writeClientModels', () => {
|
||||
it('should write to filesystem', () => {
|
||||
it('should write to filesystem', async () => {
|
||||
const models: Model[] = [
|
||||
{
|
||||
export: 'interface',
|
||||
@ -39,8 +36,8 @@ describe('writeClientModels', () => {
|
||||
settings: () => 'dummy',
|
||||
};
|
||||
|
||||
writeClientModels(models, templates, '/');
|
||||
await writeClientModels(models, templates, '/');
|
||||
|
||||
expect(fsWriteFileSync).toBeCalledWith('/Item.ts', 'dummy');
|
||||
expect(writeFile).toBeCalledWith('/Item.ts', 'dummy');
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import { Model } from '../client/interfaces/Model';
|
||||
import { writeFile } from './fileSystem';
|
||||
import { format } from './format';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { Templates } from './registerHandlebarsTemplates';
|
||||
|
||||
/**
|
||||
* Generate Models using the Handlebar template and write to disk.
|
||||
@ -11,10 +11,10 @@ import { Templates } from './readHandlebarsTemplates';
|
||||
* @param templates The loaded handlebar templates.
|
||||
* @param outputPath Directory to write the generated files to.
|
||||
*/
|
||||
export function writeClientModels(models: Model[], templates: Templates, outputPath: string): void {
|
||||
models.forEach(model => {
|
||||
export async function writeClientModels(models: Model[], templates: Templates, outputPath: string): Promise<void> {
|
||||
for (const model of models) {
|
||||
const file = path.resolve(outputPath, `${model.name}.ts`);
|
||||
const templateResult = templates.model(model);
|
||||
fs.writeFileSync(file, format(templateResult));
|
||||
});
|
||||
await writeFile(file, format(templateResult));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,15 +1,12 @@
|
||||
import * as fs from 'fs';
|
||||
|
||||
import { Model } from '../client/interfaces/Model';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { writeClientModels } from './writeClientModels';
|
||||
import { writeFile } from './fileSystem';
|
||||
import { Templates } from './registerHandlebarsTemplates';
|
||||
import { writeClientSchemas } from './writeClientSchemas';
|
||||
|
||||
jest.mock('fs');
|
||||
jest.mock('./fileSystem');
|
||||
|
||||
const fsWriteFileSync = fs.writeFileSync as jest.MockedFunction<typeof fs.writeFileSync>;
|
||||
|
||||
describe('writeClientModels', () => {
|
||||
it('should write to filesystem', () => {
|
||||
describe('writeClientSchemas', () => {
|
||||
it('should write to filesystem', async () => {
|
||||
const models: Model[] = [
|
||||
{
|
||||
export: 'interface',
|
||||
@ -39,8 +36,8 @@ describe('writeClientModels', () => {
|
||||
settings: () => 'dummy',
|
||||
};
|
||||
|
||||
writeClientModels(models, templates, '/');
|
||||
await writeClientSchemas(models, templates, '/');
|
||||
|
||||
expect(fsWriteFileSync).toBeCalledWith('/Item.ts', 'dummy');
|
||||
expect(writeFile).toBeCalledWith('/$Item.ts', 'dummy');
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import { Model } from '../client/interfaces/Model';
|
||||
import { writeFile } from './fileSystem';
|
||||
import { format } from './format';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { Templates } from './registerHandlebarsTemplates';
|
||||
|
||||
/**
|
||||
* Generate Schemas using the Handlebar template and write to disk.
|
||||
@ -11,10 +11,10 @@ import { Templates } from './readHandlebarsTemplates';
|
||||
* @param templates The loaded handlebar templates.
|
||||
* @param outputPath Directory to write the generated files to.
|
||||
*/
|
||||
export function writeClientSchemas(models: Model[], templates: Templates, outputPath: string): void {
|
||||
models.forEach(model => {
|
||||
export async function writeClientSchemas(models: Model[], templates: Templates, outputPath: string): Promise<void> {
|
||||
for (const model of models) {
|
||||
const file = path.resolve(outputPath, `$${model.name}.ts`);
|
||||
const templateResult = templates.schema(model);
|
||||
fs.writeFileSync(file, format(templateResult));
|
||||
});
|
||||
await writeFile(file, format(templateResult));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,15 +1,12 @@
|
||||
import * as fs from 'fs';
|
||||
|
||||
import { Service } from '../client/interfaces/Service';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { writeFile } from './fileSystem';
|
||||
import { Templates } from './registerHandlebarsTemplates';
|
||||
import { writeClientServices } from './writeClientServices';
|
||||
|
||||
jest.mock('fs');
|
||||
|
||||
const fsWriteFileSync = fs.writeFileSync as jest.MockedFunction<typeof fs.writeFileSync>;
|
||||
jest.mock('./fileSystem');
|
||||
|
||||
describe('writeClientServices', () => {
|
||||
it('should write to filesystem', () => {
|
||||
it('should write to filesystem', async () => {
|
||||
const services: Service[] = [
|
||||
{
|
||||
name: 'Item',
|
||||
@ -26,8 +23,8 @@ describe('writeClientServices', () => {
|
||||
settings: () => 'dummy',
|
||||
};
|
||||
|
||||
writeClientServices(services, templates, '/', false);
|
||||
await writeClientServices(services, templates, '/', false);
|
||||
|
||||
expect(fsWriteFileSync).toBeCalledWith('/Item.ts', 'dummy');
|
||||
expect(writeFile).toBeCalledWith('/Item.ts', 'dummy');
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import { Service } from '../client/interfaces/Service';
|
||||
import { writeFile } from './fileSystem';
|
||||
import { format } from './format';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { Templates } from './registerHandlebarsTemplates';
|
||||
|
||||
/**
|
||||
* Generate Services using the Handlebar template and write to disk.
|
||||
@ -12,13 +12,13 @@ import { Templates } from './readHandlebarsTemplates';
|
||||
* @param outputPath Directory to write the generated files to.
|
||||
* @param useOptions Use options or arguments functions.
|
||||
*/
|
||||
export function writeClientServices(services: Service[], templates: Templates, outputPath: string, useOptions: boolean): void {
|
||||
services.forEach(service => {
|
||||
export async function writeClientServices(services: Service[], templates: Templates, outputPath: string, useOptions: boolean): Promise<void> {
|
||||
for (const service of services) {
|
||||
const file = path.resolve(outputPath, `${service.name}.ts`);
|
||||
const templateResult = templates.service({
|
||||
...service,
|
||||
useOptions,
|
||||
});
|
||||
fs.writeFileSync(file, format(templateResult));
|
||||
});
|
||||
await writeFile(file, format(templateResult));
|
||||
}
|
||||
}
|
||||
|
||||
30
src/utils/writeClientSettings.spec.ts
Normal file
30
src/utils/writeClientSettings.spec.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { HttpClient } from '../index';
|
||||
import { writeFile } from './fileSystem';
|
||||
import { Templates } from './registerHandlebarsTemplates';
|
||||
import { writeClientSettings } from './writeClientSettings';
|
||||
|
||||
jest.mock('./fileSystem');
|
||||
|
||||
describe('writeClientSettings', () => {
|
||||
it('should write to filesystem', async () => {
|
||||
const client: Client = {
|
||||
server: 'http://localhost:8080',
|
||||
version: '1.0',
|
||||
models: [],
|
||||
services: [],
|
||||
};
|
||||
|
||||
const templates: Templates = {
|
||||
index: () => 'dummy',
|
||||
model: () => 'dummy',
|
||||
schema: () => 'dummy',
|
||||
service: () => 'dummy',
|
||||
settings: () => 'dummy',
|
||||
};
|
||||
|
||||
await writeClientSettings(client, templates, '/', HttpClient.FETCH);
|
||||
|
||||
expect(writeFile).toBeCalledWith('/OpenAPI.ts', 'dummy');
|
||||
});
|
||||
});
|
||||
@ -1,9 +1,9 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { HttpClient } from '../index';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { writeFile } from './fileSystem';
|
||||
import { Templates } from './registerHandlebarsTemplates';
|
||||
|
||||
/**
|
||||
* Generate OpenAPI configuration file "OpenAPI.ts"
|
||||
@ -12,8 +12,8 @@ import { Templates } from './readHandlebarsTemplates';
|
||||
* @param outputPath Directory to write the generated files to.
|
||||
* @param httpClient The selected httpClient (fetch or XHR).
|
||||
*/
|
||||
export function writeClientSettings(client: Client, templates: Templates, outputPath: string, httpClient: HttpClient): void {
|
||||
fs.writeFileSync(
|
||||
export async function writeClientSettings(client: Client, templates: Templates, outputPath: string, httpClient: HttpClient): Promise<void> {
|
||||
await writeFile(
|
||||
path.resolve(outputPath, 'OpenAPI.ts'),
|
||||
templates.settings({
|
||||
httpClient,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -20,29 +20,33 @@ function compile(dir) {
|
||||
compiler.emit();
|
||||
}
|
||||
|
||||
console.time('generate');
|
||||
async function run() {
|
||||
console.time('generate');
|
||||
|
||||
OpenAPI.generate({
|
||||
input: './test/mock/v2/spec.json',
|
||||
output: './test/result/v2/',
|
||||
httpClient: OpenAPI.HttpClient.FETCH,
|
||||
useOptions: true,
|
||||
useUnionTypes: true,
|
||||
exportSchemas: true,
|
||||
exportServices: true
|
||||
});
|
||||
await OpenAPI.generate({
|
||||
input: './test/mock/v2/spec.json',
|
||||
output: './test/result/v2/',
|
||||
httpClient: OpenAPI.HttpClient.FETCH,
|
||||
useOptions: true,
|
||||
useUnionTypes: true,
|
||||
exportSchemas: true,
|
||||
exportServices: true,
|
||||
});
|
||||
|
||||
OpenAPI.generate({
|
||||
input: './test/mock/v3/spec.json',
|
||||
output: './test/result/v3/',
|
||||
httpClient: OpenAPI.HttpClient.FETCH,
|
||||
useOptions: true,
|
||||
useUnionTypes: true,
|
||||
exportSchemas: true,
|
||||
exportServices: true
|
||||
});
|
||||
await OpenAPI.generate({
|
||||
input: './test/mock/v3/spec.json',
|
||||
output: './test/result/v3/',
|
||||
httpClient: OpenAPI.HttpClient.FETCH,
|
||||
useOptions: true,
|
||||
useUnionTypes: true,
|
||||
exportSchemas: true,
|
||||
exportServices: true,
|
||||
});
|
||||
|
||||
console.timeEnd('generate');
|
||||
console.timeEnd('generate');
|
||||
|
||||
compile('./test/result/v2/');
|
||||
compile('./test/result/v3/');
|
||||
compile('./test/result/v2/');
|
||||
compile('./test/result/v3/');
|
||||
}
|
||||
|
||||
run();
|
||||
|
||||
@ -4,11 +4,9 @@ const OpenAPI = require('../dist');
|
||||
const glob = require('glob');
|
||||
const fs = require('fs');
|
||||
|
||||
describe('generation', () => {
|
||||
|
||||
describe('v2', () => {
|
||||
|
||||
OpenAPI.generate({
|
||||
describe('v2', () => {
|
||||
it('should generate', async () => {
|
||||
await OpenAPI.generate({
|
||||
input: './test/mock/v2/spec.json',
|
||||
output: './test/result/v2/',
|
||||
httpClient: OpenAPI.HttpClient.FETCH,
|
||||
@ -20,18 +18,18 @@ describe('generation', () => {
|
||||
exportServices: true,
|
||||
});
|
||||
|
||||
test.each(glob
|
||||
.sync('./test/result/v2/**/*.ts')
|
||||
.map(file => [file])
|
||||
)('file(%s)', file => {
|
||||
const files = glob.sync('./test/result/v2/**/*.ts');
|
||||
|
||||
files.forEach(file => {
|
||||
const content = fs.readFileSync(file, 'utf8').toString();
|
||||
expect(content).toMatchSnapshot(file);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('v3', () => {
|
||||
|
||||
OpenAPI.generate({
|
||||
describe('v3', () => {
|
||||
it('should generate', async () => {
|
||||
await OpenAPI.generate({
|
||||
input: './test/mock/v3/spec.json',
|
||||
output: './test/result/v3/',
|
||||
httpClient: OpenAPI.HttpClient.FETCH,
|
||||
@ -43,14 +41,11 @@ describe('generation', () => {
|
||||
exportServices: true,
|
||||
});
|
||||
|
||||
test.each(glob
|
||||
.sync('./test/result/v3/**/*.ts')
|
||||
.map(file => [file])
|
||||
)('file(%s)', file => {
|
||||
const files = glob.sync('./test/result/v3/**/*.ts');
|
||||
|
||||
files.forEach(file => {
|
||||
const content = fs.readFileSync(file, 'utf8').toString();
|
||||
expect(content).toMatchSnapshot(file);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
@ -3,10 +3,10 @@
|
||||
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"target": "es6",
|
||||
"module": "es6",
|
||||
"target": "ES2017",
|
||||
"module": "ES6",
|
||||
"moduleResolution": "node",
|
||||
"lib": ["es6", "dom"],
|
||||
"lib": ["ES2017"],
|
||||
"types": ["node", "jest"],
|
||||
"typeRoots": ["node_modules/@types"],
|
||||
"declaration": false,
|
||||
@ -19,9 +19,9 @@
|
||||
"strict": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"importHelpers": false,
|
||||
"removeComments": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
|
||||
"files": [
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user