@kubb/ast 5.0.0-alpha.3 → 5.0.0-alpha.31
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 +1123 -163
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +283 -17
- package/dist/index.js +1102 -154
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/visitor-z-5U8NoF.d.ts +2200 -0
- package/package.json +3 -2
- package/src/constants.ts +118 -4
- package/src/factory.ts +332 -18
- package/src/guards.ts +63 -8
- package/src/index.ts +25 -7
- package/src/infer.ts +130 -0
- package/src/mocks.ts +12 -5
- package/src/nodes/base.ts +32 -4
- package/src/nodes/function.ts +201 -0
- package/src/nodes/http.ts +17 -5
- package/src/nodes/index.ts +21 -5
- package/src/nodes/operation.ts +69 -6
- package/src/nodes/parameter.ts +27 -1
- package/src/nodes/property.ts +23 -1
- package/src/nodes/response.ts +29 -3
- package/src/nodes/root.ts +41 -10
- package/src/nodes/schema.ts +440 -42
- package/src/printer.ts +172 -60
- package/src/refs.ts +36 -4
- package/src/resolvers.ts +45 -0
- package/src/transformers.ts +156 -0
- package/src/types.ts +13 -2
- package/src/utils.ts +431 -4
- package/src/visitor.ts +378 -81
- package/dist/visitor-oFfdU8QA.d.ts +0 -653
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/ast",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.31",
|
|
4
4
|
"description": "Spec-agnostic AST layer for Kubb. Defines nodes, visitor pattern, and factory functions used across codegen plugins.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"kubb",
|
|
@@ -45,7 +45,8 @@
|
|
|
45
45
|
"!/**/__snapshots__/**"
|
|
46
46
|
],
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@types/node": "^22.19.
|
|
48
|
+
"@types/node": "^22.19.17",
|
|
49
|
+
"@internals/utils": "0.0.0"
|
|
49
50
|
},
|
|
50
51
|
"main": "./dist/index.cjs",
|
|
51
52
|
"module": "./dist/index.js",
|
package/src/constants.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { ParameterLocation } from './nodes/parameter.ts'
|
|
|
5
5
|
import type { SchemaType } from './nodes/schema.ts'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Traversal depth used by AST visitor utilities.
|
|
9
9
|
*/
|
|
10
10
|
export type VisitorDepth = 'shallow' | 'deep'
|
|
11
11
|
|
|
@@ -21,9 +21,26 @@ export const nodeKinds = {
|
|
|
21
21
|
property: 'Property',
|
|
22
22
|
parameter: 'Parameter',
|
|
23
23
|
response: 'Response',
|
|
24
|
-
|
|
24
|
+
functionParameter: 'FunctionParameter',
|
|
25
|
+
parameterGroup: 'ParameterGroup',
|
|
26
|
+
functionParameters: 'FunctionParameters',
|
|
27
|
+
} as const satisfies Record<string, NodeKind>
|
|
25
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Canonical schema type strings used by AST schema nodes.
|
|
31
|
+
*
|
|
32
|
+
* These values are used across the AST as stable discriminators
|
|
33
|
+
* (for example `schema.type === schemaTypes.object`).
|
|
34
|
+
*
|
|
35
|
+
* The map is grouped by intent:
|
|
36
|
+
* - primitives (`string`, `number`, `boolean`, ...)
|
|
37
|
+
* - structural/composite (`object`, `array`, `union`, ...)
|
|
38
|
+
* - special OpenAPI-oriented types (`ref`, `datetime`, `uuid`, ...)
|
|
39
|
+
*/
|
|
26
40
|
export const schemaTypes = {
|
|
41
|
+
/**
|
|
42
|
+
* Text value.
|
|
43
|
+
*/
|
|
27
44
|
string: 'string',
|
|
28
45
|
/**
|
|
29
46
|
* Floating-point number (`float`, `double`).
|
|
@@ -37,27 +54,110 @@ export const schemaTypes = {
|
|
|
37
54
|
* 64-bit integer (`int64`). Only used when `integerType` is set to `'bigint'`.
|
|
38
55
|
*/
|
|
39
56
|
bigint: 'bigint',
|
|
57
|
+
/**
|
|
58
|
+
* Boolean value
|
|
59
|
+
*/
|
|
40
60
|
boolean: 'boolean',
|
|
61
|
+
/**
|
|
62
|
+
* Explicit null value.
|
|
63
|
+
*/
|
|
41
64
|
null: 'null',
|
|
65
|
+
/**
|
|
66
|
+
* Any value (no type restriction).
|
|
67
|
+
*/
|
|
42
68
|
any: 'any',
|
|
69
|
+
/**
|
|
70
|
+
* Unknown value (must be narrowed before usage).
|
|
71
|
+
*/
|
|
43
72
|
unknown: 'unknown',
|
|
73
|
+
/**
|
|
74
|
+
* No return value (`void`).
|
|
75
|
+
*/
|
|
44
76
|
void: 'void',
|
|
77
|
+
/**
|
|
78
|
+
* Object with named properties.
|
|
79
|
+
*/
|
|
45
80
|
object: 'object',
|
|
81
|
+
/**
|
|
82
|
+
* Sequential list of items.
|
|
83
|
+
*/
|
|
46
84
|
array: 'array',
|
|
85
|
+
/**
|
|
86
|
+
* Fixed-length list with position-specific items.
|
|
87
|
+
*/
|
|
47
88
|
tuple: 'tuple',
|
|
89
|
+
/**
|
|
90
|
+
* "One of" multiple schema members.
|
|
91
|
+
*/
|
|
48
92
|
union: 'union',
|
|
93
|
+
/**
|
|
94
|
+
* "All of" multiple schema members.
|
|
95
|
+
*/
|
|
49
96
|
intersection: 'intersection',
|
|
97
|
+
/**
|
|
98
|
+
* Enum schema.
|
|
99
|
+
*/
|
|
50
100
|
enum: 'enum',
|
|
101
|
+
/**
|
|
102
|
+
* Reference to another schema.
|
|
103
|
+
*/
|
|
51
104
|
ref: 'ref',
|
|
105
|
+
/**
|
|
106
|
+
* Calendar date (for example `2026-03-24`).
|
|
107
|
+
*/
|
|
52
108
|
date: 'date',
|
|
109
|
+
/**
|
|
110
|
+
* Date-time value (for example `2026-03-24T09:00:00Z`).
|
|
111
|
+
*/
|
|
53
112
|
datetime: 'datetime',
|
|
113
|
+
/**
|
|
114
|
+
* Time-only value (for example `09:00:00`).
|
|
115
|
+
*/
|
|
54
116
|
time: 'time',
|
|
117
|
+
/**
|
|
118
|
+
* UUID value.
|
|
119
|
+
*/
|
|
55
120
|
uuid: 'uuid',
|
|
121
|
+
/**
|
|
122
|
+
* Email address value.
|
|
123
|
+
*/
|
|
56
124
|
email: 'email',
|
|
125
|
+
/**
|
|
126
|
+
* URL value.
|
|
127
|
+
*/
|
|
57
128
|
url: 'url',
|
|
129
|
+
/**
|
|
130
|
+
* IPv4 address value.
|
|
131
|
+
*/
|
|
132
|
+
ipv4: 'ipv4',
|
|
133
|
+
/**
|
|
134
|
+
* IPv6 address value.
|
|
135
|
+
*/
|
|
136
|
+
ipv6: 'ipv6',
|
|
137
|
+
/**
|
|
138
|
+
* Binary/blob value.
|
|
139
|
+
*/
|
|
58
140
|
blob: 'blob',
|
|
141
|
+
/**
|
|
142
|
+
* Impossible value (`never`).
|
|
143
|
+
*/
|
|
144
|
+
never: 'never',
|
|
59
145
|
} as const satisfies Record<SchemaType, SchemaType>
|
|
60
146
|
|
|
147
|
+
export type ScalarPrimitive = 'string' | 'number' | 'integer' | 'bigint' | 'boolean'
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Primitive scalar schema types used when simplifying union members.
|
|
151
|
+
*/
|
|
152
|
+
export const SCALAR_PRIMITIVE_TYPES = new Set<ScalarPrimitive>(['string', 'number', 'integer', 'bigint', 'boolean'])
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Returns `true` when `type` is a scalar primitive schema type.
|
|
156
|
+
*/
|
|
157
|
+
export function isScalarPrimitive(type: string): type is ScalarPrimitive {
|
|
158
|
+
return SCALAR_PRIMITIVE_TYPES.has(type as ScalarPrimitive)
|
|
159
|
+
}
|
|
160
|
+
|
|
61
161
|
export const httpMethods = {
|
|
62
162
|
get: 'GET',
|
|
63
163
|
post: 'POST',
|
|
@@ -77,12 +177,26 @@ export const parameterLocations = {
|
|
|
77
177
|
} as const satisfies Record<ParameterLocation, ParameterLocation>
|
|
78
178
|
|
|
79
179
|
/**
|
|
80
|
-
* Default
|
|
180
|
+
* Default maximum number of concurrent callbacks used by `walk`.
|
|
181
|
+
*
|
|
182
|
+
* 30 is chosen to allow enough parallelism to overlap I/O-bound resolver calls
|
|
183
|
+
* without overwhelming the event loop or causing excessive memory pressure during
|
|
184
|
+
* large spec traversals.
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```ts
|
|
188
|
+
* walk(root, { concurrency: WALK_CONCURRENCY, root: () => {} })
|
|
189
|
+
* ```
|
|
81
190
|
*/
|
|
82
191
|
export const WALK_CONCURRENCY = 30
|
|
83
192
|
|
|
84
193
|
/**
|
|
85
|
-
* Fallback status code
|
|
194
|
+
* Fallback response status code used for catch-all responses.
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```ts
|
|
198
|
+
* const status = DEFAULT_STATUS_CODE // 'default'
|
|
199
|
+
* ```
|
|
86
200
|
*/
|
|
87
201
|
export const DEFAULT_STATUS_CODE = 'default' as const
|
|
88
202
|
|
package/src/factory.ts
CHANGED
|
@@ -1,12 +1,66 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { InferSchemaNode } from './infer.ts'
|
|
2
|
+
import type {
|
|
3
|
+
FunctionParameterNode,
|
|
4
|
+
FunctionParametersNode,
|
|
5
|
+
ObjectSchemaNode,
|
|
6
|
+
OperationNode,
|
|
7
|
+
ParameterGroupNode,
|
|
8
|
+
ParameterNode,
|
|
9
|
+
PrimitiveSchemaType,
|
|
10
|
+
PropertyNode,
|
|
11
|
+
ResponseNode,
|
|
12
|
+
RootNode,
|
|
13
|
+
SchemaNode,
|
|
14
|
+
TypeNode,
|
|
15
|
+
} from './nodes/index.ts'
|
|
2
16
|
|
|
3
17
|
/**
|
|
4
|
-
*
|
|
18
|
+
* Syncs property/parameter schema optionality flags from `required` and `schema.nullable`.
|
|
19
|
+
*
|
|
20
|
+
* - `optional` is set for non-required, non-nullable schemas.
|
|
21
|
+
* - `nullish` is set for non-required, nullable schemas.
|
|
22
|
+
*/
|
|
23
|
+
export function syncOptionality(schema: SchemaNode, required: boolean): SchemaNode {
|
|
24
|
+
const nullable = schema.nullable ?? false
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
...schema,
|
|
28
|
+
optional: !required && !nullable ? true : undefined,
|
|
29
|
+
nullish: !required && nullable ? true : undefined,
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Distributive `Omit` that preserves each member of a union.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* type A = { kind: 'a'; keep: string; drop: number }
|
|
39
|
+
* type B = { kind: 'b'; keep: boolean; drop: number }
|
|
40
|
+
* type Result = DistributiveOmit<A | B, 'drop'>
|
|
41
|
+
* // -> { kind: 'a'; keep: string } | { kind: 'b'; keep: boolean }
|
|
42
|
+
* ```
|
|
5
43
|
*/
|
|
6
44
|
export type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never
|
|
7
45
|
|
|
46
|
+
type CreateSchemaObjectInput = Omit<ObjectSchemaNode, 'kind' | 'properties' | 'primitive'> & { properties?: Array<PropertyNode>; primitive?: 'object' }
|
|
47
|
+
type CreateSchemaInput = CreateSchemaObjectInput | DistributiveOmit<Exclude<SchemaNode, ObjectSchemaNode>, 'kind'>
|
|
48
|
+
type CreateSchemaOutput<T extends CreateSchemaInput> = InferSchemaNode<T> & { kind: 'Schema' }
|
|
49
|
+
|
|
8
50
|
/**
|
|
9
|
-
* Creates a `RootNode`.
|
|
51
|
+
* Creates a `RootNode` with stable defaults for `schemas` and `operations`.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* const root = createRoot()
|
|
56
|
+
* // { kind: 'Root', schemas: [], operations: [] }
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* const root = createRoot({ schemas: [petSchema] })
|
|
62
|
+
* // keeps default operations: []
|
|
63
|
+
* ```
|
|
10
64
|
*/
|
|
11
65
|
export function createRoot(overrides: Partial<Omit<RootNode, 'kind'>> = {}): RootNode {
|
|
12
66
|
return {
|
|
@@ -18,7 +72,27 @@ export function createRoot(overrides: Partial<Omit<RootNode, 'kind'>> = {}): Roo
|
|
|
18
72
|
}
|
|
19
73
|
|
|
20
74
|
/**
|
|
21
|
-
* Creates an `OperationNode`.
|
|
75
|
+
* Creates an `OperationNode` with default empty arrays for `tags`, `parameters`, and `responses`.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* const operation = createOperation({
|
|
80
|
+
* operationId: 'getPetById',
|
|
81
|
+
* method: 'GET',
|
|
82
|
+
* path: '/pet/{petId}',
|
|
83
|
+
* })
|
|
84
|
+
* // tags, parameters, and responses are []
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* const operation = createOperation({
|
|
90
|
+
* operationId: 'findPets',
|
|
91
|
+
* method: 'GET',
|
|
92
|
+
* path: '/pet/findByStatus',
|
|
93
|
+
* tags: ['pet'],
|
|
94
|
+
* })
|
|
95
|
+
* ```
|
|
22
96
|
*/
|
|
23
97
|
export function createOperation(
|
|
24
98
|
props: Pick<OperationNode, 'operationId' | 'method' | 'path'> & Partial<Omit<OperationNode, 'kind' | 'operationId' | 'method' | 'path'>>,
|
|
@@ -32,53 +106,293 @@ export function createOperation(
|
|
|
32
106
|
}
|
|
33
107
|
}
|
|
34
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Maps schema `type` to its underlying `primitive`.
|
|
111
|
+
* Primitive types map to themselves; special string formats map to `'string'`.
|
|
112
|
+
* Complex types (`ref`, `enum`, `union`, `intersection`, `tuple`, `blob`) are left unset.
|
|
113
|
+
*/
|
|
114
|
+
const TYPE_TO_PRIMITIVE: Partial<Record<SchemaNode['type'], PrimitiveSchemaType>> = {
|
|
115
|
+
string: 'string',
|
|
116
|
+
number: 'number',
|
|
117
|
+
integer: 'integer',
|
|
118
|
+
bigint: 'bigint',
|
|
119
|
+
boolean: 'boolean',
|
|
120
|
+
null: 'null',
|
|
121
|
+
any: 'any',
|
|
122
|
+
unknown: 'unknown',
|
|
123
|
+
void: 'void',
|
|
124
|
+
never: 'never',
|
|
125
|
+
object: 'object',
|
|
126
|
+
array: 'array',
|
|
127
|
+
date: 'date',
|
|
128
|
+
uuid: 'string',
|
|
129
|
+
email: 'string',
|
|
130
|
+
url: 'string',
|
|
131
|
+
datetime: 'string',
|
|
132
|
+
time: 'string',
|
|
133
|
+
}
|
|
134
|
+
|
|
35
135
|
/**
|
|
36
136
|
* Creates a `SchemaNode`, narrowed to the variant of `props.type`.
|
|
37
|
-
* For object schemas, `properties` defaults to
|
|
137
|
+
* For object schemas, `properties` defaults to an empty array.
|
|
138
|
+
* `primitive` is automatically inferred from `type` when not explicitly provided.
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```ts
|
|
142
|
+
* const scalar = createSchema({ type: 'string' })
|
|
143
|
+
* // { kind: 'Schema', type: 'string', primitive: 'string' }
|
|
144
|
+
* ```
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```ts
|
|
148
|
+
* const uuid = createSchema({ type: 'uuid' })
|
|
149
|
+
* // { kind: 'Schema', type: 'uuid', primitive: 'string' }
|
|
150
|
+
* ```
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```ts
|
|
154
|
+
* const object = createSchema({ type: 'object' })
|
|
155
|
+
* // { kind: 'Schema', type: 'object', primitive: 'object', properties: [] }
|
|
156
|
+
* ```
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```ts
|
|
160
|
+
* const enumSchema = createSchema({
|
|
161
|
+
* type: 'enum',
|
|
162
|
+
* primitive: 'string',
|
|
163
|
+
* enumValues: ['available', 'pending'],
|
|
164
|
+
* })
|
|
165
|
+
* ```
|
|
38
166
|
*/
|
|
39
|
-
export function createSchema<T extends
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
export function createSchema(props: Record<string, unknown>): Record<string, unknown> {
|
|
167
|
+
export function createSchema<T extends CreateSchemaInput>(props: T): CreateSchemaOutput<T>
|
|
168
|
+
export function createSchema(props: CreateSchemaInput): SchemaNode
|
|
169
|
+
export function createSchema(props: CreateSchemaInput): SchemaNode {
|
|
170
|
+
const inferredPrimitive = TYPE_TO_PRIMITIVE[props.type as keyof typeof TYPE_TO_PRIMITIVE]
|
|
171
|
+
|
|
45
172
|
if (props['type'] === 'object') {
|
|
46
|
-
return { properties: [], ...props, kind: 'Schema' }
|
|
173
|
+
return { properties: [], primitive: 'object', ...props, kind: 'Schema' } as CreateSchemaOutput<typeof props>
|
|
47
174
|
}
|
|
48
175
|
|
|
49
|
-
return { ...props, kind: 'Schema' }
|
|
176
|
+
return { primitive: inferredPrimitive, ...props, kind: 'Schema' } as CreateSchemaOutput<typeof props>
|
|
50
177
|
}
|
|
51
178
|
|
|
52
179
|
/**
|
|
53
|
-
* Creates a `PropertyNode`.
|
|
180
|
+
* Creates a `PropertyNode`.
|
|
181
|
+
*
|
|
182
|
+
* `required` defaults to `false`.
|
|
183
|
+
* `schema.optional` and `schema.nullish` are derived from `required` and `schema.nullable`.
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```ts
|
|
187
|
+
* const property = createProperty({
|
|
188
|
+
* name: 'status',
|
|
189
|
+
* schema: createSchema({ type: 'string' }),
|
|
190
|
+
* })
|
|
191
|
+
* // required=false, schema.optional=true
|
|
192
|
+
* ```
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```ts
|
|
196
|
+
* const property = createProperty({
|
|
197
|
+
* name: 'status',
|
|
198
|
+
* required: true,
|
|
199
|
+
* schema: createSchema({ type: 'string', nullable: true }),
|
|
200
|
+
* })
|
|
201
|
+
* // required=true, no optional/nullish
|
|
202
|
+
* ```
|
|
54
203
|
*/
|
|
55
204
|
export function createProperty(props: Pick<PropertyNode, 'name' | 'schema'> & Partial<Omit<PropertyNode, 'kind' | 'name' | 'schema'>>): PropertyNode {
|
|
205
|
+
const required = props.required ?? false
|
|
206
|
+
|
|
56
207
|
return {
|
|
57
|
-
required: false,
|
|
58
208
|
...props,
|
|
59
209
|
kind: 'Property',
|
|
210
|
+
required,
|
|
211
|
+
schema: syncOptionality(props.schema, required),
|
|
60
212
|
}
|
|
61
213
|
}
|
|
62
214
|
|
|
63
215
|
/**
|
|
64
|
-
* Creates a `ParameterNode`.
|
|
216
|
+
* Creates a `ParameterNode`.
|
|
217
|
+
*
|
|
218
|
+
* `required` defaults to `false`.
|
|
219
|
+
* Nested schema flags are set from `required` and `schema.nullable`.
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```ts
|
|
223
|
+
* const param = createParameter({
|
|
224
|
+
* name: 'petId',
|
|
225
|
+
* in: 'path',
|
|
226
|
+
* required: true,
|
|
227
|
+
* schema: createSchema({ type: 'string' }),
|
|
228
|
+
* })
|
|
229
|
+
* ```
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* ```ts
|
|
233
|
+
* const param = createParameter({
|
|
234
|
+
* name: 'status',
|
|
235
|
+
* in: 'query',
|
|
236
|
+
* schema: createSchema({ type: 'string', nullable: true }),
|
|
237
|
+
* })
|
|
238
|
+
* // required=false, schema.nullish=true
|
|
239
|
+
* ```
|
|
65
240
|
*/
|
|
66
241
|
export function createParameter(
|
|
67
242
|
props: Pick<ParameterNode, 'name' | 'in' | 'schema'> & Partial<Omit<ParameterNode, 'kind' | 'name' | 'in' | 'schema'>>,
|
|
68
243
|
): ParameterNode {
|
|
244
|
+
const required = props.required ?? false
|
|
69
245
|
return {
|
|
70
|
-
required: false,
|
|
71
246
|
...props,
|
|
72
247
|
kind: 'Parameter',
|
|
248
|
+
required,
|
|
249
|
+
schema: syncOptionality(props.schema, required),
|
|
73
250
|
}
|
|
74
251
|
}
|
|
75
252
|
|
|
76
253
|
/**
|
|
77
254
|
* Creates a `ResponseNode`.
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* ```ts
|
|
258
|
+
* const response = createResponse({
|
|
259
|
+
* statusCode: '200',
|
|
260
|
+
* description: 'Success',
|
|
261
|
+
* schema: createSchema({ type: 'object', properties: [] }),
|
|
262
|
+
* })
|
|
263
|
+
* ```
|
|
78
264
|
*/
|
|
79
|
-
export function createResponse(
|
|
265
|
+
export function createResponse(
|
|
266
|
+
props: Pick<ResponseNode, 'statusCode' | 'schema'> & Partial<Omit<ResponseNode, 'kind' | 'statusCode' | 'schema'>>,
|
|
267
|
+
): ResponseNode {
|
|
80
268
|
return {
|
|
81
269
|
...props,
|
|
82
270
|
kind: 'Response',
|
|
83
271
|
}
|
|
84
272
|
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Creates a `FunctionParameterNode`.
|
|
276
|
+
*
|
|
277
|
+
* `optional` defaults to `false`.
|
|
278
|
+
*
|
|
279
|
+
* @example Required typed param
|
|
280
|
+
* ```ts
|
|
281
|
+
* createFunctionParameter({ name: 'petId', type: createTypeNode({ variant: 'reference', name: 'string' }) })
|
|
282
|
+
* // → petId: string
|
|
283
|
+
* ```
|
|
284
|
+
*
|
|
285
|
+
* @example Optional param
|
|
286
|
+
* ```ts
|
|
287
|
+
* createFunctionParameter({ name: 'params', type: createTypeNode({ variant: 'reference', name: 'QueryParams' }), optional: true })
|
|
288
|
+
* // → params?: QueryParams
|
|
289
|
+
* ```
|
|
290
|
+
*
|
|
291
|
+
* @example Param with default (implicitly optional; cannot combine with `optional: true`)
|
|
292
|
+
* ```ts
|
|
293
|
+
* createFunctionParameter({ name: 'config', type: createTypeNode({ variant: 'reference', name: 'RequestConfig' }), default: '{}' })
|
|
294
|
+
* // → config: RequestConfig = {}
|
|
295
|
+
* ```
|
|
296
|
+
*/
|
|
297
|
+
export function createFunctionParameter(
|
|
298
|
+
props: { name: string; type?: TypeNode; rest?: boolean } & ({ optional: true; default?: never } | { optional?: false; default?: string }),
|
|
299
|
+
): FunctionParameterNode {
|
|
300
|
+
return {
|
|
301
|
+
optional: false,
|
|
302
|
+
...props,
|
|
303
|
+
kind: 'FunctionParameter',
|
|
304
|
+
} as FunctionParameterNode
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Creates a {@link TypeNode} representing a language-agnostic structured type expression.
|
|
309
|
+
*
|
|
310
|
+
* Use `variant: 'struct'` for inline anonymous types and `variant: 'member'` for a single
|
|
311
|
+
* named field accessed from a group type. Each language's printer renders the variant
|
|
312
|
+
* into its own syntax (TypeScript, Python, C#, Kotlin, …).
|
|
313
|
+
*
|
|
314
|
+
* @example Reference type (TypeScript: `QueryParams`)
|
|
315
|
+
* ```ts
|
|
316
|
+
* createTypeNode({ variant: 'reference', name: 'QueryParams' })
|
|
317
|
+
* ```
|
|
318
|
+
*
|
|
319
|
+
* @example Struct type (TypeScript: `{ petId: string }`)
|
|
320
|
+
* ```ts
|
|
321
|
+
* createTypeNode({ variant: 'struct', properties: [{ name: 'petId', optional: false, type: createTypeNode({ variant: 'reference', name: 'string' }) }] })
|
|
322
|
+
* ```
|
|
323
|
+
*
|
|
324
|
+
* @example Member type (TypeScript: `DeletePetPathParams['petId']`)
|
|
325
|
+
* ```ts
|
|
326
|
+
* createTypeNode({ variant: 'member', base: 'DeletePetPathParams', key: 'petId' })
|
|
327
|
+
* ```
|
|
328
|
+
*/
|
|
329
|
+
export function createTypeNode(
|
|
330
|
+
props:
|
|
331
|
+
| { variant: 'reference'; name: string }
|
|
332
|
+
| { variant: 'struct'; properties: Array<{ name: string; optional: boolean; type: TypeNode }> }
|
|
333
|
+
| { variant: 'member'; base: string; key: string },
|
|
334
|
+
): TypeNode {
|
|
335
|
+
return { ...props, kind: 'Type' } as TypeNode
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Creates a `ParameterGroupNode` representing a group of related parameters treated as a unit.
|
|
340
|
+
*
|
|
341
|
+
* @example Grouped param (TypeScript declaration)
|
|
342
|
+
* ```ts
|
|
343
|
+
* createParameterGroup({
|
|
344
|
+
* properties: [
|
|
345
|
+
* createFunctionParameter({ name: 'id', type: createTypeNode({ variant: 'reference', name: 'string' }), optional: false }),
|
|
346
|
+
* createFunctionParameter({ name: 'name', type: createTypeNode({ variant: 'reference', name: 'string' }), optional: true }),
|
|
347
|
+
* ],
|
|
348
|
+
* default: '{}',
|
|
349
|
+
* })
|
|
350
|
+
* // declaration → { id, name? }: { id: string; name?: string } = {}
|
|
351
|
+
* // call → { id, name }
|
|
352
|
+
* ```
|
|
353
|
+
*
|
|
354
|
+
* @example Inline (spread) — children emitted as individual top-level parameters
|
|
355
|
+
* ```ts
|
|
356
|
+
* createParameterGroup({
|
|
357
|
+
* properties: [createFunctionParameter({ name: 'petId', type: createTypeNode({ variant: 'reference', name: 'string' }), optional: false })],
|
|
358
|
+
* inline: true,
|
|
359
|
+
* })
|
|
360
|
+
* // declaration → petId: string
|
|
361
|
+
* // call → petId
|
|
362
|
+
* ```
|
|
363
|
+
*/
|
|
364
|
+
export function createParameterGroup(
|
|
365
|
+
props: Pick<ParameterGroupNode, 'properties'> & Partial<Omit<ParameterGroupNode, 'kind' | 'properties'>>,
|
|
366
|
+
): ParameterGroupNode {
|
|
367
|
+
return {
|
|
368
|
+
...props,
|
|
369
|
+
kind: 'ParameterGroup',
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Creates a `FunctionParametersNode` from an ordered list of parameters.
|
|
375
|
+
*
|
|
376
|
+
* @example
|
|
377
|
+
* ```ts
|
|
378
|
+
* createFunctionParameters({
|
|
379
|
+
* params: [
|
|
380
|
+
* createFunctionParameter({ name: 'petId', type: createTypeNode({ variant: 'reference', name: 'string' }), optional: false }),
|
|
381
|
+
* createFunctionParameter({ name: 'config', type: createTypeNode({ variant: 'reference', name: 'RequestConfig' }), optional: false, default: '{}' }),
|
|
382
|
+
* ],
|
|
383
|
+
* })
|
|
384
|
+
* ```
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
* ```ts
|
|
388
|
+
* const empty = createFunctionParameters()
|
|
389
|
+
* // { kind: 'FunctionParameters', params: [] }
|
|
390
|
+
* ```
|
|
391
|
+
*/
|
|
392
|
+
export function createFunctionParameters(props: Partial<Omit<FunctionParametersNode, 'kind'>> = {}): FunctionParametersNode {
|
|
393
|
+
return {
|
|
394
|
+
params: [],
|
|
395
|
+
...props,
|
|
396
|
+
kind: 'FunctionParameters',
|
|
397
|
+
}
|
|
398
|
+
}
|
package/src/guards.ts
CHANGED
|
@@ -1,7 +1,26 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
FunctionParameterNode,
|
|
3
|
+
FunctionParametersNode,
|
|
4
|
+
Node,
|
|
5
|
+
NodeKind,
|
|
6
|
+
OperationNode,
|
|
7
|
+
ParameterGroupNode,
|
|
8
|
+
ParameterNode,
|
|
9
|
+
PropertyNode,
|
|
10
|
+
ResponseNode,
|
|
11
|
+
RootNode,
|
|
12
|
+
SchemaNode,
|
|
13
|
+
SchemaNodeByType,
|
|
14
|
+
} from './nodes/index.ts'
|
|
2
15
|
|
|
3
16
|
/**
|
|
4
|
-
* Narrows a `SchemaNode` to the
|
|
17
|
+
* Narrows a `SchemaNode` to the variant that matches `type`.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const schema = createSchema({ type: 'string' })
|
|
22
|
+
* const stringNode = narrowSchema(schema, 'string') // StringSchemaNode | undefined
|
|
23
|
+
* ```
|
|
5
24
|
*/
|
|
6
25
|
export function narrowSchema<T extends SchemaNode['type']>(node: SchemaNode | undefined, type: T): SchemaNodeByType[T] | undefined {
|
|
7
26
|
return node?.type === type ? (node as SchemaNodeByType[T]) : undefined
|
|
@@ -12,31 +31,67 @@ function isKind<T extends Node>(kind: NodeKind) {
|
|
|
12
31
|
}
|
|
13
32
|
|
|
14
33
|
/**
|
|
15
|
-
*
|
|
34
|
+
* Returns `true` when the input is a `RootNode`.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* if (isRootNode(node)) {
|
|
39
|
+
* console.log(node.schemas.length)
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
16
42
|
*/
|
|
17
43
|
export const isRootNode = isKind<RootNode>('Root')
|
|
18
44
|
|
|
19
45
|
/**
|
|
20
|
-
*
|
|
46
|
+
* Returns `true` when the input is an `OperationNode`.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* if (isOperationNode(node)) {
|
|
51
|
+
* console.log(node.operationId)
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
21
54
|
*/
|
|
22
55
|
export const isOperationNode = isKind<OperationNode>('Operation')
|
|
23
56
|
|
|
24
57
|
/**
|
|
25
|
-
*
|
|
58
|
+
* Returns `true` when the input is a `SchemaNode`.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* if (isSchemaNode(node)) {
|
|
63
|
+
* console.log(node.type)
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
26
66
|
*/
|
|
27
67
|
export const isSchemaNode = isKind<SchemaNode>('Schema')
|
|
28
68
|
|
|
29
69
|
/**
|
|
30
|
-
*
|
|
70
|
+
* Returns `true` when the input is a `PropertyNode`.
|
|
31
71
|
*/
|
|
32
72
|
export const isPropertyNode = isKind<PropertyNode>('Property')
|
|
33
73
|
|
|
34
74
|
/**
|
|
35
|
-
*
|
|
75
|
+
* Returns `true` when the input is a `ParameterNode`.
|
|
36
76
|
*/
|
|
37
77
|
export const isParameterNode = isKind<ParameterNode>('Parameter')
|
|
38
78
|
|
|
39
79
|
/**
|
|
40
|
-
*
|
|
80
|
+
* Returns `true` when the input is a `ResponseNode`.
|
|
41
81
|
*/
|
|
42
82
|
export const isResponseNode = isKind<ResponseNode>('Response')
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Returns `true` when the input is a `FunctionParameterNode`.
|
|
86
|
+
*/
|
|
87
|
+
export const isFunctionParameterNode = isKind<FunctionParameterNode>('FunctionParameter')
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Returns `true` when the input is a `ParameterGroupNode`.
|
|
91
|
+
*/
|
|
92
|
+
export const isParameterGroupNode = isKind<ParameterGroupNode>('ParameterGroup')
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Returns `true` when the input is a `FunctionParametersNode`.
|
|
96
|
+
*/
|
|
97
|
+
export const isFunctionParametersNode = isKind<FunctionParametersNode>('FunctionParameters')
|