diff --git a/src/generateValidRootSchema.ts b/src/generateValidRootSchema.ts new file mode 100644 index 00000000..45b27bc3 --- /dev/null +++ b/src/generateValidRootSchema.ts @@ -0,0 +1,33 @@ +import type * as Types from "./types"; + +export const generateValidRootSchema = (input: Types.OpenApi.Document): Types.OpenApi.Document => { + if (!input.paths) { + return input; + } + /** update undefined operation id */ + for (const [path, methods] of Object.entries(input.paths || {})) { + const targets = { + get: methods.get, + put: methods.put, + post: methods.post, + delete: methods.delete, + options: methods.options, + head: methods.head, + patch: methods.patch, + trace: methods.trace, + } satisfies Record; + for (const [method, operation] of Object.entries(targets)) { + if (!operation) { + continue; + } + // skip reference object + if ("$ref" in operation) { + continue; + } + if (!operation.operationId) { + operation.operationId = `${method.toLowerCase()}${path.charAt(0).toUpperCase() + path.slice(1)}`; + } + } + } + return input; +}; diff --git a/src/index.ts b/src/index.ts index 26d83eb0..fa6d0c45 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,6 +2,7 @@ import { EOL } from "os"; import * as Api from "./api"; import type * as Types from "./types"; +import { generateValidRootSchema } from "./generateValidRootSchema"; export interface Option { allowOperationIds?: string[]; @@ -17,7 +18,7 @@ export class CodeGenerator { private option?: Option, ) { if (typeof entryPointOrDocument === "string") { - this.rootSchema = Api.FileSystem.loadJsonOrYaml(entryPointOrDocument); + this.rootSchema = generateValidRootSchema(Api.FileSystem.loadJsonOrYaml(entryPointOrDocument)); this.resolvedReferenceDocument = Api.ResolveReference.resolve( entryPointOrDocument, entryPointOrDocument, diff --git a/test/__tests__/class/__snapshots__/typedef-with-template-test.ts.snap b/test/__tests__/class/__snapshots__/typedef-with-template-test.ts.snap index 62a9e4a7..78ad58f7 100644 --- a/test/__tests__/class/__snapshots__/typedef-with-template-test.ts.snap +++ b/test/__tests__/class/__snapshots__/typedef-with-template-test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`Typedef with template api.test.domain 1`] = ` "// @@ -572,6 +572,12 @@ export interface Response$postHelloWorldReadonly$Status$200 { message?: Schemas.Message; }; } +export interface Response$get$undefined$operation$$id$Status$200 { + "application/json": { + /** Undefined operation response */ + message?: string; + }; +} export type ResponseContentType$getHelloWorld = keyof Response$getHelloWorld$Status$200; export interface Params$getHelloWorld { parameter: Parameter$getHelloWorld; @@ -581,6 +587,7 @@ export type ResponseContentType$postHelloWorldReadonly = keyof Response$postHell export interface Params$postHelloWorldReadonly { requestBody: RequestBody$postHelloWorldReadonly["application/json"]; } +export type ResponseContentType$get$undefined$operation$$id = keyof Response$get$undefined$operation$$id$Status$200; export type HttpMethod = "GET" | "PUT" | "POST" | "DELETE" | "OPTIONS" | "HEAD" | "PATCH" | "TRACE"; export interface ObjectLike { [key: string]: any; @@ -593,10 +600,11 @@ export interface QueryParameter { export interface QueryParameters { [key: string]: QueryParameter; } -export type SuccessResponses = Response$getHelloWorld$Status$200 | Response$postHelloWorldReadonly$Status$200; +export type SuccessResponses = Response$getHelloWorld$Status$200 | Response$postHelloWorldReadonly$Status$200 | Response$get$undefined$operation$$id$Status$200; export namespace ErrorResponse { export type getHelloWorld = void; export type postHelloWorldReadonly = void; + export type get$undefined$operation$$id = void; } export interface Encoding { readonly contentType?: string; @@ -647,6 +655,17 @@ export class Client { requestBody: params.requestBody }, option); } + public async get$undefined$operation$$id(option?: RequestOption): Promise { + const url = this.baseUrl + \`/undefined/operation/:id\`; + const headers = { + Accept: "application/json" + }; + return this.apiClient.request({ + httpMethod: "GET", + url, + headers + }, option); + } } " `; diff --git a/test/__tests__/functional/__snapshots__/typedef-with-template-test.ts.snap b/test/__tests__/functional/__snapshots__/typedef-with-template-test.ts.snap index a3b74f17..0e75991c 100644 --- a/test/__tests__/functional/__snapshots__/typedef-with-template-test.ts.snap +++ b/test/__tests__/functional/__snapshots__/typedef-with-template-test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`Typedef with template api.test.domain 1`] = ` "// @@ -575,6 +575,12 @@ export interface Response$postHelloWorldReadonly$Status$200 { message?: Schemas.Message; }; } +export interface Response$get$undefined$operation$$id$Status$200 { + "application/json": { + /** Undefined operation response */ + message?: string; + }; +} export type ResponseContentType$getHelloWorld = keyof Response$getHelloWorld$Status$200; export interface Params$getHelloWorld { parameter: Parameter$getHelloWorld; @@ -584,6 +590,7 @@ export type ResponseContentType$postHelloWorldReadonly = keyof Response$postHell export interface Params$postHelloWorldReadonly { requestBody: RequestBody$postHelloWorldReadonly["application/json"]; } +export type ResponseContentType$get$undefined$operation$$id = keyof Response$get$undefined$operation$$id$Status$200; export type HttpMethod = "GET" | "PUT" | "POST" | "DELETE" | "OPTIONS" | "HEAD" | "PATCH" | "TRACE"; export interface ObjectLike { [key: string]: any; @@ -596,10 +603,11 @@ export interface QueryParameter { export interface QueryParameters { [key: string]: QueryParameter; } -export type SuccessResponses = Response$getHelloWorld$Status$200 | Response$postHelloWorldReadonly$Status$200; +export type SuccessResponses = Response$getHelloWorld$Status$200 | Response$postHelloWorldReadonly$Status$200 | Response$get$undefined$operation$$id$Status$200; export namespace ErrorResponse { export type getHelloWorld = void; export type postHelloWorldReadonly = void; + export type get$undefined$operation$$id = void; } export interface Encoding { readonly contentType?: string; @@ -649,6 +657,17 @@ export const createClient = (apiClient: ApiClient, headers, requestBody: params.requestBody }, option); + }, + get$undefined$operation$$id: (option?: RequestOption): Promise => { + const url = _baseUrl + \`/undefined/operation/:id\`; + const headers = { + Accept: "application/json" + }; + return apiClient.request({ + httpMethod: "GET", + url, + headers + }, option); } }; }; diff --git a/test/api.v2.domain/index.yml b/test/api.v2.domain/index.yml index 69a60210..32987c5d 100644 --- a/test/api.v2.domain/index.yml +++ b/test/api.v2.domain/index.yml @@ -66,3 +66,16 @@ paths: properties: message: $ref: "#/components/schemas/Message" + /undefined/operation/:id: + get: + responses: + 200: + description: 成功 + content: + application/json: + schema: + type: object + properties: + message: + type: string + description: Undefined operation response