@kubb/ast 5.0.0-alpha.8 → 5.0.0-beta.75

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/visitor.ts CHANGED
@@ -1,10 +1,21 @@
1
1
  import type { VisitorDepth } from './constants.ts'
2
2
  import { visitorDepths, WALK_CONCURRENCY } from './constants.ts'
3
- import type { Node, OperationNode, ParameterNode, PropertyNode, ResponseNode, RootNode, SchemaNode } from './nodes/index.ts'
3
+ import { createParameter, createProperty } from './factory.ts'
4
+ import type { InputNode, Node, OperationNode, OutputNode, ParameterNode, PropertyNode, ResponseNode, SchemaNode } from './nodes/index.ts'
4
5
 
5
6
  /**
6
- * Creates a concurrency-limiting wrapper. At most `concurrency` promises may be
7
- * in-flight simultaneously; additional calls are queued and dispatched as slots free.
7
+ * Creates a small async concurrency limiter.
8
+ *
9
+ * At most `concurrency` tasks are in flight at once. Extra tasks are queued.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * const limit = createLimit(2)
14
+ * for (const task of [taskA, taskB, taskC]) {
15
+ * await limit(() => task())
16
+ * }
17
+ * // only 2 tasks run at the same time
18
+ * ```
8
19
  */
9
20
  function createLimit(concurrency: number) {
10
21
  let active = 0
@@ -35,67 +46,233 @@ function createLimit(concurrency: number) {
35
46
  type LimitFn = ReturnType<typeof createLimit>
36
47
 
37
48
  /**
38
- * Shared options for `walk`, `transform`, and `collect`.
49
+ * Ordered mapping of `[NodeType, ParentType]` pairs.
50
+ *
51
+ * `ParentOf` uses this map to find parent types.
39
52
  */
40
- export type VisitorOptions = {
41
- depth?: VisitorDepth
53
+ type ParentNodeMap = [
54
+ [InputNode, undefined],
55
+ [OutputNode, undefined],
56
+ [OperationNode, InputNode],
57
+ [SchemaNode, InputNode | OperationNode | SchemaNode | PropertyNode | ParameterNode | ResponseNode],
58
+ [PropertyNode, SchemaNode],
59
+ [ParameterNode, OperationNode],
60
+ [ResponseNode, OperationNode],
61
+ ]
62
+
63
+ /**
64
+ * Resolves the parent node type for a given AST node type.
65
+ *
66
+ * This is used by visitor context so `ctx.parent` is correctly typed
67
+ * for each callback.
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * type InputParent = ParentOf<InputNode>
72
+ * // undefined
73
+ * ```
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * type PropertyParent = ParentOf<PropertyNode>
78
+ * // SchemaNode
79
+ * ```
80
+ *
81
+ * @example
82
+ * ```ts
83
+ * type SchemaParent = ParentOf<SchemaNode>
84
+ * // InputNode | OperationNode | SchemaNode | PropertyNode | ParameterNode | ResponseNode
85
+ * ```
86
+ */
87
+ export type ParentOf<T extends Node, TEntries extends ReadonlyArray<[Node, unknown]> = ParentNodeMap> = TEntries extends [
88
+ infer TEntry extends [Node, unknown],
89
+ ...infer TRest extends ReadonlyArray<[Node, unknown]>,
90
+ ]
91
+ ? T extends TEntry[0]
92
+ ? TEntry[1]
93
+ : ParentOf<T, TRest>
94
+ : Node
95
+
96
+ /**
97
+ * Traversal context passed as the second argument to every visitor callback.
98
+ * `parent` is typed from the current node type.
99
+ *
100
+ * @example
101
+ * ```ts
102
+ * const visitor: Visitor = {
103
+ * schema(node, { parent }) {
104
+ * // parent type is narrowed by node kind
105
+ * },
106
+ * }
107
+ * ```
108
+ */
109
+ export type VisitorContext<T extends Node = Node> = {
42
110
  /**
43
- * Maximum number of sibling nodes visited concurrently inside `walk`.
44
- * @default 30
111
+ * Parent node of the currently visited node.
112
+ * For `InputNode`, this is `undefined`.
45
113
  */
46
- concurrency?: number
114
+ parent?: ParentOf<T>
47
115
  }
48
116
 
49
117
  /**
50
- * Synchronous visitor for `transform` and `walk`.
118
+ * Synchronous visitor used by `transform`.
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * const visitor: Visitor = {
123
+ * operation(node) {
124
+ * return { ...node, operationId: `x_${node.operationId}` }
125
+ * },
126
+ * }
127
+ * ```
51
128
  */
52
129
  export type Visitor = {
53
- root?(node: RootNode): void | RootNode
54
- operation?(node: OperationNode): void | OperationNode
55
- schema?(node: SchemaNode): void | SchemaNode
56
- property?(node: PropertyNode): void | PropertyNode
57
- parameter?(node: ParameterNode): void | ParameterNode
58
- response?(node: ResponseNode): void | ResponseNode
130
+ input?(node: InputNode, context: VisitorContext<InputNode>): void | InputNode
131
+ output?(node: OutputNode, context: VisitorContext<OutputNode>): void | OutputNode
132
+ operation?(node: OperationNode, context: VisitorContext<OperationNode>): void | OperationNode
133
+ schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): void | SchemaNode
134
+ property?(node: PropertyNode, context: VisitorContext<PropertyNode>): void | PropertyNode
135
+ parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): void | ParameterNode
136
+ response?(node: ResponseNode, context: VisitorContext<ResponseNode>): void | ResponseNode
59
137
  }
60
138
 
139
+ /**
140
+ * Utility type for values that can be returned directly or asynchronously.
141
+ */
61
142
  type MaybePromise<T> = T | Promise<T>
62
143
 
63
144
  /**
64
145
  * Async visitor for `walk`. Synchronous `Visitor` objects are compatible.
146
+ *
147
+ * @example
148
+ * ```ts
149
+ * const visitor: AsyncVisitor = {
150
+ * async operation(node) {
151
+ * await Promise.resolve(node.operationId)
152
+ * },
153
+ * }
154
+ * ```
65
155
  */
66
156
  export type AsyncVisitor = {
67
- root?(node: RootNode): MaybePromise<void | RootNode>
68
- operation?(node: OperationNode): MaybePromise<void | OperationNode>
69
- schema?(node: SchemaNode): MaybePromise<void | SchemaNode>
70
- property?(node: PropertyNode): MaybePromise<void | PropertyNode>
71
- parameter?(node: ParameterNode): MaybePromise<void | ParameterNode>
72
- response?(node: ResponseNode): MaybePromise<void | ResponseNode>
157
+ input?(node: InputNode, context: VisitorContext<InputNode>): MaybePromise<void | InputNode>
158
+ output?(node: OutputNode, context: VisitorContext<OutputNode>): MaybePromise<void | OutputNode>
159
+ operation?(node: OperationNode, context: VisitorContext<OperationNode>): MaybePromise<void | OperationNode>
160
+ schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): MaybePromise<void | SchemaNode>
161
+ property?(node: PropertyNode, context: VisitorContext<PropertyNode>): MaybePromise<void | PropertyNode>
162
+ parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): MaybePromise<void | ParameterNode>
163
+ response?(node: ResponseNode, context: VisitorContext<ResponseNode>): MaybePromise<void | ResponseNode>
73
164
  }
