From 4ceabd8bba91ba9b91aadd9adb8ada0ad9b6391e Mon Sep 17 00:00:00 2001 From: Ferdi Koomen Date: Sat, 30 May 2020 13:10:42 +0200 Subject: [PATCH] - Creating async await compatible version --- .babelrc.js | 13 +++- bin/index.js | 9 ++- rollup.config.js | 2 +- src/index.spec.ts | 8 +-- src/index.ts | 53 +++++++--------- src/utils/__mocks__/fileSystem.ts | 6 ++ src/utils/fileSystem.ts | 25 ++++++++ src/utils/getOpenApiSpec.spec.ts | 29 +++++---- src/utils/getOpenApiSpec.ts | 15 +++-- ...ates.ts => registerHandlebarsTemplates.ts} | 2 +- src/utils/writeClient.spec.ts | 25 +++----- src/utils/writeClient.ts | 56 ++++++++--------- src/utils/writeClientIndex.spec.ts | 15 ++--- src/utils/writeClientIndex.ts | 16 +++-- src/utils/writeClientModels.spec.ts | 15 ++--- src/utils/writeClientModels.ts | 12 ++-- src/utils/writeClientSchemas.spec.ts | 16 ++--- src/utils/writeClientSchemas.ts | 12 ++-- src/utils/writeClientServices.spec.ts | 16 ++--- src/utils/writeClientServices.ts | 12 ++-- src/utils/writeClientSettings.ts | 8 +-- test/index.js | 48 +++++++------- test/index.spec.js | 63 +++++++++---------- tsconfig.json | 10 +-- 24 files changed, 258 insertions(+), 228 deletions(-) create mode 100644 src/utils/__mocks__/fileSystem.ts create mode 100644 src/utils/fileSystem.ts rename src/utils/{readHandlebarsTemplates.ts => registerHandlebarsTemplates.ts} (98%) diff --git a/.babelrc.js b/.babelrc.js index eacd411c..d59f669d 100644 --- a/.babelrc.js +++ b/.babelrc.js @@ -2,7 +2,14 @@ module.exports = { presets: [ - '@babel/preset-env', - '@babel/preset-typescript' - ] + [ + '@babel/preset-env', + { + targets: { + esmodules: true, + }, + }, + ], + '@babel/preset-typescript', + ], }; diff --git a/bin/index.js b/bin/index.js index 7ee1c645..91a089bc 100755 --- a/bin/index.js +++ b/bin/index.js @@ -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); + }); } diff --git a/rollup.config.js b/rollup.config.js index a650a26b..2f3013fa 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -50,7 +50,7 @@ export default { file: './dist/index.js', format: 'cjs', }, - external: ['fs', 'os', ...external], + external: ['fs', 'os', 'util', ...external], plugins: [ handlebarsPlugin(), typescript({ diff --git a/src/index.spec.ts b/src/index.spec.ts index d7c51c93..0a3fbae7 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -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, diff --git a/src/index.ts b/src/index.ts index caeb00f5..f3d2611a 100644 --- a/src/index.ts +++ b/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 { + // 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); } } diff --git a/src/utils/__mocks__/fileSystem.ts b/src/utils/__mocks__/fileSystem.ts new file mode 100644 index 00000000..c35190ac --- /dev/null +++ b/src/utils/__mocks__/fileSystem.ts @@ -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(); diff --git a/src/utils/fileSystem.ts b/src/utils/fileSystem.ts new file mode 100644 index 00000000..6c792a84 --- /dev/null +++ b/src/utils/fileSystem.ts @@ -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(); + } + }); + }); diff --git a/src/utils/getOpenApiSpec.spec.ts b/src/utils/getOpenApiSpec.spec.ts index 73aee617..8f3f0aa2 100644 --- a/src/utils/getOpenApiSpec.spec.ts +++ b/src/utils/getOpenApiSpec.spec.ts @@ -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; -const fsReadFileSync = fs.readFileSync as jest.MockedFunction; +const existsMocked = exists as jest.MockedFunction; +const readFileMocked = readFile as jest.MockedFunction; + +function mockPromise(value: T): Promise { + return new Promise(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!'); }); }); diff --git a/src/utils/getOpenApiSpec.ts b/src/utils/getOpenApiSpec.ts index c1d1470d..5936fbd4 100644 --- a/src/utils/getOpenApiSpec.ts +++ b/src/utils/getOpenApiSpec.ts @@ -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 { + 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 { 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': diff --git a/src/utils/readHandlebarsTemplates.ts b/src/utils/registerHandlebarsTemplates.ts similarity index 98% rename from src/utils/readHandlebarsTemplates.ts rename to src/utils/registerHandlebarsTemplates.ts index d8e5592a..f8dc03c8 100644 --- a/src/utils/readHandlebarsTemplates.ts +++ b/src/utils/registerHandlebarsTemplates.ts @@ -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 = { diff --git a/src/utils/writeClient.spec.ts b/src/utils/writeClient.spec.ts index 9ba53684..7992f5a8 100644 --- a/src/utils/writeClient.spec.ts +++ b/src/utils/writeClient.spec.ts @@ -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; -const mkdirpSync = rimraf.sync as jest.MockedFunction; -const fsWriteFileSync = fs.writeFileSync as jest.MockedFunction; +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(); }); }); diff --git a/src/utils/writeClient.ts b/src/utils/writeClient.ts index 77c36558..d2f18077 100644 --- a/src/utils/writeClient.ts +++ b/src/utils/writeClient.ts @@ -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 { + 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 { 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); } diff --git a/src/utils/writeClientIndex.spec.ts b/src/utils/writeClientIndex.spec.ts index 76dc1746..86dcd884 100644 --- a/src/utils/writeClientIndex.spec.ts +++ b/src/utils/writeClientIndex.spec.ts @@ -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; +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'); }); }); diff --git a/src/utils/writeClientIndex.ts b/src/utils/writeClientIndex.ts index ec26c1bb..919556ca 100644 --- a/src/utils/writeClientIndex.ts +++ b/src/utils/writeClientIndex.ts @@ -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 { + await writeFile( path.resolve(outputPath, 'index.ts'), templates.index({ exportCore, diff --git a/src/utils/writeClientModels.spec.ts b/src/utils/writeClientModels.spec.ts index 1fd34cbc..028dfb00 100644 --- a/src/utils/writeClientModels.spec.ts +++ b/src/utils/writeClientModels.spec.ts @@ -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; +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'); }); }); diff --git a/src/utils/writeClientModels.ts b/src/utils/writeClientModels.ts index d0f166f3..34e2ab8d 100644 --- a/src/utils/writeClientModels.ts +++ b/src/utils/writeClientModels.ts @@ -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 { + 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)); + } } diff --git a/src/utils/writeClientSchemas.spec.ts b/src/utils/writeClientSchemas.spec.ts index 1fd34cbc..c78900fa 100644 --- a/src/utils/writeClientSchemas.spec.ts +++ b/src/utils/writeClientSchemas.spec.ts @@ -1,15 +1,11 @@ -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; - +jest.mock('./fileSystem'); describe('writeClientModels', () => { - it('should write to filesystem', () => { + it('should write to filesystem', async () => { const models: Model[] = [ { export: 'interface', @@ -39,8 +35,8 @@ describe('writeClientModels', () => { settings: () => 'dummy', }; - writeClientModels(models, templates, '/'); + await writeClientModels(models, templates, '/'); - expect(fsWriteFileSync).toBeCalledWith('/Item.ts', 'dummy'); + expect(writeFile).toBeCalledWith('/Item.ts', 'dummy'); }); }); diff --git a/src/utils/writeClientSchemas.ts b/src/utils/writeClientSchemas.ts index 7e5fd2d5..8515781f 100644 --- a/src/utils/writeClientSchemas.ts +++ b/src/utils/writeClientSchemas.ts @@ -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 { + 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)); + } } diff --git a/src/utils/writeClientServices.spec.ts b/src/utils/writeClientServices.spec.ts index 68a0e797..98968a57 100644 --- a/src/utils/writeClientServices.spec.ts +++ b/src/utils/writeClientServices.spec.ts @@ -1,15 +1,11 @@ -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; - +jest.mock('./fileSystem'); describe('writeClientServices', () => { - it('should write to filesystem', () => { + it('should write to filesystem', async () => { const services: Service[] = [ { name: 'Item', @@ -26,8 +22,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'); }); }); diff --git a/src/utils/writeClientServices.ts b/src/utils/writeClientServices.ts index 04b0dbb1..ea27f6b3 100644 --- a/src/utils/writeClientServices.ts +++ b/src/utils/writeClientServices.ts @@ -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 { + 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)); + } } diff --git a/src/utils/writeClientSettings.ts b/src/utils/writeClientSettings.ts index fcb97cad..6224fa58 100644 --- a/src/utils/writeClientSettings.ts +++ b/src/utils/writeClientSettings.ts @@ -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 { + await writeFile( path.resolve(outputPath, 'OpenAPI.ts'), templates.settings({ httpClient, diff --git a/test/index.js b/test/index.js index 9acc11ac..1fd68da3 100644 --- a/test/index.js +++ b/test/index.js @@ -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(); diff --git a/test/index.spec.js b/test/index.spec.js index ab237b7f..fd965ea7 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -5,52 +5,49 @@ const glob = require('glob'); const fs = require('fs'); describe('generation', () => { - describe('v2', () => { - - OpenAPI.generate({ - input: './test/mock/v2/spec.json', - output: './test/result/v2/', - httpClient: OpenAPI.HttpClient.FETCH, - useOptions: true, - useUnionTypes: true, - exportCore: true, - exportSchemas: true, - exportModels: true, - exportServices: true, + it('generated v2', async () => { + await OpenAPI.generate({ + input: './test/mock/v2/spec.json', + output: './test/result/v2/', + httpClient: OpenAPI.HttpClient.FETCH, + useOptions: true, + useUnionTypes: true, + exportCore: true, + exportSchemas: true, + exportModels: true, + exportServices: true, + }); }); - test.each(glob - .sync('./test/result/v2/**/*.ts') - .map(file => [file]) - )('file(%s)', file => { + const files = glob.sync('./test/result/v2/**/*.ts'); + + test.each(files.map(file => [file]))('file(%s)', file => { const content = fs.readFileSync(file, 'utf8').toString(); expect(content).toMatchSnapshot(file); }); }); describe('v3', () => { - - OpenAPI.generate({ - input: './test/mock/v3/spec.json', - output: './test/result/v3/', - httpClient: OpenAPI.HttpClient.FETCH, - useOptions: true, - useUnionTypes: true, - exportCore: true, - exportSchemas: true, - exportModels: true, - exportServices: true, + it('generated v3', async () => { + await OpenAPI.generate({ + input: './test/mock/v3/spec.json', + output: './test/result/v3/', + httpClient: OpenAPI.HttpClient.FETCH, + useOptions: true, + useUnionTypes: true, + exportCore: true, + exportSchemas: true, + exportModels: true, + exportServices: true, + }); }); - test.each(glob - .sync('./test/result/v3/**/*.ts') - .map(file => [file]) - )('file(%s)', file => { + const files = glob.sync('./test/result/v3/**/*.ts'); + + test.each(files.map(file => [file]))('file(%s)', file => { const content = fs.readFileSync(file, 'utf8').toString(); expect(content).toMatchSnapshot(file); }); }); }); - - diff --git a/tsconfig.json b/tsconfig.json index 61c94a13..b2dec630 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -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": [