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

Merge pull request #1209 from hey-api/fix/openapi-3-1-1

fix: add support for OpenAPI 3.1.1 to experimental parser

authored by

Lubos and committed by
GitHub
ad33092b 8322b394

+213 -38
+5
.changeset/tender-windows-smile.md
··· 1 + --- 2 + '@hey-api/openapi-ts': patch 3 + --- 4 + 5 + fix: add support for OpenAPI 3.1.1 to experimental parser
+2 -2
packages/openapi-ts/src/index.ts
··· 431 431 defineConfig, 432 432 }; 433 433 434 - export type { OpenApiV3_0_3 } from './openApi/3.0.3'; 435 - export type { OpenApiV3_1_0 } from './openApi/3.1.0'; 434 + export type { OpenApiV3_0_0 } from './openApi/3.0.x'; 435 + export type { OpenApiV3_1_0 } from './openApi/3.1.x'; 436 436 export type { UserConfig } from './types/config';
+1 -1
packages/openapi-ts/src/ir/ir.d.ts
··· 1 - import type { JsonSchemaDraft2020_12 } from '../openApi/3.1.0/types/json-schema-draft-2020-12'; 1 + import type { JsonSchemaDraft2020_12 } from '../openApi/3.1.x/types/json-schema-draft-2020-12'; 2 2 import type { IRMediaType } from './mediaType'; 3 3 4 4 export interface IR {
-2
packages/openapi-ts/src/openApi/3.0.3/index.ts
··· 1 - export { parseV3_0_3 } from './parser'; 2 - export type { OpenApiV3_0_3 } from './types/spec';
-7
packages/openapi-ts/src/openApi/3.0.3/parser/index.ts
··· 1 - import type { IRContext } from '../../../ir/context'; 2 - import type { OpenApiV3_0_3 } from '../types/spec'; 3 - 4 - export const parseV3_0_3 = (context: IRContext<OpenApiV3_0_3>): undefined => { 5 - // TODO 6 - console.log(context.spec); 7 - };
-7
packages/openapi-ts/src/openApi/3.0.3/types/spec.d.ts
··· 1 - export interface OpenApiV3_0_3 { 2 - /** 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. 4 - */ 5 - openapi: '3.0.3'; 6 - // TODO 7 - }
+2
packages/openapi-ts/src/openApi/3.0.x/index.ts
··· 1 + export { parseV3_0_0 } from './parser'; 2 + export type { OpenApiV3_0_0 } from './types/spec';
+7
packages/openapi-ts/src/openApi/3.0.x/parser/index.ts
··· 1 + import type { IRContext } from '../../../ir/context'; 2 + import type { OpenApiV3_0_0 } from '../types/spec'; 3 + 4 + export const parseV3_0_0 = (context: IRContext<OpenApiV3_0_0>) => { 5 + // TODO 6 + console.log(context.spec); 7 + };
+22
packages/openapi-ts/src/openApi/3.0.x/types/spec.d.ts
··· 1 + /** 2 + * 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}. 3 + * 4 + * This object MAY be extended with {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.4.md#specification-extensions Specification Extensions}. 5 + */ 6 + export interface OpenApiV3_0_0 { 7 + /** 8 + * An element to hold various Objects for the OpenAPI Description. 9 + */ 10 + components?: ComponentsObject; 11 + /** 12 + * **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. 13 + */ 14 + openapi: '3.0.0' | '3.0.1' | '3.0.2' | '3.0.3' | '3.0.4'; 15 + // TODO 16 + } 17 + 18 + // TODO 19 + export interface ComponentsObject {} 20 + 21 + // TODO 22 + export interface SchemaObject {}
packages/openapi-ts/src/openApi/3.1.0/index.ts packages/openapi-ts/src/openApi/3.1.x/index.ts
packages/openapi-ts/src/openApi/3.1.0/parser/index.ts packages/openapi-ts/src/openApi/3.1.x/parser/index.ts
packages/openapi-ts/src/openApi/3.1.0/parser/mediaType.ts packages/openapi-ts/src/openApi/3.1.x/parser/mediaType.ts
packages/openapi-ts/src/openApi/3.1.0/parser/operation.ts packages/openapi-ts/src/openApi/3.1.x/parser/operation.ts
packages/openapi-ts/src/openApi/3.1.0/parser/pagination.ts packages/openapi-ts/src/openApi/3.1.x/parser/pagination.ts
packages/openapi-ts/src/openApi/3.1.0/parser/parameter.ts packages/openapi-ts/src/openApi/3.1.x/parser/parameter.ts
packages/openapi-ts/src/openApi/3.1.0/parser/schema.ts packages/openapi-ts/src/openApi/3.1.x/parser/schema.ts
packages/openapi-ts/src/openApi/3.1.0/types/json-schema-draft-2020-12.d.ts packages/openapi-ts/src/openApi/3.1.x/types/json-schema-draft-2020-12.d.ts
packages/openapi-ts/src/openApi/3.1.0/types/spec-extensions.d.ts packages/openapi-ts/src/openApi/3.1.x/types/spec-extensions.d.ts
+1 -1
packages/openapi-ts/src/openApi/3.1.0/types/spec.d.ts packages/openapi-ts/src/openApi/3.1.x/types/spec.d.ts
··· 25 25 /** 26 26 * **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. 27 27 */ 28 - openapi: '3.1.0'; 28 + openapi: '3.1.0' | '3.1.1'; 29 29 /** 30 30 * The available paths and operations for the API. 31 31 */
+137 -1
packages/openapi-ts/src/openApi/__tests__/index.spec.ts
··· 1 1 import { afterEach, describe, expect, it, vi } from 'vitest'; 2 2 3 - import { type OpenApi, parseLegacy } from '..'; 3 + import { type OpenApi, parseExperimental, parseLegacy } from '..'; 4 + import type { OpenApiV3_0_0 } from '../3.0.x'; 5 + import { parseV3_0_0 } from '../3.0.x'; 6 + import type { OpenApiV3_1_0 } from '../3.1.x'; 7 + import { parseV3_1_0 } from '../3.1.x'; 4 8 import type { ParserConfig } from '../config'; 5 9 import * as parseV2 from '../v2'; 6 10 import * as parseV3 from '../v3'; 11 + 12 + vi.mock('../3.0.x', () => ({ 13 + parseV3_0_0: vi.fn(), 14 + })); 15 + vi.mock('../3.1.x', () => ({ 16 + parseV3_1_0: vi.fn(), 17 + })); 7 18 8 19 const parserConfig: ParserConfig = { 9 20 filterFn: { ··· 93 104 ); 94 105 }); 95 106 }); 107 + 108 + describe('experimentalParser', () => { 109 + afterEach(() => { 110 + vi.restoreAllMocks(); 111 + }); 112 + 113 + it('handles OpenAPI 3.0.0', () => { 114 + const spec: OpenApiV3_0_0 = { 115 + // info: { 116 + // title: '', 117 + // version: '1', 118 + // }, 119 + openapi: '3.0.0', 120 + }; 121 + parseExperimental({ 122 + // @ts-ignore 123 + config: {}, 124 + parserConfig, 125 + spec, 126 + }); 127 + expect(parseV3_0_0).toHaveBeenCalled(); 128 + }); 129 + 130 + it('handles OpenAPI 3.0.1', () => { 131 + const spec: OpenApiV3_0_0 = { 132 + // info: { 133 + // title: '', 134 + // version: '1', 135 + // }, 136 + openapi: '3.0.1', 137 + }; 138 + parseExperimental({ 139 + // @ts-ignore 140 + config: {}, 141 + parserConfig, 142 + spec, 143 + }); 144 + expect(parseV3_0_0).toHaveBeenCalled(); 145 + }); 146 + 147 + it('handles OpenAPI 3.0.2', () => { 148 + const spec: OpenApiV3_0_0 = { 149 + // info: { 150 + // title: '', 151 + // version: '1', 152 + // }, 153 + openapi: '3.0.2', 154 + }; 155 + parseExperimental({ 156 + // @ts-ignore 157 + config: {}, 158 + parserConfig, 159 + spec, 160 + }); 161 + expect(parseV3_0_0).toHaveBeenCalled(); 162 + }); 163 + 164 + it('handles OpenAPI 3.0.3', () => { 165 + const spec: OpenApiV3_0_0 = { 166 + // info: { 167 + // title: '', 168 + // version: '1', 169 + // }, 170 + openapi: '3.0.3', 171 + }; 172 + parseExperimental({ 173 + // @ts-ignore 174 + config: {}, 175 + parserConfig, 176 + spec, 177 + }); 178 + expect(parseV3_0_0).toHaveBeenCalled(); 179 + }); 180 + 181 + it('handles OpenAPI 3.0.4', () => { 182 + const spec: OpenApiV3_0_0 = { 183 + // info: { 184 + // title: '', 185 + // version: '1', 186 + // }, 187 + openapi: '3.0.4', 188 + }; 189 + parseExperimental({ 190 + // @ts-ignore 191 + config: {}, 192 + parserConfig, 193 + spec, 194 + }); 195 + expect(parseV3_0_0).toHaveBeenCalled(); 196 + }); 197 + 198 + it('handles OpenAPI 3.1.0', () => { 199 + const spec: OpenApiV3_1_0 = { 200 + info: { 201 + title: '', 202 + version: '1', 203 + }, 204 + openapi: '3.1.0', 205 + }; 206 + parseExperimental({ 207 + // @ts-ignore 208 + config: {}, 209 + parserConfig, 210 + spec, 211 + }); 212 + expect(parseV3_1_0).toHaveBeenCalled(); 213 + }); 214 + 215 + it('handles OpenAPI 3.1.1', () => { 216 + const spec: OpenApiV3_1_0 = { 217 + info: { 218 + title: '', 219 + version: '1', 220 + }, 221 + openapi: '3.1.1', 222 + }; 223 + parseExperimental({ 224 + // @ts-ignore 225 + config: {}, 226 + parserConfig, 227 + spec, 228 + }); 229 + expect(parseV3_1_0).toHaveBeenCalled(); 230 + }); 231 + });
+12 -7
packages/openapi-ts/src/openApi/index.ts
··· 1 1 import { IRContext } from '../ir/context'; 2 2 import type { Config } from '../types/config'; 3 - import { type OpenApiV3_0_3, parseV3_0_3 } from './3.0.3'; 4 - import { type OpenApiV3_1_0, parseV3_1_0 } from './3.1.0'; 3 + import { type OpenApiV3_0_0, parseV3_0_0 } from './3.0.x'; 4 + import { type OpenApiV3_1_0, parseV3_1_0 } from './3.1.x'; 5 5 import type { Client } from './common/interfaces/client'; 6 6 import type { OpenApi } from './common/interfaces/OpenApi'; 7 7 import type { ParserConfig } from './config'; ··· 57 57 ); 58 58 } 59 59 60 - export type ParserOpenApiSpec = OpenApiV3_0_3 | OpenApiV3_1_0; 61 - 62 60 // TODO: parser - add JSDoc comment 63 61 export const parseExperimental = ({ 64 62 config, ··· 72 70 const context = new IRContext({ 73 71 config, 74 72 parserConfig, 75 - spec: spec as ParserOpenApiSpec, 73 + spec: spec as Record<string, any>, 76 74 }); 77 75 78 - switch (context.spec.openapi) { 76 + const ctx = context as IRContext<OpenApiV3_0_0 | OpenApiV3_1_0>; 77 + switch (ctx.spec.openapi) { 78 + // TODO: parser - handle Swagger 2.0 79 + case '3.0.0': 80 + case '3.0.1': 81 + case '3.0.2': 79 82 case '3.0.3': 80 - parseV3_0_3(context as IRContext<OpenApiV3_0_3>); 83 + case '3.0.4': 84 + parseV3_0_0(context as IRContext<OpenApiV3_0_0>); 81 85 break; 82 86 case '3.1.0': 87 + case '3.1.1': 83 88 parseV3_1_0(context as IRContext<OpenApiV3_1_0>); 84 89 break; 85 90 default:
+21 -9
packages/openapi-ts/src/plugins/@hey-api/schemas/plugin.ts
··· 1 1 import { compiler } from '../../../compiler'; 2 2 import type { IRContext } from '../../../ir/context'; 3 - import { 4 - ensureValidTypeScriptJavaScriptIdentifier, 5 - type ParserOpenApiSpec, 6 - } from '../../../openApi'; 7 - import type { OpenApiV3_1_0 } from '../../../openApi/3.1.0'; 8 - import type { SchemaObject as OpenApiV3_1_0SchemaObject } from '../../../openApi/3.1.0/types/spec'; 3 + import { ensureValidTypeScriptJavaScriptIdentifier } from '../../../openApi'; 4 + import type { OpenApiV3_0_0 } from '../../../openApi/3.0.x'; 5 + import type { OpenApiV3_1_0 } from '../../../openApi/3.1.x'; 6 + // import type { SchemaObject as OpenApiV3_0_0SchemaObject } from '../../../openApi/3.0.x/types/spec'; 7 + import type { SchemaObject as OpenApiV3_1_0SchemaObject } from '../../../openApi/3.1.x/types/spec'; 9 8 import type { PluginHandler } from '../../types'; 10 9 import type { Config } from './types'; 11 10 ··· 154 153 return `${validName}Schema`; 155 154 }; 156 155 156 + const schemasV3_0_0 = (context: IRContext<OpenApiV3_0_0>) => { 157 + if (!context.spec.components) { 158 + return; 159 + } 160 + 161 + // TODO: parser - handle OpenAPI 3.0.x 162 + }; 163 + 157 164 const schemasV3_1_0 = (context: IRContext<OpenApiV3_1_0>) => { 158 165 if (!context.spec.components) { 159 166 return; ··· 182 189 }); 183 190 184 191 if (context.spec.openapi) { 185 - const ctx = context as IRContext<ParserOpenApiSpec>; 186 - // TODO: parser - copy-pasted from experimental parser for now 192 + const ctx = context as IRContext<OpenApiV3_0_0 | OpenApiV3_1_0>; 187 193 switch (ctx.spec.openapi) { 194 + // TODO: parser - handle Swagger 2.0 195 + case '3.0.0': 196 + case '3.0.1': 197 + case '3.0.2': 188 198 case '3.0.3': 189 - // ... 199 + case '3.0.4': 200 + schemasV3_0_0(context as IRContext<OpenApiV3_0_0>); 190 201 break; 191 202 case '3.1.0': 203 + case '3.1.1': 192 204 schemasV3_1_0(context as IRContext<OpenApiV3_1_0>); 193 205 break; 194 206 default:
+3 -1
packages/openapi-ts/src/plugins/@hey-api/schemas/types.d.ts
··· 1 1 import type { OpenApiV2Schema, OpenApiV3Schema } from '../../../openApi'; 2 - import type { SchemaObject as OpenApiV3_1_0SchemaObject } from '../../../openApi/3.1.0/types/spec'; 2 + // TODO: parser - add new parser schema object to `nameBuilder` 3 + // import type { SchemaObject as OpenApiV3_0_0SchemaObject } from '../../../openApi/3.0.x/types/spec'; 4 + import type { SchemaObject as OpenApiV3_1_0SchemaObject } from '../../../openApi/3.1.x/types/spec'; 3 5 import type { PluginName } from '../../types'; 4 6 5 7 export interface Config extends PluginName<'@hey-api/schemas'> {