@kubb/ast 5.0.0-alpha.15 → 5.0.0-alpha.17
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/dist/index.cjs +1069 -626
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +238 -52
- package/dist/index.js +1054 -624
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/visitor-BFn3X90U.d.ts +1974 -0
- package/package.json +1 -1
- package/src/constants.ts +92 -3
- package/src/factory.ts +174 -37
- package/src/guards.ts +37 -10
- package/src/index.ts +8 -6
- package/src/infer.ts +130 -0
- package/src/mocks.ts +4 -3
- package/src/nodes/base.ts +21 -3
- package/src/nodes/function.ts +34 -22
- package/src/nodes/http.ts +17 -5
- package/src/nodes/index.ts +14 -4
- package/src/nodes/operation.ts +47 -9
- package/src/nodes/parameter.ts +27 -1
- package/src/nodes/property.ts +23 -1
- package/src/nodes/response.ts +23 -3
- package/src/nodes/root.ts +29 -8
- package/src/nodes/schema.ts +298 -36
- package/src/{functionPrinter.ts → printers/functionPrinter.ts} +20 -19
- package/src/printers/index.ts +3 -0
- package/src/{printer.ts → printers/printer.ts} +58 -42
- package/src/refs.ts +36 -4
- package/src/resolvers.ts +45 -0
- package/src/transformers.ts +196 -0
- package/src/types.ts +2 -1
- package/src/utils.ts +37 -8
- package/src/visitor.ts +204 -18
- package/dist/visitor-UlWOe-In.d.ts +0 -961
package/src/visitor.ts
CHANGED
|
@@ -4,8 +4,20 @@ import { createParameter, createProperty } from './factory.ts'
|
|
|
4
4
|
import type { Node, OperationNode, ParameterNode, PropertyNode, ResponseNode, RootNode, SchemaNode } from './nodes/index.ts'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Creates a
|
|
8
|
-
*
|
|
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
|
+
* await Promise.all([
|
|
15
|
+
* limit(() => taskA()),
|
|
16
|
+
* limit(() => taskB()),
|
|
17
|
+
* limit(() => taskC()),
|
|
18
|
+
* ])
|
|
19
|
+
* // only 2 tasks run at the same time
|
|
20
|
+
* ```
|
|
9
21
|
*/
|
|
10
22
|
function createLimit(concurrency: number) {
|
|
11
23
|
let active = 0
|
|
@@ -36,10 +48,9 @@ function createLimit(concurrency: number) {
|
|
|
36
48
|
type LimitFn = ReturnType<typeof createLimit>
|
|
37
49
|
|
|
38
50
|
/**
|
|
39
|
-
*
|
|
40
|
-
* describing which node types can be the parent of a given node in the AST.
|
|
51
|
+
* Ordered mapping of `[NodeType, ParentType]` pairs.
|
|
41
52
|
*
|
|
42
|
-
* `ParentOf`
|
|
53
|
+
* `ParentOf` uses this map to find parent types.
|
|
43
54
|
*/
|
|
44
55
|
type ParentNodeMap = [
|
|
45
56
|
[RootNode, undefined],
|
|
@@ -50,6 +61,30 @@ type ParentNodeMap = [
|
|
|
50
61
|
[ResponseNode, OperationNode],
|
|
51
62
|
]
|
|
52
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Resolves the parent node type for a given AST node type.
|
|
66
|
+
*
|
|
67
|
+
* This is used by visitor context so `ctx.parent` is correctly typed
|
|
68
|
+
* for each callback.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```ts
|
|
72
|
+
* type RootParent = ParentOf<RootNode>
|
|
73
|
+
* // undefined
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* type PropertyParent = ParentOf<PropertyNode>
|
|
79
|
+
* // SchemaNode
|
|
80
|
+
* ```
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```ts
|
|
84
|
+
* type SchemaParent = ParentOf<SchemaNode>
|
|
85
|
+
* // RootNode | OperationNode | SchemaNode | PropertyNode | ParameterNode | ResponseNode
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
53
88
|
export type ParentOf<T extends Node, TEntries extends ReadonlyArray<[Node, unknown]> = ParentNodeMap> = TEntries extends [
|
|
54
89
|
infer TEntry extends [Node, unknown],
|
|
55
90
|
...infer TRest extends ReadonlyArray<[Node, unknown]>,
|
|
@@ -61,14 +96,36 @@ export type ParentOf<T extends Node, TEntries extends ReadonlyArray<[Node, unkno
|
|
|
61
96
|
|
|
62
97
|
/**
|
|
63
98
|
* Traversal context passed as the second argument to every visitor callback.
|
|
64
|
-
*
|
|
99
|
+
* `parent` is typed from the current node type.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* const visitor: Visitor = {
|
|
104
|
+
* schema(node, { parent }) {
|
|
105
|
+
* // parent type is narrowed by node kind
|
|
106
|
+
* },
|
|
107
|
+
* }
|
|
108
|
+
* ```
|
|
65
109
|
*/
|
|
66
110
|
export type VisitorContext<T extends Node = Node> = {
|
|
111
|
+
/**
|
|
112
|
+
* Parent node of the currently visited node.
|
|
113
|
+
* For `RootNode`, this is `undefined`.
|
|
114
|
+
*/
|
|
67
115
|
parent?: ParentOf<T>
|
|
68
116
|
}
|
|
69
117
|
|
|
70
118
|
/**
|
|
71
|
-
* Synchronous visitor
|
|
119
|
+
* Synchronous visitor used by `transform`.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```ts
|
|
123
|
+
* const visitor: Visitor = {
|
|
124
|
+
* operation(node) {
|
|
125
|
+
* return { ...node, operationId: `x_${node.operationId}` }
|
|
126
|
+
* },
|
|
127
|
+
* }
|
|
128
|
+
* ```
|
|
72
129
|
*/
|
|
73
130
|
export type Visitor = {
|
|
74
131
|
root?(node: RootNode, context: VisitorContext<RootNode>): void | RootNode
|
|
@@ -79,10 +136,22 @@ export type Visitor = {
|
|
|
79
136
|
response?(node: ResponseNode, context: VisitorContext<ResponseNode>): void | ResponseNode
|
|
80
137
|
}
|
|
81
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Utility type for values that can be returned directly or asynchronously.
|
|
141
|
+
*/
|
|
82
142
|
type MaybePromise<T> = T | Promise<T>
|
|
83
143
|
|
|
84
144
|
/**
|
|
85
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
|
+
* ```
|
|
86
155
|
*/
|
|
87
156
|
export type AsyncVisitor = {
|
|
88
157
|
root?(node: RootNode, context: VisitorContext<RootNode>): MaybePromise<void | RootNode>
|
|
@@ -94,7 +163,16 @@ export type AsyncVisitor = {
|
|
|
94
163
|
}
|
|
95
164
|
|
|
96
165
|
/**
|
|
97
|
-
* Visitor
|
|
166
|
+
* Visitor used by `collect`.
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* ```ts
|
|
170
|
+
* const visitor: CollectVisitor<string> = {
|
|
171
|
+
* operation(node) {
|
|
172
|
+
* return node.operationId
|
|
173
|
+
* },
|
|
174
|
+
* }
|
|
175
|
+
* ```
|
|
98
176
|
*/
|
|
99
177
|
export type CollectVisitor<T> = {
|
|
100
178
|
root?(node: RootNode, context: VisitorContext<RootNode>): T | undefined
|
|
@@ -106,17 +184,44 @@ export type CollectVisitor<T> = {
|
|
|
106
184
|
}
|
|
107
185
|
|
|
108
186
|
/**
|
|
109
|
-
* Options for `transform
|
|
187
|
+
* Options for `transform`.
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```ts
|
|
191
|
+
* const options: TransformOptions = { depth: 'deep', schema: (node) => node }
|
|
192
|
+
* ```
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```ts
|
|
196
|
+
* // Only transform the current node, not nested children
|
|
197
|
+
* const options: TransformOptions = { depth: 'shallow', schema: (node) => node }
|
|
198
|
+
* ```
|
|
110
199
|
*/
|
|
111
200
|
export type TransformOptions = Visitor & {
|
|
201
|
+
/**
|
|
202
|
+
* Traversal depth (`'deep'` by default).
|
|
203
|
+
* @default 'deep'
|
|
204
|
+
*/
|
|
112
205
|
depth?: VisitorDepth
|
|
206
|
+
/**
|
|
207
|
+
* Internal parent override used during recursion.
|
|
208
|
+
*/
|
|
113
209
|
parent?: Node
|
|
114
210
|
}
|
|
115
211
|
|
|
116
212
|
/**
|
|
117
|
-
* Options for `walk`.
|
|
213
|
+
* Options for `walk`.
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```ts
|
|
217
|
+
* const options: WalkOptions = { depth: 'deep', concurrency: 10, root: () => {} }
|
|
218
|
+
* ```
|
|
118
219
|
*/
|
|
119
220
|
export type WalkOptions = AsyncVisitor & {
|
|
221
|
+
/**
|
|
222
|
+
* Traversal depth (`'deep'` by default).
|
|
223
|
+
* @default 'deep'
|
|
224
|
+
*/
|
|
120
225
|
depth?: VisitorDepth
|
|
121
226
|
/**
|
|
122
227
|
* Maximum number of sibling nodes visited concurrently.
|
|
@@ -126,18 +231,37 @@ export type WalkOptions = AsyncVisitor & {
|
|
|
126
231
|
}
|
|
127
232
|
|
|
128
233
|
/**
|
|
129
|
-
* Options for `collect`.
|
|
234
|
+
* Options for `collect`.
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* ```ts
|
|
238
|
+
* const options: CollectOptions<string> = { depth: 'shallow', schema: () => undefined }
|
|
239
|
+
* ```
|
|
130
240
|
*/
|
|
131
241
|
export type CollectOptions<T> = CollectVisitor<T> & {
|
|
242
|
+
/**
|
|
243
|
+
* Traversal depth (`'deep'` by default).
|
|
244
|
+
* @default 'deep'
|
|
245
|
+
*/
|
|
132
246
|
depth?: VisitorDepth
|
|
247
|
+
/**
|
|
248
|
+
* Internal parent override used during recursion.
|
|
249
|
+
*/
|
|
133
250
|
parent?: Node
|
|
134
251
|
}
|
|
135
252
|
|
|
136
253
|
/**
|
|
137
254
|
* Returns the immediate traversable children of `node`.
|
|
138
255
|
*
|
|
139
|
-
* For `Schema` nodes, children (properties
|
|
140
|
-
*
|
|
256
|
+
* For `Schema` nodes, children (`properties`, `items`, `members`, and non-boolean
|
|
257
|
+
* `additionalProperties`) are only included
|
|
258
|
+
* when `recurse` is `true`; shallow mode skips them.
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* ```ts
|
|
262
|
+
* const children = getChildren(operationNode, true)
|
|
263
|
+
* // returns parameters, requestBody schema (if present), and responses
|
|
264
|
+
* ```
|
|
141
265
|
*/
|
|
142
266
|
function getChildren(node: Node, recurse: boolean): Array<Node> {
|
|
143
267
|
switch (node.kind) {
|
|
@@ -172,11 +296,28 @@ function getChildren(node: Node, recurse: boolean): Array<Node> {
|
|
|
172
296
|
|
|
173
297
|
/**
|
|
174
298
|
* Depth-first traversal for side effects. Visitor return values are ignored.
|
|
175
|
-
* Sibling nodes at each level are visited concurrently up to `options.concurrency`
|
|
299
|
+
* Sibling nodes at each level are visited concurrently up to `options.concurrency`
|
|
300
|
+
* (default: `WALK_CONCURRENCY`).
|
|
301
|
+
*
|
|
302
|
+
* @example
|
|
303
|
+
* ```ts
|
|
304
|
+
* await walk(root, {
|
|
305
|
+
* operation(node) {
|
|
306
|
+
* console.log(node.operationId)
|
|
307
|
+
* },
|
|
308
|
+
* })
|
|
309
|
+
* ```
|
|
310
|
+
*
|
|
311
|
+
* @example
|
|
312
|
+
* ```ts
|
|
313
|
+
* // Visit only the current node
|
|
314
|
+
* await walk(root, { depth: 'shallow', root: () => {} })
|
|
315
|
+
* ```
|
|
176
316
|
*/
|
|
177
317
|
export async function walk(node: Node, options: WalkOptions): Promise<void> {
|
|
178
318
|
const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep
|
|
179
319
|
const limit = createLimit(options.concurrency ?? WALK_CONCURRENCY)
|
|
320
|
+
|
|
180
321
|
return _walk(node, options, recurse, limit, undefined)
|
|
181
322
|
}
|
|
182
323
|
|
|
@@ -211,7 +352,25 @@ async function _walk(node: Node, visitor: AsyncVisitor, recurse: boolean, limit:
|
|
|
211
352
|
}
|
|
212
353
|
|
|
213
354
|
/**
|
|
214
|
-
*
|
|
355
|
+
* Runs a depth-first immutable transform.
|
|
356
|
+
*
|
|
357
|
+
* If a visitor returns a node, it replaces the current node.
|
|
358
|
+
* If it returns `undefined`, the current node stays the same.
|
|
359
|
+
*
|
|
360
|
+
* @example
|
|
361
|
+
* ```ts
|
|
362
|
+
* const next = transform(root, {
|
|
363
|
+
* operation(node) {
|
|
364
|
+
* return { ...node, operationId: `prefixed_${node.operationId}` }
|
|
365
|
+
* },
|
|
366
|
+
* })
|
|
367
|
+
* ```
|
|
368
|
+
*
|
|
369
|
+
* @example
|
|
370
|
+
* ```ts
|
|
371
|
+
* // Shallow mode: only transform the input node
|
|
372
|
+
* const next = transform(root, { depth: 'shallow', root: (node) => node })
|
|
373
|
+
* ```
|
|
215
374
|
*/
|
|
216
375
|
export function transform(node: RootNode, options: TransformOptions): RootNode
|
|
217
376
|
export function transform(node: OperationNode, options: TransformOptions): OperationNode
|
|
@@ -305,8 +464,18 @@ export function transform(node: Node, options: TransformOptions): Node {
|
|
|
305
464
|
}
|
|
306
465
|
|
|
307
466
|
/**
|
|
308
|
-
*
|
|
309
|
-
*
|
|
467
|
+
* Composes multiple visitors into one visitor, applied left to right.
|
|
468
|
+
*
|
|
469
|
+
* For each node kind, output from one visitor is input to the next.
|
|
470
|
+
* If a visitor returns `undefined`, the previous node value is kept.
|
|
471
|
+
*
|
|
472
|
+
* @example
|
|
473
|
+
* ```ts
|
|
474
|
+
* const visitor = composeTransformers(
|
|
475
|
+
* { operation: (node) => ({ ...node, operationId: `a_${node.operationId}` }) },
|
|
476
|
+
* { operation: (node) => ({ ...node, operationId: `b_${node.operationId}` }) },
|
|
477
|
+
* )
|
|
478
|
+
* ```
|
|
310
479
|
*/
|
|
311
480
|
export function composeTransformers(...visitors: Array<Visitor>): Visitor {
|
|
312
481
|
return {
|
|
@@ -332,7 +501,24 @@ export function composeTransformers(...visitors: Array<Visitor>): Visitor {
|
|
|
332
501
|
}
|
|
333
502
|
|
|
334
503
|
/**
|
|
335
|
-
*
|
|
504
|
+
* Runs a depth-first synchronous collection pass.
|
|
505
|
+
*
|
|
506
|
+
* Non-`undefined` values returned by visitor callbacks are appended to the result.
|
|
507
|
+
*
|
|
508
|
+
* @example
|
|
509
|
+
* ```ts
|
|
510
|
+
* const ids = collect(root, {
|
|
511
|
+
* operation(node) {
|
|
512
|
+
* return node.operationId
|
|
513
|
+
* },
|
|
514
|
+
* })
|
|
515
|
+
* ```
|
|
516
|
+
*
|
|
517
|
+
* @example
|
|
518
|
+
* ```ts
|
|
519
|
+
* // Collect from only the current node
|
|
520
|
+
* const values = collect(root, { depth: 'shallow', root: () => 'root' })
|
|
521
|
+
* ```
|
|
336
522
|
*/
|
|
337
523
|
export function collect<T>(node: Node, options: CollectOptions<T>): Array<T> {
|
|
338
524
|
const { depth, parent, ...visitor } = options
|