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 #2215 from hey-api/refactor/plugin-walk

refactor(parser): replace plugin.subscribe with plugin.walk

authored by

Lubos and committed by
GitHub
0eb8683b 41280004

+506 -665
+15
.changeset/lucky-bees-exist.md
··· 1 + --- 2 + '@hey-api/openapi-ts': minor 3 + --- 4 + 5 + feat(parser): replace `plugin.subscribe()` with `plugin.forEach()` 6 + 7 + ### Added `plugin.forEach()` method 8 + 9 + This method replaces the `.subscribe()` method. Additionally, `.forEach()` is executed immediately, which means we don't need the `before` and `after` events – simply move your code before and after the `.forEach()` block. 10 + 11 + ```ts 12 + plugin.forEach('operation', 'schema', (event) => { 13 + // do something with event 14 + }); 15 + ```
+16
docs/openapi-ts/migrating.md
··· 27 27 28 28 This config option is deprecated and will be removed. 29 29 30 + ## v0.75.0 31 + 32 + ### Added `plugin.forEach()` method 33 + 34 + This method replaces the `.subscribe()` method. Additionally, `.forEach()` is executed immediately, which means we don't need the `before` and `after` events – simply move your code before and after the `.forEach()` block. 35 + 36 + ```ts 37 + plugin.subscribe('operation', (event) => { // [!code --] 38 + // do something with event // [!code --] 39 + }); // [!code --] 40 + plugin.subscribe('schema', (event) => { // [!code --] 41 + plugin.forEach('operation', 'schema', (event) => { // [!code ++] 42 + // do something with event 43 + }); 44 + ``` 45 + 30 46 ## v0.74.0 31 47 32 48 ### Single Zod schema per request
+6 -14
docs/openapi-ts/plugins/custom.md
··· 118 118 path: plugin.output, 119 119 }); 120 120 121 - plugin.subscribe('before', () => { 122 - // do something before parsing the input 123 - }); 124 - 125 - plugin.subscribe('operation', ({ operation }) => { 126 - // do something with the operation model 127 - }); 128 - 129 - plugin.subscribe('schema', ({ operation }) => { 130 - // do something with the schema model 131 - }); 132 - 133 - plugin.subscribe('after', () => { 134 - // do something after parsing the input 121 + plugin.forEach('operation', 'schema', (event) => { 122 + if (event.type === 'operation') { 123 + // do something with the operation model 124 + } else if (event.type === 'schema') { 125 + // do something with the schema model 126 + } 135 127 }); 136 128 137 129 // we're using the TypeScript Compiler API
+8 -8
packages/openapi-ts-tests/test/openapi-ts.config.ts
··· 57 57 // 'invalid', 58 58 // 'servers-entry.yaml', 59 59 // ), 60 - path: path.resolve(__dirname, 'spec', '3.1.x', 'validators.yaml'), 61 - // path: path.resolve(__dirname, 'spec', 'v3-transforms.json'), 60 + // path: path.resolve(__dirname, 'spec', '3.1.x', 'validators.yaml'), 61 + path: path.resolve(__dirname, 'spec', 'v3-transforms.json'), 62 62 // path: 'http://localhost:4000/', 63 63 // path: 'https://get.heyapi.dev/', 64 64 // path: 'https://get.heyapi.dev/hey-api/backend?branch=main&version=1.0.0', ··· 93 93 // ), 94 94 }, 95 95 plugins: [ 96 - customClientPlugin({ 97 - baseUrl: false, 98 - }), 96 + // customClientPlugin({ 97 + // baseUrl: false, 98 + // }), 99 99 // myClientPlugin(), 100 100 { 101 101 // baseUrl: false, ··· 123 123 // responseStyle: 'data', 124 124 // throwOnError: true, 125 125 // transformer: '@hey-api/transformers', 126 - // transformer: true, 126 + transformer: true, 127 127 validator: 'zod', 128 128 }, 129 129 { 130 130 // bigInt: true, 131 - dates: true, 132 - // name: '@hey-api/transformers', 131 + // dates: true, 132 + name: '@hey-api/transformers', 133 133 }, 134 134 { 135 135 enums: 'typescript+namespace',
+1 -4
packages/openapi-ts/src/generate/output.ts
··· 3 3 import ts from 'typescript'; 4 4 5 5 import { compiler } from '../compiler'; 6 - import { parseIR } from '../ir/parser'; 7 6 import type { IR } from '../ir/types'; 8 7 import { getClientPlugin } from '../plugins/@hey-api/client-core/utils'; 9 8 import { generateClientBundle } from './client'; ··· 33 32 } 34 33 35 34 for (const plugin of context.registerPlugins()) { 36 - plugin.run(); 35 + await plugin.run(); 37 36 } 38 - 39 - await parseIR({ context }); 40 37 41 38 if (!context.config.dryRun) { 42 39 const indexFile = context.createFile({
+9 -106
packages/openapi-ts/src/ir/context.ts
··· 1 1 import path from 'node:path'; 2 2 3 - import { HeyApiError } from '../error'; 4 3 import { TypeScriptFile } from '../generate/files'; 5 4 import { PluginInstance } from '../plugins/shared/utils/instance'; 6 5 import type { Config, StringCase } from '../types/config'; ··· 42 41 path: string; 43 42 } 44 43 45 - export interface Events { 46 - /** 47 - * Called after parsing. 48 - */ 49 - after: () => void; 50 - /** 51 - * Called before parsing. 52 - */ 53 - before: () => void; 54 - operation: (args: { 55 - method: keyof IR.PathItemObject; 56 - operation: IR.OperationObject; 57 - path: string; 58 - }) => void; 59 - parameter: (args: { 60 - $ref: string; 61 - name: string; 62 - parameter: IR.ParameterObject; 63 - }) => void; 64 - requestBody: (args: { 65 - $ref: string; 66 - name: string; 67 - requestBody: IR.RequestBodyObject; 68 - }) => void; 69 - schema: (args: { 70 - $ref: string; 71 - name: string; 72 - schema: IR.SchemaObject; 73 - }) => void; 74 - server: (args: { server: IR.ServerObject }) => void; 75 - } 76 - 77 - type ListenerWithMeta<T extends keyof Events> = { 78 - callbackFn: Events[T]; 79 - pluginName: string; 80 - }; 81 - 82 - type Listeners = { 83 - [T in keyof Events]?: Array<ListenerWithMeta<T>>; 84 - }; 85 - 86 44 export class IRContext<Spec extends Record<string, any> = any> { 87 45 /** 88 46 * Configuration for parsing and generating the output. This ··· 92 50 /** 93 51 * A map of files that will be generated from `spec`. 94 52 */ 95 - public files: Files; 53 + public files: Files = {}; 96 54 /** 97 55 * Intermediate representation model obtained from `spec`. 98 56 */ 99 - public ir: IR.Model; 57 + public ir: IR.Model = {}; 100 58 /** 101 59 * A map of registered plugin instances, keyed by plugin name. Plugins are 102 60 * registered through the `registerPlugin` method and can be accessed by ··· 107 65 * Resolved specification from `input`. 108 66 */ 109 67 public spec: Spec; 110 - 111 - /** 112 - * A map of event listeners. 113 - */ 114 - private listeners: Listeners; 115 68 116 69 constructor({ config, spec }: { config: Config; spec: Spec }) { 117 70 this.config = config; 118 - this.files = {}; 119 - this.ir = {}; 120 - this.listeners = {}; 121 71 this.spec = spec; 122 72 } 123 73 124 74 /** 125 - * Notify all event listeners about `event`. 126 - */ 127 - public async broadcast<T extends keyof Events>( 128 - event: T, 129 - ...args: Parameters<Events[T]> 130 - ): Promise<void> { 131 - const eventListeners = this.listeners[event]; 132 - 133 - if (eventListeners) { 134 - for (const listener of eventListeners) { 135 - try { 136 - await listener.callbackFn( 137 - // @ts-expect-error 138 - ...args, 139 - ); 140 - } catch (error) { 141 - const originalError = 142 - error instanceof Error ? error : new Error(String(error)); 143 - throw new HeyApiError({ 144 - args, 145 - error: originalError, 146 - event, 147 - name: 'BroadcastError', 148 - pluginName: listener.pluginName, 149 - }); 150 - } 151 - } 152 - } 153 - } 154 - 155 - /** 156 75 * Create and return a new TypeScript file. Also set the current file context 157 76 * to the newly created file. 158 77 */ ··· 216 135 } 217 136 218 137 /** 219 - * Generator that iterates through plugin order and registers each plugin. 220 - * Yields the registered plugin instance for each plugin name. 138 + * Registers all plugins in the order specified by the configuration and returns 139 + * an array of the registered PluginInstance objects. Each plugin is instantiated 140 + * and added to the context's plugins map. 141 + * 142 + * @returns {ReadonlyArray<PluginInstance>} An array of registered plugin instances in order. 221 143 */ 222 - public *registerPlugins(): Generator<PluginInstance> { 223 - for (const name of this.config.pluginOrder) { 224 - yield this.registerPlugin(name); 225 - } 144 + public registerPlugins(): ReadonlyArray<PluginInstance> { 145 + return this.config.pluginOrder.map((name) => this.registerPlugin(name)); 226 146 } 227 147 228 148 // TODO: parser - works the same as resolveRef, but for IR schemas. ··· 243 163 return resolveRef<T>({ 244 164 $ref, 245 165 spec: this.spec, 246 - }); 247 - } 248 - 249 - /** 250 - * Register a new `event` listener. 251 - */ 252 - public subscribe<T extends keyof Events>( 253 - event: T, 254 - callbackFn: Events[T], 255 - pluginName: string, 256 - ): void { 257 - if (!this.listeners[event]) { 258 - this.listeners[event] = []; 259 - } 260 - this.listeners[event].push({ 261 - callbackFn, 262 - pluginName: pluginName ?? '', 263 166 }); 264 167 } 265 168 }
-47
packages/openapi-ts/src/ir/parser.ts
··· 1 - import type { IR } from './types'; 2 - 3 - /** 4 - * Traverse the parsed intermediate representation model and broadcast 5 - * various events to listeners. 6 - */ 7 - export const parseIR = async ({ context }: { context: IR.Context }) => { 8 - await context.broadcast('before'); 9 - 10 - if (context.ir.servers) { 11 - for (const server of context.ir.servers) { 12 - await context.broadcast('server', { server }); 13 - } 14 - } 15 - 16 - if (context.ir.components) { 17 - for (const name in context.ir.components.schemas) { 18 - const schema = context.ir.components.schemas[name]!; 19 - const $ref = `#/components/schemas/${name}`; 20 - await context.broadcast('schema', { $ref, name, schema }); 21 - } 22 - 23 - for (const name in context.ir.components.parameters) { 24 - const parameter = context.ir.components.parameters[name]!; 25 - const $ref = `#/components/parameters/${name}`; 26 - await context.broadcast('parameter', { $ref, name, parameter }); 27 - } 28 - 29 - for (const name in context.ir.components.requestBodies) { 30 - const requestBody = context.ir.components.requestBodies[name]!; 31 - const $ref = `#/components/requestBodies/${name}`; 32 - await context.broadcast('requestBody', { $ref, name, requestBody }); 33 - } 34 - } 35 - 36 - for (const path in context.ir.paths) { 37 - const pathItem = context.ir.paths[path as keyof IR.PathsObject]; 38 - 39 - for (const _method in pathItem) { 40 - const method = _method as keyof IR.PathItemObject; 41 - const operation = pathItem[method]!; 42 - await context.broadcast('operation', { method, operation, path }); 43 - } 44 - } 45 - 46 - await context.broadcast('after'); 47 - };
+1 -2
packages/openapi-ts/src/ir/types.d.ts
··· 3 3 SecuritySchemeObject, 4 4 ServerObject, 5 5 } from '../openApi/3.1.x/types/spec'; 6 - import type { ContextFile as CtxFile, Events, IRContext } from './context'; 6 + import type { ContextFile as CtxFile, IRContext } from './context'; 7 7 import type { IRMediaType } from './mediaType'; 8 8 9 9 interface IRBodyObject { ··· 217 217 export type BodyObject = IRBodyObject; 218 218 export type ComponentsObject = IRComponentsObject; 219 219 export type Context<Spec extends Record<string, any> = any> = IRContext<Spec>; 220 - export type ContextEvents = Events; 221 220 export type ContextFile = CtxFile; 222 221 export type Model = IRModel; 223 222 export type OperationObject = IROperationObject;
+13 -15
packages/openapi-ts/src/plugins/@hey-api/sdk/plugin.ts
··· 123 123 ? createClientClassNodes({ plugin }) 124 124 : []; 125 125 126 - plugin.subscribe('operation', ({ operation }) => { 126 + plugin.forEach('operation', ({ operation }) => { 127 127 const isRequiredOptions = isOperationOptionsRequired({ 128 128 context: plugin.context, 129 129 operation, ··· 302 302 generatedClasses.add(currentClass.className); 303 303 }; 304 304 305 - plugin.subscribe('after', () => { 306 - if (clientClassNodes.length) { 307 - const node = compiler.classDeclaration({ 308 - exportClass: false, 309 - name: '_HeyApiClient', 310 - nodes: clientClassNodes, 311 - }); 312 - file.add(node); 313 - } 305 + if (clientClassNodes.length) { 306 + const node = compiler.classDeclaration({ 307 + exportClass: false, 308 + name: '_HeyApiClient', 309 + nodes: clientClassNodes, 310 + }); 311 + file.add(node); 312 + } 314 313 315 - for (const sdkClass of sdkClasses.values()) { 316 - generateClass(sdkClass); 317 - } 318 - }); 314 + for (const sdkClass of sdkClasses.values()) { 315 + generateClass(sdkClass); 316 + } 319 317 }; 320 318 321 319 const generateFlatSdk = ({ plugin }: { plugin: Plugin.Instance<Config> }) => { ··· 323 321 const isNuxtClient = client.name === '@hey-api/client-nuxt'; 324 322 const file = plugin.context.file({ id: sdkId })!; 325 323 326 - plugin.subscribe('operation', ({ operation }) => { 324 + plugin.forEach('operation', ({ operation }) => { 327 325 const isRequiredOptions = isOperationOptionsRequired({ 328 326 context: plugin.context, 329 327 operation,
+6 -18
packages/openapi-ts/src/plugins/@hey-api/transformers/plugin.ts
··· 159 159 }) => node.kind === ts.SyntaxKind.ReturnStatement; 160 160 161 161 const schemaResponseTransformerNodes = ({ 162 - context, 163 162 plugin, 164 163 schema, 165 164 }: { 166 - context: IR.Context; 167 165 plugin: Plugin.Instance<Config>; 168 166 schema: IR.SchemaObject; 169 167 }): Array<ts.Expression | ts.Statement> => { 170 168 const identifierData = compiler.identifier({ text: dataVariableName }); 171 169 const nodes = processSchemaType({ 172 - context, 173 170 dataExpression: identifierData, 174 171 plugin, 175 172 schema, ··· 185 182 }; 186 183 187 184 const processSchemaType = ({ 188 - context, 189 185 dataExpression, 190 186 plugin, 191 187 schema, 192 188 }: { 193 - context: IR.Context; 194 189 dataExpression?: ts.Expression | string; 195 190 plugin: Plugin.Instance<Config>; 196 191 schema: IR.SchemaObject; 197 192 }): Array<ts.Expression | ts.Statement> => { 198 - const file = context.file({ id: transformersId })!; 193 + const file = plugin.context.file({ id: transformersId })!; 199 194 200 195 if (schema.$ref) { 201 196 let identifier = file.identifier({ ··· 206 201 207 202 if (identifier.created && identifier.name) { 208 203 // create each schema response transformer only once 209 - const refSchema = context.resolveIrRef<IR.SchemaObject>(schema.$ref); 204 + const refSchema = plugin.context.resolveIrRef<IR.SchemaObject>( 205 + schema.$ref, 206 + ); 210 207 const nodes = schemaResponseTransformerNodes({ 211 - context, 212 208 plugin, 213 209 schema: refSchema, 214 210 }); ··· 278 274 const nodes = !schema.items 279 275 ? [] 280 276 : processSchemaType({ 281 - context, 282 277 dataExpression: 'item', 283 278 plugin, 284 279 schema: schema.items?.[0] ··· 343 338 name, 344 339 }); 345 340 const propertyNodes = processSchemaType({ 346 - context, 347 341 dataExpression: propertyAccessExpression, 348 342 plugin, 349 343 schema: property, ··· 396 390 if (schema.items) { 397 391 if (schema.items.length === 1) { 398 392 return processSchemaType({ 399 - context, 400 393 dataExpression: 'item', 401 394 plugin, 402 395 schema: schema.items[0]!, ··· 414 407 ) { 415 408 for (const item of schema.items) { 416 409 const nodes = processSchemaType({ 417 - context, 418 410 dataExpression: dataExpression || 'item', 419 411 plugin, 420 412 schema: item, ··· 468 460 path: plugin.output, 469 461 }); 470 462 471 - plugin.subscribe('operation', ({ operation }) => { 463 + plugin.forEach('operation', ({ operation }) => { 472 464 const { response } = operationResponsesMap(operation); 473 465 474 466 if (!response) { ··· 508 500 } 509 501 510 502 // TODO: parser - consider handling simple string response which is also a date 511 - const nodes = schemaResponseTransformerNodes({ 512 - context: plugin.context, 513 - plugin, 514 - schema: response, 515 - }); 503 + const nodes = schemaResponseTransformerNodes({ plugin, schema: response }); 516 504 if (nodes.length) { 517 505 file.import({ 518 506 asType: true,
+4 -5
packages/openapi-ts/src/plugins/@hey-api/typescript/clientOptions.ts
··· 32 32 }; 33 33 34 34 export const createClientOptions = ({ 35 - context, 36 35 identifier, 36 + plugin, 37 37 servers, 38 38 }: { 39 - context: IR.Context; 40 39 identifier: Identifier; 41 40 plugin: Plugin.Instance<Config>; 42 41 servers: ReadonlyArray<IR.ServerObject>; 43 42 }) => { 44 - const file = context.file({ id: typesId })!; 43 + const file = plugin.context.file({ id: typesId })!; 45 44 46 45 if (!identifier.name) { 47 46 return; 48 47 } 49 48 50 - const client = getClientPlugin(context.config); 49 + const client = getClientPlugin(plugin.context.config); 51 50 52 51 const types: Array<ts.TypeNode> = servers.map((server) => 53 52 serverToBaseUrlType({ server }), ··· 71 70 type: compiler.typeInterfaceNode({ 72 71 properties: [ 73 72 { 74 - name: getClientBaseUrlKey(context.config), 73 + name: getClientBaseUrlKey(plugin.context.config), 75 74 type: compiler.typeUnionNode({ types }), 76 75 }, 77 76 ],
+99 -165
packages/openapi-ts/src/plugins/@hey-api/typescript/plugin.ts
··· 117 117 118 118 const addJavaScriptEnum = ({ 119 119 $ref, 120 - context, 121 120 plugin, 122 121 schema, 123 122 }: { 124 123 $ref: string; 125 - context: IR.Context; 126 124 plugin: Plugin.Instance<Config>; 127 125 schema: SchemaWithType<'enum'>; 128 126 }) => { 129 - const file = context.file({ id: typesId })!; 127 + const file = plugin.context.file({ id: typesId })!; 130 128 const identifier = file.identifier({ 131 129 $ref, 132 130 create: true, ··· 239 237 240 238 const addTypeEnum = ({ 241 239 $ref, 242 - context, 243 240 plugin, 244 241 schema, 245 242 state, 246 243 }: { 247 244 $ref: string; 248 - context: IR.Context; 249 245 plugin: Plugin.Instance<Config>; 250 246 schema: SchemaWithType<'enum'>; 251 247 state: State | undefined; 252 248 }): ts.TypeAliasDeclaration | undefined => { 253 - const file = context.file({ id: typesId })!; 249 + const file = plugin.context.file({ id: typesId })!; 254 250 const identifier = file.identifier({ 255 251 $ref, 256 252 create: true, ··· 271 267 } 272 268 273 269 const type = schemaToType({ 274 - context, 275 270 plugin, 276 271 schema: { 277 272 ...schema, ··· 307 302 308 303 const addTypeScriptEnum = ({ 309 304 $ref, 310 - context, 311 305 plugin, 312 306 schema, 313 307 state, 314 308 }: { 315 309 $ref: string; 316 - context: IR.Context; 317 310 plugin: Plugin.Instance<Config>; 318 311 schema: SchemaWithType<'enum'>; 319 312 state: State | undefined; ··· 324 317 if (!shouldCreateTypeScriptEnum({ plugin, schema })) { 325 318 const node = addTypeEnum({ 326 319 $ref, 327 - context, 328 320 plugin, 329 321 schema, 330 322 state, ··· 332 324 return node; 333 325 } 334 326 335 - const file = context.file({ id: typesId })!; 327 + const file = plugin.context.file({ id: typesId })!; 336 328 const identifier = file.identifier({ 337 329 $ref, 338 330 create: true, ··· 347 339 }; 348 340 349 341 const arrayTypeToIdentifier = ({ 350 - context, 351 342 namespace, 352 343 plugin, 353 344 schema, 354 345 state, 355 346 }: { 356 - context: IR.Context; 357 347 namespace: Array<ts.Statement>; 358 348 plugin: Plugin.Instance<Config>; 359 349 schema: SchemaWithType<'array'>; ··· 373 363 374 364 for (const item of schema.items!) { 375 365 const type = schemaToType({ 376 - context, 377 366 namespace, 378 367 plugin, 379 368 schema: item, ··· 405 394 const booleanTypeToIdentifier = ({ 406 395 schema, 407 396 }: { 408 - context: IR.Context; 409 397 namespace: Array<ts.Statement>; 410 398 schema: SchemaWithType<'boolean'>; 411 399 }): ts.TypeNode => { ··· 422 410 423 411 const enumTypeToIdentifier = ({ 424 412 $ref, 425 - context, 426 413 namespace, 427 414 plugin, 428 415 schema, 429 416 state, 430 417 }: { 431 418 $ref?: string; 432 - context: IR.Context; 433 419 namespace: Array<ts.Statement>; 434 420 plugin: Plugin.Instance<Config>; 435 421 schema: SchemaWithType<'enum'>; 436 422 state: State | undefined; 437 423 }): ts.TypeNode | undefined => { 438 - const file = context.file({ id: typesId })!; 424 + const file = plugin.context.file({ id: typesId })!; 439 425 const isRefComponent = $ref ? isRefOpenApiComponent($ref) : false; 440 426 const shouldExportEnum = 441 427 isRefComponent || Boolean(plugin.config.exportInlineEnums); ··· 446 432 if (!plugin.config.enums) { 447 433 const typeNode = addTypeEnum({ 448 434 $ref, 449 - context, 450 435 plugin, 451 436 schema, 452 437 state, ··· 459 444 if (plugin.config.enums === 'javascript') { 460 445 const typeNode = addTypeEnum({ 461 446 $ref, 462 - context, 463 447 plugin, 464 448 schema, 465 449 state, ··· 470 454 471 455 const objectNode = addJavaScriptEnum({ 472 456 $ref, 473 - context, 474 457 plugin, 475 458 schema, 476 459 }); ··· 482 465 if (plugin.config.enums === 'typescript') { 483 466 const enumNode = addTypeScriptEnum({ 484 467 $ref, 485 - context, 486 468 plugin, 487 469 schema, 488 470 state, ··· 495 477 if (plugin.config.enums === 'typescript+namespace') { 496 478 const enumNode = addTypeScriptEnum({ 497 479 $ref, 498 - context, 499 480 plugin, 500 481 schema, 501 482 state, ··· 512 493 } 513 494 514 495 const type = schemaToType({ 515 - context, 516 496 plugin, 517 497 schema: { 518 498 ...schema, ··· 550 530 }; 551 531 552 532 const objectTypeToIdentifier = ({ 553 - context, 554 533 namespace, 555 534 plugin, 556 535 schema, 557 536 state, 558 537 }: { 559 - context: IR.Context; 560 538 namespace: Array<ts.Statement>; 561 539 plugin: Plugin.Instance<Config>; 562 540 schema: SchemaWithType<'object'>; ··· 586 564 587 565 const propertyType = schemaToType({ 588 566 $ref: state ? [...state.path, name].join('/') : `${irRef}${name}`, 589 - context, 590 567 namespace, 591 568 plugin, 592 569 schema: property, ··· 602 579 comment: createSchemaComment({ schema: property }), 603 580 isReadOnly: property.accessScope === 'read', 604 581 isRequired, 605 - name: fieldName({ context, name }), 582 + name: fieldName({ context: plugin.context, name }), 606 583 type: propertyType, 607 584 }); 608 585 indexPropertyItems.push(property); ··· 632 609 isRequired: !schema.propertyNames, 633 610 name: 'key', 634 611 type: schemaToType({ 635 - context, 636 612 namespace, 637 613 plugin, 638 614 schema: ··· 707 683 }; 708 684 709 685 const tupleTypeToIdentifier = ({ 710 - context, 711 686 namespace, 712 687 plugin, 713 688 schema, 714 689 state, 715 690 }: { 716 - context: IR.Context; 717 691 namespace: Array<ts.Statement>; 718 692 plugin: Plugin.Instance<Config>; 719 693 schema: SchemaWithType<'tuple'>; ··· 729 703 } else if (schema.items) { 730 704 for (const item of schema.items) { 731 705 const type = schemaToType({ 732 - context, 733 706 namespace, 734 707 plugin, 735 708 schema: item, ··· 753 726 754 727 const schemaTypeToIdentifier = ({ 755 728 $ref, 756 - context, 757 729 namespace, 758 730 plugin, 759 731 schema, 760 732 state, 761 733 }: { 762 734 $ref?: string; 763 - context: IR.Context; 764 735 namespace: Array<ts.Statement>; 765 736 plugin: Plugin.Instance<Config>; 766 737 schema: IR.SchemaObject; ··· 769 740 switch (schema.type as Required<IR.SchemaObject>['type']) { 770 741 case 'array': 771 742 return arrayTypeToIdentifier({ 772 - context, 773 743 namespace, 774 744 plugin, 775 745 schema: schema as SchemaWithType<'array'>, ··· 777 747 }); 778 748 case 'boolean': 779 749 return booleanTypeToIdentifier({ 780 - context, 781 750 namespace, 782 751 schema: schema as SchemaWithType<'boolean'>, 783 752 }); 784 753 case 'enum': 785 754 return enumTypeToIdentifier({ 786 755 $ref, 787 - context, 788 756 namespace, 789 757 plugin, 790 758 schema: schema as SchemaWithType<'enum'>, ··· 807 775 }); 808 776 case 'object': 809 777 return objectTypeToIdentifier({ 810 - context, 811 778 namespace, 812 779 plugin, 813 780 schema: schema as SchemaWithType<'object'>, ··· 821 788 }); 822 789 case 'tuple': 823 790 return tupleTypeToIdentifier({ 824 - context, 825 791 namespace, 826 792 plugin, 827 793 schema: schema as SchemaWithType<'tuple'>, ··· 879 845 }; 880 846 881 847 const operationToDataType = ({ 882 - context, 883 848 operation, 884 849 plugin, 885 850 }: { 886 - context: IR.Context; 887 851 operation: IR.OperationObject; 888 852 plugin: Plugin.Instance<Config>; 889 853 }) => { 890 - const file = context.file({ id: typesId })!; 854 + const file = plugin.context.file({ id: typesId })!; 891 855 const data: IR.SchemaObject = { 892 856 type: 'object', 893 857 }; ··· 960 924 961 925 const identifier = file.identifier({ 962 926 $ref: operationIrRef({ 963 - config: context.config, 927 + config: plugin.context.config, 964 928 id: operation.id, 965 929 type: 'data', 966 930 }), ··· 968 932 namespace: 'type', 969 933 }); 970 934 const type = schemaToType({ 971 - context, 972 935 plugin, 973 936 schema: data, 974 937 state: ··· 993 956 }; 994 957 995 958 const operationToType = ({ 996 - context, 997 959 operation, 998 960 plugin, 999 961 }: { 1000 - context: IR.Context; 1001 962 operation: IR.OperationObject; 1002 963 plugin: Plugin.Instance<Config>; 1003 964 }) => { 1004 - operationToDataType({ 1005 - context, 1006 - operation, 1007 - plugin, 1008 - }); 965 + operationToDataType({ operation, plugin }); 1009 966 1010 - const file = context.file({ id: typesId })!; 967 + const file = plugin.context.file({ id: typesId })!; 1011 968 1012 969 const { error, errors, response, responses } = 1013 970 operationResponsesMap(operation); ··· 1015 972 if (errors) { 1016 973 const identifierErrors = file.identifier({ 1017 974 $ref: operationIrRef({ 1018 - config: context.config, 975 + config: plugin.context.config, 1019 976 id: operation.id, 1020 977 type: 'errors', 1021 978 }), ··· 1024 981 }); 1025 982 if (identifierErrors.name) { 1026 983 const type = schemaToType({ 1027 - context, 1028 984 plugin, 1029 985 schema: errors, 1030 986 state: ··· 1050 1006 if (error) { 1051 1007 const identifierError = file.identifier({ 1052 1008 $ref: operationIrRef({ 1053 - config: context.config, 1009 + config: plugin.context.config, 1054 1010 id: operation.id, 1055 1011 type: 'error', 1056 1012 }), ··· 1082 1038 if (responses) { 1083 1039 const identifierResponses = file.identifier({ 1084 1040 $ref: operationIrRef({ 1085 - config: context.config, 1041 + config: plugin.context.config, 1086 1042 id: operation.id, 1087 1043 type: 'responses', 1088 1044 }), ··· 1091 1047 }); 1092 1048 if (identifierResponses.name) { 1093 1049 const type = schemaToType({ 1094 - context, 1095 1050 plugin, 1096 1051 schema: responses, 1097 1052 state: ··· 1117 1072 if (response) { 1118 1073 const identifierResponse = file.identifier({ 1119 1074 $ref: operationIrRef({ 1120 - config: context.config, 1075 + config: plugin.context.config, 1121 1076 id: operation.id, 1122 1077 type: 'response', 1123 1078 }), ··· 1175 1130 1176 1131 export const schemaToType = ({ 1177 1132 $ref, 1178 - context, 1179 1133 namespace = [], 1180 1134 plugin, 1181 1135 schema, 1182 1136 state, 1183 1137 }: { 1184 1138 $ref?: string; 1185 - context: IR.Context; 1186 1139 namespace?: Array<ts.Statement>; 1187 1140 plugin: Plugin.Instance<Config>; 1188 1141 schema: IR.SchemaObject; 1189 1142 state: State | undefined; 1190 1143 }): ts.TypeNode | undefined => { 1191 - const file = context.file({ id: typesId })!; 1144 + const file = plugin.context.file({ id: typesId })!; 1192 1145 1193 1146 let type: ts.TypeNode | undefined; 1194 1147 1195 1148 if (schema.$ref) { 1196 - const refSchema = context.resolveIrRef<IR.SchemaObject>(schema.$ref); 1149 + const refSchema = plugin.context.resolveIrRef<IR.SchemaObject>(schema.$ref); 1197 1150 1198 1151 if ( 1199 1152 !state?.accessScope || ··· 1227 1180 } else if (schema.type) { 1228 1181 type = schemaTypeToIdentifier({ 1229 1182 $ref, 1230 - context, 1231 1183 namespace, 1232 1184 plugin, 1233 1185 schema, ··· 1241 1193 for (const item of schema.items) { 1242 1194 // TODO: correctly populate state.path 1243 1195 const type = schemaToType({ 1244 - context, 1245 1196 namespace, 1246 1197 plugin, 1247 1198 schema: item, ··· 1259 1210 } else { 1260 1211 // TODO: correctly populate state.path 1261 1212 type = schemaToType({ 1262 - context, 1263 1213 namespace, 1264 1214 plugin, 1265 1215 schema, ··· 1269 1219 } else { 1270 1220 // catch-all fallback for failed schemas 1271 1221 type = schemaTypeToIdentifier({ 1272 - context, 1273 1222 namespace, 1274 1223 plugin, 1275 1224 schema: { ··· 1329 1278 namespace: 'type', 1330 1279 }); 1331 1280 1332 - plugin.subscribe('schema', ({ $ref, schema }) => { 1333 - if ( 1334 - plugin.config.readOnlyWriteOnlyBehavior === 'off' || 1335 - !isSchemaSplit({ schema }) 1336 - ) { 1337 - schemaToType({ 1338 - $ref, 1339 - context: plugin.context, 1340 - plugin, 1341 - schema, 1342 - state: { 1343 - // TODO: correctly populate state.path 1344 - path: [], 1345 - }, 1346 - }); 1347 - return; 1348 - } 1281 + const servers: Array<IR.ServerObject> = []; 1349 1282 1350 - if (hasSchemaScope({ accessScope: 'read', schema })) { 1351 - schemaToType({ 1352 - $ref: scopeToRef({ 1353 - $ref, 1354 - accessScope: 'read', 1283 + plugin.forEach( 1284 + 'operation', 1285 + 'parameter', 1286 + 'requestBody', 1287 + 'schema', 1288 + 'server', 1289 + (event) => { 1290 + if (event.type === 'operation') { 1291 + operationToType({ operation: event.operation, plugin }); 1292 + } else if (event.type === 'parameter') { 1293 + schemaToType({ 1294 + $ref: event.$ref, 1355 1295 plugin, 1356 - }), 1357 - context: plugin.context, 1358 - plugin, 1359 - schema, 1360 - state: { 1361 - accessScope: 'read', 1362 - // TODO: correctly populate state.path 1363 - path: [], 1364 - }, 1365 - }); 1366 - } 1367 - 1368 - if (hasSchemaScope({ accessScope: 'write', schema })) { 1369 - schemaToType({ 1370 - $ref: scopeToRef({ 1371 - $ref, 1372 - accessScope: 'write', 1296 + schema: event.parameter.schema, 1297 + state: { 1298 + // TODO: correctly populate state.path 1299 + path: [], 1300 + }, 1301 + }); 1302 + } else if (event.type === 'requestBody') { 1303 + schemaToType({ 1304 + $ref: event.$ref, 1373 1305 plugin, 1374 - }), 1375 - context: plugin.context, 1376 - plugin, 1377 - schema, 1378 - state: { 1379 - accessScope: 'write', 1380 - // TODO: correctly populate state.path 1381 - path: [], 1382 - }, 1383 - }); 1384 - } 1385 - }); 1386 - 1387 - plugin.subscribe('parameter', ({ $ref, parameter }) => { 1388 - schemaToType({ 1389 - $ref, 1390 - context: plugin.context, 1391 - plugin, 1392 - schema: parameter.schema, 1393 - state: { 1394 - // TODO: correctly populate state.path 1395 - path: [], 1396 - }, 1397 - }); 1398 - }); 1306 + schema: event.requestBody.schema, 1307 + state: 1308 + plugin.config.readOnlyWriteOnlyBehavior === 'off' 1309 + ? { 1310 + // TODO: correctly populate state.path 1311 + path: [], 1312 + } 1313 + : { 1314 + accessScope: 'write', 1315 + // TODO: correctly populate state.path 1316 + path: [], 1317 + }, 1318 + }); 1319 + } else if (event.type === 'schema') { 1320 + if ( 1321 + plugin.config.readOnlyWriteOnlyBehavior === 'off' || 1322 + !isSchemaSplit({ schema: event.schema }) 1323 + ) { 1324 + schemaToType({ 1325 + $ref: event.$ref, 1326 + plugin, 1327 + schema: event.schema, 1328 + state: { 1329 + // TODO: correctly populate state.path 1330 + path: [], 1331 + }, 1332 + }); 1333 + return; 1334 + } 1399 1335 1400 - plugin.subscribe('requestBody', ({ $ref, requestBody }) => { 1401 - schemaToType({ 1402 - $ref, 1403 - context: plugin.context, 1404 - plugin, 1405 - schema: requestBody.schema, 1406 - state: 1407 - plugin.config.readOnlyWriteOnlyBehavior === 'off' 1408 - ? { 1336 + if (hasSchemaScope({ accessScope: 'read', schema: event.schema })) { 1337 + schemaToType({ 1338 + $ref: scopeToRef({ 1339 + $ref: event.$ref, 1340 + accessScope: 'read', 1341 + plugin, 1342 + }), 1343 + plugin, 1344 + schema: event.schema, 1345 + state: { 1346 + accessScope: 'read', 1409 1347 // TODO: correctly populate state.path 1410 1348 path: [], 1411 - } 1412 - : { 1349 + }, 1350 + }); 1351 + } 1352 + 1353 + if (hasSchemaScope({ accessScope: 'write', schema: event.schema })) { 1354 + schemaToType({ 1355 + $ref: scopeToRef({ 1356 + $ref: event.$ref, 1357 + accessScope: 'write', 1358 + plugin, 1359 + }), 1360 + plugin, 1361 + schema: event.schema, 1362 + state: { 1413 1363 accessScope: 'write', 1414 1364 // TODO: correctly populate state.path 1415 1365 path: [], 1416 1366 }, 1417 - }); 1418 - }); 1367 + }); 1368 + } 1369 + } else if (event.type === 'server') { 1370 + servers.push(event.server); 1371 + } 1372 + }, 1373 + ); 1419 1374 1420 - plugin.subscribe('operation', ({ operation }) => { 1421 - operationToType({ 1422 - context: plugin.context, 1423 - operation, 1424 - plugin, 1425 - }); 1426 - }); 1427 - 1428 - const servers: Array<IR.ServerObject> = []; 1429 - 1430 - plugin.subscribe('server', ({ server }) => { 1431 - servers.push(server); 1432 - }); 1433 - 1434 - plugin.subscribe('after', () => { 1435 - createClientOptions({ 1436 - context: plugin.context, 1437 - identifier: clientOptions, 1438 - plugin, 1439 - servers, 1440 - }); 1441 - }); 1375 + createClientOptions({ identifier: clientOptions, plugin, servers }); 1442 1376 };
+17 -21
packages/openapi-ts/src/plugins/@tanstack/query-core/infiniteQueryOptions.ts
··· 25 25 const infiniteQueryOptionsFn = 'infiniteQueryOptions'; 26 26 27 27 const createInfiniteParamsFunction = ({ 28 - context, 29 28 plugin, 30 29 }: { 31 - context: IR.Context; 32 30 plugin: PluginInstance; 33 31 }) => { 34 - const file = context.file({ id: plugin.name })!; 32 + const file = plugin.context.file({ id: plugin.name })!; 35 33 36 34 const fn = compiler.constVariable({ 37 35 expression: compiler.arrowFunction({ ··· 221 219 }; 222 220 223 221 const infiniteQueryOptionsFunctionIdentifier = ({ 224 - context, 225 222 operation, 226 223 plugin, 227 224 }: { 228 - context: IR.Context; 229 225 operation: IR.OperationObject; 230 226 plugin: PluginInstance; 231 227 }) => { 232 228 const name = serviceFunctionIdentifier({ 233 - config: context.config, 229 + config: plugin.context.config, 234 230 id: operation.id, 235 231 operation, 236 232 }); ··· 252 248 }; 253 249 254 250 export const createInfiniteQueryOptions = ({ 255 - context, 256 251 operation, 257 252 plugin, 258 253 queryFn, 259 254 state, 260 255 }: { 261 - context: IR.Context; 262 256 operation: IR.OperationObject; 263 257 plugin: PluginInstance; 264 258 queryFn: string; ··· 271 265 return state; 272 266 } 273 267 274 - const pagination = operationPagination({ context, operation }); 268 + const pagination = operationPagination({ 269 + context: plugin.context, 270 + operation, 271 + }); 275 272 276 273 if (!pagination) { 277 274 return state; 278 275 } 279 276 280 - const file = context.file({ id: plugin.name })!; 281 - const isRequiredOptions = isOperationOptionsRequired({ context, operation }); 277 + const file = plugin.context.file({ id: plugin.name })!; 278 + const isRequiredOptions = isOperationOptionsRequired({ 279 + context: plugin.context, 280 + operation, 281 + }); 282 282 283 283 if (!state.hasInfiniteQueries) { 284 284 state.hasInfiniteQueries = true; 285 285 286 286 if (!state.hasCreateQueryKeyParamsFunction) { 287 - createQueryKeyType({ context, plugin }); 288 - createQueryKeyFunction({ context, plugin }); 287 + createQueryKeyType({ plugin }); 288 + createQueryKeyFunction({ plugin }); 289 289 state.hasCreateQueryKeyParamsFunction = true; 290 290 } 291 291 292 292 if (!state.hasCreateInfiniteParamsFunction) { 293 - createInfiniteParamsFunction({ context, plugin }); 293 + createInfiniteParamsFunction({ plugin }); 294 294 state.hasCreateInfiniteParamsFunction = true; 295 295 } 296 296 ··· 308 308 309 309 state.hasUsedQueryFn = true; 310 310 311 - const typeData = useTypeData({ context, operation, plugin }); 312 - const typeError = useTypeError({ context, operation, plugin }); 313 - const typeResponse = useTypeResponse({ context, operation, plugin }); 311 + const typeData = useTypeData({ operation, plugin }); 312 + const typeError = useTypeError({ operation, plugin }); 313 + const typeResponse = useTypeResponse({ operation, plugin }); 314 314 315 315 const typeQueryKey = `${queryKeyName}<${typeData}>`; 316 316 const typePageObjectParam = `Pick<${typeQueryKey}[0], 'body' | 'headers' | 'path' | 'query'>`; ··· 318 318 // TODO: parser - this is a bit clunky, need to compile type to string because 319 319 // `compiler.returnFunctionCall()` accepts only strings, should be cleaned up 320 320 const type = schemaToType({ 321 - context, 322 321 plugin: pluginTypeScript as Parameters<typeof schemaToType>[0]['plugin'], 323 322 schema: pagination.schema, 324 323 state: undefined, ··· 331 330 : `${typePageObjectParam}`; 332 331 333 332 const node = queryKeyStatement({ 334 - context, 335 333 isInfinite: true, 336 334 operation, 337 335 plugin, ··· 340 338 file.add(node); 341 339 342 340 const infiniteQueryKeyName = infiniteQueryKeyFunctionIdentifier({ 343 - context, 344 341 operation, 345 342 plugin, 346 343 }); ··· 519 516 ], 520 517 }), 521 518 name: infiniteQueryOptionsFunctionIdentifier({ 522 - context, 523 519 operation, 524 520 plugin, 525 521 }),
+6 -10
packages/openapi-ts/src/plugins/@tanstack/query-core/mutationOptions.ts
··· 10 10 const mutationOptionsFn = 'mutationOptions'; 11 11 12 12 const mutationOptionsFunctionIdentifier = ({ 13 - context, 14 13 operation, 15 14 plugin, 16 15 }: { 17 - context: IR.Context; 18 16 operation: IR.OperationObject; 19 17 plugin: PluginInstance; 20 18 }) => { 21 19 const name = serviceFunctionIdentifier({ 22 - config: context.config, 20 + config: plugin.context.config, 23 21 id: operation.id, 24 22 operation, 25 23 }); ··· 41 39 }; 42 40 43 41 export const createMutationOptions = ({ 44 - context, 45 42 operation, 46 43 plugin, 47 44 queryFn, 48 45 state, 49 46 }: { 50 - context: IR.Context; 51 47 operation: IR.OperationObject; 52 48 plugin: PluginInstance; 53 49 queryFn: string; ··· 69 65 ? 'MutationOptions' 70 66 : 'UseMutationOptions'; 71 67 72 - const file = context.file({ id: plugin.name })!; 68 + const file = plugin.context.file({ id: plugin.name })!; 73 69 74 70 if (!state.hasMutations) { 75 71 state.hasMutations = true; ··· 83 79 84 80 state.hasUsedQueryFn = true; 85 81 86 - const typeData = useTypeData({ context, operation, plugin }); 87 - const typeError = useTypeError({ context, operation, plugin }); 88 - const typeResponse = useTypeResponse({ context, operation, plugin }); 82 + const typeData = useTypeData({ operation, plugin }); 83 + const typeError = useTypeError({ operation, plugin }); 84 + const typeResponse = useTypeResponse({ operation, plugin }); 89 85 // TODO: better types syntax 90 86 const mutationType = `${mutationsType}<${typeResponse}, ${typeError.name}, ${typeData}>`; 91 87 ··· 175 171 : undefined, 176 172 exportConst: true, 177 173 expression, 178 - name: mutationOptionsFunctionIdentifier({ context, operation, plugin }), 174 + name: mutationOptionsFunctionIdentifier({ operation, plugin }), 179 175 }); 180 176 file.add(statement); 181 177
+14 -21
packages/openapi-ts/src/plugins/@tanstack/query-core/plugin.ts
··· 25 25 typeInfiniteData: undefined!, 26 26 }; 27 27 28 - plugin.subscribe('before', () => { 29 - file.import({ 30 - ...clientApi.Options, 31 - module: file.relativePathToFile({ context: plugin.context, id: sdkId }), 32 - }); 28 + file.import({ 29 + ...clientApi.Options, 30 + module: file.relativePathToFile({ context: plugin.context, id: sdkId }), 33 31 }); 34 32 35 - plugin.subscribe('operation', ({ operation }) => { 33 + plugin.forEach('operation', ({ operation }) => { 36 34 state.hasUsedQueryFn = false; 37 35 38 36 const sdkPlugin = plugin.getPlugin('@hey-api/sdk'); ··· 70 68 ).join('.'); 71 69 72 70 createQueryOptions({ 73 - context: plugin.context, 74 71 operation, 75 72 plugin, 76 73 queryFn, ··· 78 75 }); 79 76 80 77 createInfiniteQueryOptions({ 81 - context: plugin.context, 82 78 operation, 83 79 plugin, 84 80 queryFn, ··· 86 82 }); 87 83 88 84 createMutationOptions({ 89 - context: plugin.context, 90 85 operation, 91 86 plugin, 92 87 queryFn, ··· 101 96 } 102 97 }); 103 98 104 - plugin.subscribe('after', () => { 105 - if (state.hasQueries || state.hasInfiniteQueries) { 106 - file.import({ 107 - alias: '_heyApiClient', 108 - module: file.relativePathToFile({ 109 - context: plugin.context, 110 - id: clientId, 111 - }), 112 - name: 'client', 113 - }); 114 - } 115 - }); 99 + if (state.hasQueries || state.hasInfiniteQueries) { 100 + file.import({ 101 + alias: '_heyApiClient', 102 + module: file.relativePathToFile({ 103 + context: plugin.context, 104 + id: clientId, 105 + }), 106 + name: 'client', 107 + }); 108 + } 116 109 };
+16 -27
packages/openapi-ts/src/plugins/@tanstack/query-core/queryKey.ts
··· 15 15 const optionsIdentifier = compiler.identifier({ text: 'options' }); 16 16 17 17 export const createQueryKeyFunction = ({ 18 - context, 19 18 plugin, 20 19 }: { 21 - context: IR.Context; 22 20 plugin: PluginInstance; 23 21 }) => { 24 - const file = context.file({ id: plugin.name })!; 22 + const file = plugin.context.file({ id: plugin.name })!; 25 23 26 24 const identifierCreateQueryKey = file.identifier({ 27 25 $ref: `#/ir/${createQueryKeyFn}`, ··· 73 71 value: compiler.identifier({ text: 'id' }), 74 72 }, 75 73 { 76 - key: getClientBaseUrlKey(context.config), 74 + key: getClientBaseUrlKey(plugin.context.config), 77 75 value: compiler.identifier({ 78 - text: `(options?.client ?? _heyApiClient).getConfig().${getClientBaseUrlKey(context.config)}`, 76 + text: `(options?.client ?? _heyApiClient).getConfig().${getClientBaseUrlKey(plugin.context.config)}`, 79 77 }), 80 78 }, 81 79 ], ··· 215 213 }; 216 214 217 215 const createQueryKeyLiteral = ({ 218 - context, 219 216 id, 220 217 isInfinite, 221 218 plugin, 222 219 }: { 223 - context: IR.Context; 224 220 id: string; 225 221 isInfinite?: boolean; 226 222 plugin: PluginInstance; 227 223 }) => { 228 - const file = context.file({ id: plugin.name })!; 224 + const file = plugin.context.file({ id: plugin.name })!; 229 225 const identifierCreateQueryKey = file.identifier({ 230 226 $ref: `#/ir/${createQueryKeyFn}`, 231 227 namespace: 'value', ··· 241 237 return createQueryKeyCallExpression; 242 238 }; 243 239 244 - export const createQueryKeyType = ({ 245 - context, 246 - plugin, 247 - }: { 248 - context: IR.Context; 249 - plugin: PluginInstance; 250 - }) => { 251 - const file = context.file({ id: plugin.name })!; 240 + export const createQueryKeyType = ({ plugin }: { plugin: PluginInstance }) => { 241 + const file = plugin.context.file({ id: plugin.name })!; 252 242 253 243 const properties: Property[] = [ 254 244 { ··· 274 264 compiler.typeIntersectionNode({ 275 265 types: [ 276 266 compiler.typeReferenceNode({ 277 - typeName: `Pick<${TOptionsType}, '${getClientBaseUrlKey(context.config)}' | 'body' | 'headers' | 'path' | 'query'>`, 267 + typeName: `Pick<${TOptionsType}, '${getClientBaseUrlKey(plugin.context.config)}' | 'body' | 'headers' | 'path' | 'query'>`, 278 268 }), 279 269 compiler.typeInterfaceNode({ 280 270 properties, ··· 299 289 }; 300 290 301 291 export const infiniteQueryKeyFunctionIdentifier = ({ 302 - context, 303 292 operation, 304 293 plugin, 305 294 }: { 306 - context: IR.Context; 307 295 operation: IR.OperationObject; 308 296 plugin: PluginInstance; 309 297 }) => { 310 298 const name = serviceFunctionIdentifier({ 311 - config: context.config, 299 + config: plugin.context.config, 312 300 id: operation.id, 313 301 operation, 314 302 }); ··· 358 346 }; 359 347 360 348 export const queryKeyStatement = ({ 361 - context, 362 349 isInfinite, 363 350 operation, 364 351 plugin, 365 352 typeQueryKey, 366 353 }: { 367 - context: IR.Context; 368 354 isInfinite: boolean; 369 355 operation: IR.OperationObject; 370 356 plugin: PluginInstance; 371 357 typeQueryKey?: string; 372 358 }) => { 373 - const file = context.file({ id: plugin.name })!; 374 - const typeData = useTypeData({ context, operation, plugin }); 359 + const file = plugin.context.file({ id: plugin.name })!; 360 + const typeData = useTypeData({ operation, plugin }); 375 361 const name = isInfinite 376 - ? infiniteQueryKeyFunctionIdentifier({ context, operation, plugin }) 377 - : queryKeyFunctionIdentifier({ context, operation, plugin }); 362 + ? infiniteQueryKeyFunctionIdentifier({ operation, plugin }) 363 + : queryKeyFunctionIdentifier({ 364 + context: plugin.context, 365 + operation, 366 + plugin, 367 + }); 378 368 const identifierQueryKey = file.identifier({ 379 369 $ref: `#/queryKey/${name}`, 380 370 create: true, ··· 392 382 ], 393 383 returnType: isInfinite ? typeQueryKey : undefined, 394 384 statements: createQueryKeyLiteral({ 395 - context, 396 385 id: operation.id, 397 386 isInfinite, 398 387 plugin,
+11 -13
packages/openapi-ts/src/plugins/@tanstack/query-core/queryOptions.ts
··· 19 19 const queryOptionsFn = 'queryOptions'; 20 20 21 21 const queryOptionsFunctionIdentifier = ({ 22 - context, 23 22 operation, 24 23 plugin, 25 24 }: { 26 - context: IR.Context; 27 25 operation: IR.OperationObject; 28 26 plugin: PluginInstance; 29 27 }) => { 30 28 const name = serviceFunctionIdentifier({ 31 - config: context.config, 29 + config: plugin.context.config, 32 30 id: operation.id, 33 31 operation, 34 32 }); ··· 50 48 }; 51 49 52 50 export const createQueryOptions = ({ 53 - context, 54 51 operation, 55 52 plugin, 56 53 queryFn, 57 54 state, 58 55 }: { 59 - context: IR.Context; 60 56 operation: IR.OperationObject; 61 57 plugin: PluginInstance; 62 58 queryFn: string; ··· 69 65 return state; 70 66 } 71 67 72 - const file = context.file({ id: plugin.name })!; 73 - const isRequiredOptions = isOperationOptionsRequired({ context, operation }); 68 + const file = plugin.context.file({ id: plugin.name })!; 69 + const isRequiredOptions = isOperationOptionsRequired({ 70 + context: plugin.context, 71 + operation, 72 + }); 74 73 75 74 if (!state.hasQueries) { 76 75 state.hasQueries = true; 77 76 78 77 if (!state.hasCreateQueryKeyParamsFunction) { 79 - createQueryKeyType({ context, plugin }); 80 - createQueryKeyFunction({ context, plugin }); 78 + createQueryKeyType({ plugin }); 79 + createQueryKeyFunction({ plugin }); 81 80 state.hasCreateQueryKeyParamsFunction = true; 82 81 } 83 82 ··· 90 89 state.hasUsedQueryFn = true; 91 90 92 91 const node = queryKeyStatement({ 93 - context, 94 92 isInfinite: false, 95 93 operation, 96 94 plugin, 97 95 }); 98 96 file.add(node); 99 97 100 - const typeData = useTypeData({ context, operation, plugin }); 98 + const typeData = useTypeData({ operation, plugin }); 101 99 102 100 const queryKeyName = queryKeyFunctionIdentifier({ 103 - context, 101 + context: plugin.context, 104 102 operation, 105 103 plugin, 106 104 }); ··· 212 210 }), 213 211 ], 214 212 }), 215 - name: queryOptionsFunctionIdentifier({ context, operation, plugin }), 213 + name: queryOptionsFunctionIdentifier({ operation, plugin }), 216 214 // TODO: add type error 217 215 // TODO: AxiosError<PutSubmissionMetaError> 218 216 });
+7 -13
packages/openapi-ts/src/plugins/@tanstack/query-core/useType.ts
··· 6 6 import type { PluginInstance } from './types'; 7 7 8 8 export const useTypeData = ({ 9 - context, 10 9 operation, 11 10 plugin, 12 11 }: { 13 - context: IR.Context; 14 12 operation: IR.OperationObject; 15 13 plugin: PluginInstance; 16 14 }) => { 17 - const file = context.file({ id: plugin.name })!; 15 + const file = plugin.context.file({ id: plugin.name })!; 18 16 19 17 const typeData = operationOptionsType({ 20 - context, 18 + context: plugin.context, 21 19 file, 22 20 operation, 23 21 }); ··· 25 23 }; 26 24 27 25 export const useTypeError = ({ 28 - context, 29 26 operation, 30 27 plugin, 31 28 }: { 32 - context: IR.Context; 33 29 operation: IR.OperationObject; 34 30 plugin: PluginInstance; 35 31 }) => { 36 - const file = context.file({ id: plugin.name })!; 32 + const file = plugin.context.file({ id: plugin.name })!; 37 33 const identifierError = importIdentifier({ 38 - context, 34 + context: plugin.context, 39 35 file, 40 36 operation, 41 37 type: 'error', ··· 51 47 name: 'DefaultError', 52 48 }); 53 49 } 54 - const client = getClientPlugin(context.config); 50 + const client = getClientPlugin(plugin.context.config); 55 51 if (client.name === '@hey-api/client-axios') { 56 52 const axiosError = file.import({ 57 53 asType: true, ··· 67 63 }; 68 64 69 65 export const useTypeResponse = ({ 70 - context, 71 66 operation, 72 67 plugin, 73 68 }: { 74 - context: IR.Context; 75 69 operation: IR.OperationObject; 76 70 plugin: PluginInstance; 77 71 }) => { 78 - const file = context.file({ id: plugin.name })!; 72 + const file = plugin.context.file({ id: plugin.name })!; 79 73 const identifierResponse = importIdentifier({ 80 - context, 74 + context: plugin.context, 81 75 file, 82 76 operation, 83 77 type: 'response',
+25 -27
packages/openapi-ts/src/plugins/fastify/plugin.ts
··· 215 215 216 216 const routeHandlers: Array<Property> = []; 217 217 218 - plugin.subscribe('operation', ({ operation }) => { 218 + plugin.forEach('operation', ({ operation }) => { 219 219 const routeHandler = operationToRouteHandler({ 220 220 context: plugin.context, 221 221 operation, ··· 225 225 } 226 226 }); 227 227 228 - plugin.subscribe('after', () => { 229 - const identifier = file.identifier({ 230 - $ref: 'RouteHandlers', 231 - create: true, 232 - namespace: 'type', 233 - }); 228 + const identifier = file.identifier({ 229 + $ref: 'RouteHandlers', 230 + create: true, 231 + namespace: 'type', 232 + }); 234 233 235 - if (!identifier.name) { 236 - return; 237 - } 234 + if (!identifier.name) { 235 + return; 236 + } 238 237 239 - if (routeHandlers.length) { 240 - file.import({ 241 - asType: true, 242 - module: 'fastify', 243 - name: 'RouteHandler', 244 - }); 245 - } 238 + if (routeHandlers.length) { 239 + file.import({ 240 + asType: true, 241 + module: 'fastify', 242 + name: 'RouteHandler', 243 + }); 244 + } 246 245 247 - file.add( 248 - compiler.typeAliasDeclaration({ 249 - exportType: true, 250 - name: identifier.name, 251 - type: compiler.typeInterfaceNode({ 252 - properties: routeHandlers, 253 - useLegacyResolution: false, 254 - }), 246 + file.add( 247 + compiler.typeAliasDeclaration({ 248 + exportType: true, 249 + name: identifier.name, 250 + type: compiler.typeInterfaceNode({ 251 + properties: routeHandlers, 252 + useLegacyResolution: false, 255 253 }), 256 - ); 257 - }); 254 + }), 255 + ); 258 256 };
+37
packages/openapi-ts/src/plugins/shared/types/instance.d.ts
··· 1 + import type { IR } from '../../../ir/types'; 2 + 3 + type WalkEvents = 4 + | { 5 + method: keyof IR.PathItemObject; 6 + operation: IR.OperationObject; 7 + path: string; 8 + type: 'operation'; 9 + } 10 + | { 11 + $ref: string; 12 + name: string; 13 + parameter: IR.ParameterObject; 14 + type: 'parameter'; 15 + } 16 + | { 17 + $ref: string; 18 + name: string; 19 + requestBody: IR.RequestBodyObject; 20 + type: 'requestBody'; 21 + } 22 + | { 23 + $ref: string; 24 + name: string; 25 + schema: IR.SchemaObject; 26 + type: 'schema'; 27 + } 28 + | { 29 + server: IR.ServerObject; 30 + type: 'server'; 31 + }; 32 + 33 + export type WalkEventType = WalkEvents['type']; 34 + export type WalkEvent<T extends WalkEventType = WalkEventType> = Extract< 35 + WalkEvents, 36 + { type: T } 37 + >;
+140 -14
packages/openapi-ts/src/plugins/shared/utils/instance.ts
··· 1 + import { HeyApiError } from '../../../error'; 1 2 import type { IR } from '../../../ir/types'; 2 3 import type { OpenApi } from '../../../openApi/types'; 3 4 import type { Config } from '../../../types/config'; 4 5 import type { BaseConfig, Plugin } from '../../types'; 6 + import type { WalkEvent, WalkEventType } from '../types/instance'; 5 7 6 8 export class PluginInstance<PluginConfig extends BaseConfig = BaseConfig> { 7 9 public config: Plugin.Config<PluginConfig>['config']; ··· 38 40 } 39 41 40 42 /** 43 + * Iterates over various input elements as specified by the event types, in 44 + * a specific order: servers, schemas, parameters, request bodies, then 45 + * operations. 46 + * 47 + * This ensures, for example, that schemas are always processed before 48 + * operations, which may reference them. 49 + * 50 + * @template T - The event type(s) to yield. Defaults to all event types. 51 + * @param events - The event types to walk over. If none are provided, all event types are included. 52 + * @param callback - Function to execute for each event. 53 + * 54 + * @example 55 + * // Iterate over all operations and schemas 56 + * plugin.forEach('operation', 'schema', (event) => { 57 + * if (event.type === 'operation') { 58 + * // handle operation 59 + * } else if (event.type === 'schema') { 60 + * // handle schema 61 + * } 62 + * }); 63 + */ 64 + public forEach<T extends WalkEventType = WalkEventType>( 65 + ...args: [ 66 + ...events: ReadonlyArray<T>, 67 + callback: (event: WalkEvent<T>) => void, 68 + ] 69 + ): void { 70 + const events = args.slice(0, -1) as ReadonlyArray<T>; 71 + const callback = args[args.length - 1] as (event: WalkEvent<T>) => void; 72 + const eventSet = new Set( 73 + events.length 74 + ? events 75 + : ([ 76 + 'operation', 77 + 'parameter', 78 + 'requestBody', 79 + 'schema', 80 + 'server', 81 + ] as ReadonlyArray<WalkEventType>), 82 + ); 83 + 84 + if (eventSet.has('server') && this.context.ir.servers) { 85 + for (const server of this.context.ir.servers) { 86 + const event: WalkEvent<'server'> = { server, type: 'server' }; 87 + try { 88 + callback(event as WalkEvent<T>); 89 + } catch (error) { 90 + this.forEachError(error, event); 91 + } 92 + } 93 + } 94 + 95 + if (eventSet.has('schema') && this.context.ir.components?.schemas) { 96 + for (const name in this.context.ir.components.schemas) { 97 + const event: WalkEvent<'schema'> = { 98 + $ref: `#/components/schemas/${name}`, 99 + name, 100 + schema: this.context.ir.components.schemas[name]!, 101 + type: 'schema', 102 + }; 103 + try { 104 + callback(event as WalkEvent<T>); 105 + } catch (error) { 106 + this.forEachError(error, event); 107 + } 108 + } 109 + } 110 + 111 + if (eventSet.has('parameter') && this.context.ir.components?.parameters) { 112 + for (const name in this.context.ir.components.parameters) { 113 + const event: WalkEvent<'parameter'> = { 114 + $ref: `#/components/parameters/${name}`, 115 + name, 116 + parameter: this.context.ir.components.parameters[name]!, 117 + type: 'parameter', 118 + }; 119 + try { 120 + callback(event as WalkEvent<T>); 121 + } catch (error) { 122 + this.forEachError(error, event); 123 + } 124 + } 125 + } 126 + 127 + if ( 128 + eventSet.has('requestBody') && 129 + this.context.ir.components?.requestBodies 130 + ) { 131 + for (const name in this.context.ir.components.requestBodies) { 132 + const event: WalkEvent<'requestBody'> = { 133 + $ref: `#/components/requestBodies/${name}`, 134 + name, 135 + requestBody: this.context.ir.components.requestBodies[name]!, 136 + type: 'requestBody', 137 + }; 138 + try { 139 + callback(event as WalkEvent<T>); 140 + } catch (error) { 141 + this.forEachError(error, event); 142 + } 143 + } 144 + } 145 + 146 + if (eventSet.has('operation') && this.context.ir.paths) { 147 + for (const path in this.context.ir.paths) { 148 + const pathItem = 149 + this.context.ir.paths[path as keyof typeof this.context.ir.paths]; 150 + for (const _method in pathItem) { 151 + const method = _method as keyof typeof pathItem; 152 + const event: WalkEvent<'operation'> = { 153 + method, 154 + operation: pathItem[method]!, 155 + path, 156 + type: 'operation', 157 + }; 158 + try { 159 + callback(event as WalkEvent<T>); 160 + } catch (error) { 161 + this.forEachError(error, event); 162 + } 163 + } 164 + } 165 + } 166 + } 167 + 168 + private forEachError(error: unknown, event: WalkEvent) { 169 + const originalError = 170 + error instanceof Error ? error : new Error(String(error)); 171 + throw new HeyApiError({ 172 + args: [event], 173 + error: originalError, 174 + event: event.type, 175 + name: 'Error', 176 + pluginName: this.name, 177 + }); 178 + } 179 + 180 + /** 41 181 * Retrieves a registered plugin instance by its name from the context. This 42 182 * allows plugins to access other plugins that have been registered in the 43 183 * same context, enabling cross-plugin communication and dependencies. ··· 56 196 */ 57 197 public async run() { 58 198 await this.handler({ plugin: this }); 59 - } 60 - 61 - /** 62 - * Subscribe to an input parser event. 63 - * 64 - * @param event Event type from the parser. 65 - * @param callbackFn Function to execute on event. 66 - * @returns void 67 - */ 68 - public subscribe<T extends keyof IR.ContextEvents>( 69 - event: T, 70 - callbackFn: IR.ContextEvents[T], 71 - ) { 72 - return this.context.subscribe(event, callbackFn, this.name); 73 199 } 74 200 }
+29 -48
packages/openapi-ts/src/plugins/valibot/plugin.ts
··· 1110 1110 name: '*', 1111 1111 }); 1112 1112 1113 - plugin.subscribe('operation', ({ operation }) => { 1113 + plugin.forEach('operation', 'parameter', 'requestBody', 'schema', (event) => { 1114 1114 const state: State = { 1115 1115 circularReferenceTracker: new Set(), 1116 1116 hasCircularReference: false, 1117 1117 }; 1118 1118 1119 - operationToValibotSchema({ 1120 - operation, 1121 - plugin, 1122 - state, 1123 - }); 1124 - }); 1125 - 1126 - plugin.subscribe('parameter', ({ $ref, parameter }) => { 1127 - const state: State = { 1128 - circularReferenceTracker: new Set(), 1129 - hasCircularReference: false, 1130 - }; 1131 - 1132 - schemaToValibotSchema({ 1133 - $ref, 1134 - plugin, 1135 - schema: parameter.schema, 1136 - state, 1137 - }); 1138 - }); 1139 - 1140 - plugin.subscribe('requestBody', ({ $ref, requestBody }) => { 1141 - const state: State = { 1142 - circularReferenceTracker: new Set(), 1143 - hasCircularReference: false, 1144 - }; 1145 - 1146 - schemaToValibotSchema({ 1147 - $ref, 1148 - plugin, 1149 - schema: requestBody.schema, 1150 - state, 1151 - }); 1152 - }); 1153 - 1154 - plugin.subscribe('schema', ({ $ref, schema }) => { 1155 - const state: State = { 1156 - circularReferenceTracker: new Set(), 1157 - hasCircularReference: false, 1158 - }; 1159 - 1160 - schemaToValibotSchema({ 1161 - $ref, 1162 - plugin, 1163 - schema, 1164 - state, 1165 - }); 1119 + if (event.type === 'operation') { 1120 + operationToValibotSchema({ 1121 + operation: event.operation, 1122 + plugin, 1123 + state, 1124 + }); 1125 + } else if (event.type === 'parameter') { 1126 + schemaToValibotSchema({ 1127 + $ref: event.$ref, 1128 + plugin, 1129 + schema: event.parameter.schema, 1130 + state, 1131 + }); 1132 + } else if (event.type === 'requestBody') { 1133 + schemaToValibotSchema({ 1134 + $ref: event.$ref, 1135 + plugin, 1136 + schema: event.requestBody.schema, 1137 + state, 1138 + }); 1139 + } else if (event.type === 'schema') { 1140 + schemaToValibotSchema({ 1141 + $ref: event.$ref, 1142 + plugin, 1143 + schema: event.schema, 1144 + state, 1145 + }); 1146 + } 1166 1147 }); 1167 1148 };
+26 -87
packages/openapi-ts/src/plugins/zod/plugin.ts
··· 47 47 const zIdentifier = compiler.identifier({ text: 'z' }); 48 48 49 49 const arrayTypeToZodSchema = ({ 50 - context, 51 50 plugin, 52 51 schema, 53 52 state, 54 53 }: { 55 - context: IR.Context; 56 54 plugin: Plugin.Instance<ResolvedConfig>; 57 55 schema: SchemaWithType<'array'>; 58 56 state: State; ··· 69 67 functionName, 70 68 parameters: [ 71 69 unknownTypeToZodSchema({ 72 - context, 73 70 schema: { 74 71 type: 'unknown', 75 72 }, ··· 159 156 const booleanTypeToZodSchema = ({ 160 157 schema, 161 158 }: { 162 - context: IR.Context; 163 159 schema: SchemaWithType<'boolean'>; 164 160 }) => { 165 161 if (typeof schema.const === 'boolean') { ··· 183 179 }; 184 180 185 181 const enumTypeToZodSchema = ({ 186 - context, 187 182 schema, 188 183 }: { 189 - context: IR.Context; 190 184 schema: SchemaWithType<'enum'>; 191 185 }): ts.CallExpression => { 192 186 const enumMembers: Array<ts.LiteralExpression> = []; ··· 208 202 209 203 if (!enumMembers.length) { 210 204 return unknownTypeToZodSchema({ 211 - context, 212 205 schema: { 213 206 type: 'unknown', 214 207 }, ··· 244 237 // eslint-disable-next-line @typescript-eslint/no-unused-vars 245 238 schema, 246 239 }: { 247 - context: IR.Context; 248 240 schema: SchemaWithType<'never'>; 249 241 }) => { 250 242 const expression = compiler.callExpression({ ··· 260 252 // eslint-disable-next-line @typescript-eslint/no-unused-vars 261 253 schema, 262 254 }: { 263 - context: IR.Context; 264 255 schema: SchemaWithType<'null'>; 265 256 }) => { 266 257 const expression = compiler.callExpression({ ··· 300 291 const numberTypeToZodSchema = ({ 301 292 schema, 302 293 }: { 303 - context: IR.Context; 304 294 schema: SchemaWithType<'integer' | 'number'>; 305 295 }) => { 306 296 const isBigInt = schema.type === 'integer' && schema.format === 'int64'; ··· 478 468 const stringTypeToZodSchema = ({ 479 469 schema, 480 470 }: { 481 - context: IR.Context; 482 471 schema: SchemaWithType<'string'>; 483 472 }) => { 484 473 if (typeof schema.const === 'string') { ··· 646 635 // eslint-disable-next-line @typescript-eslint/no-unused-vars 647 636 schema, 648 637 }: { 649 - context: IR.Context; 650 638 schema: SchemaWithType<'undefined'>; 651 639 }) => { 652 640 const expression = compiler.callExpression({ ··· 662 650 // eslint-disable-next-line @typescript-eslint/no-unused-vars 663 651 schema, 664 652 }: { 665 - context: IR.Context; 666 653 schema: SchemaWithType<'unknown'>; 667 654 }) => { 668 655 const expression = compiler.callExpression({ ··· 678 665 // eslint-disable-next-line @typescript-eslint/no-unused-vars 679 666 schema, 680 667 }: { 681 - context: IR.Context; 682 668 schema: SchemaWithType<'void'>; 683 669 }) => { 684 670 const expression = compiler.callExpression({ ··· 691 677 }; 692 678 693 679 const schemaTypeToZodSchema = ({ 694 - context, 695 680 plugin, 696 681 schema, 697 682 state, 698 683 }: { 699 - context: IR.Context; 700 684 plugin: Plugin.Instance<ResolvedConfig>; 701 685 schema: IR.SchemaObject; 702 686 state: State; ··· 708 692 case 'array': 709 693 return { 710 694 expression: arrayTypeToZodSchema({ 711 - context, 712 695 plugin, 713 696 schema: schema as SchemaWithType<'array'>, 714 697 state, ··· 717 700 case 'boolean': 718 701 return { 719 702 expression: booleanTypeToZodSchema({ 720 - context, 721 703 schema: schema as SchemaWithType<'boolean'>, 722 704 }), 723 705 }; 724 706 case 'enum': 725 707 return { 726 708 expression: enumTypeToZodSchema({ 727 - context, 728 709 schema: schema as SchemaWithType<'enum'>, 729 710 }), 730 711 }; ··· 732 713 case 'number': 733 714 return { 734 715 expression: numberTypeToZodSchema({ 735 - context, 736 716 schema: schema as SchemaWithType<'integer' | 'number'>, 737 717 }), 738 718 }; 739 719 case 'never': 740 720 return { 741 721 expression: neverTypeToZodSchema({ 742 - context, 743 722 schema: schema as SchemaWithType<'never'>, 744 723 }), 745 724 }; 746 725 case 'null': 747 726 return { 748 727 expression: nullTypeToZodSchema({ 749 - context, 750 728 schema: schema as SchemaWithType<'null'>, 751 729 }), 752 730 }; ··· 759 737 case 'string': 760 738 return { 761 739 expression: stringTypeToZodSchema({ 762 - context, 763 740 schema: schema as SchemaWithType<'string'>, 764 741 }), 765 742 }; ··· 774 751 case 'undefined': 775 752 return { 776 753 expression: undefinedTypeToZodSchema({ 777 - context, 778 754 schema: schema as SchemaWithType<'undefined'>, 779 755 }), 780 756 }; 781 757 case 'unknown': 782 758 return { 783 759 expression: unknownTypeToZodSchema({ 784 - context, 785 760 schema: schema as SchemaWithType<'unknown'>, 786 761 }), 787 762 }; 788 763 case 'void': 789 764 return { 790 765 expression: voidTypeToZodSchema({ 791 - context, 792 766 schema: schema as SchemaWithType<'void'>, 793 767 }), 794 768 }; ··· 1044 1018 } 1045 1019 } 1046 1020 } else if (schema.type) { 1047 - const zodSchema = schemaTypeToZodSchema({ 1048 - context: plugin.context, 1049 - plugin, 1050 - schema, 1051 - state, 1052 - }); 1021 + const zodSchema = schemaTypeToZodSchema({ plugin, schema, state }); 1053 1022 anyType = zodSchema.anyType; 1054 1023 expression = zodSchema.expression; 1055 1024 ··· 1125 1094 } else { 1126 1095 // catch-all fallback for failed schemas 1127 1096 const zodSchema = schemaTypeToZodSchema({ 1128 - context: plugin.context, 1129 1097 plugin, 1130 1098 schema: { 1131 1099 type: 'unknown', ··· 1211 1179 name: 'z', 1212 1180 }); 1213 1181 1214 - plugin.subscribe('operation', ({ operation }) => { 1182 + plugin.forEach('operation', 'parameter', 'requestBody', 'schema', (event) => { 1215 1183 const state: State = { 1216 1184 circularReferenceTracker: new Set(), 1217 1185 hasCircularReference: false, ··· 1219 1187 nameTransformer: plugin.config.definitions.name, 1220 1188 }; 1221 1189 1222 - operationToZodSchema({ 1223 - operation, 1224 - plugin, 1225 - state, 1226 - }); 1227 - }); 1228 - 1229 - plugin.subscribe('parameter', ({ $ref, parameter }) => { 1230 - const state: State = { 1231 - circularReferenceTracker: new Set(), 1232 - hasCircularReference: false, 1233 - nameCase: plugin.config.definitions.case, 1234 - nameTransformer: plugin.config.definitions.name, 1235 - }; 1236 - 1237 - schemaToZodSchema({ 1238 - $ref, 1239 - plugin, 1240 - schema: parameter.schema, 1241 - state, 1242 - }); 1243 - }); 1244 - 1245 - plugin.subscribe('requestBody', ({ $ref, requestBody }) => { 1246 - const state: State = { 1247 - circularReferenceTracker: new Set(), 1248 - hasCircularReference: false, 1249 - nameCase: plugin.config.definitions.case, 1250 - nameTransformer: plugin.config.definitions.name, 1251 - }; 1252 - 1253 - schemaToZodSchema({ 1254 - $ref, 1255 - plugin, 1256 - schema: requestBody.schema, 1257 - state, 1258 - }); 1259 - }); 1260 - 1261 - plugin.subscribe('schema', ({ $ref, schema }) => { 1262 - const state: State = { 1263 - circularReferenceTracker: new Set(), 1264 - hasCircularReference: false, 1265 - nameCase: plugin.config.definitions.case, 1266 - nameTransformer: plugin.config.definitions.name, 1267 - }; 1268 - 1269 - schemaToZodSchema({ 1270 - $ref, 1271 - plugin, 1272 - schema, 1273 - state, 1274 - }); 1190 + if (event.type === 'operation') { 1191 + operationToZodSchema({ operation: event.operation, plugin, state }); 1192 + } else if (event.type === 'parameter') { 1193 + schemaToZodSchema({ 1194 + $ref: event.$ref, 1195 + plugin, 1196 + schema: event.parameter.schema, 1197 + state, 1198 + }); 1199 + } else if (event.type === 'requestBody') { 1200 + schemaToZodSchema({ 1201 + $ref: event.$ref, 1202 + plugin, 1203 + schema: event.requestBody.schema, 1204 + state, 1205 + }); 1206 + } else if (event.type === 'schema') { 1207 + schemaToZodSchema({ 1208 + $ref: event.$ref, 1209 + plugin, 1210 + schema: event.schema, 1211 + state, 1212 + }); 1213 + } 1275 1214 }); 1276 1215 };