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

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #1906 from hey-api/feat/exclude-deprecated

fix: support excluding deprecated fields

authored by

Lubos and committed by
GitHub
cb70338d a60e58f9

+477 -142
+5
.changeset/spotty-garlics-burn.md
··· 1 + --- 2 + '@hey-api/openapi-ts': patch 3 + --- 4 + 5 + fix: exclude and include expressions can be an array
+5
.changeset/wicked-zoos-beam.md
··· 1 + --- 2 + '@hey-api/openapi-ts': patch 3 + --- 4 + 5 + fix: support excluding deprecated fields with '@deprecated'
+35 -14
packages/openapi-ts-tests/test/2.0.x.test.ts
··· 15 15 const outputDir = path.join(__dirname, 'generated', version); 16 16 17 17 describe(`OpenAPI ${version}`, () => { 18 - const createConfig = (userConfig: UserConfig): UserConfig => ({ 19 - plugins: ['@hey-api/typescript'], 20 - ...userConfig, 21 - input: path.join( 18 + const createConfig = (userConfig: UserConfig): UserConfig => { 19 + const inputPath = path.join( 22 20 __dirname, 23 21 'spec', 24 22 version, 25 - typeof userConfig.input === 'string' ? userConfig.input : '', 26 - ), 27 - logs: { 28 - level: 'silent', 29 - }, 30 - output: path.join( 31 - outputDir, 32 - typeof userConfig.output === 'string' ? userConfig.output : '', 33 - ), 34 - }); 23 + typeof userConfig.input === 'string' 24 + ? userConfig.input 25 + : (userConfig.input.path as string), 26 + ); 27 + return { 28 + plugins: ['@hey-api/typescript'], 29 + ...userConfig, 30 + input: 31 + typeof userConfig.input === 'string' 32 + ? inputPath 33 + : { 34 + ...userConfig.input, 35 + path: inputPath, 36 + }, 37 + logs: { 38 + level: 'silent', 39 + }, 40 + output: path.join( 41 + outputDir, 42 + typeof userConfig.output === 'string' ? userConfig.output : '', 43 + ), 44 + }; 45 + }; 35 46 36 47 const scenarios = [ 37 48 { ··· 202 213 }), 203 214 description: 204 215 'handles various enum names and values (TypeScript, preserve)', 216 + }, 217 + { 218 + config: createConfig({ 219 + input: { 220 + exclude: ['@deprecated'], 221 + path: 'exclude-deprecated.yaml', 222 + }, 223 + output: 'exclude-deprecated', 224 + }), 225 + description: 'excludes deprecated fields', 205 226 }, 206 227 { 207 228 config: createConfig({
+35 -14
packages/openapi-ts-tests/test/3.0.x.test.ts
··· 15 15 const outputDir = path.join(__dirname, 'generated', version); 16 16 17 17 describe(`OpenAPI ${version}`, () => { 18 - const createConfig = (userConfig: UserConfig): UserConfig => ({ 19 - plugins: ['@hey-api/typescript'], 20 - ...userConfig, 21 - input: path.join( 18 + const createConfig = (userConfig: UserConfig): UserConfig => { 19 + const inputPath = path.join( 22 20 __dirname, 23 21 'spec', 24 22 version, 25 - typeof userConfig.input === 'string' ? userConfig.input : '', 26 - ), 27 - logs: { 28 - level: 'silent', 29 - }, 30 - output: path.join( 31 - outputDir, 32 - typeof userConfig.output === 'string' ? userConfig.output : '', 33 - ), 34 - }); 23 + typeof userConfig.input === 'string' 24 + ? userConfig.input 25 + : (userConfig.input.path as string), 26 + ); 27 + return { 28 + plugins: ['@hey-api/typescript'], 29 + ...userConfig, 30 + input: 31 + typeof userConfig.input === 'string' 32 + ? inputPath 33 + : { 34 + ...userConfig.input, 35 + path: inputPath, 36 + }, 37 + logs: { 38 + level: 'silent', 39 + }, 40 + output: path.join( 41 + outputDir, 42 + typeof userConfig.output === 'string' ? userConfig.output : '', 43 + ), 44 + }; 45 + }; 35 46 36 47 const scenarios = [ 37 48 { ··· 387 398 output: 'enum-null', 388 399 }), 389 400 description: 'handles null enums', 401 + }, 402 + { 403 + config: createConfig({ 404 + input: { 405 + exclude: ['@deprecated'], 406 + path: 'exclude-deprecated.yaml', 407 + }, 408 + output: 'exclude-deprecated', 409 + }), 410 + description: 'excludes deprecated fields', 390 411 }, 391 412 { 392 413 config: createConfig({
+35 -14
packages/openapi-ts-tests/test/3.1.x.test.ts
··· 15 15 const outputDir = path.join(__dirname, 'generated', version); 16 16 17 17 describe(`OpenAPI ${version}`, () => { 18 - const createConfig = (userConfig: UserConfig): UserConfig => ({ 19 - plugins: ['@hey-api/typescript'], 20 - ...userConfig, 21 - input: path.join( 18 + const createConfig = (userConfig: UserConfig): UserConfig => { 19 + const inputPath = path.join( 22 20 __dirname, 23 21 'spec', 24 22 version, 25 - typeof userConfig.input === 'string' ? userConfig.input : '', 26 - ), 27 - logs: { 28 - level: 'silent', 29 - }, 30 - output: path.join( 31 - outputDir, 32 - typeof userConfig.output === 'string' ? userConfig.output : '', 33 - ), 34 - }); 23 + typeof userConfig.input === 'string' 24 + ? userConfig.input 25 + : (userConfig.input.path as string), 26 + ); 27 + return { 28 + plugins: ['@hey-api/typescript'], 29 + ...userConfig, 30 + input: 31 + typeof userConfig.input === 'string' 32 + ? inputPath 33 + : { 34 + ...userConfig.input, 35 + path: inputPath, 36 + }, 37 + logs: { 38 + level: 'silent', 39 + }, 40 + output: path.join( 41 + outputDir, 42 + typeof userConfig.output === 'string' ? userConfig.output : '', 43 + ), 44 + }; 45 + }; 35 46 36 47 const scenarios = [ 37 48 { ··· 401 412 output: 'enum-null', 402 413 }), 403 414 description: 'handles null enums', 415 + }, 416 + { 417 + config: createConfig({ 418 + input: { 419 + exclude: ['@deprecated'], 420 + path: 'exclude-deprecated.yaml', 421 + }, 422 + output: 'exclude-deprecated', 423 + }), 424 + description: 'excludes deprecated fields', 404 425 }, 405 426 { 406 427 config: createConfig({
+2
packages/openapi-ts-tests/test/__snapshots__/2.0.x/exclude-deprecated/index.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + export * from './types.gen';
+21
packages/openapi-ts-tests/test/__snapshots__/2.0.x/exclude-deprecated/types.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export type Foo = string; 4 + 5 + export type PostFooData = { 6 + body: Foo; 7 + path?: never; 8 + query?: never; 9 + url: '/foo'; 10 + }; 11 + 12 + export type PostFooResponses = { 13 + /** 14 + * OK 15 + */ 16 + 200: unknown; 17 + }; 18 + 19 + export type ClientOptions = { 20 + baseUrl: string; 21 + };
+2
packages/openapi-ts-tests/test/__snapshots__/3.0.x/exclude-deprecated/index.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + export * from './types.gen';
+21
packages/openapi-ts-tests/test/__snapshots__/3.0.x/exclude-deprecated/types.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export type Foo = string; 4 + 5 + export type PostFooData = { 6 + body: Foo; 7 + path?: never; 8 + query?: never; 9 + url: '/foo'; 10 + }; 11 + 12 + export type PostFooResponses = { 13 + /** 14 + * OK 15 + */ 16 + 200: unknown; 17 + }; 18 + 19 + export type ClientOptions = { 20 + baseUrl: `${string}://${string}` | (string & {}); 21 + };
+2
packages/openapi-ts-tests/test/__snapshots__/3.1.x/exclude-deprecated/index.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + export * from './types.gen';
+21
packages/openapi-ts-tests/test/__snapshots__/3.1.x/exclude-deprecated/types.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export type Foo = string; 4 + 5 + export type PostFooData = { 6 + body: Foo; 7 + path?: never; 8 + query?: never; 9 + url: '/foo'; 10 + }; 11 + 12 + export type PostFooResponses = { 13 + /** 14 + * OK 15 + */ 16 + 200: unknown; 17 + }; 18 + 19 + export type ClientOptions = { 20 + baseUrl: `${string}://${string}` | (string & {}); 21 + };
+5 -2
packages/openapi-ts-tests/test/openapi-ts.config.ts
··· 16 16 // experimentalParser: false, 17 17 input: { 18 18 // branch: 'main', 19 - // exclude: '^#/components/schemas/ModelWithCircularReference$', 19 + // exclude: [ 20 + // '^#/components/schemas/ModelWithCircularReference$', 21 + // '@deprecated', 22 + // ], 20 23 // fetch: { 21 24 // headers: { 22 25 // 'x-foo': 'bar', ··· 33 36 // openapi: '3.1.0', 34 37 // paths: {}, 35 38 // }, 36 - path: path.resolve(__dirname, 'spec', '3.1.x', 'validators.json'), 39 + path: path.resolve(__dirname, 'spec', '3.1.x', 'full.json'), 37 40 // path: path.resolve(__dirname, 'spec', '3.1.x', 'read-write-only.yaml'), 38 41 // path: 'http://localhost:4000/', 39 42 // path: 'https://get.heyapi.dev/',
+38
packages/openapi-ts-tests/test/spec/2.0.x/exclude-deprecated.yaml
··· 1 + swagger: '2.0' 2 + info: 3 + title: OpenAPI 2.0 exclude deprecated example 4 + version: '1' 5 + produces: 6 + - application/json 7 + consumes: 8 + - application/json 9 + paths: 10 + /foo: 11 + post: 12 + parameters: 13 + - name: body 14 + in: body 15 + required: true 16 + schema: 17 + $ref: '#/definitions/Foo' 18 + responses: 19 + '200': 20 + description: OK 21 + /bar: 22 + post: 23 + deprecated: true 24 + parameters: 25 + - name: body 26 + in: body 27 + required: true 28 + schema: 29 + $ref: '#/definitions/Bar' 30 + responses: 31 + '200': 32 + description: OK 33 + definitions: 34 + Foo: 35 + type: string 36 + Bar: 37 + deprecated: true 38 + type: string
+35
packages/openapi-ts-tests/test/spec/3.0.x/exclude-deprecated.yaml
··· 1 + openapi: 3.0.4 2 + info: 3 + title: OpenAPI 3.0.4 exclude deprecated example 4 + version: 1 5 + paths: 6 + /foo: 7 + post: 8 + requestBody: 9 + content: 10 + 'application/json': 11 + schema: 12 + $ref: '#/components/schemas/Foo' 13 + required: true 14 + responses: 15 + '200': 16 + description: OK 17 + /bar: 18 + post: 19 + deprecated: true 20 + requestBody: 21 + content: 22 + 'application/json': 23 + schema: 24 + $ref: '#/components/schemas/Bar' 25 + required: true 26 + responses: 27 + '200': 28 + description: OK 29 + components: 30 + schemas: 31 + Foo: 32 + type: string 33 + Bar: 34 + deprecated: true 35 + type: string
+35
packages/openapi-ts-tests/test/spec/3.1.x/exclude-deprecated.yaml
··· 1 + openapi: 3.1.1 2 + info: 3 + title: OpenAPI 3.1.1 exclude deprecated example 4 + version: 1 5 + paths: 6 + /foo: 7 + post: 8 + requestBody: 9 + content: 10 + 'application/json': 11 + schema: 12 + $ref: '#/components/schemas/Foo' 13 + required: true 14 + responses: 15 + '200': 16 + description: OK 17 + /bar: 18 + post: 19 + deprecated: true 20 + requestBody: 21 + content: 22 + 'application/json': 23 + schema: 24 + $ref: '#/components/schemas/Bar' 25 + required: true 26 + responses: 27 + '200': 28 + description: OK 29 + components: 30 + schemas: 31 + Foo: 32 + type: string 33 + Bar: 34 + deprecated: true 35 + type: string
+26 -20
packages/openapi-ts/src/openApi/2.0.x/parser/index.ts
··· 1 1 import type { IR } from '../../../ir/types'; 2 - import { canProcessRef } from '../../shared/utils/filter'; 2 + import { canProcessRef, createFilters } from '../../shared/utils/filter'; 3 3 import { mergeParametersObjects } from '../../shared/utils/parameter'; 4 4 import type { 5 5 OpenApiV2_0_X, ··· 20 20 const operationIds = new Map<string, string>(); 21 21 const securitySchemesMap = new Map<string, SecuritySchemeObject>(); 22 22 23 - const excludeRegExp = context.config.input.exclude 24 - ? new RegExp(context.config.input.exclude) 25 - : undefined; 26 - const includeRegExp = context.config.input.include 27 - ? new RegExp(context.config.input.include) 28 - : undefined; 23 + const excludeFilters = createFilters(context.config.input.exclude); 24 + const includeFilters = createFilters(context.config.input.include); 29 25 30 - const shouldProcessRef = ($ref: string) => 26 + const shouldProcessRef = ($ref: string, schema: Record<string, any>) => 31 27 canProcessRef({ 32 28 $ref, 33 - excludeRegExp, 34 - includeRegExp, 29 + excludeFilters, 30 + includeFilters, 31 + schema, 35 32 }); 36 33 37 34 for (const name in context.spec.securityDefinitions) { ··· 42 39 if (context.spec.definitions) { 43 40 for (const name in context.spec.definitions) { 44 41 const $ref = `#/definitions/${name}`; 45 - if (!shouldProcessRef($ref)) { 42 + const schema = context.spec.definitions[name]!; 43 + 44 + if (!shouldProcessRef($ref, schema)) { 46 45 continue; 47 46 } 48 - 49 - const schema = context.spec.definitions[name]!; 50 47 51 48 parseSchema({ 52 49 $ref, ··· 96 93 }; 97 94 98 95 const $refDelete = `#/paths${path}/delete`; 99 - if (finalPathItem.delete && shouldProcessRef($refDelete)) { 96 + if ( 97 + finalPathItem.delete && 98 + shouldProcessRef($refDelete, finalPathItem.delete) 99 + ) { 100 100 const parameters = mergeParametersObjects({ 101 101 source: parametersArrayToObject({ 102 102 context, ··· 117 117 } 118 118 119 119 const $refGet = `#/paths${path}/get`; 120 - if (finalPathItem.get && shouldProcessRef($refGet)) { 120 + if (finalPathItem.get && shouldProcessRef($refGet, finalPathItem.get)) { 121 121 const parameters = mergeParametersObjects({ 122 122 source: parametersArrayToObject({ 123 123 context, ··· 138 138 } 139 139 140 140 const $refHead = `#/paths${path}/head`; 141 - if (finalPathItem.head && shouldProcessRef($refHead)) { 141 + if (finalPathItem.head && shouldProcessRef($refHead, finalPathItem.head)) { 142 142 const parameters = mergeParametersObjects({ 143 143 source: parametersArrayToObject({ 144 144 context, ··· 159 159 } 160 160 161 161 const $refOptions = `#/paths${path}/options`; 162 - if (finalPathItem.options && shouldProcessRef($refOptions)) { 162 + if ( 163 + finalPathItem.options && 164 + shouldProcessRef($refOptions, finalPathItem.options) 165 + ) { 163 166 const parameters = mergeParametersObjects({ 164 167 source: parametersArrayToObject({ 165 168 context, ··· 180 183 } 181 184 182 185 const $refPatch = `#/paths${path}/patch`; 183 - if (finalPathItem.patch && shouldProcessRef($refPatch)) { 186 + if ( 187 + finalPathItem.patch && 188 + shouldProcessRef($refPatch, finalPathItem.patch) 189 + ) { 184 190 const parameters = mergeParametersObjects({ 185 191 source: parametersArrayToObject({ 186 192 context, ··· 201 207 } 202 208 203 209 const $refPost = `#/paths${path}/post`; 204 - if (finalPathItem.post && shouldProcessRef($refPost)) { 210 + if (finalPathItem.post && shouldProcessRef($refPost, finalPathItem.post)) { 205 211 const parameters = mergeParametersObjects({ 206 212 source: parametersArrayToObject({ 207 213 context, ··· 222 228 } 223 229 224 230 const $refPut = `#/paths${path}/put`; 225 - if (finalPathItem.put && shouldProcessRef($refPut)) { 231 + if (finalPathItem.put && shouldProcessRef($refPut, finalPathItem.put)) { 226 232 const parameters = mergeParametersObjects({ 227 233 source: parametersArrayToObject({ 228 234 context,
+38 -29
packages/openapi-ts/src/openApi/3.0.x/parser/index.ts
··· 1 1 import type { IR } from '../../../ir/types'; 2 - import { canProcessRef } from '../../shared/utils/filter'; 2 + import { canProcessRef, createFilters } from '../../shared/utils/filter'; 3 3 import { mergeParametersObjects } from '../../shared/utils/parameter'; 4 4 import type { 5 5 OpenApiV3_0_X, ··· 19 19 const operationIds = new Map<string, string>(); 20 20 const securitySchemesMap = new Map<string, SecuritySchemeObject>(); 21 21 22 - const excludeRegExp = context.config.input.exclude 23 - ? new RegExp(context.config.input.exclude) 24 - : undefined; 25 - const includeRegExp = context.config.input.include 26 - ? new RegExp(context.config.input.include) 27 - : undefined; 22 + const excludeFilters = createFilters(context.config.input.exclude); 23 + const includeFilters = createFilters(context.config.input.include); 28 24 29 - const shouldProcessRef = ($ref: string) => 25 + const shouldProcessRef = ($ref: string, schema: Record<string, any>) => 30 26 canProcessRef({ 31 27 $ref, 32 - excludeRegExp, 33 - includeRegExp, 28 + excludeFilters, 29 + includeFilters, 30 + schema, 34 31 }); 35 32 36 33 // TODO: parser - handle more component types, old parser handles only parameters and schemas ··· 47 44 48 45 for (const name in context.spec.components.parameters) { 49 46 const $ref = `#/components/parameters/${name}`; 50 - if (!shouldProcessRef($ref)) { 51 - continue; 52 - } 53 - 54 47 const parameterOrReference = context.spec.components.parameters[name]!; 55 48 const parameter = 56 49 '$ref' in parameterOrReference 57 50 ? context.resolveRef<ParameterObject>(parameterOrReference.$ref) 58 51 : parameterOrReference; 52 + 53 + if (!shouldProcessRef($ref, parameter)) { 54 + continue; 55 + } 59 56 60 57 parseParameter({ 61 58 $ref, ··· 66 63 67 64 for (const name in context.spec.components.requestBodies) { 68 65 const $ref = `#/components/requestBodies/${name}`; 69 - if (!shouldProcessRef($ref)) { 70 - continue; 71 - } 72 - 73 66 const requestBodyOrReference = 74 67 context.spec.components.requestBodies[name]!; 75 68 const requestBody = ··· 77 70 ? context.resolveRef<RequestBodyObject>(requestBodyOrReference.$ref) 78 71 : requestBodyOrReference; 79 72 73 + if (!shouldProcessRef($ref, requestBody)) { 74 + continue; 75 + } 76 + 80 77 parseRequestBody({ 81 78 $ref, 82 79 context, ··· 86 83 87 84 for (const name in context.spec.components.schemas) { 88 85 const $ref = `#/components/schemas/${name}`; 89 - if (!shouldProcessRef($ref)) { 86 + const schema = context.spec.components.schemas[name]!; 87 + 88 + if (!shouldProcessRef($ref, schema)) { 90 89 continue; 91 90 } 92 - 93 - const schema = context.spec.components.schemas[name]!; 94 91 95 92 parseSchema({ 96 93 $ref, ··· 139 136 }; 140 137 141 138 const $refDelete = `#/paths${path}/delete`; 142 - if (finalPathItem.delete && shouldProcessRef($refDelete)) { 139 + if ( 140 + finalPathItem.delete && 141 + shouldProcessRef($refDelete, finalPathItem.delete) 142 + ) { 143 143 parseOperation({ 144 144 ...operationArgs, 145 145 method: 'delete', ··· 158 158 } 159 159 160 160 const $refGet = `#/paths${path}/get`; 161 - if (finalPathItem.get && shouldProcessRef($refGet)) { 161 + if (finalPathItem.get && shouldProcessRef($refGet, finalPathItem.get)) { 162 162 parseOperation({ 163 163 ...operationArgs, 164 164 method: 'get', ··· 177 177 } 178 178 179 179 const $refHead = `#/paths${path}/head`; 180 - if (finalPathItem.head && shouldProcessRef($refHead)) { 180 + if (finalPathItem.head && shouldProcessRef($refHead, finalPathItem.head)) { 181 181 parseOperation({ 182 182 ...operationArgs, 183 183 method: 'head', ··· 196 196 } 197 197 198 198 const $refOptions = `#/paths${path}/options`; 199 - if (finalPathItem.options && shouldProcessRef($refOptions)) { 199 + if ( 200 + finalPathItem.options && 201 + shouldProcessRef($refOptions, finalPathItem.options) 202 + ) { 200 203 parseOperation({ 201 204 ...operationArgs, 202 205 method: 'options', ··· 215 218 } 216 219 217 220 const $refPatch = `#/paths${path}/patch`; 218 - if (finalPathItem.patch && shouldProcessRef($refPatch)) { 221 + if ( 222 + finalPathItem.patch && 223 + shouldProcessRef($refPatch, finalPathItem.patch) 224 + ) { 219 225 parseOperation({ 220 226 ...operationArgs, 221 227 method: 'patch', ··· 234 240 } 235 241 236 242 const $refPost = `#/paths${path}/post`; 237 - if (finalPathItem.post && shouldProcessRef($refPost)) { 243 + if (finalPathItem.post && shouldProcessRef($refPost, finalPathItem.post)) { 238 244 parseOperation({ 239 245 ...operationArgs, 240 246 method: 'post', ··· 253 259 } 254 260 255 261 const $refPut = `#/paths${path}/put`; 256 - if (finalPathItem.put && shouldProcessRef($refPut)) { 262 + if (finalPathItem.put && shouldProcessRef($refPut, finalPathItem.put)) { 257 263 parseOperation({ 258 264 ...operationArgs, 259 265 method: 'put', ··· 272 278 } 273 279 274 280 const $refTrace = `#/paths${path}/trace`; 275 - if (finalPathItem.trace && shouldProcessRef($refTrace)) { 281 + if ( 282 + finalPathItem.trace && 283 + shouldProcessRef($refTrace, finalPathItem.trace) 284 + ) { 276 285 parseOperation({ 277 286 ...operationArgs, 278 287 method: 'trace',
+38 -29
packages/openapi-ts/src/openApi/3.1.x/parser/index.ts
··· 1 1 import type { IR } from '../../../ir/types'; 2 - import { canProcessRef } from '../../shared/utils/filter'; 2 + import { canProcessRef, createFilters } from '../../shared/utils/filter'; 3 3 import { mergeParametersObjects } from '../../shared/utils/parameter'; 4 4 import type { 5 5 OpenApiV3_1_X, ··· 19 19 const operationIds = new Map<string, string>(); 20 20 const securitySchemesMap = new Map<string, SecuritySchemeObject>(); 21 21 22 - const excludeRegExp = context.config.input.exclude 23 - ? new RegExp(context.config.input.exclude) 24 - : undefined; 25 - const includeRegExp = context.config.input.include 26 - ? new RegExp(context.config.input.include) 27 - : undefined; 22 + const excludeFilters = createFilters(context.config.input.exclude); 23 + const includeFilters = createFilters(context.config.input.include); 28 24 29 - const shouldProcessRef = ($ref: string) => 25 + const shouldProcessRef = ($ref: string, schema: Record<string, any>) => 30 26 canProcessRef({ 31 27 $ref, 32 - excludeRegExp, 33 - includeRegExp, 28 + excludeFilters, 29 + includeFilters, 30 + schema, 34 31 }); 35 32 36 33 // TODO: parser - handle more component types, old parser handles only parameters and schemas ··· 47 44 48 45 for (const name in context.spec.components.parameters) { 49 46 const $ref = `#/components/parameters/${name}`; 50 - if (!shouldProcessRef($ref)) { 51 - continue; 52 - } 53 - 54 47 const parameterOrReference = context.spec.components.parameters[name]!; 55 48 const parameter = 56 49 '$ref' in parameterOrReference 57 50 ? context.resolveRef<ParameterObject>(parameterOrReference.$ref) 58 51 : parameterOrReference; 52 + 53 + if (!shouldProcessRef($ref, parameter)) { 54 + continue; 55 + } 59 56 60 57 parseParameter({ 61 58 $ref, ··· 66 63 67 64 for (const name in context.spec.components.requestBodies) { 68 65 const $ref = `#/components/requestBodies/${name}`; 69 - if (!shouldProcessRef($ref)) { 70 - continue; 71 - } 72 - 73 66 const requestBodyOrReference = 74 67 context.spec.components.requestBodies[name]!; 75 68 const requestBody = ··· 77 70 ? context.resolveRef<RequestBodyObject>(requestBodyOrReference.$ref) 78 71 : requestBodyOrReference; 79 72 73 + if (!shouldProcessRef($ref, requestBody)) { 74 + continue; 75 + } 76 + 80 77 parseRequestBody({ 81 78 $ref, 82 79 context, ··· 86 83 87 84 for (const name in context.spec.components.schemas) { 88 85 const $ref = `#/components/schemas/${name}`; 89 - if (!shouldProcessRef($ref)) { 86 + const schema = context.spec.components.schemas[name]!; 87 + 88 + if (!shouldProcessRef($ref, schema)) { 90 89 continue; 91 90 } 92 - 93 - const schema = context.spec.components.schemas[name]!; 94 91 95 92 parseSchema({ 96 93 $ref, ··· 132 129 }; 133 130 134 131 const $refDelete = `#/paths${path}/delete`; 135 - if (finalPathItem.delete && shouldProcessRef($refDelete)) { 132 + if ( 133 + finalPathItem.delete && 134 + shouldProcessRef($refDelete, finalPathItem.delete) 135 + ) { 136 136 parseOperation({ 137 137 ...operationArgs, 138 138 method: 'delete', ··· 151 151 } 152 152 153 153 const $refGet = `#/paths${path}/get`; 154 - if (finalPathItem.get && shouldProcessRef($refGet)) { 154 + if (finalPathItem.get && shouldProcessRef($refGet, finalPathItem.get)) { 155 155 parseOperation({ 156 156 ...operationArgs, 157 157 method: 'get', ··· 170 170 } 171 171 172 172 const $refHead = `#/paths${path}/head`; 173 - if (finalPathItem.head && shouldProcessRef($refHead)) { 173 + if (finalPathItem.head && shouldProcessRef($refHead, finalPathItem.head)) { 174 174 parseOperation({ 175 175 ...operationArgs, 176 176 method: 'head', ··· 189 189 } 190 190 191 191 const $refOptions = `#/paths${path}/options`; 192 - if (finalPathItem.options && shouldProcessRef($refOptions)) { 192 + if ( 193 + finalPathItem.options && 194 + shouldProcessRef($refOptions, finalPathItem.options) 195 + ) { 193 196 parseOperation({ 194 197 ...operationArgs, 195 198 method: 'options', ··· 208 211 } 209 212 210 213 const $refPatch = `#/paths${path}/patch`; 211 - if (finalPathItem.patch && shouldProcessRef($refPatch)) { 214 + if ( 215 + finalPathItem.patch && 216 + shouldProcessRef($refPatch, finalPathItem.patch) 217 + ) { 212 218 parseOperation({ 213 219 ...operationArgs, 214 220 method: 'patch', ··· 227 233 } 228 234 229 235 const $refPost = `#/paths${path}/post`; 230 - if (finalPathItem.post && shouldProcessRef($refPost)) { 236 + if (finalPathItem.post && shouldProcessRef($refPost, finalPathItem.post)) { 231 237 parseOperation({ 232 238 ...operationArgs, 233 239 method: 'post', ··· 246 252 } 247 253 248 254 const $refPut = `#/paths${path}/put`; 249 - if (finalPathItem.put && shouldProcessRef($refPut)) { 255 + if (finalPathItem.put && shouldProcessRef($refPut, finalPathItem.put)) { 250 256 parseOperation({ 251 257 ...operationArgs, 252 258 method: 'put', ··· 265 271 } 266 272 267 273 const $refTrace = `#/paths${path}/trace`; 268 - if (finalPathItem.trace && shouldProcessRef($refTrace)) { 274 + if ( 275 + finalPathItem.trace && 276 + shouldProcessRef($refTrace, finalPathItem.trace) 277 + ) { 269 278 parseOperation({ 270 279 ...operationArgs, 271 280 method: 'trace',
+67 -12
packages/openapi-ts/src/openApi/shared/utils/filter.ts
··· 1 + type Filter = RegExp | ReadonlyArray<string>; 2 + type Filters = ReadonlyArray<Filter> | undefined; 3 + 4 + const isFiltersMatch = ({ 5 + $ref, 6 + filters, 7 + schema, 8 + }: { 9 + $ref: string; 10 + filters: NonNullable<Filters>; 11 + schema: Record<string, unknown>; 12 + }): boolean => { 13 + for (const filter of filters) { 14 + if (filter instanceof RegExp) { 15 + filter.lastIndex = 0; 16 + if (filter.test($ref)) { 17 + return true; 18 + } 19 + } else { 20 + const field = filter[0] || ''; 21 + const value = filter[1]; 22 + if (value === undefined) { 23 + if (schema[field]) { 24 + return true; 25 + } 26 + } else if (schema[field] === value) { 27 + return true; 28 + } 29 + } 30 + } 31 + 32 + return false; 33 + }; 34 + 1 35 /** 2 36 * Exclude takes precedence over include. 3 37 */ 4 38 export const canProcessRef = ({ 5 - $ref, 6 - excludeRegExp, 7 - includeRegExp, 39 + excludeFilters, 40 + includeFilters, 41 + ...state 8 42 }: { 9 43 $ref: string; 10 - excludeRegExp?: RegExp; 11 - includeRegExp?: RegExp; 44 + excludeFilters: Filters; 45 + includeFilters: Filters; 46 + schema: Record<string, unknown>; 12 47 }): boolean => { 13 - if (!excludeRegExp && !includeRegExp) { 48 + if (!excludeFilters && !includeFilters) { 14 49 return true; 15 50 } 16 51 17 - if (excludeRegExp) { 18 - excludeRegExp.lastIndex = 0; 19 - if (excludeRegExp.test($ref)) { 52 + if (excludeFilters) { 53 + if (isFiltersMatch({ ...state, filters: excludeFilters })) { 20 54 return false; 21 55 } 22 56 } 23 57 24 - if (includeRegExp) { 25 - includeRegExp.lastIndex = 0; 26 - return includeRegExp.test($ref); 58 + if (includeFilters) { 59 + return isFiltersMatch({ ...state, filters: includeFilters }); 27 60 } 28 61 29 62 return true; 30 63 }; 64 + 65 + const createFilter = (matcher: string): Filter => { 66 + if (matcher.startsWith('@')) { 67 + return matcher.slice(1).split(':'); 68 + } 69 + 70 + return new RegExp(matcher); 71 + }; 72 + 73 + export const createFilters = ( 74 + matchers: ReadonlyArray<string> | string | undefined, 75 + ): Filters => { 76 + if (!matchers) { 77 + return; 78 + } 79 + 80 + if (typeof matchers === 'string') { 81 + return [createFilter(matchers)]; 82 + } 83 + 84 + return matchers.map((matcher) => createFilter(matcher)); 85 + };
+11 -8
packages/openapi-ts/src/types/config.d.ts
··· 39 39 */ 40 40 commit_sha?: string; 41 41 /** 42 - * Prevent parts matching the regular expression from being processed. 42 + * Prevent parts matching the regular expression(s) from being processed. 43 43 * You can select both operations and components by reference within 44 - * the bundled input. In case of conflicts, `exclude` takes precedence 45 - * over `include`. 44 + * the bundled input. 45 + * 46 + * In case of conflicts, `exclude` takes precedence over `include`. 46 47 * 47 48 * @example 48 49 * operation: '^#/paths/api/v1/foo/get$' 49 50 * schema: '^#/components/schemas/Foo$' 51 + * deprecated: '@deprecated' 50 52 */ 51 - exclude?: string; 53 + exclude?: ReadonlyArray<string> | string; 52 54 /** 53 55 * You pass any valid Fetch API options to the request for fetching your 54 56 * specification. This is useful if your file is behind auth for example. 55 57 */ 56 58 fetch?: RequestInit; 57 59 /** 58 - * Process only parts matching the regular expression. You can select both 59 - * operations and components by reference within the bundled input. In 60 - * case of conflicts, `exclude` takes precedence over `include`. 60 + * Process only parts matching the regular expression(s). You can select both 61 + * operations and components by reference within the bundled input. 62 + * 63 + * In case of conflicts, `exclude` takes precedence over `include`. 61 64 * 62 65 * @example 63 66 * operation: '^#/paths/api/v1/foo/get$' 64 67 * schema: '^#/components/schemas/Foo$' 65 68 */ 66 - include?: string; 69 + include?: ReadonlyArray<string> | string; 67 70 /** 68 71 * **Requires `path` to start with `https://get.heyapi.dev` or be undefined** 69 72 *