From 3a80b9fd009c8229d69f3f349acbfb19b7549a94 Mon Sep 17 00:00:00 2001 From: Lubos Date: Tue, 29 Oct 2024 20:02:31 +0800 Subject: [PATCH] fix: add support for OpenAPI 3.1.1 to experimental parser --- .changeset/tender-windows-smile.md | 5 + packages/openapi-ts/src/index.ts | 4 +- packages/openapi-ts/src/ir/ir.d.ts | 2 +- .../openapi-ts/src/openApi/3.0.3/index.ts | 2 - .../src/openApi/3.0.3/parser/index.ts | 7 - .../src/openApi/3.0.3/types/spec.d.ts | 7 - .../openapi-ts/src/openApi/3.0.x/index.ts | 2 + .../src/openApi/3.0.x/parser/index.ts | 7 + .../src/openApi/3.0.x/types/spec.d.ts | 22 +++ .../src/openApi/{3.1.0 => 3.1.x}/index.ts | 0 .../openApi/{3.1.0 => 3.1.x}/parser/index.ts | 0 .../{3.1.0 => 3.1.x}/parser/mediaType.ts | 0 .../{3.1.0 => 3.1.x}/parser/operation.ts | 0 .../{3.1.0 => 3.1.x}/parser/pagination.ts | 0 .../{3.1.0 => 3.1.x}/parser/parameter.ts | 0 .../openApi/{3.1.0 => 3.1.x}/parser/schema.ts | 0 .../types/json-schema-draft-2020-12.d.ts | 0 .../types/spec-extensions.d.ts | 0 .../openApi/{3.1.0 => 3.1.x}/types/spec.d.ts | 2 +- .../src/openApi/__tests__/index.spec.ts | 138 +++++++++++++++++- packages/openapi-ts/src/openApi/index.ts | 19 ++- .../src/plugins/@hey-api/schemas/plugin.ts | 30 ++-- .../src/plugins/@hey-api/schemas/types.d.ts | 4 +- 23 files changed, 213 insertions(+), 38 deletions(-) create mode 100644 .changeset/tender-windows-smile.md delete mode 100644 packages/openapi-ts/src/openApi/3.0.3/index.ts delete mode 100644 packages/openapi-ts/src/openApi/3.0.3/parser/index.ts delete mode 100644 packages/openapi-ts/src/openApi/3.0.3/types/spec.d.ts create mode 100644 packages/openapi-ts/src/openApi/3.0.x/index.ts create mode 100644 packages/openapi-ts/src/openApi/3.0.x/parser/index.ts create mode 100644 packages/openapi-ts/src/openApi/3.0.x/types/spec.d.ts rename packages/openapi-ts/src/openApi/{3.1.0 => 3.1.x}/index.ts (100%) rename packages/openapi-ts/src/openApi/{3.1.0 => 3.1.x}/parser/index.ts (100%) rename packages/openapi-ts/src/openApi/{3.1.0 => 3.1.x}/parser/mediaType.ts (100%) rename packages/openapi-ts/src/openApi/{3.1.0 => 3.1.x}/parser/operation.ts (100%) rename packages/openapi-ts/src/openApi/{3.1.0 => 3.1.x}/parser/pagination.ts (100%) rename packages/openapi-ts/src/openApi/{3.1.0 => 3.1.x}/parser/parameter.ts (100%) rename packages/openapi-ts/src/openApi/{3.1.0 => 3.1.x}/parser/schema.ts (100%) rename packages/openapi-ts/src/openApi/{3.1.0 => 3.1.x}/types/json-schema-draft-2020-12.d.ts (100%) rename packages/openapi-ts/src/openApi/{3.1.0 => 3.1.x}/types/spec-extensions.d.ts (100%) rename packages/openapi-ts/src/openApi/{3.1.0 => 3.1.x}/types/spec.d.ts (99%) diff --git a/.changeset/tender-windows-smile.md b/.changeset/tender-windows-smile.md new file mode 100644 index 000000000..818d1abee --- /dev/null +++ b/.changeset/tender-windows-smile.md @@ -0,0 +1,5 @@ +--- +'@hey-api/openapi-ts': patch +--- + +fix: add support for OpenAPI 3.1.1 to experimental parser diff --git a/packages/openapi-ts/src/index.ts b/packages/openapi-ts/src/index.ts index 65736902c..1d7abe168 100644 --- a/packages/openapi-ts/src/index.ts +++ b/packages/openapi-ts/src/index.ts @@ -431,6 +431,6 @@ export default { defineConfig, }; -export type { OpenApiV3_0_3 } from './openApi/3.0.3'; -export type { OpenApiV3_1_0 } from './openApi/3.1.0'; +export type { OpenApiV3_0_0 } from './openApi/3.0.x'; +export type { OpenApiV3_1_0 } from './openApi/3.1.x'; export type { UserConfig } from './types/config'; diff --git a/packages/openapi-ts/src/ir/ir.d.ts b/packages/openapi-ts/src/ir/ir.d.ts index a7d85c42b..4f4704508 100644 --- a/packages/openapi-ts/src/ir/ir.d.ts +++ b/packages/openapi-ts/src/ir/ir.d.ts @@ -1,4 +1,4 @@ -import type { JsonSchemaDraft2020_12 } from '../openApi/3.1.0/types/json-schema-draft-2020-12'; +import type { JsonSchemaDraft2020_12 } from '../openApi/3.1.x/types/json-schema-draft-2020-12'; import type { IRMediaType } from './mediaType'; export interface IR { diff --git a/packages/openapi-ts/src/openApi/3.0.3/index.ts b/packages/openapi-ts/src/openApi/3.0.3/index.ts deleted file mode 100644 index 7b24221c9..000000000 --- a/packages/openapi-ts/src/openApi/3.0.3/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { parseV3_0_3 } from './parser'; -export type { OpenApiV3_0_3 } from './types/spec'; diff --git a/packages/openapi-ts/src/openApi/3.0.3/parser/index.ts b/packages/openapi-ts/src/openApi/3.0.3/parser/index.ts deleted file mode 100644 index b5d0220ce..000000000 --- a/packages/openapi-ts/src/openApi/3.0.3/parser/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { IRContext } from '../../../ir/context'; -import type { OpenApiV3_0_3 } from '../types/spec'; - -export const parseV3_0_3 = (context: IRContext): undefined => { - // TODO - console.log(context.spec); -}; diff --git a/packages/openapi-ts/src/openApi/3.0.3/types/spec.d.ts b/packages/openapi-ts/src/openApi/3.0.3/types/spec.d.ts deleted file mode 100644 index d5545adcf..000000000 --- a/packages/openapi-ts/src/openApi/3.0.3/types/spec.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface OpenApiV3_0_3 { - /** - * **REQUIRED**. This string MUST be the {@link https://semver.org/spec/v2.0.0.html semantic version number} of the {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#versions OpenAPI Specification version} that the OpenAPI document uses. The `openapi` field SHOULD be used by tooling specifications and clients to interpret the OpenAPI document. This is _not_ related to the API {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#infoVersion `info.version`} string. - */ - openapi: '3.0.3'; - // TODO -} diff --git a/packages/openapi-ts/src/openApi/3.0.x/index.ts b/packages/openapi-ts/src/openApi/3.0.x/index.ts new file mode 100644 index 000000000..87b97fe58 --- /dev/null +++ b/packages/openapi-ts/src/openApi/3.0.x/index.ts @@ -0,0 +1,2 @@ +export { parseV3_0_0 } from './parser'; +export type { OpenApiV3_0_0 } from './types/spec'; diff --git a/packages/openapi-ts/src/openApi/3.0.x/parser/index.ts b/packages/openapi-ts/src/openApi/3.0.x/parser/index.ts new file mode 100644 index 000000000..07f6a6674 --- /dev/null +++ b/packages/openapi-ts/src/openApi/3.0.x/parser/index.ts @@ -0,0 +1,7 @@ +import type { IRContext } from '../../../ir/context'; +import type { OpenApiV3_0_0 } from '../types/spec'; + +export const parseV3_0_0 = (context: IRContext) => { + // TODO + console.log(context.spec); +}; diff --git a/packages/openapi-ts/src/openApi/3.0.x/types/spec.d.ts b/packages/openapi-ts/src/openApi/3.0.x/types/spec.d.ts new file mode 100644 index 000000000..52628368f --- /dev/null +++ b/packages/openapi-ts/src/openApi/3.0.x/types/spec.d.ts @@ -0,0 +1,22 @@ +/** + * This is the root object of the {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.4.md#openapi-description OpenAPI Description}. + * + * This object MAY be extended with {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.4.md#specification-extensions Specification Extensions}. + */ +export interface OpenApiV3_0_0 { + /** + * An element to hold various Objects for the OpenAPI Description. + */ + components?: ComponentsObject; + /** + * **REQUIRED**. This string MUST be the {@link https://semver.org/spec/v2.0.0.html semantic version number} of the {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#versions OpenAPI Specification version} that the OpenAPI document uses. The `openapi` field SHOULD be used by tooling specifications and clients to interpret the OpenAPI document. This is _not_ related to the API {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#infoVersion `info.version`} string. + */ + openapi: '3.0.0' | '3.0.1' | '3.0.2' | '3.0.3' | '3.0.4'; + // TODO +} + +// TODO +export interface ComponentsObject {} + +// TODO +export interface SchemaObject {} diff --git a/packages/openapi-ts/src/openApi/3.1.0/index.ts b/packages/openapi-ts/src/openApi/3.1.x/index.ts similarity index 100% rename from packages/openapi-ts/src/openApi/3.1.0/index.ts rename to packages/openapi-ts/src/openApi/3.1.x/index.ts diff --git a/packages/openapi-ts/src/openApi/3.1.0/parser/index.ts b/packages/openapi-ts/src/openApi/3.1.x/parser/index.ts similarity index 100% rename from packages/openapi-ts/src/openApi/3.1.0/parser/index.ts rename to packages/openapi-ts/src/openApi/3.1.x/parser/index.ts diff --git a/packages/openapi-ts/src/openApi/3.1.0/parser/mediaType.ts b/packages/openapi-ts/src/openApi/3.1.x/parser/mediaType.ts similarity index 100% rename from packages/openapi-ts/src/openApi/3.1.0/parser/mediaType.ts rename to packages/openapi-ts/src/openApi/3.1.x/parser/mediaType.ts diff --git a/packages/openapi-ts/src/openApi/3.1.0/parser/operation.ts b/packages/openapi-ts/src/openApi/3.1.x/parser/operation.ts similarity index 100% rename from packages/openapi-ts/src/openApi/3.1.0/parser/operation.ts rename to packages/openapi-ts/src/openApi/3.1.x/parser/operation.ts diff --git a/packages/openapi-ts/src/openApi/3.1.0/parser/pagination.ts b/packages/openapi-ts/src/openApi/3.1.x/parser/pagination.ts similarity index 100% rename from packages/openapi-ts/src/openApi/3.1.0/parser/pagination.ts rename to packages/openapi-ts/src/openApi/3.1.x/parser/pagination.ts diff --git a/packages/openapi-ts/src/openApi/3.1.0/parser/parameter.ts b/packages/openapi-ts/src/openApi/3.1.x/parser/parameter.ts similarity index 100% rename from packages/openapi-ts/src/openApi/3.1.0/parser/parameter.ts rename to packages/openapi-ts/src/openApi/3.1.x/parser/parameter.ts diff --git a/packages/openapi-ts/src/openApi/3.1.0/parser/schema.ts b/packages/openapi-ts/src/openApi/3.1.x/parser/schema.ts similarity index 100% rename from packages/openapi-ts/src/openApi/3.1.0/parser/schema.ts rename to packages/openapi-ts/src/openApi/3.1.x/parser/schema.ts diff --git a/packages/openapi-ts/src/openApi/3.1.0/types/json-schema-draft-2020-12.d.ts b/packages/openapi-ts/src/openApi/3.1.x/types/json-schema-draft-2020-12.d.ts similarity index 100% rename from packages/openapi-ts/src/openApi/3.1.0/types/json-schema-draft-2020-12.d.ts rename to packages/openapi-ts/src/openApi/3.1.x/types/json-schema-draft-2020-12.d.ts diff --git a/packages/openapi-ts/src/openApi/3.1.0/types/spec-extensions.d.ts b/packages/openapi-ts/src/openApi/3.1.x/types/spec-extensions.d.ts similarity index 100% rename from packages/openapi-ts/src/openApi/3.1.0/types/spec-extensions.d.ts rename to packages/openapi-ts/src/openApi/3.1.x/types/spec-extensions.d.ts diff --git a/packages/openapi-ts/src/openApi/3.1.0/types/spec.d.ts b/packages/openapi-ts/src/openApi/3.1.x/types/spec.d.ts similarity index 99% rename from packages/openapi-ts/src/openApi/3.1.0/types/spec.d.ts rename to packages/openapi-ts/src/openApi/3.1.x/types/spec.d.ts index 4d49f9c84..22272ad42 100644 --- a/packages/openapi-ts/src/openApi/3.1.0/types/spec.d.ts +++ b/packages/openapi-ts/src/openApi/3.1.x/types/spec.d.ts @@ -25,7 +25,7 @@ export interface OpenApiV3_1_0 { /** * **REQUIRED**. This string MUST be the {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#versions version number} of the OpenAPI Specification that the OpenAPI document uses. The `openapi` field SHOULD be used by tooling to interpret the OpenAPI document. This is _not_ related to the API {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#infoVersion `info.version`} string. */ - openapi: '3.1.0'; + openapi: '3.1.0' | '3.1.1'; /** * The available paths and operations for the API. */ diff --git a/packages/openapi-ts/src/openApi/__tests__/index.spec.ts b/packages/openapi-ts/src/openApi/__tests__/index.spec.ts index 0c8716033..20101182c 100644 --- a/packages/openapi-ts/src/openApi/__tests__/index.spec.ts +++ b/packages/openapi-ts/src/openApi/__tests__/index.spec.ts @@ -1,10 +1,21 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; -import { type OpenApi, parseLegacy } from '..'; +import { type OpenApi, parseExperimental, parseLegacy } from '..'; +import type { OpenApiV3_0_0 } from '../3.0.x'; +import { parseV3_0_0 } from '../3.0.x'; +import type { OpenApiV3_1_0 } from '../3.1.x'; +import { parseV3_1_0 } from '../3.1.x'; import type { ParserConfig } from '../config'; import * as parseV2 from '../v2'; import * as parseV3 from '../v3'; +vi.mock('../3.0.x', () => ({ + parseV3_0_0: vi.fn(), +})); +vi.mock('../3.1.x', () => ({ + parseV3_1_0: vi.fn(), +})); + const parserConfig: ParserConfig = { filterFn: { operation: () => true, @@ -93,3 +104,128 @@ describe('parse', () => { ); }); }); + +describe('experimentalParser', () => { + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('handles OpenAPI 3.0.0', () => { + const spec: OpenApiV3_0_0 = { + // info: { + // title: '', + // version: '1', + // }, + openapi: '3.0.0', + }; + parseExperimental({ + // @ts-ignore + config: {}, + parserConfig, + spec, + }); + expect(parseV3_0_0).toHaveBeenCalled(); + }); + + it('handles OpenAPI 3.0.1', () => { + const spec: OpenApiV3_0_0 = { + // info: { + // title: '', + // version: '1', + // }, + openapi: '3.0.1', + }; + parseExperimental({ + // @ts-ignore + config: {}, + parserConfig, + spec, + }); + expect(parseV3_0_0).toHaveBeenCalled(); + }); + + it('handles OpenAPI 3.0.2', () => { + const spec: OpenApiV3_0_0 = { + // info: { + // title: '', + // version: '1', + // }, + openapi: '3.0.2', + }; + parseExperimental({ + // @ts-ignore + config: {}, + parserConfig, + spec, + }); + expect(parseV3_0_0).toHaveBeenCalled(); + }); + + it('handles OpenAPI 3.0.3', () => { + const spec: OpenApiV3_0_0 = { + // info: { + // title: '', + // version: '1', + // }, + openapi: '3.0.3', + }; + parseExperimental({ + // @ts-ignore + config: {}, + parserConfig, + spec, + }); + expect(parseV3_0_0).toHaveBeenCalled(); + }); + + it('handles OpenAPI 3.0.4', () => { + const spec: OpenApiV3_0_0 = { + // info: { + // title: '', + // version: '1', + // }, + openapi: '3.0.4', + }; + parseExperimental({ + // @ts-ignore + config: {}, + parserConfig, + spec, + }); + expect(parseV3_0_0).toHaveBeenCalled(); + }); + + it('handles OpenAPI 3.1.0', () => { + const spec: OpenApiV3_1_0 = { + info: { + title: '', + version: '1', + }, + openapi: '3.1.0', + }; + parseExperimental({ + // @ts-ignore + config: {}, + parserConfig, + spec, + }); + expect(parseV3_1_0).toHaveBeenCalled(); + }); + + it('handles OpenAPI 3.1.1', () => { + const spec: OpenApiV3_1_0 = { + info: { + title: '', + version: '1', + }, + openapi: '3.1.1', + }; + parseExperimental({ + // @ts-ignore + config: {}, + parserConfig, + spec, + }); + expect(parseV3_1_0).toHaveBeenCalled(); + }); +}); diff --git a/packages/openapi-ts/src/openApi/index.ts b/packages/openapi-ts/src/openApi/index.ts index 7c89fb5cf..bc9c0fa67 100644 --- a/packages/openapi-ts/src/openApi/index.ts +++ b/packages/openapi-ts/src/openApi/index.ts @@ -1,7 +1,7 @@ import { IRContext } from '../ir/context'; import type { Config } from '../types/config'; -import { type OpenApiV3_0_3, parseV3_0_3 } from './3.0.3'; -import { type OpenApiV3_1_0, parseV3_1_0 } from './3.1.0'; +import { type OpenApiV3_0_0, parseV3_0_0 } from './3.0.x'; +import { type OpenApiV3_1_0, parseV3_1_0 } from './3.1.x'; import type { Client } from './common/interfaces/client'; import type { OpenApi } from './common/interfaces/OpenApi'; import type { ParserConfig } from './config'; @@ -57,8 +57,6 @@ export function parseLegacy({ ); } -export type ParserOpenApiSpec = OpenApiV3_0_3 | OpenApiV3_1_0; - // TODO: parser - add JSDoc comment export const parseExperimental = ({ config, @@ -72,14 +70,21 @@ export const parseExperimental = ({ const context = new IRContext({ config, parserConfig, - spec: spec as ParserOpenApiSpec, + spec: spec as Record, }); - switch (context.spec.openapi) { + const ctx = context as IRContext; + switch (ctx.spec.openapi) { + // TODO: parser - handle Swagger 2.0 + case '3.0.0': + case '3.0.1': + case '3.0.2': case '3.0.3': - parseV3_0_3(context as IRContext); + case '3.0.4': + parseV3_0_0(context as IRContext); break; case '3.1.0': + case '3.1.1': parseV3_1_0(context as IRContext); break; default: diff --git a/packages/openapi-ts/src/plugins/@hey-api/schemas/plugin.ts b/packages/openapi-ts/src/plugins/@hey-api/schemas/plugin.ts index 96869952c..5f686d5ab 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/schemas/plugin.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/schemas/plugin.ts @@ -1,11 +1,10 @@ import { compiler } from '../../../compiler'; import type { IRContext } from '../../../ir/context'; -import { - ensureValidTypeScriptJavaScriptIdentifier, - type ParserOpenApiSpec, -} from '../../../openApi'; -import type { OpenApiV3_1_0 } from '../../../openApi/3.1.0'; -import type { SchemaObject as OpenApiV3_1_0SchemaObject } from '../../../openApi/3.1.0/types/spec'; +import { ensureValidTypeScriptJavaScriptIdentifier } from '../../../openApi'; +import type { OpenApiV3_0_0 } from '../../../openApi/3.0.x'; +import type { OpenApiV3_1_0 } from '../../../openApi/3.1.x'; +// import type { SchemaObject as OpenApiV3_0_0SchemaObject } from '../../../openApi/3.0.x/types/spec'; +import type { SchemaObject as OpenApiV3_1_0SchemaObject } from '../../../openApi/3.1.x/types/spec'; import type { PluginHandler } from '../../types'; import type { Config } from './types'; @@ -154,6 +153,14 @@ const schemaName = ({ return `${validName}Schema`; }; +const schemasV3_0_0 = (context: IRContext) => { + if (!context.spec.components) { + return; + } + + // TODO: parser - handle OpenAPI 3.0.x +}; + const schemasV3_1_0 = (context: IRContext) => { if (!context.spec.components) { return; @@ -182,13 +189,18 @@ export const handler: PluginHandler = ({ context }) => { }); if (context.spec.openapi) { - const ctx = context as IRContext; - // TODO: parser - copy-pasted from experimental parser for now + const ctx = context as IRContext; switch (ctx.spec.openapi) { + // TODO: parser - handle Swagger 2.0 + case '3.0.0': + case '3.0.1': + case '3.0.2': case '3.0.3': - // ... + case '3.0.4': + schemasV3_0_0(context as IRContext); break; case '3.1.0': + case '3.1.1': schemasV3_1_0(context as IRContext); break; default: diff --git a/packages/openapi-ts/src/plugins/@hey-api/schemas/types.d.ts b/packages/openapi-ts/src/plugins/@hey-api/schemas/types.d.ts index 416036d7c..45e11cde1 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/schemas/types.d.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/schemas/types.d.ts @@ -1,5 +1,7 @@ import type { OpenApiV2Schema, OpenApiV3Schema } from '../../../openApi'; -import type { SchemaObject as OpenApiV3_1_0SchemaObject } from '../../../openApi/3.1.0/types/spec'; +// TODO: parser - add new parser schema object to `nameBuilder` +// import type { SchemaObject as OpenApiV3_0_0SchemaObject } from '../../../openApi/3.0.x/types/spec'; +import type { SchemaObject as OpenApiV3_1_0SchemaObject } from '../../../openApi/3.1.x/types/spec'; import type { PluginName } from '../../types'; export interface Config extends PluginName<'@hey-api/schemas'> {