74
165
 
75
166
  /**
76
- * Visitor for `collect`.
167
+ * Visitor used by `collect`.
168
+ *
169
+ * @example
170
+ * ```ts
171
+ * const visitor: CollectVisitor<string> = {
172
+ * operation(node) {
173
+ * return node.operationId
174
+ * },
175
+ * }
176
+ * ```
77
177
  */
78
178
  export type CollectVisitor<T> = {
79
- root?(node: RootNode): T | undefined
80
- operation?(node: OperationNode): T | undefined
81
- schema?(node: SchemaNode): T | undefined
82
- property?(node: PropertyNode): T | undefined
83
- parameter?(node: ParameterNode): T | undefined
84
- response?(node: ResponseNode): T | undefined
179
+ input?(node: InputNode, context: VisitorContext<InputNode>): T | undefined
180
+ output?(node: OutputNode, context: VisitorContext<OutputNode>): T | undefined
181
+ operation?(node: OperationNode, context: VisitorContext<OperationNode>): T | undefined
182
+ schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): T | undefined
183
+ property?(node: PropertyNode, context: VisitorContext<PropertyNode>): T | undefined
184
+ parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): T | undefined
185
+ response?(node: ResponseNode, context: VisitorContext<ResponseNode>): T | undefined
186
+ }
187
+
188
+ /**
189
+ * Options for `transform`.
190
+ *
191
+ * @example
192
+ * ```ts
193
+ * const options: TransformOptions = { depth: 'deep', schema: (node) => node }
194
+ * ```
195
+ *
196
+ * @example
197
+ * ```ts
198
+ * // Only transform the current node, not nested children
199
+ * const options: TransformOptions = { depth: 'shallow', schema: (node) => node }
200
+ * ```
201
+ */
202
+ export type TransformOptions = Visitor & {
203
+ /**
204
+ * Traversal depth (`'deep'` by default).
205
+ * @default 'deep'
206
+ */
207
+ depth?: VisitorDepth
208
+ /**
209
+ * Internal parent override used during recursion.
210
+ */
211
+ parent?: Node
212
+ }
213
+
214
+ /**
215
+ * Options for `walk`.
216
+ *
217
+ * @example
218
+ * ```ts
219
+ * const options: WalkOptions = { depth: 'deep', concurrency: 10, root: () => {} }
220
+ * ```
221
+ */
222
+ export type WalkOptions = AsyncVisitor & {
223
+ /**
224
+ * Traversal depth (`'deep'` by default).
225
+ * @default 'deep'
226
+ */
227
+ depth?: VisitorDepth
228
+ /**
229
+ * Maximum number of sibling nodes visited concurrently.
230
+ * @default 30
231
+ */
232
+ concurrency?: number
233
+ }
234
+
235
+ /**
236
+ * Options for `collect`.
237
+ *
238
+ * @example
239
+ * ```ts
240
+ * const options: CollectOptions<string> = { depth: 'shallow', schema: () => undefined }
241
+ * ```
242
+ */
243
+ export type CollectOptions<T> = CollectVisitor<T> & {
244
+ /**
245
+ * Traversal depth (`'deep'` by default).
246
+ * @default 'deep'
247
+ */
248
+ depth?: VisitorDepth
249
+ /**
250
+ * Internal parent override used during recursion.
251
+ */
252
+ parent?: Node
85
253
  }
