diff --git a/src/index.ts b/src/index.ts index 2949881a..fc733540 100644 --- a/src/index.ts +++ b/src/index.ts @@ -36,6 +36,7 @@ export type Options = { * @param input The relative location of the OpenAPI spec * @param output The relative location of the output directory * @param httpClient The selected httpClient (fetch, xhr, node or axios) + * @param clientName Custom client class name * @param useOptions Use options or arguments functions * @param useUnionTypes Use union types instead of enums * @param exportCore: Generate core client classes @@ -51,6 +52,7 @@ export async function generate({ input, output, httpClient = HttpClient.FETCH, + clientName, useOptions = false, useUnionTypes = false, exportCore = true, @@ -88,6 +90,7 @@ export async function generate({ exportSchemas, indent, postfix, + clientName, request ); break; @@ -110,6 +113,7 @@ export async function generate({ exportSchemas, indent, postfix, + clientName, request ); break; diff --git a/src/templates/client.hbs b/src/templates/client.hbs index 51afc61a..aea06c0e 100644 --- a/src/templates/client.hbs +++ b/src/templates/client.hbs @@ -5,7 +5,7 @@ import type { OpenAPIConfig } from './core/OpenAPI'; import { {{{httpRequest}}} } from './core/{{{httpRequest}}}'; {{#if services}} {{#each services}} -import { {{{name}}} } from './services/{{{name}}}'; +import { {{{name}}}{{{@root.postfix}}} } from './services/{{{name}}}{{{@root.postfix}}}'; {{/each}} {{/if}} @@ -14,10 +14,10 @@ type HttpRequestConstructor = new (config: OpenAPIConfig) => BaseHttpRequest; export class {{{clientName}}} { {{#each services}} - readonly {{{name}}}: {{{name}}}; + public readonly {{{name}}}: {{{name}}}{{{@root.postfix}}}; {{/each}} - readonly request: BaseHttpRequest; + public readonly request: BaseHttpRequest; constructor(config?: OpenAPIConfig, HttpRequest: HttpRequestConstructor = {{{httpRequest}}}) { this.request = new HttpRequest({ @@ -33,7 +33,7 @@ export class {{{clientName}}} { }); {{#each services}} - this.{{{name}}} = new {{{name}}}(this.request); + this.{{{name}}} = new {{{name}}}{{{@root.postfix}}}(this.request); {{/each}} } } diff --git a/src/templates/core/HttpRequest.hbs b/src/templates/core/HttpRequest.hbs index ed97a39b..01804e38 100644 --- a/src/templates/core/HttpRequest.hbs +++ b/src/templates/core/HttpRequest.hbs @@ -6,9 +6,9 @@ import { request as __request } from './request'; export class {{HttpRequest}} extends BaseHttpRequest { - constructor(config: OpenAPIConfig) { - super(config); - } + constructor(config: OpenAPIConfig) { + super(config); + } /** * Request method @@ -16,7 +16,7 @@ export class {{HttpRequest}} extends BaseHttpRequest { * @returns CancelablePromise * @throws ApiError */ - public request(options: ApiRequestOptions): CancelablePromise { - return __request(this.config, options); - } + public request(options: ApiRequestOptions): CancelablePromise { + return __request(this.config, options); + } } diff --git a/src/utils/registerHandlebarTemplates.ts b/src/utils/registerHandlebarTemplates.ts index 72569938..db4ec97c 100644 --- a/src/utils/registerHandlebarTemplates.ts +++ b/src/utils/registerHandlebarTemplates.ts @@ -1,6 +1,7 @@ import Handlebars from 'handlebars/runtime'; import { HttpClient } from '../HttpClient'; +import templateClient from '../templates/client.hbs'; import templateCoreApiError from '../templates/core/ApiError.hbs'; import templateCoreApiRequestOptions from '../templates/core/ApiRequestOptions.hbs'; import templateCoreApiResult from '../templates/core/ApiResult.hbs'; @@ -10,6 +11,7 @@ import axiosGetResponseBody from '../templates/core/axios/getResponseBody.hbs'; import axiosGetResponseHeader from '../templates/core/axios/getResponseHeader.hbs'; import axiosRequest from '../templates/core/axios/request.hbs'; import axiosSendRequest from '../templates/core/axios/sendRequest.hbs'; +import templateCoreBaseHttpRequest from '../templates/core/BaseHttpRequest.hbs'; import templateCancelablePromise from '../templates/core/CancelablePromise.hbs'; import fetchGetHeaders from '../templates/core/fetch/getHeaders.hbs'; import fetchGetRequestBody from '../templates/core/fetch/getRequestBody.hbs'; @@ -29,6 +31,7 @@ import functionIsString from '../templates/core/functions/isString.hbs'; import functionIsStringWithValue from '../templates/core/functions/isStringWithValue.hbs'; import functionIsSuccess from '../templates/core/functions/isSuccess.hbs'; import functionResolve from '../templates/core/functions/resolve.hbs'; +import templateCoreHttpRequest from '../templates/core/HttpRequest.hbs'; import nodeGetHeaders from '../templates/core/node/getHeaders.hbs'; import nodeGetRequestBody from '../templates/core/node/getRequestBody.hbs'; import nodeGetResponseBody from '../templates/core/node/getResponseBody.hbs'; @@ -78,6 +81,7 @@ import { registerHandlebarHelpers } from './registerHandlebarHelpers'; export interface Templates { index: Handlebars.TemplateDelegate; + client: Handlebars.TemplateDelegate; exports: { model: Handlebars.TemplateDelegate; schema: Handlebars.TemplateDelegate; @@ -90,6 +94,8 @@ export interface Templates { apiResult: Handlebars.TemplateDelegate; cancelablePromise: Handlebars.TemplateDelegate; request: Handlebars.TemplateDelegate; + baseHttpRequest: Handlebars.TemplateDelegate; + httpRequest: Handlebars.TemplateDelegate; }; } @@ -107,6 +113,7 @@ export function registerHandlebarTemplates(root: { // Main templates (entry points for the files we write to disk) const templates: Templates = { index: Handlebars.template(templateIndex), + client: Handlebars.template(templateClient), exports: { model: Handlebars.template(templateExportModel), schema: Handlebars.template(templateExportSchema), @@ -119,6 +126,8 @@ export function registerHandlebarTemplates(root: { apiResult: Handlebars.template(templateCoreApiResult), cancelablePromise: Handlebars.template(templateCancelablePromise), request: Handlebars.template(templateCoreRequest), + httpRequest: Handlebars.template(templateCoreBaseHttpRequest), + baseHttpRequest: Handlebars.template(templateCoreHttpRequest), }, }; diff --git a/src/utils/writeClient.spec.ts b/src/utils/writeClient.spec.ts index 5c472bea..bc38b4b6 100644 --- a/src/utils/writeClient.spec.ts +++ b/src/utils/writeClient.spec.ts @@ -18,6 +18,7 @@ describe('writeClient', () => { const templates: Templates = { index: () => 'index', + client: () => 'client', exports: { model: () => 'model', schema: () => 'schema', @@ -30,6 +31,8 @@ describe('writeClient', () => { apiResult: () => 'apiResult', cancelablePromise: () => 'cancelablePromise', request: () => 'request', + baseHttpRequest: () => 'baseHttpRequest', + httpRequest: () => 'httpRequest', }, }; @@ -45,7 +48,8 @@ describe('writeClient', () => { true, true, Indent.SPACE_4, - '' + 'Service', + 'AppClient' ); expect(rmdir).toBeCalled(); diff --git a/src/utils/writeClient.ts b/src/utils/writeClient.ts index 9f09ecd9..65571b63 100644 --- a/src/utils/writeClient.ts +++ b/src/utils/writeClient.ts @@ -4,8 +4,10 @@ import type { Client } from '../client/interfaces/Client'; import { HttpClient } from '../HttpClient'; import { Indent } from '../Indent'; import { mkdir, rmdir } from './fileSystem'; +import { isDefined } from './isDefined'; import { isSubDirectory } from './isSubdirectory'; import { Templates } from './registerHandlebarTemplates'; +import { writeClientClass } from './writeClientClass'; import { writeClientCore } from './writeClientCore'; import { writeClientIndex } from './writeClientIndex'; import { writeClientModels } from './writeClientModels'; @@ -27,6 +29,7 @@ import { writeClientServices } from './writeClientServices'; * @param exportSchemas: Generate schemas * @param indent: Indentation options (4, 2 or tab) * @param postfix: Service name postfix + * @param clientName: Custom client class name * @param request: Path to custom request file */ export async function writeClient( @@ -42,6 +45,7 @@ export async function writeClient( exportSchemas: boolean, indent: Indent, postfix: string, + clientName?: string, request?: string ): Promise { const outputPath = resolve(process.cwd(), output); @@ -87,6 +91,11 @@ export async function writeClient( await writeClientModels(client.models, templates, outputPathModels, httpClient, useUnionTypes, indent); } + if (isDefined(clientName)) { + await mkdir(outputPath); + await writeClientClass(client, templates, outputPath, httpClient, clientName, indent, postfix); + } + if (exportCore || exportServices || exportSchemas || exportModels) { await mkdir(outputPath); await writeClientIndex( diff --git a/src/utils/writeClientClass.spec.ts b/src/utils/writeClientClass.spec.ts new file mode 100644 index 00000000..871e2052 --- /dev/null +++ b/src/utils/writeClientClass.spec.ts @@ -0,0 +1,45 @@ +import type { Client } from '../client/interfaces/Client'; +import { HttpClient } from '../HttpClient'; +import { Indent } from '../Indent'; +import { mkdir, rmdir, writeFile } from './fileSystem'; +import { Templates } from './registerHandlebarTemplates'; +import { writeClientClass } from './writeClientClass'; + +jest.mock('./fileSystem'); + +describe('writeClientClass', () => { + it('should write to filesystem', async () => { + const client: Client = { + server: 'http://localhost:8080', + version: 'v1', + models: [], + services: [], + }; + + const templates: Templates = { + index: () => 'index', + client: () => 'client', + exports: { + model: () => 'model', + schema: () => 'schema', + service: () => 'service', + }, + core: { + settings: () => 'settings', + apiError: () => 'apiError', + apiRequestOptions: () => 'apiRequestOptions', + apiResult: () => 'apiResult', + cancelablePromise: () => 'cancelablePromise', + request: () => 'request', + baseHttpRequest: () => 'baseHttpRequest', + httpRequest: () => 'httpRequest', + }, + }; + + await writeClientClass(client, templates, './dist', HttpClient.FETCH, 'AppClient', Indent.SPACE_4, ''); + + expect(rmdir).toBeCalled(); + expect(mkdir).toBeCalled(); + expect(writeFile).toBeCalled(); + }); +}); diff --git a/src/utils/writeClientClass.ts b/src/utils/writeClientClass.ts new file mode 100644 index 00000000..ff0ef816 --- /dev/null +++ b/src/utils/writeClientClass.ts @@ -0,0 +1,44 @@ +import { resolve } from 'path'; + +import type { Client } from '../client/interfaces/Client'; +import { HttpClient } from '../HttpClient'; +import { Indent } from '../Indent'; +import { writeFile } from './fileSystem'; +import { formatCode as f } from './formatCode'; +import { formatIndentation as i } from './formatIndentation'; +import { Templates } from './registerHandlebarTemplates'; +import { sortModelsByName } from './sortModelsByName'; +import { sortServicesByName } from './sortServicesByName'; +/** + * 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 templates The loaded handlebar templates + * @param outputPath Directory to write the generated files to + * @param httpClient The selected httpClient (fetch, xhr, node or axios) + * @param clientName Custom client class name + * @param indent: Indentation options (4, 2 or tab) + * @param postfix: Service name postfix + */ +export async function writeClientClass( + client: Client, + templates: Templates, + outputPath: string, + httpClient: HttpClient, + clientName: string, + indent: Indent, + postfix: string +): Promise { + const templateResult = templates.client({ + clientName, + postfix, + server: client.server, + version: client.version, + models: sortModelsByName(client.models), + services: sortServicesByName(client.services), + httpRequest: 'XhrBaseRequest', + }); + + await writeFile(resolve(outputPath, 'client.ts'), i(f(templateResult), indent)); +} diff --git a/src/utils/writeClientCore.spec.ts b/src/utils/writeClientCore.spec.ts index b96780ad..b9222227 100644 --- a/src/utils/writeClientCore.spec.ts +++ b/src/utils/writeClientCore.spec.ts @@ -18,6 +18,7 @@ describe('writeClientCore', () => { const templates: Templates = { index: () => 'index', + client: () => 'client', exports: { model: () => 'model', schema: () => 'schema', @@ -30,6 +31,8 @@ describe('writeClientCore', () => { apiResult: () => 'apiResult', cancelablePromise: () => 'cancelablePromise', request: () => 'request', + baseHttpRequest: () => 'baseHttpRequest', + httpRequest: () => 'httpRequest', }, }; diff --git a/src/utils/writeClientIndex.spec.ts b/src/utils/writeClientIndex.spec.ts index a5d243b1..ffc365bd 100644 --- a/src/utils/writeClientIndex.spec.ts +++ b/src/utils/writeClientIndex.spec.ts @@ -16,6 +16,7 @@ describe('writeClientIndex', () => { const templates: Templates = { index: () => 'index', + client: () => 'client', exports: { model: () => 'model', schema: () => 'schema', @@ -28,6 +29,8 @@ describe('writeClientIndex', () => { apiResult: () => 'apiResult', cancelablePromise: () => 'cancelablePromise', request: () => 'request', + baseHttpRequest: () => 'baseHttpRequest', + httpRequest: () => 'httpRequest', }, }; diff --git a/src/utils/writeClientIndex.ts b/src/utils/writeClientIndex.ts index 8336471e..6fe74fa2 100644 --- a/src/utils/writeClientIndex.ts +++ b/src/utils/writeClientIndex.ts @@ -31,19 +31,18 @@ export async function writeClientIndex( exportSchemas: boolean, postfix: string ): Promise { - await writeFile( - resolve(outputPath, 'index.ts'), - templates.index({ - exportCore, - exportServices, - exportModels, - exportSchemas, - useUnionTypes, - postfix, - server: client.server, - version: client.version, - models: sortModelsByName(client.models), - services: sortServicesByName(client.services), - }) - ); + const templateResult = templates.index({ + exportCore, + exportServices, + exportModels, + exportSchemas, + useUnionTypes, + postfix, + server: client.server, + version: client.version, + models: sortModelsByName(client.models), + services: sortServicesByName(client.services), + }); + + await writeFile(resolve(outputPath, 'index.ts'), templateResult); } diff --git a/src/utils/writeClientModels.spec.ts b/src/utils/writeClientModels.spec.ts index 359849dc..61e2255b 100644 --- a/src/utils/writeClientModels.spec.ts +++ b/src/utils/writeClientModels.spec.ts @@ -31,6 +31,7 @@ describe('writeClientModels', () => { const templates: Templates = { index: () => 'index', + client: () => 'client', exports: { model: () => 'model', schema: () => 'schema', @@ -43,6 +44,8 @@ describe('writeClientModels', () => { apiResult: () => 'apiResult', cancelablePromise: () => 'cancelablePromise', request: () => 'request', + baseHttpRequest: () => 'baseHttpRequest', + httpRequest: () => 'httpRequest', }, }; diff --git a/src/utils/writeClientSchemas.spec.ts b/src/utils/writeClientSchemas.spec.ts index 4c1f34ce..1f917223 100644 --- a/src/utils/writeClientSchemas.spec.ts +++ b/src/utils/writeClientSchemas.spec.ts @@ -31,6 +31,7 @@ describe('writeClientSchemas', () => { const templates: Templates = { index: () => 'index', + client: () => 'client', exports: { model: () => 'model', schema: () => 'schema', @@ -43,6 +44,8 @@ describe('writeClientSchemas', () => { apiResult: () => 'apiResult', cancelablePromise: () => 'cancelablePromise', request: () => 'request', + baseHttpRequest: () => 'baseHttpRequest', + httpRequest: () => 'httpRequest', }, }; diff --git a/src/utils/writeClientServices.spec.ts b/src/utils/writeClientServices.spec.ts index 1f185db8..387ea208 100644 --- a/src/utils/writeClientServices.spec.ts +++ b/src/utils/writeClientServices.spec.ts @@ -19,6 +19,7 @@ describe('writeClientServices', () => { const templates: Templates = { index: () => 'index', + client: () => 'client', exports: { model: () => 'model', schema: () => 'schema', @@ -31,6 +32,8 @@ describe('writeClientServices', () => { apiResult: () => 'apiResult', cancelablePromise: () => 'cancelablePromise', request: () => 'request', + baseHttpRequest: () => 'baseHttpRequest', + httpRequest: () => 'httpRequest', }, };