Skip to content

Options for custom template files #1472

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ $ openapi --help
--postfixServices Service name postfix (default: "Service")
--postfixModels Model name postfix
--request <value> Path to custom request file
--serviceTemplate <value> Path to custom service handlebars template to generate the service files
--clientTemplate <value> Path to custom client handlebars template to generate the client file
--indexTemplate <value> Path to custom index handlebars template to generate the index file
-h, --help display help for command

Examples
Expand Down
10 changes: 10 additions & 0 deletions bin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@ const params = program
.option('--exportCore <value>', 'Write core files to disk', true)
.option('--exportServices <value>', 'Write services to disk', true)
.option('--exportModels <value>', 'Write models to disk', true)
.option('--exportClient <value>', 'Write main Client file to disk', true)
.option('--exportIndex <value>', 'Write Index to disk', true)
.option('--exportSchemas <value>', 'Write schemas to disk', false)
.option('--indent <value>', 'Indentation options [4, 2, tabs]', '4')
.option('--postfixServices <value>', 'Service name postfix', 'Service')
.option('--postfixModels <value>', 'Model name postfix')
.option('--request <value>', 'Path to custom request file')
.option('--serviceTemplate <value>', 'Path to custom service handlebars template to generate the service files')
.option('--clientTemplate <value>', 'Path to custom client handlebars template to generate the client file')
.option('--indexTemplate <value>', 'Path to custom index handlebars template to generate the index file')
.parse(process.argv)
.opts();

