From d3f64ad05ecf73f2b9d80d7ffdb1799adff3d606 Mon Sep 17 00:00:00 2001 From: Himenon Date: Thu, 18 Feb 2021 17:04:10 +0900 Subject: [PATCH 1/7] feat(comment): Use the defined comment --- src/Converter/v3/components/Header.ts | 1 - src/Converter/v3/components/Headers.ts | 1 - src/Converter/v3/components/MediaType.ts | 2 +- src/Converter/v3/components/Parameter.ts | 5 +-- src/Converter/v3/components/Parameters.ts | 2 -- src/Converter/v3/components/PathItems.ts | 1 - src/Converter/v3/components/RequestBodies.ts | 1 - src/Converter/v3/components/RequestBody.ts | 1 - src/Converter/v3/components/Responses.ts | 2 -- src/Converter/v3/components/Schema.ts | 1 + src/Converter/v3/components/Schemas.ts | 1 - .../v3/components/SecuritySchemas.ts | 1 - .../__snapshots__/snapshot-test.ts.snap | 34 ++++--------------- .../ForPathItems/FullRemoteReference.yml | 2 +- .../ForPathItems/FullRemoteReference.yml | 1 + .../components/responses/ResponseA.yml | 1 + 16 files changed, 14 insertions(+), 43 deletions(-) diff --git a/src/Converter/v3/components/Header.ts b/src/Converter/v3/components/Header.ts index 7eab25d3..6a6f702f 100644 --- a/src/Converter/v3/components/Header.ts +++ b/src/Converter/v3/components/Header.ts @@ -84,7 +84,6 @@ export const generateInterface = ( return factory.InterfaceDeclaration.create({ export: true, name: converterContext.escapeDeclarationText(name), - comment: `@see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#headerObject`, members: generatePropertySignatures(entryPoint, currentPoint, factory, headers, context, converterContext), }); }; diff --git a/src/Converter/v3/components/Headers.ts b/src/Converter/v3/components/Headers.ts index 5c463e0f..12d23463 100644 --- a/src/Converter/v3/components/Headers.ts +++ b/src/Converter/v3/components/Headers.ts @@ -22,7 +22,6 @@ export const generateNamespace = ( store.addComponent("headers", { kind: "namespace", name: Name.Components.Headers, - comment: `@see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#componentsObject`, }); Object.entries(headers).forEach(([name, header]) => { if (Guard.isReference(header)) { diff --git a/src/Converter/v3/components/MediaType.ts b/src/Converter/v3/components/MediaType.ts index 86e10913..db3c0d49 100644 --- a/src/Converter/v3/components/MediaType.ts +++ b/src/Converter/v3/components/MediaType.ts @@ -18,6 +18,7 @@ export const generatePropertySignature = ( name: converterContext.escapePropertySignatureName(protocol), optional: false, type: ToTypeNode.convert(entryPoint, currentPoint, factory, schema, context, converterContext), + comment: schema.description, }); }; @@ -50,6 +51,5 @@ export const generateInterface = ( export: true, name, members: generatePropertySignatures(entryPoint, currentPoint, factory, content, context, converterContext), - comment: `@see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#mediaTypeObject`, }); }; diff --git a/src/Converter/v3/components/Parameter.ts b/src/Converter/v3/components/Parameter.ts index 7c600ed5..c97346d4 100644 --- a/src/Converter/v3/components/Parameter.ts +++ b/src/Converter/v3/components/Parameter.ts @@ -53,6 +53,7 @@ export const generatePropertySignature = ( return factory.PropertySignature.create({ name: converterContext.escapePropertySignatureName(localRef.name), optional: false, + comment: localRef.description, type: factory.TypeReferenceNode.create({ name: context.resolveReferencePath(currentPoint, reference.path).name, }), @@ -62,6 +63,7 @@ export const generatePropertySignature = ( return factory.PropertySignature.create({ name: converterContext.escapePropertySignatureName(reference.data.name), optional: isPathProperty ? false : !reference.data.required, + comment: reference.data.description, type: ToTypeNode.convert( entryPoint, reference.referencePoint, @@ -77,6 +79,7 @@ export const generatePropertySignature = ( name: converterContext.escapePropertySignatureName(parameter.name), optional: isPathProperty ? false : !parameter.required, type: ToTypeNode.convert(entryPoint, currentPoint, factory, parameter.schema || { type: "null" }, context, converterContext), + comment: parameter.description, }); }; @@ -107,7 +110,6 @@ export const generateInterface = ( return factory.InterfaceDeclaration.create({ export: true, name, - comment: `@see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#headerObject`, members: generatePropertySignatures(entryPoint, currentPoint, store, factory, parameters, context, converterContext), }); }; @@ -128,7 +130,6 @@ export const generateAliasInterface = ( return factory.InterfaceDeclaration.create({ export: true, name: converterContext.escapeDeclarationText(name), - comment: `@see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#headerObject`, members: generatePropertySignatures(entryPoint, currentPoint, store, factory, parameters, context, converterContext), }); }; diff --git a/src/Converter/v3/components/Parameters.ts b/src/Converter/v3/components/Parameters.ts index de2cdcfe..f7ef0d72 100644 --- a/src/Converter/v3/components/Parameters.ts +++ b/src/Converter/v3/components/Parameters.ts @@ -23,7 +23,6 @@ export const generateNamespace = ( store.addComponent("parameters", { kind: "namespace", name: Name.Components.Parameters, - comment: `@see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#parameterObject`, }); Object.entries(parameters).forEach(([name, parameter]) => { @@ -81,7 +80,6 @@ export const generateNamespaceWithList = ( store.addComponent("parameters", { kind: "namespace", name: Name.Components.Parameters, - comment: `@see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#parameterObject`, }); parameters.forEach(parameter => { diff --git a/src/Converter/v3/components/PathItems.ts b/src/Converter/v3/components/PathItems.ts index 24cbd37e..9a71cbf7 100644 --- a/src/Converter/v3/components/PathItems.ts +++ b/src/Converter/v3/components/PathItems.ts @@ -24,7 +24,6 @@ export const generateNamespace = ( store.addComponent("pathItems", { kind: "namespace", name: Name.Components.PathItems, - comment: `@see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#componentsObject`, }); Object.entries(pathItems).forEach(([key, pathItem]) => { diff --git a/src/Converter/v3/components/RequestBodies.ts b/src/Converter/v3/components/RequestBodies.ts index 0c986b50..d9b0c2bb 100644 --- a/src/Converter/v3/components/RequestBodies.ts +++ b/src/Converter/v3/components/RequestBodies.ts @@ -23,7 +23,6 @@ export const generateNamespace = ( store.addComponent("requestBodies", { kind: "namespace", name: Name.Components.RequestBodies, - comment: `@see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#componentsObject`, }); Object.entries(requestBodies).forEach(([name, requestBody]) => { diff --git a/src/Converter/v3/components/RequestBody.ts b/src/Converter/v3/components/RequestBody.ts index 018db121..8cf4e168 100644 --- a/src/Converter/v3/components/RequestBody.ts +++ b/src/Converter/v3/components/RequestBody.ts @@ -28,7 +28,6 @@ export const generateInterface = ( export: true, name, members: contentSignatures, - comment: `@see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#requestBodyObject`, }); }; diff --git a/src/Converter/v3/components/Responses.ts b/src/Converter/v3/components/Responses.ts index 8025c660..64c920a7 100644 --- a/src/Converter/v3/components/Responses.ts +++ b/src/Converter/v3/components/Responses.ts @@ -27,7 +27,6 @@ export const generateNamespace = ( store.addComponent("responses", { kind: "namespace", name: Name.Components.Responses, - comment: `@see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responsesObject`, }); Object.entries(responses).forEach(([name, response]) => { if (Guard.isReference(response)) { @@ -69,7 +68,6 @@ export const generateNamespaceWithStatusCode = ( store.addStatement(basePath, { kind: "namespace", name: Name.ComponentChild.Response, - comment: `@see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responsesObject`, }); Object.entries(responses).forEach(([statusCode, response]) => { diff --git a/src/Converter/v3/components/Schema.ts b/src/Converter/v3/components/Schema.ts index 7eacc1f1..e7f8c507 100644 --- a/src/Converter/v3/components/Schema.ts +++ b/src/Converter/v3/components/Schema.ts @@ -26,6 +26,7 @@ export const generatePropertySignatures = ( return factory.PropertySignature.create({ name: convertContext.escapePropertySignatureName(propertyName), optional: !required.includes(propertyName), + comment: schema.description, type: factory.TypeNode.create({ type: "any", }), diff --git a/src/Converter/v3/components/Schemas.ts b/src/Converter/v3/components/Schemas.ts index e823bb85..f70a3d69 100644 --- a/src/Converter/v3/components/Schemas.ts +++ b/src/Converter/v3/components/Schemas.ts @@ -39,7 +39,6 @@ export const generateNamespace = ( store.addComponent("schemas", { kind: "namespace", name: Name.Components.Schemas, - comment: `@see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#schemaObject`, }); Object.entries(schemas).forEach(([name, targetSchema]) => { if (Guard.isReference(targetSchema)) { diff --git a/src/Converter/v3/components/SecuritySchemas.ts b/src/Converter/v3/components/SecuritySchemas.ts index 7f9b4f00..326a823b 100644 --- a/src/Converter/v3/components/SecuritySchemas.ts +++ b/src/Converter/v3/components/SecuritySchemas.ts @@ -17,7 +17,6 @@ export const generateNamespace = ( store.addComponent("securitySchemes", { kind: "namespace", name: Name.Components.SecuritySchemas, - comment: `@see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#securitySchemeObject`, }); Object.entries(requestBodies).forEach(([name, requestBody]) => { if (Guard.isReference(requestBody)) { diff --git a/test/__tests__/__snapshots__/snapshot-test.ts.snap b/test/__tests__/__snapshots__/snapshot-test.ts.snap index f32a3fbf..ac18dcef 100644 --- a/test/__tests__/__snapshots__/snapshot-test.ts.snap +++ b/test/__tests__/__snapshots__/snapshot-test.ts.snap @@ -10,7 +10,6 @@ exports[`Generate Code Snapshot Test api.test.domain 1`] = ` // -/** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#schemaObject */ export namespace Schemas { /** String Literal */ export type StringType = string; @@ -128,7 +127,6 @@ export namespace Schemas { children: Child[]; } } -/** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#componentsObject */ export namespace Headers { export type StringHeader = string; export type A = number; @@ -137,7 +135,6 @@ export namespace Headers { } export type ReferenceOfHeaderToSchema = Schemas.DirectRef.ForHeader; } -/** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responsesObject */ export namespace Responses { /** * Status Code 100 @@ -151,35 +148,31 @@ export namespace Responses { export namespace SwitchingProtocol { } /** Type Reference - string */ export namespace LocalReferenceStringDateTimeType { - /** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#mediaTypeObject */ export interface Content { \\"application/json\\": Schemas.StringDateTimeType; } } /** Local Reference - object */ export namespace LocalReferenceObjectType { - /** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#mediaTypeObject */ export interface Content { \\"application/json\\": Schemas.ObjectHasPropertiesType; } } /** Response -> Schema */ export namespace ReferenceOfResponseToSchema { - /** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#mediaTypeObject */ export interface Content { \\"application/json\\": Schemas.DirectRef.ForResponse; } } /** response A definition */ export namespace ResponseA { - /** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#headerObject */ export interface Header { HeaderA: Headers.A; HeaderB: string; } - /** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#mediaTypeObject */ export interface Content { \\"application/json\\": { + /** responseA description */ name?: \\"responseA\\"; }; } @@ -187,7 +180,6 @@ export namespace Responses { export namespace Level1 { /** response B definition */ export namespace ResponseB { - /** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#mediaTypeObject */ export interface Content { \\"application/json\\": { name?: \\"responseB\\"; @@ -197,7 +189,6 @@ export namespace Responses { export namespace Level2 { /** response C definition */ export namespace ResponseC { - /** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#mediaTypeObject */ export interface Content { \\"application/json\\": { name?: \\"responseC\\"; @@ -209,21 +200,19 @@ export namespace Responses { export namespace ForPathItems { /** response A definition */ export namespace FullRemoteReference { - /** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#headerObject */ export interface Header { HeaderA: Headers.A; HeaderB: string; } - /** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#mediaTypeObject */ export interface Content { \\"application/json\\": { + /** responseA description */ name?: \\"responseA\\"; }; } } } } -/** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#parameterObject */ export namespace Parameters { /** parameters.StringQueryParams */ export type StringQueryParams = string; @@ -250,32 +239,27 @@ export namespace Parameters { }; }; } -/** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#componentsObject */ export namespace RequestBodies { /** Request body string type */ export namespace StringType { - /** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#requestBodyObject */ export interface Content { \\"application/json\\": string; } } /** Request body Local reference string type */ export namespace LocalReferenceStringType { - /** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#requestBodyObject */ export interface Content { \\"application/json\\": Schemas.StringHasEnumType; } } /** requestBodies -> schemas */ export namespace ReferenceOfRequestBodyToSchema { - /** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#requestBodyObject */ export interface Content { \\"application/json\\": Schemas.DirectRef.ForRequestBody; } } /** Remote Request body A */ export namespace RequestBodyA { - /** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#requestBodyObject */ export interface Content { \\"application/json\\": { body?: string; @@ -285,7 +269,6 @@ export namespace RequestBodies { export namespace Level1 { /** Remote Request body B */ export namespace RequestBodyB { - /** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#requestBodyObject */ export interface Content { \\"application/json\\": { body?: string; @@ -295,7 +278,6 @@ export namespace RequestBodies { export namespace Level2 { /** Remote Request body C */ export namespace RequestBodyC { - /** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#requestBodyObject */ export interface Content { \\"application/json\\": { body?: string; @@ -305,35 +287,32 @@ export namespace RequestBodies { } } } -/** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#headerObject */ export interface Parameter$getIncludeLocalReference { + /** parameters.StringQueryParams */ StringQuery: string; } -/** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#mediaTypeObject */ export interface Response$getIncludeLocalReference$Status$200 { \\"application/json\\": { meta: string; }; } -/** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#headerObject */ export interface Parameter$getIncludeRemoteReference { + /** remote reference parameter */ IncludeRemoteReference: number; } -/** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#requestBodyObject */ export interface RequestBody$getIncludeRemoteReference { \\"application/json\\": string; } -/** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#headerObject */ export interface Parameter$getFullRemoteReference { + /** Full Remote Reference */ FullRemoteReferenceQuery: Schemas.FullRemoteReference.ForParameters; } -/** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#mediaTypeObject */ export interface Response$getFullRemoteReference$Status$200 { \\"application/json\\": { + /** responseA description */ name?: \\"responseA\\"; }; } -/** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#mediaTypeObject */ export interface Response$getReferenceItems$Status$200 { \\"application/json\\": { books?: Schemas.Item[]; @@ -422,7 +401,6 @@ exports[`Generate Code Snapshot Test infer.domain 1`] = ` // -/** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#schemaObject */ export namespace Schemas { export type InferArrayEmptyItems = {}[]; export type InferArrayType = string[]; diff --git a/test/api.test.domain/components/parameters/ForPathItems/FullRemoteReference.yml b/test/api.test.domain/components/parameters/ForPathItems/FullRemoteReference.yml index 6e3b8bee..cb6ef703 100644 --- a/test/api.test.domain/components/parameters/ForPathItems/FullRemoteReference.yml +++ b/test/api.test.domain/components/parameters/ForPathItems/FullRemoteReference.yml @@ -1,6 +1,6 @@ name: FullRemoteReferenceQuery in: query -description: Full Remote REference +description: Full Remote Reference required: true schema: $ref: "../../schemas/FullRemoteReference/ForParameters.yml" diff --git a/test/api.test.domain/components/responses/ForPathItems/FullRemoteReference.yml b/test/api.test.domain/components/responses/ForPathItems/FullRemoteReference.yml index 8396c337..7741c7d3 100644 --- a/test/api.test.domain/components/responses/ForPathItems/FullRemoteReference.yml +++ b/test/api.test.domain/components/responses/ForPathItems/FullRemoteReference.yml @@ -14,3 +14,4 @@ content: name: type: string enum: [responseA] + description: responseA description diff --git a/test/api.test.domain/components/responses/ResponseA.yml b/test/api.test.domain/components/responses/ResponseA.yml index 6282679b..aa4c3d4e 100644 --- a/test/api.test.domain/components/responses/ResponseA.yml +++ b/test/api.test.domain/components/responses/ResponseA.yml @@ -14,3 +14,4 @@ content: name: type: string enum: [responseA] + description: responseA description From e44c29bb2466c464485936a6db311753a3bc41c5 Mon Sep 17 00:00:00 2001 From: Himenon Date: Mon, 22 Feb 2021 00:48:29 +0900 Subject: [PATCH 2/7] chore(codegen): add error response names --- src/Converter/v3/Generator.ts | 21 +++++++++++---- src/Converter/v3/types/CodeGeneratorParams.ts | 3 +++ .../ApiClientClass/ApiClientInterface.ts | 26 +++++++++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/Converter/v3/Generator.ts b/src/Converter/v3/Generator.ts index 208ecaaf..5c81cd9c 100644 --- a/src/Converter/v3/Generator.ts +++ b/src/Converter/v3/Generator.ts @@ -14,7 +14,7 @@ const extractPickedParameter = (parameter: OpenApi.Parameter): PickedParameter = }; }; -const extractSuccessStatusCode = (responses: { [statusCode: string]: OpenApi.Response }): string[] => { +const extractResponseNamesByStatusCode = (type: "success" | "error", responses: { [statusCode: string]: OpenApi.Response }): string[] => { const statusCodeList: string[] = []; Object.entries(responses || {}).forEach(([statusCodeLike, response]) => { // ContentTypeの定義が存在しない場合はstatusCodeを読み取らない @@ -23,8 +23,14 @@ const extractSuccessStatusCode = (responses: { [statusCode: string]: OpenApi.Res } if (typeof statusCodeLike === "string") { const statusCodeNumberValue = parseInt(statusCodeLike, 10); - if (200 <= statusCodeNumberValue && statusCodeNumberValue < 300) { - statusCodeList.push(statusCodeNumberValue.toString()); + if (type === "success") { + if (200 <= statusCodeNumberValue && statusCodeNumberValue < 300) { + statusCodeList.push(statusCodeNumberValue.toString()); + } + } else if (type === "error") { + if (400 <= statusCodeNumberValue && statusCodeNumberValue < 600) { + statusCodeList.push(statusCodeNumberValue.toString()); + } } } }); @@ -37,7 +43,7 @@ const getRequestContentTypeList = (requestBody: OpenApi.RequestBody): string[] = const getSuccessResponseContentTypeList = (responses: { [statusCode: string]: OpenApi.Response }): string[] => { let contentTypeList: string[] = []; - extractSuccessStatusCode(responses).forEach(statusCode => { + extractResponseNamesByStatusCode("success", responses).forEach(statusCode => { const response = responses[statusCode]; contentTypeList = contentTypeList.concat(Object.keys(response.content || {})); }); @@ -55,7 +61,10 @@ const generateCodeGeneratorParamsList = (store: Store.Type, converterContext: Co const operationState = store.getNoReferenceOperationState(); const params: CodeGeneratorParams[] = []; Object.entries(operationState).forEach(([operationId, item]) => { - const responseSuccessNames = extractSuccessStatusCode(item.responses).map(statusCode => + const responseSuccessNames = extractResponseNamesByStatusCode("success", item.responses).map(statusCode => + converterContext.generateResponseName(operationId, statusCode), + ); + const responseErrorNames = extractResponseNamesByStatusCode("error", item.responses).map(statusCode => converterContext.generateResponseName(operationId, statusCode), ); const requestContentTypeList = item.requestBody ? getRequestContentTypeList(item.requestBody) : []; @@ -65,6 +74,7 @@ const generateCodeGeneratorParamsList = (store: Store.Type, converterContext: Co const formatParams: CodeGeneratorParams = { operationId: operationId, + escapedOperationId: converterContext.escapeOperationIdText(operationId), rawRequestUri: item.requestUri, httpMethod: item.httpMethod, argumentParamsTypeDeclaration: converterContext.generateArgumentParamsTypeDeclaration(operationId), @@ -88,6 +98,7 @@ const generateCodeGeneratorParamsList = (store: Store.Type, converterContext: Co responseSuccessNames: responseSuccessNames, responseFirstSuccessName: responseSuccessNames.length === 1 ? responseSuccessNames[0] : undefined, has2OrMoreSuccessNames: hasOver2SuccessNames, + responseErrorNames: responseErrorNames, // Response Success Content Type successResponseContentTypes: responseSuccessContentTypes, successResponseFirstContentType: responseSuccessContentTypes.length === 1 ? responseSuccessContentTypes[0] : undefined, diff --git a/src/Converter/v3/types/CodeGeneratorParams.ts b/src/Converter/v3/types/CodeGeneratorParams.ts index 9f87147a..09b68dba 100644 --- a/src/Converter/v3/types/CodeGeneratorParams.ts +++ b/src/Converter/v3/types/CodeGeneratorParams.ts @@ -4,6 +4,7 @@ export type PickedParameter = Pick 1 + // Response Error Response Name + responseErrorNames: string[]; // Response Success Name responseSuccessNames: string[]; // `Response$${operationId}$Status$${statusCode}`[] responseFirstSuccessName: string | undefined; // responseSuccessNames.length === 1 only diff --git a/src/DefaultCodeTemplate/ApiClientClass/ApiClientInterface.ts b/src/DefaultCodeTemplate/ApiClientClass/ApiClientInterface.ts index 9ff92d7e..be0ed031 100644 --- a/src/DefaultCodeTemplate/ApiClientClass/ApiClientInterface.ts +++ b/src/DefaultCodeTemplate/ApiClientClass/ApiClientInterface.ts @@ -5,6 +5,27 @@ import { CodeGeneratorParams } from "../../Converter/v3"; const httpMethodList: string[] = ["GET", "PUT", "POST", "DELETE", "OPTIONS", "HEAD", "PATCH", "TRACE"]; +const createErrorResponsesTypeAlias = (typeName: string, factory: Factory.Type, errorResponseNames: string[]) => { + if (errorResponseNames.length === 0) { + return factory.TypeAliasDeclaration.create({ + export: true, + name: typeName, + type: ts.factory.createToken(ts.SyntaxKind.VoidKeyword), + }); + } + return factory.TypeAliasDeclaration.create({ + export: true, + name: typeName, + type: factory.UnionTypeNode.create({ + typeNodes: errorResponseNames.map(name => { + return factory.TypeReferenceNode.create({ + name, + }); + }), + }), + }); +}; + const createSuccessResponseTypeAlias = (typeName: string, factory: Factory.Type, successResponseNames: string[]) => { if (successResponseNames.length === 0) { return factory.TypeAliasDeclaration.create({ @@ -134,6 +155,10 @@ export const create = (factory: Factory.Type, list: CodeGeneratorParams[]): ts.S const successResponseNames = list.map(item => item.responseSuccessNames).flat(); + const errorResponseTypes = list.map(item => { + return createErrorResponsesTypeAlias(`ErrorResponses$${item.escapedOperationId}`, factory, item.responseErrorNames); + }); + const functionType = factory.FunctionTypeNode.create({ typeParameters: [ factory.TypeParameterDeclaration.create({ @@ -165,6 +190,7 @@ export const create = (factory: Factory.Type, list: CodeGeneratorParams[]): ts.S createObjectLikeInterface(factory), ...createQueryParamsDeclarations(factory), createSuccessResponseTypeAlias("SuccessResponses", factory, successResponseNames), + ...errorResponseTypes, factory.InterfaceDeclaration.create({ export: true, name: "ApiClient", From feff14995b9b563e1cfa7c79b1eb2be0d0eb3bad Mon Sep 17 00:00:00 2001 From: Himenon Date: Mon, 22 Feb 2021 00:51:24 +0900 Subject: [PATCH 3/7] test: update snapshot --- test/__tests__/__snapshots__/snapshot-test.ts.snap | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/__tests__/__snapshots__/snapshot-test.ts.snap b/test/__tests__/__snapshots__/snapshot-test.ts.snap index ac18dcef..cc0b3271 100644 --- a/test/__tests__/__snapshots__/snapshot-test.ts.snap +++ b/test/__tests__/__snapshots__/snapshot-test.ts.snap @@ -345,6 +345,10 @@ export interface QueryParameters { [key: string]: QueryParameter; } export type SuccessResponses = Response$getIncludeLocalReference$Status$200 | Response$getFullRemoteReference$Status$200 | Response$getReferenceItems$Status$200; +export type ErrorResponses$getIncludeLocalReference = void; +export type ErrorResponses$getIncludeRemoteReference = void; +export type ErrorResponses$getFullRemoteReference = void; +export type ErrorResponses$getReferenceItems = void; export interface ApiClient { request: (httpMethod: HttpMethod, url: string, headers: ObjectLike | any, requestBody: ObjectLike | any, queryParameters: QueryParameters | undefined, options?: RequestOption) => Promise; } From 315c821524c130f6e2809f56234b0b2edd172805 Mon Sep 17 00:00:00 2001 From: Himenon Date: Mon, 22 Feb 2021 01:07:00 +0900 Subject: [PATCH 4/7] feat: add error response namespace --- .../ApiClientClass/ApiClientInterface.ts | 10 +++++++--- test/__tests__/__snapshots__/snapshot-test.ts.snap | 10 ++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/DefaultCodeTemplate/ApiClientClass/ApiClientInterface.ts b/src/DefaultCodeTemplate/ApiClientClass/ApiClientInterface.ts index be0ed031..c6db3751 100644 --- a/src/DefaultCodeTemplate/ApiClientClass/ApiClientInterface.ts +++ b/src/DefaultCodeTemplate/ApiClientClass/ApiClientInterface.ts @@ -155,8 +155,12 @@ export const create = (factory: Factory.Type, list: CodeGeneratorParams[]): ts.S const successResponseNames = list.map(item => item.responseSuccessNames).flat(); - const errorResponseTypes = list.map(item => { - return createErrorResponsesTypeAlias(`ErrorResponses$${item.escapedOperationId}`, factory, item.responseErrorNames); + const errorResponseNamespace = factory.Namespace.create({ + export: true, + name: "ErrorResponse", + statements: list.map(item => { + return createErrorResponsesTypeAlias(`${item.escapedOperationId}`, factory, item.responseErrorNames); + }), }); const functionType = factory.FunctionTypeNode.create({ @@ -190,7 +194,7 @@ export const create = (factory: Factory.Type, list: CodeGeneratorParams[]): ts.S createObjectLikeInterface(factory), ...createQueryParamsDeclarations(factory), createSuccessResponseTypeAlias("SuccessResponses", factory, successResponseNames), - ...errorResponseTypes, + errorResponseNamespace, factory.InterfaceDeclaration.create({ export: true, name: "ApiClient", diff --git a/test/__tests__/__snapshots__/snapshot-test.ts.snap b/test/__tests__/__snapshots__/snapshot-test.ts.snap index cc0b3271..255dfbc4 100644 --- a/test/__tests__/__snapshots__/snapshot-test.ts.snap +++ b/test/__tests__/__snapshots__/snapshot-test.ts.snap @@ -345,10 +345,12 @@ export interface QueryParameters { [key: string]: QueryParameter; } export type SuccessResponses = Response$getIncludeLocalReference$Status$200 | Response$getFullRemoteReference$Status$200 | Response$getReferenceItems$Status$200; -export type ErrorResponses$getIncludeLocalReference = void; -export type ErrorResponses$getIncludeRemoteReference = void; -export type ErrorResponses$getFullRemoteReference = void; -export type ErrorResponses$getReferenceItems = void; +export namespace ErrorResponse { + export type getIncludeLocalReference = void; + export type getIncludeRemoteReference = void; + export type getFullRemoteReference = void; + export type getReferenceItems = void; +} export interface ApiClient { request: (httpMethod: HttpMethod, url: string, headers: ObjectLike | any, requestBody: ObjectLike | any, queryParameters: QueryParameters | undefined, options?: RequestOption) => Promise; } From a6712409c53cb47f4049e0851989710e12e86cd4 Mon Sep 17 00:00:00 2001 From: Himenon Date: Tue, 2 Mar 2021 21:11:43 +0900 Subject: [PATCH 5/7] feat: add allow operationId list --- src/Converter/v3/Generator.ts | 12 ++++++++++-- src/Converter/v3/index.ts | 4 +++- src/index.ts | 23 +++++++++++++++++++---- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/Converter/v3/Generator.ts b/src/Converter/v3/Generator.ts index 5c81cd9c..68887b49 100644 --- a/src/Converter/v3/Generator.ts +++ b/src/Converter/v3/Generator.ts @@ -57,10 +57,17 @@ const hasQueryParameters = (parameters?: OpenApi.Parameter[]): boolean => { return parameters.filter(parameter => parameter.in === "query").length > 0; }; -const generateCodeGeneratorParamsList = (store: Store.Type, converterContext: ConverterContext.Types): CodeGeneratorParams[] => { +const generateCodeGeneratorParamsList = ( + store: Store.Type, + converterContext: ConverterContext.Types, + allowOperationIds: string[] | undefined, +): CodeGeneratorParams[] => { const operationState = store.getNoReferenceOperationState(); const params: CodeGeneratorParams[] = []; Object.entries(operationState).forEach(([operationId, item]) => { + if (allowOperationIds && !allowOperationIds.includes(operationId)) { + return; + } const responseSuccessNames = extractResponseNamesByStatusCode("success", item.responses).map(statusCode => converterContext.generateResponseName(operationId, statusCode), ); @@ -124,7 +131,8 @@ export const generateApiClientCode = ( context: ts.TransformationContext, converterContext: ConverterContext.Types, rewriteCodeAfterTypeDeclaration: RewriteCodeAfterTypeDeclaration, + allowOperationIds: string[] | undefined, ): void => { - const codeGeneratorParamsList = generateCodeGeneratorParamsList(store, converterContext); + const codeGeneratorParamsList = generateCodeGeneratorParamsList(store, converterContext, allowOperationIds); store.addAdditionalStatement(rewriteCodeAfterTypeDeclaration(context, codeGeneratorParamsList)); }; diff --git a/src/Converter/v3/index.ts b/src/Converter/v3/index.ts index be807b55..c3a2e3c0 100644 --- a/src/Converter/v3/index.ts +++ b/src/Converter/v3/index.ts @@ -28,6 +28,8 @@ export interface Option { * It is possible to rewrite the implementation after the type declaration. */ rewriteCodeAfterTypeDeclaration: Generator.RewriteCodeAfterTypeDeclaration; + + allowOperationIds?: string[]; } export const create = (entryPoint: string, rootSchema: OpenApi.Document, noReferenceOpenApiSchema: OpenApi.Document, option: Option): Type => { @@ -97,7 +99,7 @@ export const create = (entryPoint: string, rootSchema: OpenApi.Document, noRefer } if (rootSchema.paths) { Paths.generateStatements(entryPoint, currentPoint, store, factory, rootSchema.paths, toTypeNodeContext, converterContext); - Generator.generateApiClientCode(store, context, converterContext, option.rewriteCodeAfterTypeDeclaration); + Generator.generateApiClientCode(store, context, converterContext, option.rewriteCodeAfterTypeDeclaration, option.allowOperationIds); } return store.getRootStatements(); }; diff --git a/src/index.ts b/src/index.ts index dcf2a8da..323f1771 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,11 +17,20 @@ export interface Params { /** default: true */ enableValidate?: boolean; log?: { - validator?: Validator.v3.LogOption; + validator?: { + /** + * default: undefined (all logs) + * Number of lines displayed in the latest log + */ + displayLogLines?: number; + }; + }; + filter?: { + allowOperationIds?: string[]; }; } -export const generateTypeScriptCode = ({ entryPoint, option, enableValidate = true, log }: Params): string => { +export const generateTypeScriptCode = ({ entryPoint, option, enableValidate = true, log, filter = {} }: Params): string => { const schema = fileSystem.loadJsonOrYaml(entryPoint); const resolvedReferenceDocument = ResolveReference.resolve(entryPoint, entryPoint, JSON.parse(JSON.stringify(schema))); @@ -30,8 +39,14 @@ export const generateTypeScriptCode = ({ entryPoint, option, enableValidate = tr } const convertOption: Converter.v3.Option = option - ? { rewriteCodeAfterTypeDeclaration: option.rewriteCodeAfterTypeDeclaration || DefaultCodeTemplate.rewriteCodeAfterTypeDeclaration } - : { rewriteCodeAfterTypeDeclaration: DefaultCodeTemplate.rewriteCodeAfterTypeDeclaration }; + ? { + rewriteCodeAfterTypeDeclaration: option.rewriteCodeAfterTypeDeclaration || DefaultCodeTemplate.rewriteCodeAfterTypeDeclaration, + allowOperationIds: filter.allowOperationIds || [], + } + : { + rewriteCodeAfterTypeDeclaration: DefaultCodeTemplate.rewriteCodeAfterTypeDeclaration, + allowOperationIds: filter.allowOperationIds || [], + }; const { createFunction, generateLeadingComment } = Converter.v3.create(entryPoint, schema, resolvedReferenceDocument, convertOption); return [generateLeadingComment(), TypeScriptCodeGenerator.generate(createFunction)].join(EOL + EOL + EOL); }; From 0beeaba945d95a7e599d6aaedfe65decb26abe49 Mon Sep 17 00:00:00 2001 From: Himenon Date: Mon, 22 Mar 2021 23:42:21 +0900 Subject: [PATCH 6/7] test: update snapshot --- .../__snapshots__/snapshot-test.ts.snap | 60 +------------------ 1 file changed, 2 insertions(+), 58 deletions(-) diff --git a/test/__tests__/__snapshots__/snapshot-test.ts.snap b/test/__tests__/__snapshots__/snapshot-test.ts.snap index 255dfbc4..2807c6ac 100644 --- a/test/__tests__/__snapshots__/snapshot-test.ts.snap +++ b/test/__tests__/__snapshots__/snapshot-test.ts.snap @@ -318,20 +318,6 @@ export interface Response$getReferenceItems$Status$200 { books?: Schemas.Item[]; }; } -export type ResponseContentType$getIncludeLocalReference = keyof Response$getIncludeLocalReference$Status$200; -export interface Params$getIncludeLocalReference { - parameter: Parameter$getIncludeLocalReference; -} -export type RequestContentType$getIncludeRemoteReference = keyof RequestBody$getIncludeRemoteReference; -export interface Params$getIncludeRemoteReference { - parameter: Parameter$getIncludeRemoteReference; - requestBody: RequestBody$getIncludeRemoteReference[\\"application/json\\"]; -} -export type ResponseContentType$getFullRemoteReference = keyof Response$getFullRemoteReference$Status$200; -export interface Params$getFullRemoteReference { - parameter: Parameter$getFullRemoteReference; -} -export type ResponseContentType$getReferenceItems = keyof Response$getReferenceItems$Status$200; export type HttpMethod = \\"GET\\" | \\"PUT\\" | \\"POST\\" | \\"DELETE\\" | \\"OPTIONS\\" | \\"HEAD\\" | \\"PATCH\\" | \\"TRACE\\"; export interface ObjectLike { [key: string]: any; @@ -344,55 +330,13 @@ export interface QueryParameter { export interface QueryParameters { [key: string]: QueryParameter; } -export type SuccessResponses = Response$getIncludeLocalReference$Status$200 | Response$getFullRemoteReference$Status$200 | Response$getReferenceItems$Status$200; -export namespace ErrorResponse { - export type getIncludeLocalReference = void; - export type getIncludeRemoteReference = void; - export type getFullRemoteReference = void; - export type getReferenceItems = void; -} +export type SuccessResponses = void; +export namespace ErrorResponse { } export interface ApiClient { request: (httpMethod: HttpMethod, url: string, headers: ObjectLike | any, requestBody: ObjectLike | any, queryParameters: QueryParameters | undefined, options?: RequestOption) => Promise; } export class Client { constructor(private apiClient: ApiClient, private baseUrl: string) { } - public async getIncludeLocalReference(params: Params$getIncludeLocalReference, option?: RequestOption): Promise { - const url = this.baseUrl + \`/get/IncludeLocalReference\`; - const headers = { - Accept: \\"application/json\\" - }; - const queryParameters: QueryParameters = { - StringQuery: { value: params.parameter.StringQuery, explode: false } - }; - return this.apiClient.request(\\"GET\\", url, headers, undefined, queryParameters, option); - } - public async getIncludeRemoteReference(params: Params$getIncludeRemoteReference, option?: RequestOption): Promise { - const url = this.baseUrl + \`/get/IncludeRemoteReference\`; - const headers = { - \\"Content-Type\\": \\"application/json\\" - }; - const queryParameters: QueryParameters = { - IncludeRemoteReference: { value: params.parameter.IncludeRemoteReference, explode: false } - }; - return this.apiClient.request(\\"GET\\", url, headers, params.requestBody, queryParameters, option); - } - public async getFullRemoteReference(params: Params$getFullRemoteReference, option?: RequestOption): Promise { - const url = this.baseUrl + \`/FullRemoteReference\`; - const headers = { - Accept: \\"application/json\\" - }; - const queryParameters: QueryParameters = { - FullRemoteReferenceQuery: { value: params.parameter.FullRemoteReferenceQuery, explode: false } - }; - return this.apiClient.request(\\"GET\\", url, headers, undefined, queryParameters, option); - } - public async getReferenceItems(option?: RequestOption): Promise { - const url = this.baseUrl + \`/get/reference/items\`; - const headers = { - Accept: \\"application/json\\" - }; - return this.apiClient.request(\\"GET\\", url, headers, undefined, undefined, option); - } } " `; From b7a770f22ff961648a6e1cbb58160e72a1f49fd2 Mon Sep 17 00:00:00 2001 From: Himenon Date: Mon, 22 Mar 2021 23:55:49 +0900 Subject: [PATCH 7/7] test: update snapshot --- src/index.ts | 4 +- .../__snapshots__/snapshot-test.ts.snap | 60 ++++++++++++++++++- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/index.ts b/src/index.ts index 323f1771..49d8f7b7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -41,11 +41,11 @@ export const generateTypeScriptCode = ({ entryPoint, option, enableValidate = tr const convertOption: Converter.v3.Option = option ? { rewriteCodeAfterTypeDeclaration: option.rewriteCodeAfterTypeDeclaration || DefaultCodeTemplate.rewriteCodeAfterTypeDeclaration, - allowOperationIds: filter.allowOperationIds || [], + allowOperationIds: filter.allowOperationIds, } : { rewriteCodeAfterTypeDeclaration: DefaultCodeTemplate.rewriteCodeAfterTypeDeclaration, - allowOperationIds: filter.allowOperationIds || [], + allowOperationIds: filter.allowOperationIds, }; const { createFunction, generateLeadingComment } = Converter.v3.create(entryPoint, schema, resolvedReferenceDocument, convertOption); return [generateLeadingComment(), TypeScriptCodeGenerator.generate(createFunction)].join(EOL + EOL + EOL); diff --git a/test/__tests__/__snapshots__/snapshot-test.ts.snap b/test/__tests__/__snapshots__/snapshot-test.ts.snap index 2807c6ac..255dfbc4 100644 --- a/test/__tests__/__snapshots__/snapshot-test.ts.snap +++ b/test/__tests__/__snapshots__/snapshot-test.ts.snap @@ -318,6 +318,20 @@ export interface Response$getReferenceItems$Status$200 { books?: Schemas.Item[]; }; } +export type ResponseContentType$getIncludeLocalReference = keyof Response$getIncludeLocalReference$Status$200; +export interface Params$getIncludeLocalReference { + parameter: Parameter$getIncludeLocalReference; +} +export type RequestContentType$getIncludeRemoteReference = keyof RequestBody$getIncludeRemoteReference; +export interface Params$getIncludeRemoteReference { + parameter: Parameter$getIncludeRemoteReference; + requestBody: RequestBody$getIncludeRemoteReference[\\"application/json\\"]; +} +export type ResponseContentType$getFullRemoteReference = keyof Response$getFullRemoteReference$Status$200; +export interface Params$getFullRemoteReference { + parameter: Parameter$getFullRemoteReference; +} +export type ResponseContentType$getReferenceItems = keyof Response$getReferenceItems$Status$200; export type HttpMethod = \\"GET\\" | \\"PUT\\" | \\"POST\\" | \\"DELETE\\" | \\"OPTIONS\\" | \\"HEAD\\" | \\"PATCH\\" | \\"TRACE\\"; export interface ObjectLike { [key: string]: any; @@ -330,13 +344,55 @@ export interface QueryParameter { export interface QueryParameters { [key: string]: QueryParameter; } -export type SuccessResponses = void; -export namespace ErrorResponse { } +export type SuccessResponses = Response$getIncludeLocalReference$Status$200 | Response$getFullRemoteReference$Status$200 | Response$getReferenceItems$Status$200; +export namespace ErrorResponse { + export type getIncludeLocalReference = void; + export type getIncludeRemoteReference = void; + export type getFullRemoteReference = void; + export type getReferenceItems = void; +} export interface ApiClient { request: (httpMethod: HttpMethod, url: string, headers: ObjectLike | any, requestBody: ObjectLike | any, queryParameters: QueryParameters | undefined, options?: RequestOption) => Promise; } export class Client { constructor(private apiClient: ApiClient, private baseUrl: string) { } + public async getIncludeLocalReference(params: Params$getIncludeLocalReference, option?: RequestOption): Promise { + const url = this.baseUrl + \`/get/IncludeLocalReference\`; + const headers = { + Accept: \\"application/json\\" + }; + const queryParameters: QueryParameters = { + StringQuery: { value: params.parameter.StringQuery, explode: false } + }; + return this.apiClient.request(\\"GET\\", url, headers, undefined, queryParameters, option); + } + public async getIncludeRemoteReference(params: Params$getIncludeRemoteReference, option?: RequestOption): Promise { + const url = this.baseUrl + \`/get/IncludeRemoteReference\`; + const headers = { + \\"Content-Type\\": \\"application/json\\" + }; + const queryParameters: QueryParameters = { + IncludeRemoteReference: { value: params.parameter.IncludeRemoteReference, explode: false } + }; + return this.apiClient.request(\\"GET\\", url, headers, params.requestBody, queryParameters, option); + } + public async getFullRemoteReference(params: Params$getFullRemoteReference, option?: RequestOption): Promise { + const url = this.baseUrl + \`/FullRemoteReference\`; + const headers = { + Accept: \\"application/json\\" + }; + const queryParameters: QueryParameters = { + FullRemoteReferenceQuery: { value: params.parameter.FullRemoteReferenceQuery, explode: false } + }; + return this.apiClient.request(\\"GET\\", url, headers, undefined, queryParameters, option); + } + public async getReferenceItems(option?: RequestOption): Promise { + const url = this.baseUrl + \`/get/reference/items\`; + const headers = { + Accept: \\"application/json\\" + }; + return this.apiClient.request(\\"GET\\", url, headers, undefined, undefined, option); + } } " `;