fork of hey-api/openapi-ts because I need some additional things
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #364 from hey-api/feat/services-to-compiler-api

authored by

Jordan Shatford and committed by
GitHub
12b7bf86 d89553fa

+52 -107
+1 -5
packages/openapi-ts/rollup.config.ts
··· 27 27 dataDestructure: true, 28 28 dataParameters: true, 29 29 equals: true, 30 - escapeComment: true, 31 30 escapeDescription: true, 32 - getDefaultPrintable: true, 33 - hasDefault: true, 34 - ifOperationDataOptional: true, 35 31 ifdef: true, 36 - modelIsRequired: true, 37 32 nameOperationDataType: true, 38 33 notEquals: true, 34 + toOperationComment: true, 39 35 useDateType: true, 40 36 }, 41 37 knownHelpersOnly: true,
+5 -26
packages/openapi-ts/src/templates/exportService.hbs
··· 14 14 {{/equals}} 15 15 {{/if}} 16 16 {{#each operations}} 17 - /** 18 - {{#if deprecated}} 19 - * @deprecated 20 - {{/if}} 21 - {{#if summary}} 22 - * {{{escapeComment summary}}} 23 - {{/if}} 24 - {{#if description}} 25 - * {{{escapeComment description}}} 26 - {{/if}} 27 - {{#unless @root.$config.useOptions}} 28 - {{#if parameters}} 29 - {{#each parameters}} 30 - * @param {{{name}}} {{#if description}}{{{escapeComment description}}}{{/if}} 31 - {{/each}} 32 - {{/if}} 33 - {{/unless}} 34 - {{#each results}} 35 - * @returns {{{type}}} {{#if description}}{{{escapeComment description}}}{{/if}} 36 - {{/each}} 37 - * @throws ApiError 38 - */ 17 + {{{toOperationComment this}}} 39 18 {{#if @root.$config.name}} 40 19 {{#equals @root.$config.client 'angular'}} 41 - public {{{name}}}({{>operationParameters}}): Observable<{{>operationResult}}> { 20 + public {{{name}}}({{{nameOperationDataType 'req' this}}}): Observable<{{{nameOperationDataType 'res' this}}}> { 42 21 {{{dataDestructure this}}} 43 22 return this.httpRequest.request({ 44 23 {{else}} 45 - public {{{name}}}({{>operationParameters}}): CancelablePromise<{{>operationResult}}> { 24 + public {{{name}}}({{{nameOperationDataType 'req' this}}}): CancelablePromise<{{{nameOperationDataType 'res' this}}}> { 46 25 {{{dataDestructure this}}} 47 26 return this.httpRequest.request({ 48 27 {{/equals}} 49 28 {{else}} 50 29 {{#equals @root.$config.client 'angular'}} 51 - public {{{name}}}({{>operationParameters}}): Observable<{{>operationResult}}> { 30 + public {{{name}}}({{{nameOperationDataType 'req' this}}}): Observable<{{{nameOperationDataType 'res' this}}}> { 52 31 {{{dataDestructure this}}} 53 32 return __request(OpenAPI, this.http, { 54 33 {{else}} 55 - public static {{{name}}}({{>operationParameters}}): CancelablePromise<{{>operationResult}}> { 34 + public static {{{name}}}({{{nameOperationDataType 'req' this}}}): CancelablePromise<{{{nameOperationDataType 'res' this}}}> { 56 35 {{{dataDestructure this}}} 57 36 return __request(OpenAPI, { 58 37 {{/equals}}
-10
packages/openapi-ts/src/templates/partials/operationParameters.hbs
··· 1 - {{#if @root.$config.useOptions~}} 2 - {{#if parameters}}data: {{{nameOperationDataType 'req' this}}}{{#ifOperationDataOptional parameters}} = {}{{/ifOperationDataOptional}}{{/if}} 3 - {{~else}} 4 - {{#if parameters}} 5 - 6 - {{#each parameters}} 7 - {{{name}}}{{{modelIsRequired this}}}: {{{nameOperationDataType 'req' ../this name}}}{{#hasDefault this}} = {{{getDefaultPrintable this}}}{{/hasDefault}}, 8 - {{/each}} 9 - {{/if}} 10 - {{/if}}
-7
packages/openapi-ts/src/templates/partials/operationResult.hbs
··· 1 - {{~#if @root.$config.useOptions~}} 2 - {{~#equals @root.$config.serviceResponse 'response'}}ApiResult<{{/equals~}} 3 - {{~/if~}} 4 - {{{nameOperationDataType 'res' this}}} 5 - {{~#if @root.$config.useOptions~}} 6 - {{~#equals @root.$config.serviceResponse 'response'}}>{{/equals~}} 7 - {{~/if~}}
-3
packages/openapi-ts/src/utils/__tests__/handlebars.spec.ts
··· 31 31 expect(helpers).toContain('dataDestructure'); 32 32 expect(helpers).toContain('dataParameters'); 33 33 expect(helpers).toContain('equals'); 34 - expect(helpers).toContain('escapeComment'); 35 34 expect(helpers).toContain('escapeDescription'); 36 35 expect(helpers).toContain('ifdef'); 37 - expect(helpers).toContain('ifOperationDataOptional'); 38 - expect(helpers).toContain('modelIsRequired'); 39 36 expect(helpers).toContain('nameOperationDataType'); 40 37 expect(helpers).toContain('notEquals'); 41 38 });
+46 -56
packages/openapi-ts/src/utils/handlebars.ts
··· 1 1 import camelCase from 'camelcase'; 2 2 import Handlebars from 'handlebars/runtime'; 3 3 4 + import { compiler } from '../compiler'; 5 + import { addLeadingComment } from '../compiler/utils'; 4 6 import type { Operation, OperationParameter, Service } from '../openApi'; 5 7 import templateClient from '../templates/client.hbs'; 6 8 import angularGetHeaders from '../templates/core/angular/getHeaders.hbs'; ··· 47 49 import xhrRequest from '../templates/core/xhr/request.hbs'; 48 50 import xhrSendRequest from '../templates/core/xhr/sendRequest.hbs'; 49 51 import templateExportService from '../templates/exportService.hbs'; 50 - import partialOperationParameters from '../templates/partials/operationParameters.hbs'; 51 - import partialOperationResult from '../templates/partials/operationResult.hbs'; 52 52 import { getConfig } from './config'; 53 53 import { escapeComment, escapeDescription, escapeName } from './escape'; 54 54 import { getDefaultPrintable, modelIsRequired } from './required'; ··· 78 78 }; 79 79 80 80 const dataParameters = (parameters: OperationParameter[]) => { 81 - // if (config.experimental) { 82 - // let output = parameters 83 - // .filter(parameter => getDefaultPrintable(parameter) !== undefined) 84 - // .map(parameter => { 85 - // const key = parameter.prop; 86 - // const value = parameter.name; 87 - // if (key === value || escapeName(key) === key) { 88 - // return `${key}: ${getDefaultPrintable(parameter)}`; 89 - // } 90 - // return `'${key}': ${getDefaultPrintable(parameter)}`; 91 - // }); 92 - // if (parameters.every(parameter => parameter.in === 'query')) { 93 - // output = [...output, '...query']; 94 - // } 95 - // return output.join(', '); 96 - // } 97 - 98 81 const output = parameters.map(parameter => { 99 82 const key = parameter.prop; 100 83 const value = parameter.name; ··· 111 94 112 95 export const serviceExportedNamespace = () => '$OpenApiTs'; 113 96 114 - export const nameOperationDataType = ( 115 - namespace: 'req' | 'res', 116 - operation: Service['operations'][number], 117 - name?: string | object 118 - ) => { 97 + export const nameOperationDataType = (namespace: 'req' | 'res', operation: Service['operations'][number]) => { 98 + const config = getConfig(); 119 99 const exported = serviceExportedNamespace(); 100 + const baseTypePath = `${exported}['${operation.path}']['${operation.method.toLocaleLowerCase()}']['${namespace}']`; 120 101 if (namespace === 'req') { 121 - const path = `${exported}['${operation.path}']['${operation.method.toLocaleLowerCase()}']['${namespace}']`; 122 - return name && typeof name === 'string' ? `${path}['${name}']` : path; 102 + if (!operation.parameters.length) { 103 + return ''; 104 + } 105 + 106 + if (config.useOptions) { 107 + const isOptional = operation.parameters.every(p => !p.isRequired); 108 + return isOptional ? `data: ${baseTypePath} = {}` : `data: ${baseTypePath}`; 109 + } 110 + 111 + return operation.parameters 112 + .map(p => { 113 + const typePath = `${baseTypePath}['${p.name}']`; 114 + const defaultValue = getDefaultPrintable(p); 115 + const defaultString = defaultValue !== undefined ? ` = ${defaultValue}` : ''; 116 + return `${p.name}${modelIsRequired(p)}: ${typePath}${defaultString}`; 117 + }) 118 + .join(', '); 123 119 } 124 120 const results = operation.results.filter(result => result.code >= 200 && result.code < 300); 125 121 // TODO: we should return nothing when results don't exist 126 122 // can't remove this logic without removing request/name config 127 123 // as it complicates things 128 124 if (!results.length) { 129 - return 'void'; 125 + return compiler.utils.toString(compiler.typedef.basic('void')); 130 126 } 131 - return results 132 - .map(result => { 133 - const path = `${exported}['${operation.path}']['${operation.method.toLocaleLowerCase()}']['${namespace}'][${String(result.code)}]`; 134 - return path; 135 - }) 136 - .join(' | '); 127 + const types = results.map(result => `${baseTypePath}[${String(result.code)}]`); 128 + const union = compiler.utils.toString(compiler.typedef.union(types)); 129 + if (config.useOptions && config.serviceResponse === 'response') { 130 + return `ApiResult<${union}>`; 131 + } 132 + return union; 137 133 }; 138 134 139 135 export const registerHandlebarHelpers = (): void => { ··· 148 144 } 149 145 ); 150 146 151 - Handlebars.registerHelper('escapeComment', escapeComment); 152 147 Handlebars.registerHelper('escapeDescription', escapeDescription); 153 148 154 - Handlebars.registerHelper( 155 - 'hasDefault', 156 - function (this: unknown, p: OperationParameter, options: Handlebars.HelperOptions) { 157 - if (getDefaultPrintable(p) !== undefined) { 158 - return options.fn(this); 159 - } 160 - return options.inverse(this); 149 + Handlebars.registerHelper('toOperationComment', (operation: Operation) => { 150 + const config = getConfig(); 151 + let params: string[] = []; 152 + if (!config.useOptions && operation.parameters.length) { 153 + params = operation.parameters.map( 154 + p => `@param ${p.name} ${p.description ? escapeComment(p.description) : ''}` 155 + ); 161 156 } 162 - ); 163 - 164 - Handlebars.registerHelper('getDefaultPrintable', getDefaultPrintable); 157 + const comment = [ 158 + operation.deprecated && '@deprecated', 159 + operation.summary && escapeComment(operation.summary), 160 + operation.description && escapeComment(operation.description), 161 + ...params, 162 + ...operation.results.map(r => `@returns ${r.type} ${r.description ? escapeComment(r.description) : ''}`), 163 + '@throws ApiError', 164 + ]; 165 + return addLeadingComment(undefined, comment, false, true); 166 + }); 165 167 166 168 Handlebars.registerHelper('ifdef', function (this: unknown, ...args): string { 167 169 const options = args.pop(); ··· 171 173 return options.inverse(this); 172 174 }); 173 175 174 - Handlebars.registerHelper( 175 - 'ifOperationDataOptional', 176 - function (this: unknown, parameters: OperationParameter[], options: Handlebars.HelperOptions) { 177 - return parameters.every(parameter => !parameter.isRequired) ? options.fn(this) : options.inverse(this); 178 - } 179 - ); 180 - 181 - Handlebars.registerHelper('modelIsRequired', modelIsRequired); 182 176 Handlebars.registerHelper('nameOperationDataType', nameOperationDataType); 183 177 184 178 Handlebars.registerHelper( ··· 230 224 service: Handlebars.template(templateExportService), 231 225 }, 232 226 }; 233 - 234 - // Partials for the generations of the models, services, etc. 235 - Handlebars.registerPartial('operationParameters', Handlebars.template(partialOperationParameters)); 236 - Handlebars.registerPartial('operationResult', Handlebars.template(partialOperationResult)); 237 227 238 228 // Generic functions used in 'request' file @see src/templates/core/request.hbs for more info 239 229 Handlebars.registerPartial('functions/base64', Handlebars.template(functionBase64));