diff --git a/README.md b/README.md index 429f905ee..58fb0c86f 100644 --- a/README.md +++ b/README.md @@ -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] @@ -51,6 +65,7 @@ $ openapi --help --postfixServices Service name postfix (default: "Service") --postfixModels Model name postfix --request Path to custom request file + --serviceTemplate Path to custom service handlebars template to generate the service files -h, --help display help for command Examples diff --git a/bin/index.js b/bin/index.js index ed8b0889b..f1db68a8c 100755 --- a/bin/index.js +++ b/bin/index.js @@ -25,6 +25,7 @@ const params = program .option('--postfixServices ', 'Service name postfix', 'Service') .option('--postfixModels ', 'Model name postfix') .option('--request ', 'Path to custom request file') + .option('--serviceTemplate ', 'Path to custom service handlebars template to generate the service files') .parse(process.argv) .opts(); @@ -46,6 +47,7 @@ if (OpenAPI) { postfixServices: params.postfixServices ?? params.postfix, postfixModels: params.postfixModels, request: params.request, + serviceTemplate: params.serviceTemplate, }) .then(() => { process.exit(0); diff --git a/src/client/interfaces/OperationParameter.d.ts b/src/client/interfaces/OperationParameter.d.ts index 77c0da771..6738024f0 100644 --- a/src/client/interfaces/OperationParameter.d.ts +++ b/src/client/interfaces/OperationParameter.d.ts @@ -4,4 +4,5 @@ export interface OperationParameter extends Model { in: 'path' | 'query' | 'header' | 'formData' | 'body' | 'cookie'; prop: string; mediaType: string | null; + allMediaTypes: string[]; } diff --git a/src/client/interfaces/OperationResponse.d.ts b/src/client/interfaces/OperationResponse.d.ts index 0eed91537..eb35999ff 100644 --- a/src/client/interfaces/OperationResponse.d.ts +++ b/src/client/interfaces/OperationResponse.d.ts @@ -3,4 +3,6 @@ import type { Model } from './Model'; export interface OperationResponse extends Model { in: 'response' | 'header'; code: number; + mediaType: string | null; + allMediaTypes: string[]; } diff --git a/src/index.ts b/src/index.ts index e63919085..d3a6245a3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,5 @@ +import HandlebarsRuntime from 'handlebars/runtime'; + import { HttpClient } from './HttpClient'; import { Indent } from './Indent'; import { parse as parseV2 } from './openApi/v2'; @@ -28,6 +30,8 @@ export type Options = { postfixModels?: string; request?: string; write?: boolean; + handlebars?: typeof HandlebarsRuntime; + serviceTemplate?: Handlebars.TemplateDelegate; }; /** @@ -49,6 +53,8 @@ export type Options = { * @param postfixModels Model name postfix * @param request Path to custom request file * @param write Write the files to disk (true or false) + * @param handlebars Handlebars runtime + * @param serviceTemplate Service template */ export const generate = async ({ input, @@ -66,19 +72,24 @@ export const generate = async ({ postfixModels = '', request, write = true, + handlebars, + serviceTemplate, }: Options): Promise => { const openApi = isString(input) ? await getOpenApiSpec(input) : input; const openApiVersion = getOpenApiVersion(openApi); const templates = registerHandlebarTemplates({ + handlebars, httpClient, useUnionTypes, useOptions, + serviceTemplate, }); + let clientFinal; switch (openApiVersion) { case OpenApiVersion.V2: { const client = parseV2(openApi); - const clientFinal = postProcessClient(client); + clientFinal = postProcessClient(client); if (!write) break; await writeClient( clientFinal, @@ -102,7 +113,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, diff --git a/src/openApi/v2/parser/getOperationParameter.ts b/src/openApi/v2/parser/getOperationParameter.ts index 6b68c9d5a..7006605e3 100644 --- a/src/openApi/v2/parser/getOperationParameter.ts +++ b/src/openApi/v2/parser/getOperationParameter.ts @@ -43,6 +43,7 @@ export const getOperationParameter = (openApi: OpenApi, parameter: OpenApiParame enums: [], properties: [], mediaType: null, + allMediaTypes: [], }; if (parameter.$ref) { diff --git a/src/openApi/v2/parser/getOperationResponse.ts b/src/openApi/v2/parser/getOperationResponse.ts index 8f6c3ca56..248156b85 100644 --- a/src/openApi/v2/parser/getOperationResponse.ts +++ b/src/openApi/v2/parser/getOperationResponse.ts @@ -30,6 +30,8 @@ export const getOperationResponse = ( enum: [], enums: [], properties: [], + mediaType: null, + allMediaTypes: [], }; // If this response has a schema, then we need to check two things: diff --git a/src/openApi/v2/parser/getOperationResults.ts b/src/openApi/v2/parser/getOperationResults.ts index 9d8111fe8..b4ab910c5 100644 --- a/src/openApi/v2/parser/getOperationResults.ts +++ b/src/openApi/v2/parser/getOperationResults.ts @@ -39,6 +39,8 @@ export const getOperationResults = (operationResponses: OperationResponse[]): Op enum: [], enums: [], properties: [], + mediaType: null, + allMediaTypes: [], }); } diff --git a/src/openApi/v3/parser/getContent.ts b/src/openApi/v3/parser/getContent.ts index 976625817..5e5c6d8f2 100644 --- a/src/openApi/v3/parser/getContent.ts +++ b/src/openApi/v3/parser/getContent.ts @@ -6,15 +6,19 @@ import type { OpenApiSchema } from '../interfaces/OpenApiSchema'; export interface Content { mediaType: string; + allMediaTypes: string[]; schema: OpenApiSchema; } const BASIC_MEDIA_TYPES = [ 'application/json-patch+json', 'application/json', - 'application/x-www-form-urlencoded', 'text/json', 'text/plain', + 'application/xml', + 'application/javascript', + 'application/octet-stream', + 'application/x-www-form-urlencoded', 'multipart/form-data', 'multipart/mixed', 'multipart/related', @@ -31,6 +35,7 @@ export const getContent = (openApi: OpenApi, content: Dictionary(openApi, content.schema); } diff --git a/src/openApi/v3/parser/getOperationResults.ts b/src/openApi/v3/parser/getOperationResults.ts index 9d8111fe8..b4ab910c5 100644 --- a/src/openApi/v3/parser/getOperationResults.ts +++ b/src/openApi/v3/parser/getOperationResults.ts @@ -39,6 +39,8 @@ export const getOperationResults = (operationResponses: OperationResponse[]): Op enum: [], enums: [], properties: [], + mediaType: null, + allMediaTypes: [], }); } diff --git a/src/utils/registerHandlebarHelpers.ts b/src/utils/registerHandlebarHelpers.ts index 88f47c19b..f843a4f80 100644 --- a/src/utils/registerHandlebarHelpers.ts +++ b/src/utils/registerHandlebarHelpers.ts @@ -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'; @@ -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)) { @@ -104,4 +107,8 @@ export const registerHandlebarHelpers = (root: { Handlebars.registerHelper('camelCase', function (value: string): string { return camelCase(value); }); + + Handlebars.registerHelper('toJSON', function (object): any { + return new Handlebars.SafeString(JSON.stringify(object)); + }); }; diff --git a/src/utils/registerHandlebarTemplates.ts b/src/utils/registerHandlebarTemplates.ts index bf77cbdc1..98297738d 100644 --- a/src/utils/registerHandlebarTemplates.ts +++ b/src/utils/registerHandlebarTemplates.ts @@ -1,4 +1,4 @@ -import Handlebars from 'handlebars/runtime'; +import HandlebarsRuntime from 'handlebars/runtime'; import { HttpClient } from '../HttpClient'; import templateClient from '../templates/client.hbs'; @@ -113,7 +113,11 @@ export const registerHandlebarTemplates = (root: { httpClient: HttpClient; useOptions: boolean; useUnionTypes: boolean; + handlebars?: typeof HandlebarsRuntime; + serviceTemplate?: Handlebars.TemplateDelegate; }): Templates => { + const Handlebars = root.handlebars || HandlebarsRuntime; + registerHandlebarHelpers(root); // Main templates (entry points for the files we write to disk) @@ -123,7 +127,7 @@ export const registerHandlebarTemplates = (root: { exports: { model: Handlebars.template(templateExportModel), schema: Handlebars.template(templateExportSchema), - service: Handlebars.template(templateExportService), + service: Handlebars.template(root.serviceTemplate || templateExportService), }, core: { settings: Handlebars.template(templateCoreSettings), diff --git a/src/utils/writeClient.ts b/src/utils/writeClient.ts index cea2f3d88..1a202440f 100644 --- a/src/utils/writeClient.ts +++ b/src/utils/writeClient.ts @@ -26,7 +26,6 @@ import { writeClientServices } from './writeClientServices'; * @param exportServices Generate services * @param exportModels Generate models * @param exportSchemas Generate schemas - * @param exportSchemas Generate schemas * @param indent Indentation options (4, 2 or tab) * @param postfixServices Service name postfix * @param postfixModels Model name postfix