@kubb/ast 5.0.0-beta.22 → 5.0.0-beta.23
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 +55 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +143 -93
- package/dist/index.js +55 -34
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/factory.ts +6 -3
- package/src/infer.ts +15 -4
- package/src/nodes/code.ts +21 -21
- package/src/nodes/file.ts +12 -12
- package/src/printer.ts +19 -12
- package/src/utils.ts +4 -4
- package/src/visitor.ts +72 -43
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/ast",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.23",
|
|
4
4
|
"description": "Spec-agnostic AST layer for Kubb. Defines the node tree, visitor pattern, factory functions, and type guards used across all code generation plugins.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ast",
|
package/src/factory.ts
CHANGED
|
@@ -33,10 +33,13 @@ import type {
|
|
|
33
33
|
import { combineExports, combineImports, combineSources, extractStringsFromNodes } from './utils.ts'
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
36
|
+
* Updates a schema's `optional` and `nullish` flags from a parent's `required`
|
|
37
|
+
* value and the schema's own `nullable`. Mirrors how OpenAPI parameters and
|
|
38
|
+
* object properties combine "required" and "nullable" into a single AST.
|
|
37
39
|
*
|
|
38
|
-
* -
|
|
39
|
-
* -
|
|
40
|
+
* - Non-required + non-nullable → `optional: true`.
|
|
41
|
+
* - Non-required + nullable → `nullish: true`.
|
|
42
|
+
* - Required → both flags cleared.
|
|
40
43
|
*/
|
|
41
44
|
export function syncOptionality(schema: SchemaNode, required: boolean): SchemaNode {
|
|
42
45
|
const nullable = schema.nullable ?? false
|
package/src/infer.ts
CHANGED
|
@@ -20,15 +20,25 @@ import type {
|
|
|
20
20
|
*/
|
|
21
21
|
export type ParserOptions = {
|
|
22
22
|
/**
|
|
23
|
-
* How `format: 'date-time'` schemas are represented
|
|
23
|
+
* How `format: 'date-time'` schemas are represented downstream.
|
|
24
|
+
* - `false` falls through to a plain `string` (no validation).
|
|
25
|
+
* - `'string'` emits a datetime string node.
|
|
26
|
+
* - `'stringOffset'` emits a datetime node with timezone offset.
|
|
27
|
+
* - `'stringLocal'` emits a local datetime node.
|
|
28
|
+
* - `'date'` emits a `date` node (JavaScript `Date` object).
|
|
24
29
|
*/
|
|
25
30
|
dateType: false | 'string' | 'stringOffset' | 'stringLocal' | 'date'
|
|
26
31
|
/**
|
|
27
|
-
*
|
|
32
|
+
* How `type: 'integer'` (and `format: 'int64'`) maps to TypeScript.
|
|
33
|
+
* - `'number'` fits most JSON APIs; loses precision above `Number.MAX_SAFE_INTEGER`.
|
|
34
|
+
* - `'bigint'` is exact for 64-bit IDs, but does not round-trip through JSON.
|
|
35
|
+
*
|
|
36
|
+
* @default 'number'
|
|
28
37
|
*/
|
|
29
38
|
integerType?: 'number' | 'bigint'
|
|
30
39
|
/**
|
|
31
|
-
* AST type used when
|
|
40
|
+
* AST type used when a schema's type cannot be inferred from the spec
|
|
41
|
+
* (`additionalProperties: true`, missing `type`, ...).
|
|
32
42
|
*/
|
|
33
43
|
unknownType: 'any' | 'unknown' | 'void'
|
|
34
44
|
/**
|
|
@@ -36,7 +46,8 @@ export type ParserOptions = {
|
|
|
36
46
|
*/
|
|
37
47
|
emptySchemaType: 'any' | 'unknown' | 'void'
|
|
38
48
|
/**
|
|
39
|
-
* Suffix appended to derived enum names when
|
|
49
|
+
* Suffix appended to derived enum names when Kubb has to invent one
|
|
50
|
+
* (typically for inline enums on object properties).
|
|
40
51
|
*/
|
|
41
52
|
enumSuffix: 'enum' | (string & {})
|
|
42
53
|
}
|
package/src/nodes/code.ts
CHANGED
|
@@ -36,21 +36,21 @@ export type ConstNode = BaseNode & {
|
|
|
36
36
|
* Whether the declaration should be exported.
|
|
37
37
|
* @default false
|
|
38
38
|
*/
|
|
39
|
-
export?: boolean
|
|
39
|
+
export?: boolean | null
|
|
40
40
|
/**
|
|
41
41
|
* Optional explicit type annotation.
|
|
42
42
|
* @example 'Pet'
|
|
43
43
|
*/
|
|
44
|
-
type?: string
|
|
44
|
+
type?: string | null
|
|
45
45
|
/**
|
|
46
46
|
* JSDoc documentation metadata.
|
|
47
47
|
*/
|
|
48
|
-
JSDoc?: JSDocNode
|
|
48
|
+
JSDoc?: JSDocNode | null
|
|
49
49
|
/**
|
|
50
50
|
* Whether to append `as const` to the declaration.
|
|
51
51
|
* @default false
|
|
52
52
|
*/
|
|
53
|
-
asConst?: boolean
|
|
53
|
+
asConst?: boolean | null
|
|
54
54
|
/**
|
|
55
55
|
* Child nodes representing the value of the constant (children of the `Const` component).
|
|
56
56
|
* Each entry is a {@link CodeNode}; use {@link TextNode} for raw string content.
|
|
@@ -83,11 +83,11 @@ export type TypeNode = BaseNode & {
|
|
|
83
83
|
* Whether the declaration should be exported.
|
|
84
84
|
* @default false
|
|
85
85
|
*/
|
|
86
|
-
export?: boolean
|
|
86
|
+
export?: boolean | null
|
|
87
87
|
/**
|
|
88
88
|
* JSDoc documentation metadata.
|
|
89
89
|
*/
|
|
90
|
-
JSDoc?: JSDocNode
|
|
90
|
+
JSDoc?: JSDocNode | null
|
|
91
91
|
/**
|
|
92
92
|
* Child nodes representing the type body (children of the `Type` component).
|
|
93
93
|
* Each entry is a {@link CodeNode}; use {@link TextNode} for raw string content.
|
|
@@ -126,35 +126,35 @@ export type FunctionNode = BaseNode & {
|
|
|
126
126
|
* Whether the function is a default export.
|
|
127
127
|
* @default false
|
|
128
128
|
*/
|
|
129
|
-
default?: boolean
|
|
129
|
+
default?: boolean | null
|
|
130
130
|
/**
|
|
131
131
|
* Function parameter list rendered as a string (e.g. from `FunctionParams.toConstructor()`).
|
|
132
132
|
*/
|
|
133
|
-
params?: string
|
|
133
|
+
params?: string | null
|
|
134
134
|
/**
|
|
135
135
|
* Whether the function should be exported.
|
|
136
136
|
* @default false
|
|
137
137
|
*/
|
|
138
|
-
export?: boolean
|
|
138
|
+
export?: boolean | null
|
|
139
139
|
/**
|
|
140
140
|
* Whether the function is async. When `true`, the return type is wrapped in `Promise<>`.
|
|
141
141
|
* @default false
|
|
142
142
|
*/
|
|
143
|
-
async?: boolean
|
|
143
|
+
async?: boolean | null
|
|
144
144
|
/**
|
|
145
145
|
* TypeScript generic type parameters.
|
|
146
146
|
* @example ['T', 'U extends string']
|
|
147
147
|
*/
|
|
148
|
-
generics?: string | string[]
|
|
148
|
+
generics?: string | string[] | null
|
|
149
149
|
/**
|
|
150
150
|
* Return type annotation.
|
|
151
151
|
* @example 'Pet'
|
|
152
152
|
*/
|
|
153
|
-
returnType?: string
|
|
153
|
+
returnType?: string | null
|
|
154
154
|
/**
|
|
155
155
|
* JSDoc documentation metadata.
|
|
156
156
|
*/
|
|
157
|
-
JSDoc?: JSDocNode
|
|
157
|
+
JSDoc?: JSDocNode | null
|
|
158
158
|
/**
|
|
159
159
|
* Child nodes representing the function body (children of the `Function` component).
|
|
160
160
|
* Each entry is a {@link CodeNode}; use {@link TextNode} for raw string content.
|
|
@@ -187,40 +187,40 @@ export type ArrowFunctionNode = BaseNode & {
|
|
|
187
187
|
* Whether the function is a default export.
|
|
188
188
|
* @default false
|
|
189
189
|
*/
|
|
190
|
-
default?: boolean
|
|
190
|
+
default?: boolean | null
|
|
191
191
|
/**
|
|
192
192
|
* Function parameter list rendered as a string (e.g. from `FunctionParams.toConstructor()`).
|
|
193
193
|
*/
|
|
194
|
-
params?: string
|
|
194
|
+
params?: string | null
|
|
195
195
|
/**
|
|
196
196
|
* Whether the arrow function should be exported.
|
|
197
197
|
* @default false
|
|
198
198
|
*/
|
|
199
|
-
export?: boolean
|
|
199
|
+
export?: boolean | null
|
|
200
200
|
/**
|
|
201
201
|
* Whether the arrow function is async. When `true`, the return type is wrapped in `Promise<>`.
|
|
202
202
|
* @default false
|
|
203
203
|
*/
|
|
204
|
-
async?: boolean
|
|
204
|
+
async?: boolean | null
|
|
205
205
|
/**
|
|
206
206
|
* TypeScript generic type parameters.
|
|
207
207
|
* @example ['T', 'U extends string']
|
|
208
208
|
*/
|
|
209
|
-
generics?: string | string[]
|
|
209
|
+
generics?: string | string[] | null
|
|
210
210
|
/**
|
|
211
211
|
* Return type annotation.
|
|
212
212
|
* @example 'Pet'
|
|
213
213
|
*/
|
|
214
|
-
returnType?: string
|
|
214
|
+
returnType?: string | null
|
|
215
215
|
/**
|
|
216
216
|
* JSDoc documentation metadata.
|
|
217
217
|
*/
|
|
218
|
-
JSDoc?: JSDocNode
|
|
218
|
+
JSDoc?: JSDocNode | null
|
|
219
219
|
/**
|
|
220
220
|
* Render the arrow function body as a single-line expression.
|
|
221
221
|
* @default false
|
|
222
222
|
*/
|
|
223
|
-
singleLine?: boolean
|
|
223
|
+
singleLine?: boolean | null
|
|
224
224
|
/**
|
|
225
225
|
* Child nodes representing the function body (children of the `Function.Arrow` component).
|
|
226
226
|
* Each entry is a {@link CodeNode}; use {@link TextNode} for raw string content.
|
package/src/nodes/file.ts
CHANGED
|
@@ -50,18 +50,18 @@ export type ImportNode = BaseNode & {
|
|
|
50
50
|
* - `false` generates `import { Type } from './path'`
|
|
51
51
|
* @default false
|
|
52
52
|
*/
|
|
53
|
-
isTypeOnly?: boolean
|
|
53
|
+
isTypeOnly?: boolean | null
|
|
54
54
|
/**
|
|
55
55
|
* Import entire module as namespace.
|
|
56
56
|
* - `true` generates `import * as Name from './path'`
|
|
57
57
|
* - `false` generates standard import
|
|
58
58
|
* @default false
|
|
59
59
|
*/
|
|
60
|
-
isNameSpace?: boolean
|
|
60
|
+
isNameSpace?: boolean | null
|
|
61
61
|
/**
|
|
62
62
|
* When set, the import path is resolved relative to this root.
|
|
63
63
|
*/
|
|
64
|
-
root?: string
|
|
64
|
+
root?: string | null
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
/**
|
|
@@ -94,7 +94,7 @@ export type ExportNode = BaseNode & {
|
|
|
94
94
|
* @example ['useState']
|
|
95
95
|
* @example 'React'
|
|
96
96
|
*/
|
|
97
|
-
name?: string | Array<string>
|
|
97
|
+
name?: string | Array<string> | null
|
|
98
98
|
/**
|
|
99
99
|
* Path for the export.
|
|
100
100
|
* @example '@kubb/core'
|
|
@@ -106,14 +106,14 @@ export type ExportNode = BaseNode & {
|
|
|
106
106
|
* - `false` generates `export { Type } from './path'`
|
|
107
107
|
* @default false
|
|
108
108
|
*/
|
|
109
|
-
isTypeOnly?: boolean
|
|
109
|
+
isTypeOnly?: boolean | null
|
|
110
110
|
/**
|
|
111
111
|
* Export as an aliased namespace.
|
|
112
112
|
* - `true` generates `export * as aliasName from './path'`
|
|
113
113
|
* - `false` generates a standard export
|
|
114
114
|
* @default false
|
|
115
115
|
*/
|
|
116
|
-
asAlias?: boolean
|
|
116
|
+
asAlias?: boolean | null
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
/**
|
|
@@ -134,22 +134,22 @@ export type SourceNode = BaseNode & {
|
|
|
134
134
|
/**
|
|
135
135
|
* Optional name identifying this source (used for deduplication and barrel generation).
|
|
136
136
|
*/
|
|
137
|
-
name?: string
|
|
137
|
+
name?: string | null
|
|
138
138
|
/**
|
|
139
139
|
* Mark this source as a type-only export.
|
|
140
140
|
* @default false
|
|
141
141
|
*/
|
|
142
|
-
isTypeOnly?: boolean
|
|
142
|
+
isTypeOnly?: boolean | null
|
|
143
143
|
/**
|
|
144
144
|
* Include `export` keyword in the generated source.
|
|
145
145
|
* @default false
|
|
146
146
|
*/
|
|
147
|
-
isExportable?: boolean
|
|
147
|
+
isExportable?: boolean | null
|
|
148
148
|
/**
|
|
149
149
|
* Include this source in barrel/index file generation.
|
|
150
150
|
* @default false
|
|
151
151
|
*/
|
|
152
|
-
isIndexable?: boolean
|
|
152
|
+
isIndexable?: boolean | null
|
|
153
153
|
/**
|
|
154
154
|
* Structured child nodes representing the content of this source fragment, in DOM order.
|
|
155
155
|
* Each entry is a {@link CodeNode}; use {@link TextNode} for raw string content.
|
|
@@ -180,8 +180,8 @@ export type SourceNode = BaseNode & {
|
|
|
180
180
|
export type FileNode<TMeta extends object = object> = BaseNode & {
|
|
181
181
|
kind: 'File'
|
|
182
182
|
/**
|
|
183
|
-
* Unique identifier derived from a SHA256 hash of the file path.
|
|
184
|
-
*
|
|
183
|
+
* Unique identifier derived from a SHA256 hash of the file path. Computed
|
|
184
|
+
* by `createFile`; callers do not need to provide it.
|
|
185
185
|
*/
|
|
186
186
|
id: string
|
|
187
187
|
/**
|
package/src/printer.ts
CHANGED
|
@@ -148,22 +148,27 @@ type PrinterBuilder<T extends PrinterFactoryOptions> = (options: T['options']) =
|
|
|
148
148
|
print?: (this: PrinterHandlerContext<T['output'], T['options']>, node: SchemaNode) => T['printOutput'] | null
|
|
149
149
|
}
|
|
150
150
|
/**
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
151
|
+
* Defines a schema printer: a function that takes a `SchemaNode` and emits
|
|
152
|
+
* code in your target language. Each plugin that produces code from schemas
|
|
153
|
+
* (TypeScript types, Zod schemas, Faker factories) ships a printer built
|
|
154
|
+
* with this helper.
|
|
154
155
|
*
|
|
155
156
|
* The builder receives resolved options and returns:
|
|
156
|
-
* - `name` — a unique identifier for the printer
|
|
157
|
-
* - `options` — options stored on the returned printer instance
|
|
158
|
-
* - `nodes` — a map of `SchemaType` → handler functions that convert a `SchemaNode` to `TOutput`
|
|
159
|
-
* - `print` _(optional)_ — top-level override exposed as `printer.print`
|
|
160
|
-
* - Inside this function, use `this.transform(node)` to dispatch to the `nodes` map
|
|
161
|
-
* - This keeps recursion safe and avoids self-calls
|
|
162
157
|
*
|
|
163
|
-
*
|
|
158
|
+
* - `name` — unique identifier for the printer.
|
|
159
|
+
* - `options` — stored on the returned printer instance.
|
|
160
|
+
* - `nodes` — map of `SchemaType` → handler. Handlers return the rendered
|
|
161
|
+
* output (a string, a TypeScript AST node, ...) for that schema type.
|
|
162
|
+
* - `print` (optional) — top-level override exposed as `printer.print`.
|
|
163
|
+
* Use `this.transform(node)` inside it to dispatch to `nodes` recursively.
|
|
164
|
+
*
|
|
165
|
+
* Without a `print` override, `printer.print` falls back to `printer.transform`
|
|
166
|
+
* (the node-level dispatcher).
|
|
164
167
|
*
|
|
165
|
-
* @example
|
|
168
|
+
* @example Tiny Zod printer
|
|
166
169
|
* ```ts
|
|
170
|
+
* import { definePrinter, type PrinterFactoryOptions } from '@kubb/ast'
|
|
171
|
+
*
|
|
167
172
|
* type PrinterZod = PrinterFactoryOptions<'zod', { strict?: boolean }, string>
|
|
168
173
|
*
|
|
169
174
|
* export const zodPrinter = definePrinter<PrinterZod>((options) => ({
|
|
@@ -172,7 +177,9 @@ type PrinterBuilder<T extends PrinterFactoryOptions> = (options: T['options']) =
|
|
|
172
177
|
* nodes: {
|
|
173
178
|
* string: () => 'z.string()',
|
|
174
179
|
* object(node) {
|
|
175
|
-
* const props = node.properties
|
|
180
|
+
* const props = node.properties
|
|
181
|
+
* .map((p) => `${p.name}: ${this.transform(p.schema)}`)
|
|
182
|
+
* .join(', ')
|
|
176
183
|
* return `z.object({ ${props} })`
|
|
177
184
|
* },
|
|
178
185
|
* },
|
package/src/utils.ts
CHANGED
|
@@ -556,15 +556,15 @@ function sourceKey(source: SourceNode): string {
|
|
|
556
556
|
return `${nameKey}:${source.isExportable ?? false}:${source.isTypeOnly ?? false}`
|
|
557
557
|
}
|
|
558
558
|
|
|
559
|
-
function pathTypeKey(path: string, isTypeOnly: boolean | undefined): string {
|
|
559
|
+
function pathTypeKey(path: string, isTypeOnly: boolean | null | undefined): string {
|
|
560
560
|
return `${path}:${isTypeOnly ?? false}`
|
|
561
561
|
}
|
|
562
562
|
|
|
563
|
-
function exportKey(path: string, name: string | undefined, isTypeOnly: boolean | undefined, asAlias: boolean | undefined): string {
|
|
563
|
+
function exportKey(path: string, name: string | null | undefined, isTypeOnly: boolean | null | undefined, asAlias: boolean | null | undefined): string {
|
|
564
564
|
return `${path}:${name ?? ''}:${isTypeOnly ?? false}:${asAlias ?? ''}`
|
|
565
565
|
}
|
|
566
566
|
|
|
567
|
-
function importKey(path: string, name: string | undefined, isTypeOnly: boolean | undefined): string {
|
|
567
|
+
function importKey(path: string, name: string | null | undefined, isTypeOnly: boolean | null | undefined): string {
|
|
568
568
|
return `${path}:${name ?? ''}:${isTypeOnly ?? false}`
|
|
569
569
|
}
|
|
570
570
|
|
|
@@ -572,7 +572,7 @@ function importKey(path: string, name: string | undefined, isTypeOnly: boolean |
|
|
|
572
572
|
* Computes a multi-level sort key for exports and imports:
|
|
573
573
|
* non-array names first (wildcards/namespace aliases); type-only before value; alphabetical path; unnamed before named.
|
|
574
574
|
*/
|
|
575
|
-
function sortKey(node: { name?: string | Array<unknown
|
|
575
|
+
function sortKey(node: { name?: string | Array<unknown> | null; isTypeOnly?: boolean | null; path: string }): string {
|
|
576
576
|
const isArray = Array.isArray(node.name) ? '1' : '0'
|
|
577
577
|
const typeOnly = node.isTypeOnly ? '0' : '1'
|
|
578
578
|
const hasName = node.name != null ? '1' : '0'
|
package/src/visitor.ts
CHANGED
|
@@ -115,25 +115,40 @@ export type VisitorContext<T extends Node = Node> = {
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
/**
|
|
118
|
-
* Synchronous visitor
|
|
118
|
+
* Synchronous visitor consumed by `transform`. Each optional callback runs
|
|
119
|
+
* for the matching node type. Return a new node to replace it, or `undefined`
|
|
120
|
+
* to leave it untouched.
|
|
119
121
|
*
|
|
120
|
-
*
|
|
122
|
+
* Plugins typically expose `transformer` so users can supply a `Visitor` that
|
|
123
|
+
* rewrites operation IDs, drops descriptions, or otherwise tweaks the AST
|
|
124
|
+
* before printing.
|
|
125
|
+
*
|
|
126
|
+
* @example Prefix every operationId
|
|
121
127
|
* ```ts
|
|
122
128
|
* const visitor: Visitor = {
|
|
123
129
|
* operation(node) {
|
|
124
|
-
* return { ...node, operationId: `
|
|
130
|
+
* return { ...node, operationId: `api_${node.operationId}` }
|
|
131
|
+
* },
|
|
132
|
+
* }
|
|
133
|
+
* ```
|
|
134
|
+
*
|
|
135
|
+
* @example Strip schema descriptions
|
|
136
|
+
* ```ts
|
|
137
|
+
* const visitor: Visitor = {
|
|
138
|
+
* schema(node) {
|
|
139
|
+
* return { ...node, description: undefined }
|
|
125
140
|
* },
|
|
126
141
|
* }
|
|
127
142
|
* ```
|
|
128
143
|
*/
|
|
129
144
|
export type Visitor = {
|
|
130
|
-
input?(node: InputNode, context: VisitorContext<InputNode>):
|
|
131
|
-
output?(node: OutputNode, context: VisitorContext<OutputNode>):
|
|
132
|
-
operation?(node: OperationNode, context: VisitorContext<OperationNode>):
|
|
133
|
-
schema?(node: SchemaNode, context: VisitorContext<SchemaNode>):
|
|
134
|
-
property?(node: PropertyNode, context: VisitorContext<PropertyNode>):
|
|
135
|
-
parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>):
|
|
136
|
-
response?(node: ResponseNode, context: VisitorContext<ResponseNode>):
|
|
145
|
+
input?(node: InputNode, context: VisitorContext<InputNode>): undefined | null | InputNode
|
|
146
|
+
output?(node: OutputNode, context: VisitorContext<OutputNode>): undefined | null | OutputNode
|
|
147
|
+
operation?(node: OperationNode, context: VisitorContext<OperationNode>): undefined | null | OperationNode
|
|
148
|
+
schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): undefined | null | SchemaNode
|
|
149
|
+
property?(node: PropertyNode, context: VisitorContext<PropertyNode>): undefined | null | PropertyNode
|
|
150
|
+
parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): undefined | null | ParameterNode
|
|
151
|
+
response?(node: ResponseNode, context: VisitorContext<ResponseNode>): undefined | null | ResponseNode
|
|
137
152
|
}
|
|
138
153
|
|
|
139
154
|
/**
|
|
@@ -154,13 +169,13 @@ type MaybePromise<T> = T | Promise<T>
|
|
|
154
169
|
* ```
|
|
155
170
|
*/
|
|
156
171
|
export type AsyncVisitor = {
|
|
157
|
-
input?(node: InputNode, context: VisitorContext<InputNode>): MaybePromise<
|
|
158
|
-
output?(node: OutputNode, context: VisitorContext<OutputNode>): MaybePromise<
|
|
159
|
-
operation?(node: OperationNode, context: VisitorContext<OperationNode>): MaybePromise<
|
|
160
|
-
schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): MaybePromise<
|
|
161
|
-
property?(node: PropertyNode, context: VisitorContext<PropertyNode>): MaybePromise<
|
|
162
|
-
parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): MaybePromise<
|
|
163
|
-
response?(node: ResponseNode, context: VisitorContext<ResponseNode>): MaybePromise<
|
|
172
|
+
input?(node: InputNode, context: VisitorContext<InputNode>): MaybePromise<undefined | null | InputNode>
|
|
173
|
+
output?(node: OutputNode, context: VisitorContext<OutputNode>): MaybePromise<undefined | null | OutputNode>
|
|
174
|
+
operation?(node: OperationNode, context: VisitorContext<OperationNode>): MaybePromise<undefined | null | OperationNode>
|
|
175
|
+
schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): MaybePromise<undefined | null | SchemaNode>
|
|
176
|
+
property?(node: PropertyNode, context: VisitorContext<PropertyNode>): MaybePromise<undefined | null | PropertyNode>
|
|
177
|
+
parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): MaybePromise<undefined | null | ParameterNode>
|
|
178
|
+
response?(node: ResponseNode, context: VisitorContext<ResponseNode>): MaybePromise<undefined | null | ResponseNode>
|
|
164
179
|
}
|
|
165
180
|
|
|
166
181
|
/**
|
|
@@ -310,11 +325,14 @@ function* getChildren(node: Node, recurse: boolean): Generator<Node, void, undef
|
|
|
310
325
|
}
|
|
311
326
|
|
|
312
327
|
/**
|
|
313
|
-
*
|
|
314
|
-
*
|
|
315
|
-
* (default: `WALK_CONCURRENCY`).
|
|
328
|
+
* Async depth-first traversal for side effects. Visitor return values are
|
|
329
|
+
* ignored. Use `transform` when you want to rewrite nodes.
|
|
316
330
|
*
|
|
317
|
-
*
|
|
331
|
+
* Sibling nodes at each depth run concurrently up to `options.concurrency`
|
|
332
|
+
* (defaults to `WALK_CONCURRENCY`). Higher values overlap I/O-bound visitor
|
|
333
|
+
* work; lower values reduce memory pressure.
|
|
334
|
+
*
|
|
335
|
+
* @example Log every operation
|
|
318
336
|
* ```ts
|
|
319
337
|
* await walk(root, {
|
|
320
338
|
* operation(node) {
|
|
@@ -323,10 +341,9 @@ function* getChildren(node: Node, recurse: boolean): Generator<Node, void, undef
|
|
|
323
341
|
* })
|
|
324
342
|
* ```
|
|
325
343
|
*
|
|
326
|
-
* @example
|
|
344
|
+
* @example Only visit the root node
|
|
327
345
|
* ```ts
|
|
328
|
-
*
|
|
329
|
-
* await walk(root, { depth: 'shallow', root: () => {} })
|
|
346
|
+
* await walk(root, { depth: 'shallow', input: () => {} })
|
|
330
347
|
* ```
|
|
331
348
|
*/
|
|
332
349
|
export async function walk(node: Node, options: WalkOptions): Promise<void> {
|
|
@@ -368,12 +385,13 @@ async function _walk(node: Node, visitor: AsyncVisitor, recurse: boolean, limit:
|
|
|
368
385
|
}
|
|
369
386
|
|
|
370
387
|
/**
|
|
371
|
-
*
|
|
388
|
+
* Synchronous depth-first transform. Each visitor callback gets a chance to
|
|
389
|
+
* return a replacement node; `undefined` keeps the original.
|
|
372
390
|
*
|
|
373
|
-
*
|
|
374
|
-
*
|
|
391
|
+
* The transform is immutable. The original tree is not mutated; a new tree
|
|
392
|
+
* is returned. Use `depth: 'shallow'` to skip recursion into children.
|
|
375
393
|
*
|
|
376
|
-
* @example
|
|
394
|
+
* @example Prefix every operationId
|
|
377
395
|
* ```ts
|
|
378
396
|
* const next = transform(root, {
|
|
379
397
|
* operation(node) {
|
|
@@ -382,10 +400,12 @@ async function _walk(node: Node, visitor: AsyncVisitor, recurse: boolean, limit:
|
|
|
382
400
|
* })
|
|
383
401
|
* ```
|
|
384
402
|
*
|
|
385
|
-
* @example
|
|
403
|
+
* @example Replace only the root node
|
|
386
404
|
* ```ts
|
|
387
|
-
*
|
|
388
|
-
*
|
|
405
|
+
* const next = transform(root, {
|
|
406
|
+
* depth: 'shallow',
|
|
407
|
+
* input: (node) => ({ ...node, meta: { ...node.meta, title: 'Rewritten' } }),
|
|
408
|
+
* })
|
|
389
409
|
* ```
|
|
390
410
|
*/
|
|
391
411
|
export function transform(node: InputNode, options: TransformOptions): InputNode
|
|
@@ -485,23 +505,19 @@ export function transform(node: Node, options: TransformOptions): Node {
|
|
|
485
505
|
return node
|
|
486
506
|
}
|
|
487
507
|
/**
|
|
488
|
-
*
|
|
489
|
-
*
|
|
490
|
-
* Non-`null` values returned by visitor callbacks are appended to the result.
|
|
508
|
+
* Lazy depth-first collection pass. Yields every non-null value returned by
|
|
509
|
+
* the visitor callbacks. Use `collect` for the eager array form.
|
|
491
510
|
*
|
|
492
|
-
* @example
|
|
511
|
+
* @example Collect every operationId
|
|
493
512
|
* ```ts
|
|
494
|
-
* const ids =
|
|
513
|
+
* const ids: string[] = []
|
|
514
|
+
* for (const id of collectLazy<string>(root, {
|
|
495
515
|
* operation(node) {
|
|
496
516
|
* return node.operationId
|
|
497
517
|
* },
|
|
498
|
-
* })
|
|
499
|
-
*
|
|
500
|
-
*
|
|
501
|
-
* @example
|
|
502
|
-
* ```ts
|
|
503
|
-
* // Collect from only the current node
|
|
504
|
-
* const values = collect(root, { depth: 'shallow', root: () => 'root' })
|
|
518
|
+
* })) {
|
|
519
|
+
* ids.push(id)
|
|
520
|
+
* }
|
|
505
521
|
* ```
|
|
506
522
|
*/
|
|
507
523
|
export function* collectLazy<T>(node: Node, options: CollectOptions<T>): Generator<T, void, undefined> {
|
|
@@ -539,6 +555,19 @@ export function* collectLazy<T>(node: Node, options: CollectOptions<T>): Generat
|
|
|
539
555
|
}
|
|
540
556
|
}
|
|
541
557
|
|
|
558
|
+
/**
|
|
559
|
+
* Eager depth-first collection pass. Returns an array of every non-null value
|
|
560
|
+
* the visitor callbacks return.
|
|
561
|
+
*
|
|
562
|
+
* @example Collect every operationId
|
|
563
|
+
* ```ts
|
|
564
|
+
* const ids = collect<string>(root, {
|
|
565
|
+
* operation(node) {
|
|
566
|
+
* return node.operationId
|
|
567
|
+
* },
|
|
568
|
+
* })
|
|
569
|
+
* ```
|
|
570
|
+
*/
|
|
542
571
|
export function collect<T>(node: Node, options: CollectOptions<T>): Array<T> {
|
|
543
572
|
return Array.from(collectLazy(node, options))
|
|
544
573
|
}
|