@kubb/ast 4.33.5 → 4.35.0
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 +91 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.js +91 -9
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/{visitor-D9_Eb8I1.d.ts → visitor-8N3AiSUr.d.ts} +170 -49
- package/package.json +1 -1
- package/src/constants.ts +5 -0
- package/src/guards.ts +1 -1
- package/src/index.ts +1 -0
- package/src/nodes/base.ts +1 -1
- package/src/nodes/index.ts +1 -1
- package/src/nodes/operation.ts +1 -1
- package/src/nodes/parameter.ts +1 -1
- package/src/nodes/property.ts +1 -1
- package/src/nodes/response.ts +1 -1
- package/src/nodes/root.ts +21 -1
- package/src/nodes/schema.ts +14 -14
- package/src/printer.ts +127 -0
- package/src/types.ts +3 -1
- package/src/visitor.ts +50 -13
package/src/nodes/schema.ts
CHANGED
|
@@ -20,7 +20,7 @@ export type ScalarSchemaType = Exclude<
|
|
|
20
20
|
/**
|
|
21
21
|
* Base fields shared by every schema variant. Does not include spec-specific fields.
|
|
22
22
|
*/
|
|
23
|
-
|
|
23
|
+
type SchemaNodeBase = BaseNode & {
|
|
24
24
|
kind: 'Schema'
|
|
25
25
|
/**
|
|
26
26
|
* Named schema identifier (e.g. `"Pet"` from `#/components/schemas/Pet`). `undefined` for inline schemas.
|
|
@@ -48,7 +48,7 @@ interface SchemaNodeBase extends BaseNode {
|
|
|
48
48
|
/**
|
|
49
49
|
* Object schema with ordered property definitions.
|
|
50
50
|
*/
|
|
51
|
-
export
|
|
51
|
+
export type ObjectSchemaNode = SchemaNodeBase & {
|
|
52
52
|
type: 'object'
|
|
53
53
|
properties?: Array<PropertyNode>
|
|
54
54
|
/**
|
|
@@ -61,7 +61,7 @@ export interface ObjectSchemaNode extends SchemaNodeBase {
|
|
|
61
61
|
/**
|
|
62
62
|
* Array or tuple schema.
|
|
63
63
|
*/
|
|
64
|
-
export
|
|
64
|
+
export type ArraySchemaNode = SchemaNodeBase & {
|
|
65
65
|
type: 'array' | 'tuple'
|
|
66
66
|
items?: Array<SchemaNode>
|
|
67
67
|
/**
|
|
@@ -76,14 +76,14 @@ export interface ArraySchemaNode extends SchemaNodeBase {
|
|
|
76
76
|
/**
|
|
77
77
|
* Shared base for union and intersection schemas.
|
|
78
78
|
*/
|
|
79
|
-
|
|
79
|
+
type CompositeSchemaNodeBase = SchemaNodeBase & {
|
|
80
80
|
members?: Array<SchemaNode>
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
/**
|
|
84
84
|
* Union schema (`oneOf` / `anyOf`).
|
|
85
85
|
*/
|
|
86
|
-
export
|
|
86
|
+
export type UnionSchemaNode = CompositeSchemaNodeBase & {
|
|
87
87
|
type: 'union'
|
|
88
88
|
/**
|
|
89
89
|
* Discriminator property from OAS `discriminator.propertyName`.
|
|
@@ -94,14 +94,14 @@ export interface UnionSchemaNode extends CompositeSchemaNodeBase {
|
|
|
94
94
|
/**
|
|
95
95
|
* Intersection schema (`allOf`).
|
|
96
96
|
*/
|
|
97
|
-
export
|
|
97
|
+
export type IntersectionSchemaNode = CompositeSchemaNodeBase & {
|
|
98
98
|
type: 'intersection'
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
/**
|
|
102
102
|
* A named enum variant.
|
|
103
103
|
*/
|
|
104
|
-
export
|
|
104
|
+
export type EnumValueNode = {
|
|
105
105
|
name: string
|
|
106
106
|
value: string | number | boolean
|
|
107
107
|
format: 'string' | 'number' | 'boolean'
|
|
@@ -110,7 +110,7 @@ export interface EnumValueNode {
|
|
|
110
110
|
/**
|
|
111
111
|
* Enum schema.
|
|
112
112
|
*/
|
|
113
|
-
export
|
|
113
|
+
export type EnumSchemaNode = SchemaNodeBase & {
|
|
114
114
|
type: 'enum'
|
|
115
115
|
/**
|
|
116
116
|
* Enum member type. Generators should use const assertions for `'number'` / `'boolean'`.
|
|
@@ -129,7 +129,7 @@ export interface EnumSchemaNode extends SchemaNodeBase {
|
|
|
129
129
|
/**
|
|
130
130
|
* Ref schema — pointer to another schema definition.
|
|
131
131
|
*/
|
|
132
|
-
export
|
|
132
|
+
export type RefSchemaNode = SchemaNodeBase & {
|
|
133
133
|
type: 'ref'
|
|
134
134
|
name?: string
|
|
135
135
|
/**
|
|
@@ -145,7 +145,7 @@ export interface RefSchemaNode extends SchemaNodeBase {
|
|
|
145
145
|
/**
|
|
146
146
|
* Datetime schema.
|
|
147
147
|
*/
|
|
148
|
-
export
|
|
148
|
+
export type DatetimeSchemaNode = SchemaNodeBase & {
|
|
149
149
|
type: 'datetime'
|
|
150
150
|
/**
|
|
151
151
|
* Includes timezone offset (`dateType: 'stringOffset'`).
|
|
@@ -160,7 +160,7 @@ export interface DatetimeSchemaNode extends SchemaNodeBase {
|
|
|
160
160
|
/**
|
|
161
161
|
* Base for `date` and `time` schemas.
|
|
162
162
|
*/
|
|
163
|
-
|
|
163
|
+
type TemporalSchemaNodeBase<T extends 'date' | 'time'> = SchemaNodeBase & {
|
|
164
164
|
type: T
|
|
165
165
|
/**
|
|
166
166
|
* Representation in generated code: native `Date` or plain string.
|
|
@@ -181,7 +181,7 @@ export type TimeSchemaNode = TemporalSchemaNodeBase<'time'>
|
|
|
181
181
|
/**
|
|
182
182
|
* String schema.
|
|
183
183
|
*/
|
|
184
|
-
export
|
|
184
|
+
export type StringSchemaNode = SchemaNodeBase & {
|
|
185
185
|
type: 'string'
|
|
186
186
|
min?: number
|
|
187
187
|
max?: number
|
|
@@ -191,7 +191,7 @@ export interface StringSchemaNode extends SchemaNodeBase {
|
|
|
191
191
|
/**
|
|
192
192
|
* Number, integer, or bigint schema.
|
|
193
193
|
*/
|
|
194
|
-
export
|
|
194
|
+
export type NumberSchemaNode = SchemaNodeBase & {
|
|
195
195
|
type: 'number' | 'integer' | 'bigint'
|
|
196
196
|
min?: number
|
|
197
197
|
max?: number
|
|
@@ -202,7 +202,7 @@ export interface NumberSchemaNode extends SchemaNodeBase {
|
|
|
202
202
|
/**
|
|
203
203
|
* Schema for scalar types with no additional constraints.
|
|
204
204
|
*/
|
|
205
|
-
export
|
|
205
|
+
export type ScalarSchemaNode = SchemaNodeBase & {
|
|
206
206
|
type: ScalarSchemaType
|
|
207
207
|
}
|
|
208
208
|
|
package/src/printer.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type { SchemaNode, SchemaNodeByType, SchemaType } from './nodes/index.ts'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Handler context for `definePrinter` — mirrors `PluginContext` from `@kubb/core`.
|
|
5
|
+
* Available as `this` inside each node handler.
|
|
6
|
+
*/
|
|
7
|
+
export type PrinterHandlerContext<TOutput, TOptions extends object> = {
|
|
8
|
+
/**
|
|
9
|
+
* Recursively print a nested `SchemaNode`.
|
|
10
|
+
*/
|
|
11
|
+
print: (node: SchemaNode) => TOutput | null | undefined
|
|
12
|
+
/**
|
|
13
|
+
* Options for this printer instance.
|
|
14
|
+
*/
|
|
15
|
+
options: TOptions
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Handler for a specific `SchemaNode` variant identified by `SchemaType` key `T`.
|
|
20
|
+
* Use a regular function (not an arrow function) so that `this` is available.
|
|
21
|
+
*/
|
|
22
|
+
export type PrinterHandler<TOutput, TOptions extends object, T extends SchemaType = SchemaType> = (
|
|
23
|
+
this: PrinterHandlerContext<TOutput, TOptions>,
|
|
24
|
+
node: SchemaNodeByType[T],
|
|
25
|
+
) => TOutput | null | undefined
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Shape of the type parameter passed to `definePrinter`.
|
|
29
|
+
* Mirrors `AdapterFactoryOptions` / `PluginFactoryOptions` from `@kubb/core`.
|
|
30
|
+
*
|
|
31
|
+
* - `TName` — unique string identifier (e.g. `'zod'`, `'ts'`)
|
|
32
|
+
* - `TOptions` — options passed to and stored on the printer
|
|
33
|
+
* - `TOutput` — the type emitted by `print` (typically `string`)
|
|
34
|
+
*/
|
|
35
|
+
export type PrinterFactoryOptions<TName extends string = string, TOptions extends object = object, TOutput = unknown> = {
|
|
36
|
+
name: TName
|
|
37
|
+
options: TOptions
|
|
38
|
+
output: TOutput
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The object returned by calling a `definePrinter` instance.
|
|
43
|
+
* Mirrors the shape of `Adapter` from `@kubb/core`.
|
|
44
|
+
*/
|
|
45
|
+
export type Printer<T extends PrinterFactoryOptions = PrinterFactoryOptions> = {
|
|
46
|
+
/**
|
|
47
|
+
* Unique identifier supplied at creation time.
|
|
48
|
+
*/
|
|
49
|
+
name: T['name']
|
|
50
|
+
/**
|
|
51
|
+
* Options for this printer instance.
|
|
52
|
+
*/
|
|
53
|
+
options: T['options']
|
|
54
|
+
/**
|
|
55
|
+
* Emits `TOutput` from a `SchemaNode`. Returns `null | undefined` when no handler matches.
|
|
56
|
+
*/
|
|
57
|
+
print: (node: SchemaNode) => T['output'] | null | undefined
|
|
58
|
+
/**
|
|
59
|
+
* Maps `print` over an array of `SchemaNode`s.
|
|
60
|
+
*/
|
|
61
|
+
for: (nodes: Array<SchemaNode>) => Array<T['output'] | null | undefined>
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
type PrinterBuilder<T extends PrinterFactoryOptions> = (options: T['options']) => {
|
|
65
|
+
name: T['name']
|
|
66
|
+
/**
|
|
67
|
+
* Options to store on the printer.
|
|
68
|
+
*/
|
|
69
|
+
options: T['options']
|
|
70
|
+
nodes: Partial<{
|
|
71
|
+
[K in SchemaType]: PrinterHandler<T['output'], T['options'], K>
|
|
72
|
+
}>
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Creates a named printer factory. Mirrors the `definePlugin` / `defineAdapter` pattern
|
|
77
|
+
* from `@kubb/core` — wraps a builder to make options optional and separates raw options
|
|
78
|
+
* from resolved options.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* type ZodPrinter = PrinterFactoryOptions<'zod', { strict?: boolean }, { strict: boolean }, string>
|
|
83
|
+
*
|
|
84
|
+
* export const zodPrinter = definePrinter<ZodPrinter>((options) => {
|
|
85
|
+
* const { strict = true } = options
|
|
86
|
+
* return {
|
|
87
|
+
* name: 'zod',
|
|
88
|
+
* options: { strict },
|
|
89
|
+
* nodes: {
|
|
90
|
+
* string(node) {
|
|
91
|
+
* return `z.string()`
|
|
92
|
+
* },
|
|
93
|
+
* object(node) {
|
|
94
|
+
* const props = node.properties
|
|
95
|
+
* ?.map(p => `${p.name}: ${this.print(p)}`)
|
|
96
|
+
* .join(', ') ?? ''
|
|
97
|
+
* return `z.object({ ${props} })`
|
|
98
|
+
* },
|
|
99
|
+
* },
|
|
100
|
+
* }
|
|
101
|
+
* })
|
|
102
|
+
*
|
|
103
|
+
* const printer = zodPrinter({ strict: false })
|
|
104
|
+
* printer.name // 'zod'
|
|
105
|
+
* printer.options // { strict: false }
|
|
106
|
+
* printer.print(node) // 'z.string()'
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export function definePrinter<T extends PrinterFactoryOptions = PrinterFactoryOptions>(build: PrinterBuilder<T>): (options?: T['options']) => Printer<T> {
|
|
110
|
+
return (options) => {
|
|
111
|
+
const { name, options: resolvedOptions, nodes } = build(options ?? ({} as T['options']))
|
|
112
|
+
|
|
113
|
+
function print(node: SchemaNode): T['output'] | null | undefined {
|
|
114
|
+
const type = node.type as SchemaType
|
|
115
|
+
|
|
116
|
+
const handler = nodes[type]
|
|
117
|
+
if (handler) {
|
|
118
|
+
const context: PrinterHandlerContext<T['output'], T['options']> = { print, options: resolvedOptions }
|
|
119
|
+
return (handler as PrinterHandler<T['output'], T['options']>).call(context, node as SchemaNodeByType[SchemaType])
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return undefined
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return { name, options: resolvedOptions, print, for: (nodes) => nodes.map(print) }
|
|
126
|
+
}
|
|
127
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -23,6 +23,7 @@ export type {
|
|
|
23
23
|
PropertyNode,
|
|
24
24
|
RefSchemaNode,
|
|
25
25
|
ResponseNode,
|
|
26
|
+
RootMeta,
|
|
26
27
|
RootNode,
|
|
27
28
|
ScalarSchemaNode,
|
|
28
29
|
ScalarSchemaType,
|
|
@@ -35,5 +36,6 @@ export type {
|
|
|
35
36
|
TimeSchemaNode,
|
|
36
37
|
UnionSchemaNode,
|
|
37
38
|
} from './nodes/index.ts'
|
|
39
|
+
export type { Printer } from './printer.ts'
|
|
38
40
|
export type { RefMap } from './refs.ts'
|
|
39
|
-
export type { AsyncVisitor, CollectVisitor, Visitor
|
|
41
|
+
export type { AsyncVisitor, CollectVisitor, Visitor } from './visitor.ts'
|
package/src/visitor.ts
CHANGED
|
@@ -1,18 +1,51 @@
|
|
|
1
1
|
import type { VisitorDepth } from './constants.ts'
|
|
2
|
-
import { visitorDepths } from './constants.ts'
|
|
2
|
+
import { visitorDepths, WALK_CONCURRENCY } from './constants.ts'
|
|
3
3
|
import type { Node, OperationNode, ParameterNode, PropertyNode, ResponseNode, RootNode, SchemaNode } from './nodes/index.ts'
|
|
4
4
|
|
|
5
|
+
function createLimit(concurrency: number) {
|
|
6
|
+
let active = 0
|
|
7
|
+
const queue: Array<() => void> = []
|
|
8
|
+
|
|
9
|
+
function next() {
|
|
10
|
+
if (active < concurrency && queue.length > 0) {
|
|
11
|
+
active++
|
|
12
|
+
queue.shift()!()
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return function limit<T>(fn: () => Promise<T> | T): Promise<T> {
|
|
17
|
+
return new Promise<T>((resolve, reject) => {
|
|
18
|
+
queue.push(() => {
|
|
19
|
+
Promise.resolve(fn())
|
|
20
|
+
.then(resolve, reject)
|
|
21
|
+
.finally(() => {
|
|
22
|
+
active--
|
|
23
|
+
next()
|
|
24
|
+
})
|
|
25
|
+
})
|
|
26
|
+
next()
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
type LimitFn = ReturnType<typeof createLimit>
|
|
32
|
+
|
|
5
33
|
/**
|
|
6
34
|
* Shared options for `walk`, `transform`, and `collect`.
|
|
7
35
|
*/
|
|
8
36
|
export type VisitorOptions = {
|
|
9
37
|
depth?: VisitorDepth
|
|
38
|
+
/**
|
|
39
|
+
* Maximum number of sibling nodes visited concurrently inside `walk`.
|
|
40
|
+
* @default 30
|
|
41
|
+
*/
|
|
42
|
+
concurrency?: number
|
|
10
43
|
}
|
|
11
44
|
|
|
12
45
|
/**
|
|
13
46
|
* Synchronous visitor for `transform` and `walk`.
|
|
14
47
|
*/
|
|
15
|
-
export
|
|
48
|
+
export type Visitor = {
|
|
16
49
|
root?(node: RootNode): void | RootNode
|
|
17
50
|
operation?(node: OperationNode): void | OperationNode
|
|
18
51
|
schema?(node: SchemaNode): void | SchemaNode
|
|
@@ -26,7 +59,7 @@ type MaybePromise<T> = T | Promise<T>
|
|
|
26
59
|
/**
|
|
27
60
|
* Async visitor for `walk`. Synchronous `Visitor` objects are compatible.
|
|
28
61
|
*/
|
|
29
|
-
export
|
|
62
|
+
export type AsyncVisitor = {
|
|
30
63
|
root?(node: RootNode): MaybePromise<void | RootNode>
|
|
31
64
|
operation?(node: OperationNode): MaybePromise<void | OperationNode>
|
|
32
65
|
schema?(node: SchemaNode): MaybePromise<void | SchemaNode>
|
|
@@ -38,7 +71,7 @@ export interface AsyncVisitor {
|
|
|
38
71
|
/**
|
|
39
72
|
* Visitor for `collect`.
|
|
40
73
|
*/
|
|
41
|
-
export
|
|
74
|
+
export type CollectVisitor<T> = {
|
|
42
75
|
root?(node: RootNode): T | undefined
|
|
43
76
|
operation?(node: OperationNode): T | undefined
|
|
44
77
|
schema?(node: SchemaNode): T | undefined
|
|
@@ -78,34 +111,38 @@ function getChildren(node: Node, recurse: boolean): Array<Node> {
|
|
|
78
111
|
|
|
79
112
|
/**
|
|
80
113
|
* Depth-first traversal for side effects. Visitor return values are ignored.
|
|
114
|
+
* Sibling nodes at each level are visited concurrently up to `options.concurrency` (default: 30).
|
|
81
115
|
*/
|
|
82
116
|
export async function walk(node: Node, visitor: AsyncVisitor, options: VisitorOptions = {}): Promise<void> {
|
|
83
117
|
const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep
|
|
118
|
+
const limit = createLimit(options.concurrency ?? WALK_CONCURRENCY)
|
|
119
|
+
return _walk(node, visitor, recurse, limit)
|
|
120
|
+
}
|
|
84
121
|
|
|
122
|
+
async function _walk(node: Node, visitor: AsyncVisitor, recurse: boolean, limit: LimitFn): Promise<void> {
|
|
85
123
|
switch (node.kind) {
|
|
86
124
|
case 'Root':
|
|
87
|
-
await visitor.root?.(node)
|
|
125
|
+
await limit(() => visitor.root?.(node))
|
|
88
126
|
break
|
|
89
127
|
case 'Operation':
|
|
90
|
-
await visitor.operation?.(node)
|
|
128
|
+
await limit(() => visitor.operation?.(node))
|
|
91
129
|
break
|
|
92
130
|
case 'Schema':
|
|
93
|
-
await visitor.schema?.(node)
|
|
131
|
+
await limit(() => visitor.schema?.(node))
|
|
94
132
|
break
|
|
95
133
|
case 'Property':
|
|
96
|
-
await visitor.property?.(node)
|
|
134
|
+
await limit(() => visitor.property?.(node))
|
|
97
135
|
break
|
|
98
136
|
case 'Parameter':
|
|
99
|
-
await visitor.parameter?.(node)
|
|
137
|
+
await limit(() => visitor.parameter?.(node))
|
|
100
138
|
break
|
|
101
139
|
case 'Response':
|
|
102
|
-
await visitor.response?.(node)
|
|
140
|
+
await limit(() => visitor.response?.(node))
|
|
103
141
|
break
|
|
104
142
|
}
|
|
105
143
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
144
|
+
const children = getChildren(node, recurse)
|
|
145
|
+
await Promise.all(children.map((child) => _walk(child, visitor, recurse, limit)))
|
|
109
146
|
}
|
|
110
147
|
|
|
111
148
|
/**
|