From 47d479f268f4c6c3254ae944ca774cd84f828c43 Mon Sep 17 00:00:00 2001 From: Ferdi Koomen Date: Wed, 27 Jan 2021 22:06:03 +0100 Subject: [PATCH] - Fixed configuration values beeing passed to partials when using composition --- rollup.config.js | 2 ++ src/index.ts | 6 +++- src/openApi/v2/parser/getModel.ts | 3 +- src/openApi/v2/parser/getOperationResponse.ts | 28 +++++++++--------- src/openApi/v3/parser/getModel.ts | 7 +++-- src/openApi/v3/parser/getOperationResponse.ts | 28 +++++++++--------- src/templates/partials/typeEnum.hbs | 9 ++---- src/templates/partials/typeIntersection.hbs | 6 +--- src/utils/registerHandlebarHelpers.spec.ts | 8 ++++- src/utils/registerHandlebarHelpers.ts | 29 ++++++++++++++----- src/utils/registerHandlebarTemplates.spec.ts | 7 ++++- src/utils/registerHandlebarTemplates.ts | 5 ++-- test/__snapshots__/index.spec.js.snap | 6 ++-- 13 files changed, 85 insertions(+), 59 deletions(-) diff --git a/rollup.config.js b/rollup.config.js index 4dfa1a27..4449108b 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -36,6 +36,8 @@ const handlebarsPlugin = () => ({ notEquals: true, containsSpaces: true, union: true, + intersection: true, + enumerator: true, }, }); return `export default ${templateSpec};`; diff --git a/src/index.ts b/src/index.ts index f0714b74..7a67ee56 100644 --- a/src/index.ts +++ b/src/index.ts @@ -55,7 +55,11 @@ export async function generate({ }: Options): Promise { const openApi = isString(input) ? await getOpenApiSpec(input) : input; const openApiVersion = getOpenApiVersion(openApi); - const templates = registerHandlebarTemplates(); + const templates = registerHandlebarTemplates({ + httpClient, + useUnionTypes, + useOptions, + }); switch (openApiVersion) { case OpenApiVersion.V2: { diff --git a/src/openApi/v2/parser/getModel.ts b/src/openApi/v2/parser/getModel.ts index d5cc866d..5c3c5ac8 100644 --- a/src/openApi/v2/parser/getModel.ts +++ b/src/openApi/v2/parser/getModel.ts @@ -122,8 +122,8 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti const composition = getModelComposition(openApi, definition, definition.allOf, 'all-of', getModel); model.export = composition.type; model.imports.push(...composition.imports); - model.enums.push(...composition.enums); model.properties.push(...composition.properties); + model.enums.push(...composition.enums); return model; } @@ -136,6 +136,7 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti const properties = getModelProperties(openApi, definition, getModel); properties.forEach(property => { model.imports.push(...property.imports); + model.enums.push(...property.enums); model.properties.push(property); if (property.export === 'enum') { model.enums.push(property); diff --git a/src/openApi/v2/parser/getOperationResponse.ts b/src/openApi/v2/parser/getOperationResponse.ts index e552fe30..1e0e9ab4 100644 --- a/src/openApi/v2/parser/getOperationResponse.ts +++ b/src/openApi/v2/parser/getOperationResponse.ts @@ -27,20 +27,6 @@ export function getOperationResponse(openApi: OpenApi, response: OpenApiResponse properties: [], }; - // We support basic properties from response headers, since both - // fetch and XHR client just support string types. - if (response.headers) { - for (const name in response.headers) { - if (response.headers.hasOwnProperty(name)) { - operationResponse.in = 'header'; - operationResponse.name = name; - operationResponse.type = 'string'; - operationResponse.base = 'string'; - return operationResponse; - } - } - } - // If this response has a schema, then we need to check two things: // if this is a reference then the parameter is just the 'name' of // this reference type. Otherwise it might be a complex schema and @@ -86,5 +72,19 @@ export function getOperationResponse(openApi: OpenApi, response: OpenApiResponse } } + // We support basic properties from response headers, since both + // fetch and XHR client just support string types. + if (response.headers) { + for (const name in response.headers) { + if (response.headers.hasOwnProperty(name)) { + operationResponse.in = 'header'; + operationResponse.name = name; + operationResponse.type = 'string'; + operationResponse.base = 'string'; + return operationResponse; + } + } + } + return operationResponse; } diff --git a/src/openApi/v3/parser/getModel.ts b/src/openApi/v3/parser/getModel.ts index 7be4180f..c5d415bb 100644 --- a/src/openApi/v3/parser/getModel.ts +++ b/src/openApi/v3/parser/getModel.ts @@ -130,8 +130,8 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti const composition = getModelComposition(openApi, definition, definition.oneOf, 'one-of', getModel); model.export = composition.type; model.imports.push(...composition.imports); - model.enums.push(...composition.enums); model.properties.push(...composition.properties); + model.enums.push(...composition.enums); return model; } @@ -139,8 +139,8 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti const composition = getModelComposition(openApi, definition, definition.anyOf, 'any-of', getModel); model.export = composition.type; model.imports.push(...composition.imports); - model.enums.push(...composition.enums); model.properties.push(...composition.properties); + model.enums.push(...composition.enums); return model; } @@ -148,8 +148,8 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti const composition = getModelComposition(openApi, definition, definition.allOf, 'all-of', getModel); model.export = composition.type; model.imports.push(...composition.imports); - model.enums.push(...composition.enums); model.properties.push(...composition.properties); + model.enums.push(...composition.enums); return model; } @@ -163,6 +163,7 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti const properties = getModelProperties(openApi, definition, getModel); properties.forEach(property => { model.imports.push(...property.imports); + model.enums.push(...property.enums); model.properties.push(property); if (property.export === 'enum') { model.enums.push(property); diff --git a/src/openApi/v3/parser/getOperationResponse.ts b/src/openApi/v3/parser/getOperationResponse.ts index ee5e7055..45abaa0a 100644 --- a/src/openApi/v3/parser/getOperationResponse.ts +++ b/src/openApi/v3/parser/getOperationResponse.ts @@ -28,20 +28,6 @@ export function getOperationResponse(openApi: OpenApi, response: OpenApiResponse properties: [], }; - // We support basic properties from response headers, since both - // fetch and XHR client just support string types. - if (response.headers) { - for (const name in response.headers) { - if (response.headers.hasOwnProperty(name)) { - operationResponse.in = 'header'; - operationResponse.name = name; - operationResponse.type = 'string'; - operationResponse.base = 'string'; - return operationResponse; - } - } - } - if (response.content) { const schema = getContent(openApi, response.content); if (schema) { @@ -86,5 +72,19 @@ export function getOperationResponse(openApi: OpenApi, response: OpenApiResponse } } + // We support basic properties from response headers, since both + // fetch and XHR client just support string types. + if (response.headers) { + for (const name in response.headers) { + if (response.headers.hasOwnProperty(name)) { + operationResponse.in = 'header'; + operationResponse.name = name; + operationResponse.type = 'string'; + operationResponse.base = 'string'; + return operationResponse; + } + } + } + return operationResponse; } diff --git a/src/templates/partials/typeEnum.hbs b/src/templates/partials/typeEnum.hbs index 9693459b..781fd5ec 100644 --- a/src/templates/partials/typeEnum.hbs +++ b/src/templates/partials/typeEnum.hbs @@ -1,7 +1,2 @@ -{{~#if @root.useUnionTypes~}} -{{#each enum}}{{{value}}}{{#unless @last}} | {{/unless}}{{/each}}{{>isNullable}} -{{~else if parent~}} -{{{parent}}}.{{{name}}}{{>isNullable}} -{{~else~}} -{{#each enum}}{{{value}}}{{#unless @last}} | {{/unless}}{{/each}}{{>isNullable}} -{{~/if~}} +{{#enumerator enum parent name}}{{this}}{{/enumerator}}{{>isNullable}} + diff --git a/src/templates/partials/typeIntersection.hbs b/src/templates/partials/typeIntersection.hbs index 2328f936..69667c08 100644 --- a/src/templates/partials/typeIntersection.hbs +++ b/src/templates/partials/typeIntersection.hbs @@ -1,5 +1 @@ -{{~#if parent~}} -({{#each properties}}{{>type parent=../parent}}{{#unless @last}} & {{/unless}}{{/each}}){{>isNullable}} -{{~else~}} -({{#each properties}}{{>type}}{{#unless @last}} & {{/unless}}{{/each}}){{>isNullable}} -{{~/if~}} +({{#intersection properties parent}}{{this}}{{/intersection}}){{>isNullable}} diff --git a/src/utils/registerHandlebarHelpers.spec.ts b/src/utils/registerHandlebarHelpers.spec.ts index 2b79c085..1c9ecdad 100644 --- a/src/utils/registerHandlebarHelpers.spec.ts +++ b/src/utils/registerHandlebarHelpers.spec.ts @@ -1,14 +1,20 @@ import * as Handlebars from 'handlebars/runtime'; +import { HttpClient } from '../HttpClient'; import { registerHandlebarHelpers } from './registerHandlebarHelpers'; describe('registerHandlebarHelpers', () => { it('should register the helpers', () => { - registerHandlebarHelpers(); + registerHandlebarHelpers({ + httpClient: HttpClient.FETCH, + useOptions: false, + useUnionTypes: false, + }); const helpers = Object.keys(Handlebars.helpers); expect(helpers).toContain('equals'); expect(helpers).toContain('notEquals'); expect(helpers).toContain('containsSpaces'); expect(helpers).toContain('union'); + expect(helpers).toContain('intersection'); }); }); diff --git a/src/utils/registerHandlebarHelpers.ts b/src/utils/registerHandlebarHelpers.ts index a0fecc54..d3aca318 100644 --- a/src/utils/registerHandlebarHelpers.ts +++ b/src/utils/registerHandlebarHelpers.ts @@ -1,9 +1,11 @@ import * as Handlebars from 'handlebars/runtime'; +import { Enum } from '../client/interfaces/Enum'; import { Model } from '../client/interfaces/Model'; +import { HttpClient } from '../HttpClient'; import { unique } from './unique'; -export function registerHandlebarHelpers(): void { +export function registerHandlebarHelpers(root: { httpClient: HttpClient; useOptions: boolean; useUnionTypes: boolean }): void { Handlebars.registerHelper('equals', function (this: any, a: string, b: string, options: Handlebars.HelperOptions): string { return a === b ? options.fn(this) : options.inverse(this); }); @@ -18,12 +20,25 @@ export function registerHandlebarHelpers(): void { Handlebars.registerHelper('union', function (this: any, properties: Model[], parent: string | undefined, options: Handlebars.HelperOptions) { const type = Handlebars.partials['type']; - const types = properties.map(property => - type({ - ...property, - parent, - }) - ); + const types = properties.map(property => type({ ...root, ...property, parent })); return options.fn(types.filter(unique).join(' | ')); }); + + Handlebars.registerHelper('intersection', function (this: any, properties: Model[], parent: string | undefined, options: Handlebars.HelperOptions) { + const type = Handlebars.partials['type']; + const types = properties.map(property => type({ ...root, ...property, parent })); + return options.fn(types.filter(unique).join(' & ')); + }); + + Handlebars.registerHelper('enumerator', function (this: any, enumerators: Enum[], parent: string | undefined, name: string | undefined, options: Handlebars.HelperOptions) { + if (!root.useUnionTypes && parent && name) { + return `${parent}.${name}`; + } + return options.fn( + enumerators + .map(enumerator => enumerator.value) + .filter(unique) + .join(' | ') + ); + }); } diff --git a/src/utils/registerHandlebarTemplates.spec.ts b/src/utils/registerHandlebarTemplates.spec.ts index 352746bd..5e130238 100644 --- a/src/utils/registerHandlebarTemplates.spec.ts +++ b/src/utils/registerHandlebarTemplates.spec.ts @@ -1,8 +1,13 @@ +import { HttpClient } from '../HttpClient'; import { registerHandlebarTemplates } from './registerHandlebarTemplates'; describe('registerHandlebarTemplates', () => { it('should return correct templates', () => { - const templates = registerHandlebarTemplates(); + const templates = registerHandlebarTemplates({ + httpClient: HttpClient.FETCH, + useOptions: false, + useUnionTypes: false, + }); expect(templates.index).toBeDefined(); expect(templates.exports.model).toBeDefined(); expect(templates.exports.schema).toBeDefined(); diff --git a/src/utils/registerHandlebarTemplates.ts b/src/utils/registerHandlebarTemplates.ts index 6772eebd..347b2b98 100644 --- a/src/utils/registerHandlebarTemplates.ts +++ b/src/utils/registerHandlebarTemplates.ts @@ -1,5 +1,6 @@ import * as Handlebars from 'handlebars/runtime'; +import { HttpClient } from '../HttpClient'; import templateCoreApiError from '../templates/core/ApiError.hbs'; import templateCoreApiRequestOptions from '../templates/core/ApiRequestOptions.hbs'; import templateCoreApiResult from '../templates/core/ApiResult.hbs'; @@ -87,8 +88,8 @@ export interface Templates { * Read all the Handlebar templates that we need and return on wrapper object * so we can easily access the templates in out generator / write functions. */ -export function registerHandlebarTemplates(): Templates { - registerHandlebarHelpers(); +export function registerHandlebarTemplates(root: { httpClient: HttpClient; useOptions: boolean; useUnionTypes: boolean }): Templates { + registerHandlebarHelpers(root); // Main templates (entry points for the files we write to disk) const templates: Templates = { diff --git a/test/__snapshots__/index.spec.js.snap b/test/__snapshots__/index.spec.js.snap index c1df4159..c96a4034 100644 --- a/test/__snapshots__/index.spec.js.snap +++ b/test/__snapshots__/index.spec.js.snap @@ -4961,13 +4961,13 @@ import { OpenAPI } from '../core/OpenAPI'; export class TypesService { /** - * @param parameterObject This is an object parameter * @param parameterArray This is an array parameter * @param parameterDictionary This is a dictionary parameter * @param parameterEnum This is an enum parameter * @param parameterNumber This is a number parameter * @param parameterString This is a string parameter * @param parameterBoolean This is a boolean parameter + * @param parameterObject This is an object parameter * @param id This is a number parameter * @returns number Response is a simple number * @returns string Response is a simple string @@ -4976,26 +4976,26 @@ export class TypesService { * @throws ApiError */ public static async types( - parameterObject: any, parameterArray: Array | null, parameterDictionary: any, parameterEnum: 'Success' | 'Warning' | 'Error' | null, parameterNumber: number = 123, parameterString: string | null = 'default', parameterBoolean: boolean | null = true, + parameterObject: any = null, id?: number, ): Promise { const result = await __request({ method: 'GET', path: \`/api/v\${OpenAPI.VERSION}/types\`, query: { - 'parameterObject': parameterObject, 'parameterArray': parameterArray, 'parameterDictionary': parameterDictionary, 'parameterEnum': parameterEnum, 'parameterNumber': parameterNumber, 'parameterString': parameterString, 'parameterBoolean': parameterBoolean, + 'parameterObject': parameterObject, }, }); return result.body;