Skip to content

Add option to pass in a custom handlebars template to generate the service files #1268

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

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
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
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ junit.xml
.idea
.vscode
*.iml
dist
coverage
test/generated
test/e2e/generated
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# OpenAPI Typescript Codegen

Fork ([diff](https://github.com/ferdikoomen/openapi-typescript-codegen/compare/master...mb21:openapi-typescript-codegen:generate-custom))
which adds a `--serviceTemplate` option.

Can be used in another project by adding to `package.json`::

```json
"openapi-typescript-codegen": "https://github.com/mb21/openapi-typescript-codegen.git#generate-custom",
```

To release a new version, run `npm run release` and push everything, including the `dist/index.js` file to GitHub. Then, in the project using it, delete the
`openapi-typescript-codegen` entry in the `package-lock.json` and run `npm install` to install the new version.

---

[![NPM][npm-image]][npm-url]
[![License][license-image]][license-url]
[![Coverage][coverage-image]][coverage-url]
Expand Down Expand Up @@ -50,6 +64,7 @@ $ openapi --help
--indent <value> Indentation options [4, 2, tab] (default: "4")
--postfix <value> Service name postfix (default: "Service")
--request <value> Path to custom request file
--serviceTemplate Path to custom service handlebars template to generate the service files
-h, --help display help for command

Examples
Expand Down
2 changes: 2 additions & 0 deletions bin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const params = program
.option('--indent <value>', 'Indentation options [4, 2, tabs]', '4')
.option('--postfix <value>', 'Service name postfix', 'Service')
.option('--request <value>', 'Path to custom request file')
.option('--serviceTemplate <value>', 'Path to custom service handlebars template to generate the service files')
.parse(process.argv)
.opts();

Expand All @@ -43,6 +44,7 @@ if (OpenAPI) {
indent: params.indent,
postfix: params.postfix,
request: params.request,
serviceTemplate: params.serviceTemplate,
})
.then(() => {
process.exit(0);
Expand Down
1 change: 1 addition & 0 deletions dist/index.js

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -121,5 +121,8 @@
},
"resolutions": {
"node-fetch": "2.6.7"
},
"volta": {
"node": "16.17.0"
}
}
25 changes: 23 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { isString } from './utils/isString';
import { postProcessClient } from './utils/postProcessClient';
import { registerHandlebarTemplates } from './utils/registerHandlebarTemplates';
import { writeClient } from './utils/writeClient';
import { writeClientServicesCustomTemplate } from './utils/writeClientServicesCustomTemplate';

export { HttpClient } from './HttpClient';
export { Indent } from './Indent';
Expand All @@ -26,6 +27,7 @@ export type Options = {
indent?: Indent;
postfix?: string;
request?: string;
serviceTemplate?: string;
write?: boolean;
};

Expand Down Expand Up @@ -62,6 +64,7 @@ export const generate = async ({
indent = Indent.SPACE_4,
postfix = 'Service',
request,
serviceTemplate,
write = true,
}: Options): Promise<void> => {
const openApi = isString(input) ? await getOpenApiSpec(input) : input;
Expand All @@ -72,10 +75,15 @@ export const generate = async ({
useOptions,
});

if (serviceTemplate) {
exportServices = false;
}

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 @@ -98,7 +106,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 @@ -119,6 +127,19 @@ export const generate = async ({
break;
}
}

if (serviceTemplate) {
await writeClientServicesCustomTemplate(
clientFinal,
output,
httpClient,
useOptions,
useUnionTypes,
indent,
postfix,
serviceTemplate
);
}
};

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
51 changes: 51 additions & 0 deletions src/utils/writeClientServicesCustomTemplate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { mkdir, 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 } from './formatCode';
import { formatIndentation } from './formatIndentation';
import { registerHandlebarTemplates } from './registerHandlebarTemplates';

export const writeClientServicesCustomTemplate = async (
client: Client,
outputPath: string,
httpClient: HttpClient,
useOptions: boolean,
useUnionTypes: boolean,
indent: Indent,
postfix: string,
templatePath: 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 serviceTemplate = Handlebars.compile(await readFile(templatePath, 'utf8'));

const servicesDir = resolve(outputPath, 'services');
await remove(servicesDir);
await mkdir(servicesDir);

for (const service of client.services) {
const file = resolve(outputPath, `services/${service.name}${postfix}.ts`);
const templateResult = serviceTemplate({
...service,
serviceBaseUrl: client.server,
httpClient,
useUnionTypes,
useOptions,
postfix,
});
await writeFile(file, formatIndentation(formatCode(templateResult), indent));
}
};