From 91dd581d85705aec049c7bd8b44a77768b672ba2 Mon Sep 17 00:00:00 2001 From: Ferdi Koomen Date: Thu, 7 Nov 2019 01:54:52 +0100 Subject: [PATCH] - Cleanup of generator --- src/client/interfaces/OperationResponse.d.ts | 4 +++ src/openApi/v2/parser/getArrayType.ts | 4 +-- src/openApi/v2/parser/getOperation.ts | 15 ++++++--- src/openApi/v2/parser/getOperationResponse.ts | 31 +++++++++++++++++++ .../v2/parser/getOperationResponses.ts | 28 +++++++++++++++-- src/openApi/v2/parser/getOperationResult.ts | 19 ------------ src/openApi/v2/parser/getParameter.ts | 23 ++++++++++++-- src/openApi/v2/parser/getSchema.ts | 12 +++++++ src/openApi/v2/parser/getType.ts | 18 +++++------ src/templates/typescript/core/request.ts | 2 +- .../typescript/core/requestUsingFetch.ts | 2 +- .../typescript/core/requestUsingXHR.ts | 2 +- src/templates/typescript/service.hbs | 2 +- 13 files changed, 118 insertions(+), 44 deletions(-) create mode 100644 src/openApi/v2/parser/getOperationResponse.ts delete mode 100644 src/openApi/v2/parser/getOperationResult.ts create mode 100644 src/openApi/v2/parser/getSchema.ts diff --git a/src/client/interfaces/OperationResponse.d.ts b/src/client/interfaces/OperationResponse.d.ts index 06fc4054..5c8d1f92 100644 --- a/src/client/interfaces/OperationResponse.d.ts +++ b/src/client/interfaces/OperationResponse.d.ts @@ -1,4 +1,8 @@ export interface OperationResponse { code: number; text: string; + type: string; + base: string; + template: string | null; + imports: string[]; } diff --git a/src/openApi/v2/parser/getArrayType.ts b/src/openApi/v2/parser/getArrayType.ts index 20d73876..337195b1 100644 --- a/src/openApi/v2/parser/getArrayType.ts +++ b/src/openApi/v2/parser/getArrayType.ts @@ -8,7 +8,7 @@ export function getArrayType(items: OpenApiItems): ArrayType { let itemsType = 'any'; let itemsBase = 'any'; let itemsTemplate: string | null = null; - const itemsImports: string[] = []; + let itemsImports: string[] = []; // If the parameter has a type than it can be a basic or generic type. if (items.type) { @@ -16,7 +16,7 @@ export function getArrayType(items: OpenApiItems): ArrayType { itemsType = itemsData.type; itemsBase = itemsData.base; itemsTemplate = itemsData.template; - itemsImports.push(...itemsData.imports); + itemsImports = [...itemsData.imports]; // If the parameter is an Array type, we check for the child type, // so we can create a typed array, otherwise this will be a "any[]". diff --git a/src/openApi/v2/parser/getOperation.ts b/src/openApi/v2/parser/getOperation.ts index 4abf02c1..62a7c25a 100644 --- a/src/openApi/v2/parser/getOperation.ts +++ b/src/openApi/v2/parser/getOperation.ts @@ -10,6 +10,9 @@ import { getComment } from './getComment'; import { getOperationResponses } from './getOperationResponses'; import { OperationParameters } from '../../../client/interfaces/OperationParameters'; import { OperationResponse } from '../../../client/interfaces/OperationResponse'; +import { getOperationResponse } from './getOperationResponse'; +import { getOperationErrors } from './getOperationErrors'; +import { OperationError } from '../../../client/interfaces/OperationError'; export function getOperation(openApi: OpenApi, url: string, method: string, op: OpenApiOperation): Operation { const serviceName = (op.tags && op.tags[0]) || 'Service'; @@ -53,11 +56,13 @@ export function getOperation(openApi: OpenApi, url: string, method: string, op: // Parse the operation responses. if (op.responses) { const responses: OperationResponse[] = getOperationResponses(openApi, op.responses); - // const result: OperationResponse = getOperationResult(responses); - // const errors = getOperationErrors(responses); - // operation.imports.push(...result.imports); - // operation.errors = errors; - // operation.result = result.type; + const response: OperationResponse = getOperationResponse(responses); + const errors: OperationError[] = getOperationErrors(responses); + operation.imports.push(...response.imports); + operation.errors = errors; + operation.result = response.type; + + console.log(operation.result); } return operation; diff --git a/src/openApi/v2/parser/getOperationResponse.ts b/src/openApi/v2/parser/getOperationResponse.ts new file mode 100644 index 00000000..466a5933 --- /dev/null +++ b/src/openApi/v2/parser/getOperationResponse.ts @@ -0,0 +1,31 @@ +import { OperationResponse } from '../../../client/interfaces/OperationResponse'; + +export function getOperationResponse(responses: OperationResponse[]): OperationResponse { + let responseCode = 200; + let responseText = ''; + let responseType = 'any'; + let responseBase = 'any'; + let responseTemplate: string | null = null; + let responseImports: string[] = []; + + // Fetch the first valid (2XX range) response code and return that type. + const result: OperationResponse | undefined = responses.find(response => response.code && response.code >= 200 && response.code < 300); + + if (result) { + responseCode = result.code; + responseText = result.text; + responseType = result.type; + responseBase = result.base; + responseTemplate = result.template; + responseImports = [...result.imports]; + } + + return { + code: responseCode, + text: responseText, + type: responseType, + base: responseBase, + template: responseTemplate, + imports: responseImports, + }; +} diff --git a/src/openApi/v2/parser/getOperationResponses.ts b/src/openApi/v2/parser/getOperationResponses.ts index 1ef6118d..7d3fae85 100644 --- a/src/openApi/v2/parser/getOperationResponses.ts +++ b/src/openApi/v2/parser/getOperationResponses.ts @@ -5,6 +5,11 @@ import { OpenApiResponse } from '../interfaces/OpenApiResponse'; import { OpenApiReference } from '../interfaces/OpenApiReference'; import { getRef } from './getRef'; import { OpenApi } from '../interfaces/OpenApi'; +import { getType } from './getType'; +import { Type } from '../../../client/interfaces/Type'; +import { Schema } from '../../../client/interfaces/Schema'; +import { getSchema } from './getSchema'; +import { OpenApiSchema } from '../interfaces/OpenApiSchema'; export function getOperationResponses(openApi: OpenApi, responses: OpenApiResponses): OperationResponse[] { const result: OperationResponse[] = []; @@ -17,16 +22,35 @@ export function getOperationResponses(openApi: OpenApi, responses: OpenApiRespon const response: OpenApiResponse = getRef(openApi, responseOrReference); const responseCode: number | null = getOperationResponseCode(code); const responseText: string = response.description || ''; + let responseType = 'any'; + let responseBase = 'any'; + let responseTemplate: string | null = null; + let responseImports: string[] = []; - // TODO: if (response.schema) { - console.log('response.schema', response.schema); + if (response.schema.$ref) { + const schemaReference: Type = getType(response.schema.$ref); + responseType = schemaReference.type; + responseBase = schemaReference.base; + responseTemplate = schemaReference.template; + responseImports = [...schemaReference.imports]; + } else { + const schema: Schema = getSchema(openApi, response.schema as OpenApiSchema); + responseType = schema.type; + responseBase = schema.base; + responseTemplate = schema.template; + responseImports = [...schema.imports]; + } } if (responseCode) { result.push({ code: responseCode, text: responseText, + type: responseType, + base: responseBase, + template: responseTemplate, + imports: responseImports, }); } } diff --git a/src/openApi/v2/parser/getOperationResult.ts b/src/openApi/v2/parser/getOperationResult.ts deleted file mode 100644 index 28419ed8..00000000 --- a/src/openApi/v2/parser/getOperationResult.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { OperationResponse } from '../../../client/interfaces/OperationResponse'; - -export function getOperationResult(responses: OperationResponse[]): OperationResponse { - const resultCode = 200; - const resultTes: string[] = []; - - // Fetch the first valid (2XX range) response code and return that type. - const result: OperationResponse | undefined = responses.find(response => response.code && response.code >= 200 && response.code < 300 && response.property); - - if (result && result.property) { - resultType = result.property.type; - resultImports = [...result.property.imports]; - } - - return { - type: resultType, - imports: resultImports, - }; -} diff --git a/src/openApi/v2/parser/getParameter.ts b/src/openApi/v2/parser/getParameter.ts index b0ac1ea5..8d2f6d9a 100644 --- a/src/openApi/v2/parser/getParameter.ts +++ b/src/openApi/v2/parser/getParameter.ts @@ -9,6 +9,9 @@ import { ArrayType } from '../../../client/interfaces/ArrayType'; import { getEnumType } from './getEnumType'; import { getEnumTypeFromDescription } from './getEnumTypeFromDescription'; import { getComment } from './getComment'; +import { getSchema } from './getSchema'; +import { Schema } from '../../../client/interfaces/Schema'; +import { OpenApiSchema } from '../interfaces/OpenApiSchema'; export function getParameter(openApi: OpenApi, parameter: OpenApiParameter): Parameter { let parameterType = 'any'; @@ -35,10 +38,24 @@ export function getParameter(openApi: OpenApi, parameter: OpenApiParameter): Par } } - // If this parameter has a schema, then we should treat it as an embedded parameter. - // We can just parse the schema name ($ref) and use that as the parameter type. + // If this parameter 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 + // then we need to parse the schema! if (parameter.schema) { - // TODO: console.log('parameter.schema', parameter.schema); + if (parameter.schema.$ref) { + const schemaReference: Type = getType(parameter.schema.$ref); + parameterType = schemaReference.type; + parameterBase = schemaReference.base; + parameterTemplate = schemaReference.template; + parameterImports.push(...schemaReference.imports); + } else { + const schema: Schema = getSchema(openApi, parameter.schema as OpenApiSchema); + parameterType = schema.type; + parameterBase = schema.base; + parameterTemplate = schema.template; + parameterImports.push(...schema.imports); + } } // If the param is a enum then return the values as an inline type. diff --git a/src/openApi/v2/parser/getSchema.ts b/src/openApi/v2/parser/getSchema.ts new file mode 100644 index 00000000..4fdd47a2 --- /dev/null +++ b/src/openApi/v2/parser/getSchema.ts @@ -0,0 +1,12 @@ +import { OpenApi } from '../interfaces/OpenApi'; +import { Schema } from '../../../client/interfaces/Schema'; +import { OpenApiSchema } from '../interfaces/OpenApiSchema'; + +export function getSchema(openApi: OpenApi, schema: OpenApiSchema): Schema { + return { + type: 'todo', + base: 'todo', + template: null, + imports: [], + }; +} diff --git a/src/openApi/v2/parser/getType.ts b/src/openApi/v2/parser/getType.ts index ced5a2d3..7034aea9 100644 --- a/src/openApi/v2/parser/getType.ts +++ b/src/openApi/v2/parser/getType.ts @@ -7,18 +7,18 @@ import { getMappedType, hasMappedType } from './getMappedType'; * @param value String value like "integer" or "Link[Model]". * @param template Optional template class from parent (needed to process generics) */ -export function getType(value: string, template: string | null = null): Type { +export function getType(value: string | undefined, template: string | null = null): Type { let propertyType = 'any'; let propertyBase = 'any'; let propertyTemplate: string | null = null; let propertyImports: string[] = []; // Remove definitions prefix and cleanup string. - const valueTrimmed: string = stripNamespace(value || ''); + const valueClean: string = stripNamespace(value || ''); // Check of we have an Array type or generic type, for instance: "Link[Model]". - if (/\[.*\]$/g.test(valueTrimmed)) { - const matches: RegExpMatchArray | null = valueTrimmed.match(/(.*?)\[(.*)\]$/); + if (/\[.*\]$/g.test(valueClean)) { + const matches: RegExpMatchArray | null = valueClean.match(/(.*?)\[(.*)\]$/); if (matches) { // Both of the types can be complex types so parse each of them. const match1: Type = getType(matches[1]); @@ -46,14 +46,14 @@ export function getType(value: string, template: string | null = null): Type { propertyImports.push(...match1.imports); propertyImports.push(...match2.imports); } - } else if (hasMappedType(valueTrimmed)) { - const mapped: string = getMappedType(valueTrimmed); + } else if (hasMappedType(valueClean)) { + const mapped: string = getMappedType(valueClean); propertyType = mapped; propertyBase = mapped; } else { - propertyType = valueTrimmed; - propertyBase = valueTrimmed; - propertyImports.push(valueTrimmed); + propertyType = valueClean; + propertyBase = valueClean; + propertyImports.push(valueClean); } // If the property that we found matched the parent template class diff --git a/src/templates/typescript/core/request.ts b/src/templates/typescript/core/request.ts index 2cb7d412..a505edc9 100644 --- a/src/templates/typescript/core/request.ts +++ b/src/templates/typescript/core/request.ts @@ -14,7 +14,7 @@ import { Result } from './Result'; * @param options Request method options. * @returns Result object (see above) */ -export async function request(options: Readonly): Promise> { +export async function request(options: Readonly): Promise> { // Create the request URL let url: string = `${OpenAPI.BASE}${options.path}`; diff --git a/src/templates/typescript/core/requestUsingFetch.ts b/src/templates/typescript/core/requestUsingFetch.ts index ea133038..8d3134f5 100644 --- a/src/templates/typescript/core/requestUsingFetch.ts +++ b/src/templates/typescript/core/requestUsingFetch.ts @@ -11,7 +11,7 @@ import { Result } from './Result'; * @param url The url to request. * @param request The request object, containing method, headers, body, etc. */ -export async function requestUsingFetch(url: string, request: Readonly): Promise> { +export async function requestUsingFetch(url: string, request: Readonly): Promise> { // Fetch response using fetch API. const response: Response = await fetch(url, request); diff --git a/src/templates/typescript/core/requestUsingXHR.ts b/src/templates/typescript/core/requestUsingXHR.ts index 7203899d..515b05e0 100644 --- a/src/templates/typescript/core/requestUsingXHR.ts +++ b/src/templates/typescript/core/requestUsingXHR.ts @@ -13,7 +13,7 @@ import { isSuccess } from './isSuccess'; * @param url The url to request. * @param request The request object, containing method, headers, body, etc. */ -export async function requestUsingXHR(url: string, request: Readonly): Promise> { +export async function requestUsingXHR(url: string, request: Readonly): Promise> { return new Promise(resolve => { const xhr: XMLHttpRequest = new XMLHttpRequest(); diff --git a/src/templates/typescript/service.hbs b/src/templates/typescript/service.hbs index 1938841c..99eb386b 100644 --- a/src/templates/typescript/service.hbs +++ b/src/templates/typescript/service.hbs @@ -41,7 +41,7 @@ export class {{{name}}} { {{/each}} {{/if}} - const result: Result<{{{result}}}> = await request<{{{result}}}>({ + const result: Result = await request({ method: '{{{method}}}', path: `{{{path}}}`,{{#if parametersHeader}} headers: {