Expand All @@ -40,11 +45,16 @@ if (OpenAPI) {
exportCore: JSON.parse(params.exportCore) === true,
exportServices: JSON.parse(params.exportServices) === true,
exportModels: JSON.parse(params.exportModels) === true,
exportClient: JSON.parse(params.exportClient) === true,
exportIndex: JSON.parse(params.exportIndex) === true,
exportSchemas: JSON.parse(params.exportSchemas) === true,
indent: params.indent,
postfixServices: params.postfixServices,
postfixModels: params.postfixModels,
request: params.request,
serviceTemplate: params.serviceTemplate,
clientTemplate: params.clientTemplate,
indexTemplate: params.indexTemplate,
})
.then(() => {
process.exit(0);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@
"typescript": "4.9.5",
"zone.js": "0.13.0"
},
"overrides" : {
"overrides": {
"node-fetch": "2.6.9",
"rollup": "3.20.2",
"typescript": "4.9.5"
Expand Down
71 changes: 69 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import { isString } from './utils/isString';
import { postProcessClient } from './utils/postProcessClient';
import { registerHandlebarTemplates } from './utils/registerHandlebarTemplates';
import { writeClient } from './utils/writeClient';
import { writeClientClassCustomTemplate } from './utils/writeClientCustomTemplate/clientClass';
import { writeClientIndexCustomTemplate } from './utils/writeClientCustomTemplate/index';
import { writeClientServicesCustomTemplate } from './utils/writeClientCustomTemplate/services';

export { HttpClient } from './HttpClient';
export { Indent } from './Indent';
Expand All @@ -22,11 +25,16 @@ export type Options = {
exportCore?: boolean;
exportServices?: boolean;
exportModels?: boolean;
exportClient?: boolean;
exportIndex?: boolean;
exportSchemas?: boolean;
indent?: Indent;
postfixServices?: string;
postfixModels?: string;
request?: string;
serviceTemplate?: string;
clientTemplate?: string;
indexTemplate?: string;
write?: boolean;
};

Expand Down Expand Up @@ -60,11 +68,16 @@ export const generate = async ({
exportCore = true,
exportServices = true,
exportModels = true,
exportClient = true,
exportIndex = true,
exportSchemas = false,
indent = Indent.SPACE_4,
postfixServices = 'Service',
postfixModels = '',
request,
serviceTemplate,
clientTemplate,
indexTemplate,
write = true,
}: Options): Promise<void> => {
const openApi = isString(input) ? await getOpenApiSpec(input) : input;
Expand All @@ -75,10 +88,11 @@ export const generate = async ({
useOptions,
});

let clientFinal;
switch (openApiVersion) {
case OpenApiVersion.V2: {
const client = parseV2(openApi);
const clientFinal = postProcessClient(client);
clientFinal = postProcessClient(client);
if (!write) break;
await writeClient(
clientFinal,
Expand All @@ -90,6 +104,8 @@ export const generate = async ({
exportCore,
exportServices,
exportModels,
exportClient,
exportIndex,
exportSchemas,
indent,
postfixServices,
Expand All @@ -102,7 +118,7 @@ export const generate = async ({

case OpenApiVersion.V3: {
const client = parseV3(openApi);
const clientFinal = postProcessClient(client);
clientFinal = postProcessClient(client);
if (!write) break;
await writeClient(
clientFinal,
Expand All @@ -114,6 +130,8 @@ export const generate = async ({
exportCore,
exportServices,
exportModels,
exportClient,
exportIndex,
exportSchemas,
indent,
postfixServices,
Expand All @@ -124,6 +142,55 @@ export const generate = async ({
break;
}
}

if (serviceTemplate)
await writeClientServicesCustomTemplate(
clientFinal,
output,
httpClient,
useOptions,
useUnionTypes,
indent,
postfixServices,
postfixModels,
serviceTemplate,
exportClient,
exportModels,
exportSchemas,
clientName
);

if (clientTemplate)
await writeClientClassCustomTemplate(
clientFinal,
output,
httpClient,
useOptions,
useUnionTypes,
indent,
postfixServices,
clientTemplate,
clientName
);

if (indexTemplate)
await writeClientIndexCustomTemplate(
clientFinal,
output,
httpClient,
useOptions,
useUnionTypes,
indent,
postfixServices,
postfixModels,
indexTemplate,
exportCore,
exportServices,
exportModels,
exportSchemas,
exportClient,
clientName
);
};

export default {
Expand Down
5 changes: 4 additions & 1 deletion src/utils/registerHandlebarHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import camelCase from 'camelcase';
import Handlebars from 'handlebars/runtime';
import HandlebarsRuntime from 'handlebars/runtime';
import { EOL } from 'os';

import type { Enum } from '../client/interfaces/Enum';
Expand All @@ -11,7 +11,10 @@ export const registerHandlebarHelpers = (root: {
httpClient: HttpClient;
useOptions: boolean;
useUnionTypes: boolean;
handlebars?: typeof HandlebarsRuntime;
}): void => {
const Handlebars = root.handlebars || HandlebarsRuntime;

Handlebars.registerHelper('ifdef', function (this: any, ...args): string {
const options = args.pop();
if (!args.every(value => !value)) {
Expand Down
5 changes: 4 additions & 1 deletion src/utils/registerHandlebarTemplates.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Handlebars from 'handlebars/runtime';
import HandlebarsRuntime from 'handlebars/runtime';

import { HttpClient } from '../HttpClient';
import templateClient from '../templates/client.hbs';
Expand Down Expand Up @@ -113,7 +113,10 @@ export const registerHandlebarTemplates = (root: {
httpClient: HttpClient;
useOptions: boolean;
useUnionTypes: boolean;
handlebars?: typeof HandlebarsRuntime;
}): Templates => {
const Handlebars = root.handlebars || HandlebarsRuntime;

registerHandlebarHelpers(root);

// Main templates (entry points for the files we write to disk)
Expand Down
2 changes: 2 additions & 0 deletions src/utils/writeClient.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ describe('writeClient', () => {
true,
true,
true,
true,
true,
Indent.SPACE_4,
'Service',
'AppClient'
Expand Down
6 changes: 4 additions & 2 deletions src/utils/writeClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ export const writeClient = async (
exportCore: boolean,
exportServices: boolean,
exportModels: boolean,
exportClient: boolean,
exportIndex: boolean,
exportSchemas: boolean,
indent: Indent,
postfixServices: string,
Expand Down Expand Up @@ -94,12 +96,12 @@ export const writeClient = async (
await writeClientModels(client.models, templates, outputPathModels, httpClient, useUnionTypes, indent);
}

if (isDefined(clientName)) {
if (isDefined(clientName) && exportClient) {
await mkdir(outputPath);
await writeClientClass(client, templates, outputPath, httpClient, clientName, indent, postfixServices);
}

if (exportCore || exportServices || exportSchemas || exportModels) {
if ((exportCore || exportServices || exportSchemas || exportModels) && exportIndex) {
await mkdir(outputPath);
await writeClientIndex(
client,
Expand Down
54 changes: 54 additions & 0 deletions src/utils/writeClientCustomTemplate/clientClass.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { readFile, remove } from 'fs-extra';
import Handlebars from 'handlebars';
import { resolve } from 'path';

import { 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 { getHttpRequestName } from '../getHttpRequestName.js';
import { registerHandlebarTemplates } from '../registerHandlebarTemplates';
import { sortModelsByName } from '../sortModelsByName.js';
import { sortServicesByName } from '../sortServicesByName.js';

export const writeClientClassCustomTemplate = async (
client: Client,
outputPath: string,
httpClient: HttpClient,
useOptions: boolean,
useUnionTypes: boolean,
indent: Indent,
postfix: string,
templatePath: string,
clientName?: string
) => {
registerHandlebarTemplates({
httpClient,
useUnionTypes,
useOptions,
handlebars: Handlebars, // since we're not using precompiled templates, we need a different object here
});
Handlebars.registerHelper('capitalize', str => {
return str.charAt(0).toUpperCase() + str.slice(1);
});

const clientClassTemplate = Handlebars.compile(await readFile(templatePath, 'utf8'));

const clientClassFile = resolve(outputPath, `${clientName}.ts`);
await remove(clientClassFile);

const templateResult = clientClassTemplate({
clientName,
httpClient,
postfix,
server: client.server,
version: client.version,
models: sortModelsByName(client.models),
services: sortServicesByName(client.services),
httpRequest: getHttpRequestName(httpClient),
});

await writeFile(resolve(outputPath, `${clientName}.ts`), i(f(templateResult), indent));
};
65 changes: 65 additions & 0 deletions src/utils/writeClientCustomTemplate/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { readFile, remove } from 'fs-extra';
import Handlebars from 'handlebars';
import { resolve } from 'path';

import { 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 { isDefined } from '../isDefined.js';
import { registerHandlebarTemplates } from '../registerHandlebarTemplates';
import { sortModelsByName } from '../sortModelsByName.js';
import { sortServicesByName } from '../sortServicesByName.js';

export const writeClientIndexCustomTemplate = async (
client: Client,
outputPath: string,
httpClient: HttpClient,
useOptions: boolean,
useUnionTypes: boolean,
indent: Indent,
postfixServices: string,
postfixModels: string,
templatePath: string,
exportCore: boolean,
exportServices: boolean,
exportModels: boolean,
exportSchemas: boolean,
exportClient: boolean,
clientName?: string
) => {
registerHandlebarTemplates({
httpClient,
useUnionTypes,
useOptions,
handlebars: Handlebars, // since we're not using precompiled templates, we need a different object here
});
Handlebars.registerHelper('capitalize', str => {
return str.charAt(0).toUpperCase() + str.slice(1);
});

const indexTemplate = Handlebars.compile(await readFile(templatePath, 'utf8'));

const dir = resolve(outputPath, 'index.ts');
await remove(dir);

const templateResult = indexTemplate({
serviceBaseUrl: client.server,
exportCore,
exportServices,
exportModels,
exportSchemas,
useUnionTypes,
postfixServices,
postfixModels,
clientName,
server: client.server,
version: client.version,
models: sortModelsByName(client.models),
services: sortServicesByName(client.services),
exportClient: isDefined(clientName) && exportClient,
});
await writeFile(resolve(outputPath, 'index.ts'), i(f(templateResult), indent));
};
Loading