- Added write client class methods

This commit is contained in:
Ferdi Koomen 2022-01-25 12:15:37 +01:00
parent d0900cee8c
commit 7b4352c48f
14 changed files with 155 additions and 26 deletions

View File

@ -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;

View File

@ -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}}
}
}

View File

@ -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<T>
* @throws ApiError
*/
public request<T>(options: ApiRequestOptions): CancelablePromise<T> {
return __request(this.config, options);
}
public request<T>(options: ApiRequestOptions): CancelablePromise<T> {
return __request(this.config, options);
}
}

View File

@ -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),
},
};

View File

@ -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();

View File

@ -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<void> {
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(

View File

@ -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();
});
});

View File

@ -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<void> {
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));
}

View File

@ -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',
},
};

View File

@ -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',
},
};

View File

@ -31,19 +31,18 @@ export async function writeClientIndex(
exportSchemas: boolean,
postfix: string
): Promise<void> {
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);
}

View File

@ -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',
},
};

View File

@ -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',
},
};

View File

@ -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',
},
};