86
254
 
87
255
  /**
88
256
  * Returns the immediate traversable children of `node`.
89
257
  *
90
- * For `Schema` nodes, children (properties, items, members) are only included
91
- * when `recurse` is `true`; shallow traversal omits them entirely.
258
+ * For `Schema` nodes, children (`properties`, `items`, `members`, and non-boolean
259
+ * `additionalProperties`) are only included
260
+ * when `recurse` is `true`; shallow mode skips them.
261
+ *
262
+ * @example
263
+ * ```ts
264
+ * const children = getChildren(operationNode, true)
265
+ * // returns parameters, requestBody schema (if present), and responses
266
+ * ```
92
267
  */
93
268
  function getChildren(node: Node, recurse: boolean): Array<Node> {
94
269
  switch (node.kind) {
95
- case 'Root':
270
+ case 'Input':
96
271
  return [...node.schemas, ...node.operations]
272
+ case 'Output':
273
+ return []
97
274
  case 'Operation':
98
- return [...node.parameters, ...(node.requestBody ? [node.requestBody] : []), ...node.responses]
275
+ return [...node.parameters, ...(node.requestBody?.content?.flatMap((c) => (c.schema ? [c.schema] : [])) ?? []), ...node.responses]
99
276
  case 'Schema': {
100
277
  const children: Array<Node> = []
101
278
 
@@ -104,6 +281,7 @@ function getChildren(node: Node, recurse: boolean): Array<Node> {
104
281
  if ('properties' in node && node.properties.length > 0) children.push(...node.properties)
105
282
  if ('items' in node && node.items) children.push(...node.items)
106
283
  if ('members' in node && node.members) children.push(...node.members)
284
+ if ('additionalProperties' in node && node.additionalProperties && node.additionalProperties !== true) children.push(node.additionalProperties)
107
285
 
108
286
  return children
109
287
  }
@@ -113,162 +291,299 @@ function getChildren(node: Node, recurse: boolean): Array<Node> {
113
291
  return [node.schema]
114
292
  case 'Response':
115
293
  return node.schema ? [node.schema] : []
294
+ case 'FunctionParameter':
295
+ case 'ParameterGroup':
296
+ case 'FunctionParameters':
297
+ case 'Type':
298
+ return []
299
+ default:
300
+ return []
116
301
  }
117
302
  }
118
303
 
119
304
  /**
120
305
  * Depth-first traversal for side effects. Visitor return values are ignored.
121
- * Sibling nodes at each level are visited concurrently up to `options.concurrency` (default: 30).
306
+ * Sibling nodes at each level are visited concurrently up to `options.concurrency`
307
+ * (default: `WALK_CONCURRENCY`).
308
+ *
309
+ * @example
310
+ * ```ts
311
+ * await walk(root, {
312
+ * operation(node) {
313
+ * console.log(node.operationId)
314
+ * },
315
+ * })
316
+ * ```
317
+ *
318
+ * @example
319
+ * ```ts
320
+ * // Visit only the current node
321
+ * await walk(root, { depth: 'shallow', root: () => {} })
322
+ * ```
122
323
  */
123
- export async function walk(node: Node, visitor: AsyncVisitor, options: VisitorOptions = {}): Promise<void> {
324
+ export async function walk(node: Node, options: WalkOptions): Promise<void> {
124
325
  const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep
125
326
  const limit = createLimit(options.concurrency ?? WALK_CONCURRENCY)
126
- return _walk(node, visitor, recurse, limit)
327
+
328
+ return _walk(node, options, recurse, limit, undefined)
127
329
  }
128
330
 
129
- /**
130
- * Internal recursive walk implementation — calls visitor then recurses into children.
131
- */
132
- async function _walk(node: Node, visitor: AsyncVisitor, recurse: boolean, limit: LimitFn): Promise<void> {
331
+ async function _walk(node: Node, visitor: AsyncVisitor, recurse: boolean, limit: LimitFn, parent: Node | undefined): Promise<void> {
133
332
  switch (node.kind) {
134
- case 'Root':
135
- await limit(() => visitor.root?.(node))
333
+ case 'Input':
334
+ await limit(() => visitor.input?.(node, { parent: parent as ParentOf<InputNode> }))
335
+ break
336
+ case 'Output':
337
+ await limit(() => visitor.output?.(node, { parent: parent as ParentOf<OutputNode> }))
136
338
  break
137
339
  case 'Operation':
138
- await limit(() => visitor.operation?.(node))
340
+ await limit(() =>
341
+ visitor.operation?.(node, {
342
+ parent: parent as ParentOf<OperationNode>,
343
+ }),
344
+ )
139
345
  break
140
346
  case 'Schema':
141
- await limit(() => visitor.schema?.(node))
347
+ await limit(() => visitor.schema?.(node, { parent: parent as ParentOf<SchemaNode> }))
142
348
  break
143
349
  case 'Property':
144
- await limit(() => visitor.property?.(node))
350
+ await limit(() => visitor.property?.(node, { parent: parent as ParentOf<PropertyNode> }))
145
351
  break
146
352
  case 'Parameter':
147
- await limit(() => visitor.parameter?.(node))
353
+ await limit(() =>
354
+ visitor.parameter?.(node, {
355
+ parent: parent as ParentOf<ParameterNode>,
356
+ }),
357
+ )
148
358
  break
149
359
  case 'Response':
150
- await limit(() => visitor.response?.(node))
360
+ await limit(() => visitor.response?.(node, { parent: parent as ParentOf<ResponseNode> }))
361
+ break
362
+ case 'FunctionParameter':
363
+ case 'ParameterGroup':
364
+ case 'FunctionParameters':
151
365
  break
152
366
  }
153
367
 
154
368
  const children = getChildren(node, recurse)
155
- await Promise.all(children.map((child) => _walk(child, visitor, recurse, limit)))
369
+ for (const child of children) {
370
+ await _walk(child, visitor, recurse, limit, node)
371
+ }
156
372
  }
157
373
 
158
374
  /**
159
- * Depth-first immutable transformation. Visitor return values replace nodes; `undefined` keeps the original.
375
+ * Runs a depth-first immutable transform.
376
+ *
377
+ * If a visitor returns a node, it replaces the current node.
378
+ * If it returns `undefined`, the current node stays the same.
379
+ *
380
+ * @example
381
+ * ```ts
382
+ * const next = transform(root, {
383
+ * operation(node) {
384
+ * return { ...node, operationId: `prefixed_${node.operationId}` }
385
+ * },
386
+ * })
387
+ * ```
388
+ *
389
+ * @example
390
+ * ```ts
391
+ * // Shallow mode: only transform the input node
392
+ * const next = transform(root, { depth: 'shallow', root: (node) => node })
393
+ * ```
160
394
  */
161
- export function transform(node: RootNode, visitor: Visitor, options?: VisitorOptions): RootNode
162
- export function transform(node: OperationNode, visitor: Visitor, options?: VisitorOptions): OperationNode
163
- export function transform(node: SchemaNode, visitor: Visitor, options?: VisitorOptions): SchemaNode
164
- export function transform(node: PropertyNode, visitor: Visitor, options?: VisitorOptions): PropertyNode
165
- export function transform(node: ParameterNode, visitor: Visitor, options?: VisitorOptions): ParameterNode
166
- export function transform(node: ResponseNode, visitor: Visitor, options?: VisitorOptions): ResponseNode
167
- export function transform(node: Node, visitor: Visitor, options?: VisitorOptions): Node
168
- export function transform(node: Node, visitor: Visitor, options: VisitorOptions = {}): Node {
169
- const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep
395
+ export function transform(node: InputNode, options: TransformOptions): InputNode
396
+ export function transform(node: OutputNode, options: TransformOptions): OutputNode
397
+ export function transform(node: OperationNode, options: TransformOptions): OperationNode
398
+ export function transform(node: SchemaNode, options: TransformOptions): SchemaNode
399
+ export function transform(node: PropertyNode, options: TransformOptions): PropertyNode
400
+ export function transform(node: ParameterNode, options: TransformOptions): ParameterNode
401
+ export function transform(node: ResponseNode, options: TransformOptions): ResponseNode
402
+ export function transform(node: Node, options: TransformOptions): Node
403
+ export function transform(node: Node, options: TransformOptions): Node {
404
+ const { depth, parent, ...visitor } = options
405
+ const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep
170
406
 
171
407
  switch (node.kind) {
172
- case 'Root': {
173
- let root = node
174
- const replaced = visitor.root?.(root)
175
- if (replaced) root = replaced
408
+ case 'Input': {
409
+ let input = node
410
+ const replaced = visitor.input?.(input, {
411
+ parent: parent as ParentOf<InputNode>,
412
+ })
413
+ if (replaced) input = replaced
176
414
 
177
415
  return {
178
- ...root,
179
- schemas: root.schemas.map((s) => transform(s, visitor, options)),
180
- operations: root.operations.map((op) => transform(op, visitor, options)),
416
+ ...input,
417
+ schemas: input.schemas.map((s) => transform(s, { ...options, parent: input })),
418
+ operations: input.operations.map((op) => transform(op, { ...options, parent: input })),
181
419
  }
182
420
  }
421
+ case 'Output': {
422
+ let output = node
423
+ const replaced = visitor.output?.(output, {
424
+ parent: parent as ParentOf<OutputNode>,
425
+ })
426
+ if (replaced) output = replaced
427
+
428
+ return output
429
+ }
183
430
  case 'Operation': {
184
431
  let op = node
185
- const replaced = visitor.operation?.(op)
432
+ const replaced = visitor.operation?.(op, {
433
+ parent: parent as ParentOf<OperationNode>,
434
+ })
186
435
  if (replaced) op = replaced
187
436
 
188
437
  return {
189
438
  ...op,
190
- parameters: op.parameters.map((p) => transform(p, visitor, options)),
191
- requestBody: op.requestBody ? transform(op.requestBody, visitor, options) : undefined,
192
- responses: op.responses.map((r) => transform(r, visitor, options)),
439
+ parameters: op.parameters.map((p) => transform(p, { ...options, parent: op })),
440
+ requestBody: op.requestBody
441
+ ? {
442
+ ...op.requestBody,
443
+ content: op.requestBody.content?.map((c) => ({
444
+ ...c,
445
+ schema: c.schema ? transform(c.schema, { ...options, parent: op }) : undefined,
446
+ })),
447
+ }
448
+ : undefined,
449
+ responses: op.responses.map((r) => transform(r, { ...options, parent: op })),
193
450
  }
194
451
  }
195
452
  case 'Schema': {
196
453
  let schema = node
197
- const replaced = visitor.schema?.(schema)
454
+ const replaced = visitor.schema?.(schema, {
455
+ parent: parent as ParentOf<SchemaNode>,
456
+ })
198
457
  if (replaced) schema = replaced
199
458
 
459
+ const childOptions = { ...options, parent: schema }
460
+
200
461
  return {
201
462
  ...schema,
202
- ...('properties' in schema && recurse ? { properties: schema.properties.map((p) => transform(p, visitor, options)) } : {}),
203
- ...('items' in schema && recurse ? { items: schema.items?.map((i) => transform(i, visitor, options)) } : {}),
204
- ...('members' in schema && recurse ? { members: schema.members?.map((m) => transform(m, visitor, options)) } : {}),
205
- }
463
+ ...('properties' in schema && recurse
464
+ ? {
465
+ properties: schema.properties.map((p) => transform(p, childOptions)),
466
+ }
467
+ : {}),
468
+ ...('items' in schema && recurse ? { items: schema.items?.map((i) => transform(i, childOptions)) } : {}),
469
+ ...('members' in schema && recurse ? { members: schema.members?.map((m) => transform(m, childOptions)) } : {}),
470
+ ...('additionalProperties' in schema && recurse && schema.additionalProperties && schema.additionalProperties !== true
471
+ ? {
472
+ additionalProperties: transform(schema.additionalProperties, childOptions),
473
+ }
474
+ : {}),
475
+ } as SchemaNode
206
476
  }
207
477
  case 'Property': {
208
478
  let prop = node
209
- const replaced = visitor.property?.(prop)
479
+ const replaced = visitor.property?.(prop, {
480
+ parent: parent as ParentOf<PropertyNode>,
481
+ })
210
482
  if (replaced) prop = replaced
211
483
 
212
- return {
484
+ return createProperty({
213
485
  ...prop,
214
- schema: transform(prop.schema, visitor, options),
215
- }
486
+ schema: transform(prop.schema, { ...options, parent: prop }),
487
+ })
216
488
  }
217
489
  case 'Parameter': {
218
490
  let param = node
219
- const replaced = visitor.parameter?.(param)
491
+ const replaced = visitor.parameter?.(param, {
492
+ parent: parent as ParentOf<ParameterNode>,
493
+ })
220
494
  if (replaced) param = replaced
221
495
 
222
- return {
496
+ return createParameter({
223
497
  ...param,
224
- schema: transform(param.schema, visitor, options),
225
- }
498
+ schema: transform(param.schema, { ...options, parent: param }),
499
+ })
226
500
  }
227
501
  case 'Response': {
228
502
  let response = node
229
- const replaced = visitor.response?.(response)
503
+ const replaced = visitor.response?.(response, {
504
+ parent: parent as ParentOf<ResponseNode>,
505
+ })
230
506
  if (replaced) response = replaced
231
507
 
232
508
  return {
233
509
  ...response,
234
- schema: response.schema ? transform(response.schema, visitor, options) : undefined,
510
+ schema: transform(response.schema, { ...options, parent: response }),
235
511
  }
236
512
  }
513
+ case 'FunctionParameter':
514
+ case 'ParameterGroup':
515
+ case 'FunctionParameters':
516
+ case 'Type':
517
+ return node
518
+ default:
519
+ return node
237
520
  }
238
521
  }
239
-
240
522
  /**
241
- * Depth-first synchronous reduction. Collects non-`undefined` visitor return values into an array.
523
+ * Runs a depth-first synchronous collection pass.
524
+ *
525
+ * Non-`undefined` values returned by visitor callbacks are appended to the result.
526
+ *
527
+ * @example
528
+ * ```ts
529
+ * const ids = collect(root, {
530
+ * operation(node) {
531
+ * return node.operationId
532
+ * },
533
+ * })
534
+ * ```
535
+ *
536
+ * @example
537
+ * ```ts
538
+ * // Collect from only the current node
539
+ * const values = collect(root, { depth: 'shallow', root: () => 'root' })
540
+ * ```
242
541
  */
243
- export function collect<T>(node: Node, visitor: CollectVisitor<T>, options: VisitorOptions = {}): Array<T> {
244
- const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep
542
+ export function collect<T>(node: Node, options: CollectOptions<T>): Array<T> {
543
+ const { depth, parent, ...visitor } = options
544
+ const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep
245
545
  const results: Array<T> = []
246
546
 
247
547
  let v: T | undefined
248
548
  switch (node.kind) {
249
- case 'Root':
250
- v = visitor.root?.(node)
549
+ case 'Input':
550
+ v = visitor.input?.(node, { parent: parent as ParentOf<InputNode> })
551
+ break
552
+ case 'Output':
553
+ v = visitor.output?.(node, { parent: parent as ParentOf<OutputNode> })
251
554
  break
252
555
  case 'Operation':
253
- v = visitor.operation?.(node)
556
+ v = visitor.operation?.(node, {
557
+ parent: parent as ParentOf<OperationNode>,
558
+ })
254
559
  break
255
560
  case 'Schema':
256
- v = visitor.schema?.(node)
561
+ v = visitor.schema?.(node, { parent: parent as ParentOf<SchemaNode> })
257
562
  break
258
563
  case 'Property':
259
- v = visitor.property?.(node)
564
+ v = visitor.property?.(node, {
565
+ parent: parent as ParentOf<PropertyNode>,
566
+ })
260
567
  break
261
568
  case 'Parameter':
262
- v = visitor.parameter?.(node)
569
+ v = visitor.parameter?.(node, {
570
+ parent: parent as ParentOf<ParameterNode>,
571
+ })
263
572
  break
264
573
  case 'Response':
265
- v = visitor.response?.(node)
574
+ v = visitor.response?.(node, {
575
+ parent: parent as ParentOf<ResponseNode>,
576
+ })
577
+ break
578
+ case 'FunctionParameter':
579
+ case 'ParameterGroup':
580
+ case 'FunctionParameters':
266
581
  break
267
582
  }
268
583
  if (v !== undefined) results.push(v)
269
584
 
270
585
  for (const child of getChildren(node, recurse)) {
271
- for (const item of collect(child, visitor, options)) {
586
+ for (const item of collect(child, { ...options, parent: node })) {
272
587
  results.push(item)
273
588
  }
274
589
  }
package/dist/types.cjs DELETED
File without changes
package/dist/types.d.ts DELETED
@@ -1,2 +0,0 @@
1
- import { $ as UnionSchemaNode, A as MediaType, B as IntersectionSchemaNode, C as Node, D as OperationNode, E as HttpMethod, F as ComplexSchemaType, G as ScalarSchemaNode, H as ObjectSchemaNode, I as DateSchemaNode, J as SchemaNodeByType, K as ScalarSchemaType, L as DatetimeSchemaNode, M as ParameterLocation, N as ParameterNode, O as ResponseNode, P as ArraySchemaNode, Q as TimeSchemaNode, R as EnumSchemaNode, T as RootNode, U as PrimitiveSchemaType, V as NumberSchemaNode, W as RefSchemaNode, X as SpecialSchemaType, Y as SchemaType, Z as StringSchemaNode, d as Printer, et as UrlSchemaNode, f as PrinterFactoryOptions, g as DistributiveOmit, it as VisitorDepth, j as StatusCode, k as HttpStatusCode, m as PrinterHandlerContext, n as CollectVisitor, nt as BaseNode, p as PrinterHandler, q as SchemaNode, r as Visitor, rt as NodeKind, s as RefMap, t as AsyncVisitor, tt as PropertyNode, w as RootMeta, z as EnumValueNode } from "./visitor-CrkOJoGa.js";
2
- export { type ArraySchemaNode, type AsyncVisitor, type BaseNode, type CollectVisitor, type ComplexSchemaType, type DateSchemaNode, type DatetimeSchemaNode, type DistributiveOmit, type EnumSchemaNode, type EnumValueNode, type HttpMethod, type HttpStatusCode, type IntersectionSchemaNode, type MediaType, type Node, type NodeKind, type NumberSchemaNode, type ObjectSchemaNode, type OperationNode, type ParameterLocation, type ParameterNode, type PrimitiveSchemaType, type Printer, type PrinterFactoryOptions, type PrinterHandler, type PrinterHandlerContext, type PropertyNode, type RefMap, type RefSchemaNode, type ResponseNode, type RootMeta, type RootNode, type ScalarSchemaNode, type ScalarSchemaType, type SchemaNode, type SchemaNodeByType, type SchemaType, type SpecialSchemaType, type StatusCode, type StringSchemaNode, type TimeSchemaNode, type UnionSchemaNode, type UrlSchemaNode, type Visitor, type VisitorDepth };
package/dist/types.js DELETED
@@ -1 +0,0 @@
1
- export {};