@kubb/ast 5.0.0-beta.56 → 5.0.0-beta.58

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.
Files changed (59) hide show
  1. package/README.md +13 -9
  2. package/dist/{types-BL7RpQAE.d.ts → ast-ClnJg9BN.d.ts} +1630 -2443
  3. package/dist/chunk-CNktS9qV.js +17 -0
  4. package/dist/extractStringsFromNodes-Bn9cOos9.d.ts +14 -0
  5. package/dist/factory-C5gHvtLU.js +138 -0
  6. package/dist/factory-C5gHvtLU.js.map +1 -0
  7. package/dist/factory-JN-Ylfl6.cjs +155 -0
  8. package/dist/factory-JN-Ylfl6.cjs.map +1 -0
  9. package/dist/factory.cjs +31 -0
  10. package/dist/factory.d.ts +62 -0
  11. package/dist/factory.js +3 -0
  12. package/dist/index.cjs +56 -1751
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.ts +6 -47
  15. package/dist/index.js +7 -1697
  16. package/dist/index.js.map +1 -1
  17. package/dist/types-CB2oY8Dw.d.ts +769 -0
  18. package/dist/types.d.ts +4 -2
  19. package/dist/utils-C8bWAzhv.cjs +2696 -0
  20. package/dist/utils-C8bWAzhv.cjs.map +1 -0
  21. package/dist/utils-DN4XLVqz.js +2099 -0
  22. package/dist/utils-DN4XLVqz.js.map +1 -0
  23. package/dist/utils.cjs +12 -1
  24. package/dist/utils.d.ts +21 -2
  25. package/dist/utils.js +2 -2
  26. package/package.json +5 -1
  27. package/src/dedupe.ts +1 -1
  28. package/src/factory.ts +22 -764
  29. package/src/guards.ts +1 -53
  30. package/src/index.ts +20 -39
  31. package/src/mocks.ts +6 -1
  32. package/src/node.ts +128 -0
  33. package/src/nodes/base.ts +3 -12
  34. package/src/nodes/code.ts +115 -0
  35. package/src/nodes/content.ts +19 -0
  36. package/src/nodes/file.ts +54 -0
  37. package/src/nodes/function.ts +222 -147
  38. package/src/nodes/index.ts +11 -3
  39. package/src/nodes/input.ts +37 -0
  40. package/src/nodes/operation.ts +59 -1
  41. package/src/nodes/output.ts +23 -0
  42. package/src/nodes/parameter.ts +33 -0
  43. package/src/nodes/property.ts +36 -0
  44. package/src/nodes/requestBody.ts +23 -1
  45. package/src/nodes/response.ts +39 -1
  46. package/src/nodes/schema.ts +72 -0
  47. package/src/printer.ts +3 -3
  48. package/src/registry.ts +70 -0
  49. package/src/transformers.ts +2 -2
  50. package/src/types.ts +6 -4
  51. package/src/utils/ast.ts +103 -243
  52. package/src/utils/extractStringsFromNodes.ts +34 -0
  53. package/src/utils/index.ts +44 -0
  54. package/src/visitor.ts +3 -47
  55. package/dist/chunk-C0LytTxp.js +0 -8
  56. package/dist/utils-0p8ZO287.js +0 -570
  57. package/dist/utils-0p8ZO287.js.map +0 -1
  58. package/dist/utils-cdQ6Pzyi.cjs +0 -726
  59. package/dist/utils-cdQ6Pzyi.cjs.map +0 -1
@@ -1,84 +1,110 @@
1
+ import { defineNode } from '../node.ts'
1
2
  import type { BaseNode } from './base.ts'
2
3
 
3
4
  /**
4
- * AST node representing a language-agnostic type expression used as a function parameter
5
- * type annotation. Each language printer renders the variant into its own syntax.
5
+ * A language-agnostic type expression used as a function parameter type annotation.
6
6
  *
7
- * - `struct` an inline anonymous type grouping named fields.
8
- * TypeScript renders as `{ petId: string; name?: string }`.
9
- * - `member` a single named field accessed from a named group type.
10
- * TypeScript renders as `PathParams['petId']`.
7
+ * - a plain `string` is a type reference rendered as-is, e.g. `'string'`, `'QueryParams'`, `'Partial<Config>'`
8
+ * - a {@link TypeLiteralNode} is an inline anonymous type, e.g. `{ petId: string; name?: string }`
9
+ * - an {@link IndexedAccessTypeNode} is a single field accessed from a named type, e.g. `PathParams['petId']`
10
+ */
11
+ export type TypeExpression = string | TypeLiteralNode | IndexedAccessTypeNode
12
+
13
+ /**
14
+ * AST node for an inline anonymous object type grouping named fields.
15
+ * TypeScript renders as `{ key: Type; other?: OtherType }`.
11
16
  *
12
- * @example Reference variant
17
+ * @example
13
18
  * ```ts
14
- * createParamsType({ variant: 'reference', name: 'QueryParams' })
15
- * // QueryParams
19
+ * createTypeLiteral({ members: [{ name: 'petId', type: 'string', optional: false }] })
20
+ * // { petId: string }
16
21
  * ```
22
+ */
23
+ export type TypeLiteralNode = BaseNode & {
24
+ /**
25
+ * Node kind.
26
+ */
27
+ kind: 'TypeLiteral'
28
+ /**
29
+ * Members of the object type, rendered in order.
30
+ */
31
+ members: Array<{
32
+ /**
33
+ * Member key.
34
+ */
35
+ name: string
36
+ /**
37
+ * Member type expression.
38
+ */
39
+ type: TypeExpression
40
+ /**
41
+ * Whether the member is optional, rendered with `?`.
42
+ */
43
+ optional?: boolean
44
+ }>
45
+ }
46
+
47
+ /**
48
+ * AST node for a single field accessed from a named group type.
49
+ * TypeScript renders as `objectType['indexType']`.
17
50
  *
18
- * @example Struct variant
51
+ * @example
19
52
  * ```ts
20
- * createParamsType({ variant: 'struct', properties: [{ name: 'petId', optional: false, type: createParamsType({ variant: 'reference', name: 'string' }) }] })
21
- * // { petId: string }
53
+ * createIndexedAccessType({ objectType: 'GetPetPathParams', indexType: 'petId' })
54
+ * // GetPetPathParams['petId']
22
55
  * ```
56
+ */
57
+ export type IndexedAccessTypeNode = BaseNode & {
58
+ /**
59
+ * Node kind.
60
+ */
61
+ kind: 'IndexedAccessType'
62
+ /**
63
+ * Name of the type being indexed, e.g. `'GetPetPathParams'`.
64
+ */
65
+ objectType: string
66
+ /**
67
+ * Field key to access, e.g. `'petId'`.
68
+ */
69
+ indexType: string
70
+ }
71
+
72
+ /**
73
+ * AST node for an object destructuring binding, used as the name of a grouped function parameter.
74
+ * TypeScript renders as `{ id, name }` or `{ id: renamed }` when `propertyName` differs.
23
75
  *
24
- * @example Member variant
76
+ * @example
25
77
  * ```ts
26
- * createParamsType({ variant: 'member', base: 'PathParams', key: 'petId' })
27
- * // PathParams['petId']
78
+ * createObjectBindingPattern({ elements: [{ name: 'id' }, { name: 'name' }] })
79
+ * // { id, name }
28
80
  * ```
29
81
  */
30
- export type ParamsTypeNode = BaseNode & {
82
+ export type ObjectBindingPatternNode = BaseNode & {
31
83
  /**
32
84
  * Node kind.
33
85
  */
34
- kind: 'ParamsType'
35
- } & (
36
- | {
37
- /**
38
- * Reference variant, a plain type name or identifier.
39
- * TypeScript renders as-is, e.g. `string`, `QueryParams`, `Partial<Config>`.
40
- */
41
- variant: 'reference'
42
- /**
43
- * The full type name string, e.g. `'string'`, `'QueryParams'`, `'Partial<Config>'`.
44
- */
45
- name: string
46
- }
47
- | {
48
- /**
49
- * Struct variant, an inline anonymous type grouping named fields.
50
- * TypeScript renders as `{ key: Type; other?: OtherType }`.
51
- */
52
- variant: 'struct'
53
- /**
54
- * Properties of the struct type.
55
- */
56
- properties: Array<{
57
- name: string
58
- optional: boolean
59
- type: ParamsTypeNode
60
- }>
61
- }
62
- | {
63
- /**
64
- * Member variant, a single named field accessed from a group type.
65
- * TypeScript renders as `Base['key']`.
66
- */
67
- variant: 'member'
68
- /**
69
- * Base type name, e.g. `'DeletePetPathParams'`.
70
- */
71
- base: string
72
- /**
73
- * The field name to access, e.g. `'petId'`.
74
- */
75
- key: string
76
- }
77
- )
86
+ kind: 'ObjectBindingPattern'
87
+ /**
88
+ * Bound elements, rendered in order.
89
+ */
90
+ elements: Array<{
91
+ /**
92
+ * Local binding name.
93
+ */
94
+ name: string
95
+ /**
96
+ * Source key when it differs from the binding name, rendered as `propertyName: name`.
97
+ */
98
+ propertyName?: string
99
+ }>
100
+ }
78
101
 
79
102
  /**
80
103
  * AST node for one function parameter.
81
104
  *
105
+ * A simple parameter has a `string` name. A destructured group has an
106
+ * {@link ObjectBindingPatternNode} name paired with a {@link TypeLiteralNode} type.
107
+ *
82
108
  * @example Required parameter
83
109
  * `name: Type`
84
110
  *
@@ -90,6 +116,9 @@ export type ParamsTypeNode = BaseNode & {
90
116
  *
91
117
  * @example Rest parameter
92
118
  * `...name: Type[]`
119
+ *
120
+ * @example Destructured group
121
+ * `{ id, name? }: { id: string; name?: string } = {}`
93
122
  */
94
123
  export type FunctionParameterNode = BaseNode & {
95
124
  /**
@@ -97,96 +126,25 @@ export type FunctionParameterNode = BaseNode & {
97
126
  */
98
127
  kind: 'FunctionParameter'
99
128
  /**
100
- * Parameter name in the generated signature.
101
- */
102
- name: string
103
- /**
104
- * Type annotation as a structured {@link ParamsTypeNode}.
105
- * Omit for untyped output.
106
- *
107
- * @example Reference type node
108
- * `{ kind: 'ParamsType', variant: 'reference', name: 'string' }` → `petId: string`
109
- *
110
- * @example Struct type node
111
- * `{ kind: 'ParamsType', variant: 'struct', properties: [...] }` → `{ key: Type; other?: OtherType }`
112
- *
113
- * @example Member type node
114
- * `{ kind: 'ParamsType', variant: 'member', base: 'PathParams', key: 'petId' }` → `PathParams['petId']`
115
- */
116
- type?: ParamsTypeNode
117
- /**
118
- * When `true` the parameter is emitted as a rest parameter.
119
- *
120
- * @example Rest parameter
121
- * `...name: Type[]`
122
- */
123
- rest?: boolean
124
- } /**
125
- * Optional parameter, rendered with `?` and may be omitted by the caller.
126
- * Cannot be combined with `default` because a defaulted parameter is already optional.
127
- */ & (
128
- | { optional: true; default?: never }
129
- /**
130
- * Required parameter, or a parameter with a default value.
131
- *
132
- * @example Required
133
- * `name: Type`
134
- *
135
- * @example With default
136
- * `name: Type = default`
137
- */
138
- | { optional?: false; default?: string }
139
- )
140
-
141
- /**
142
- * AST node for a group of related function parameters treated as a single unit.
143
- *
144
- * Each language printer decides how to render this group:
145
- * - TypeScript/JS: destructured object `{ key1, key2 }: { key1: Type1; key2: Type2 } = {}`
146
- * - Python: keyword-only args or a typed dict parameter
147
- * - C# / Kotlin: named record / data-class parameter
148
- *
149
- * When `inline` is `true`, the group is spread as individual top-level parameters
150
- * rather than wrapped in a single grouped construct.
151
- *
152
- * @example Grouped destructuring
153
- * `{ id, name }: { id: string; name: string } = {}`
154
- *
155
- * @example Inline (spread as individual parameters)
156
- * `id: string, name: string`
157
- */
158
- export type ParameterGroupNode = BaseNode & {
159
- /**
160
- * Node kind.
161
- */
162
- kind: 'ParameterGroup'
163
- /**
164
- * The individual parameters that form the group.
165
- * Rendered as a destructured object or spread inline when `inline` is `true`.
129
+ * Parameter name, or an {@link ObjectBindingPatternNode} for a destructured group.
166
130
  */
167
- properties: Array<FunctionParameterNode>
131
+ name: string | ObjectBindingPatternNode
168
132
  /**
169
- * Optional explicit type annotation for the whole group.
170
- * When absent, printers auto-compute it from `properties`.
133
+ * Type annotation as a {@link TypeExpression}. Omit for untyped output.
171
134
  */
172
- type?: ParamsTypeNode
135
+ type?: TypeExpression
173
136
  /**
174
- * When `true`, `properties` are emitted as individual top-level parameters instead of
175
- * being wrapped in a single grouped construct.
176
- *
177
- * @default false
178
- */
179
- inline?: boolean
180
- /**
181
- * Whether the group as a whole is optional.
182
- * If omitted, printers infer this from child properties.
137
+ * Whether the parameter is optional, rendered with `?`.
183
138
  */
184
139
  optional?: boolean
185
140
  /**
186
- * Default value for the group, written verbatim after `=`.
187
- * Commonly `'{}'` to allow omitting the argument entirely.
141
+ * Default value, written verbatim after `=`. Commonly `'{}'` for a destructured group.
188
142
  */
189
143
  default?: string
144
+ /**
145
+ * When `true` the parameter is emitted as a rest parameter, e.g. `...name: Type[]`.
146
+ */
147
+ rest?: boolean
190
148
  }
191
149
 
192
150
  /**
@@ -198,8 +156,6 @@ export type ParameterGroupNode = BaseNode & {
198
156
  * Renders differently depending on the output mode:
199
157
  * - `declaration` → `(id: string, config: Config = {})` function declaration parameters
200
158
  * - `call` → `(id, { method, url })` function call arguments
201
- * - `keys` → `{ id, config }` key names only (for destructuring)
202
- * - `values` → `{ id: id, config: config }` key → value pairs
203
159
  */
204
160
  export type FunctionParametersNode = BaseNode & {
205
161
  /**
@@ -209,15 +165,134 @@ export type FunctionParametersNode = BaseNode & {
209
165
  /**
210
166
  * Ordered parameter nodes.
211
167
  */
212
- params: ReadonlyArray<FunctionParameterNode | ParameterGroupNode>
168
+ params: ReadonlyArray<FunctionParameterNode>
213
169
  }
214
170
 
215
171
  /**
216
172
  * Union of all function-parameter AST node variants used by the function-parameter printer.
217
173
  */
218
- export type FunctionParamNode = FunctionParameterNode | ParameterGroupNode | FunctionParametersNode | ParamsTypeNode
174
+ export type FunctionParamNode = FunctionParameterNode | FunctionParametersNode | TypeLiteralNode | IndexedAccessTypeNode | ObjectBindingPatternNode
175
+
176
+ /**
177
+ * Handler-map keys for the function-parameter printer, one per {@link FunctionParamNode} kind.
178
+ */
179
+ export type FunctionParamKind = FunctionParamNode['kind']
180
+
181
+ /**
182
+ * Definition for the {@link TypeLiteralNode}.
183
+ */
184
+ export const typeLiteralDef = defineNode<TypeLiteralNode, Pick<TypeLiteralNode, 'members'>>({ kind: 'TypeLiteral' })
185
+
186
+ /**
187
+ * Creates a {@link TypeLiteralNode} representing an inline anonymous object type.
188
+ *
189
+ * @example
190
+ * ```ts
191
+ * createTypeLiteral({ members: [{ name: 'petId', type: 'string', optional: false }] })
192
+ * // { petId: string }
193
+ * ```
194
+ */
195
+ export const createTypeLiteral = typeLiteralDef.create
196
+
197
+ /**
198
+ * Definition for the {@link IndexedAccessTypeNode}.
199
+ */
200
+ export const indexedAccessTypeDef = defineNode<IndexedAccessTypeNode, Omit<IndexedAccessTypeNode, 'kind'>>({ kind: 'IndexedAccessType' })
201
+
202
+ /**
203
+ * Creates an {@link IndexedAccessTypeNode} representing a single field accessed from a named type.
204
+ *
205
+ * @example
206
+ * ```ts
207
+ * createIndexedAccessType({ objectType: 'DeletePetPathParams', indexType: 'petId' })
208
+ * // DeletePetPathParams['petId']
209
+ * ```
210
+ */
211
+ export const createIndexedAccessType = indexedAccessTypeDef.create
219
212
 
220
213
  /**
221
- * Handler map keys, one per `FunctionParamNode` kind.
214
+ * Definition for the {@link ObjectBindingPatternNode}.
222
215
  */
223
- export type FunctionNodeType = 'functionParameter' | 'parameterGroup' | 'functionParameters' | 'paramsType'
216
+ export const objectBindingPatternDef = defineNode<ObjectBindingPatternNode, Pick<ObjectBindingPatternNode, 'elements'>>({ kind: 'ObjectBindingPattern' })
217
+
218
+ /**
219
+ * Creates an {@link ObjectBindingPatternNode} for a destructured parameter binding.
220
+ *
221
+ * @example
222
+ * ```ts
223
+ * createObjectBindingPattern({ elements: [{ name: 'id' }, { name: 'name' }] })
224
+ * // { id, name }
225
+ * ```
226
+ */
227
+ export const createObjectBindingPattern = objectBindingPatternDef.create
228
+
229
+ /**
230
+ * Plain property descriptor for a destructured group built by {@link createFunctionParameter}.
231
+ */
232
+ type FunctionParameterProperty = {
233
+ name: string
234
+ type: TypeExpression
235
+ optional?: boolean
236
+ }
237
+
238
+ type FunctionParameterInput =
239
+ | { name: string; type?: TypeExpression; optional?: boolean; default?: string; rest?: boolean }
240
+ | { properties: Array<FunctionParameterProperty>; optional?: boolean; default?: string }
241
+
242
+ /**
243
+ * Definition for the {@link FunctionParameterNode}. `optional` defaults to `false`.
244
+ * Passing `properties` builds a destructured group: an {@link ObjectBindingPatternNode} name
245
+ * paired with a {@link TypeLiteralNode} type.
246
+ */
247
+ export const functionParameterDef = defineNode<FunctionParameterNode, FunctionParameterInput>({
248
+ kind: 'FunctionParameter',
249
+ build: (input) => {
250
+ if ('properties' in input) {
251
+ return {
252
+ name: createObjectBindingPattern({ elements: input.properties.map((p) => ({ name: p.name })) }),
253
+ type: createTypeLiteral({ members: input.properties.map((p) => ({ name: p.name, type: p.type, optional: p.optional ?? false })) }),
254
+ optional: input.optional ?? false,
255
+ ...(input.default !== undefined ? { default: input.default } : {}),
256
+ }
257
+ }
258
+ return { optional: false, ...input }
259
+ },
260
+ })
261
+
262
+ /**
263
+ * Creates a `FunctionParameterNode`. `optional` defaults to `false`.
264
+ *
265
+ * @example Optional param
266
+ * ```ts
267
+ * createFunctionParameter({ name: 'params', type: 'QueryParams', optional: true })
268
+ * // → params?: QueryParams
269
+ * ```
270
+ *
271
+ * @example Destructured group
272
+ * ```ts
273
+ * createFunctionParameter({ properties: [{ name: 'id', type: 'string' }, { name: 'name', type: 'string', optional: true }], default: '{}' })
274
+ * // → { id, name }: { id: string; name?: string } = {}
275
+ * ```
276
+ */
277
+ export const createFunctionParameter = functionParameterDef.create
278
+
279
+ /**
280
+ * Definition for the {@link FunctionParametersNode}.
281
+ */
282
+ export const functionParametersDef = defineNode<FunctionParametersNode, Partial<Omit<FunctionParametersNode, 'kind'>>>({
283
+ kind: 'FunctionParameters',
284
+ defaults: { params: [] },
285
+ })
286
+
287
+ /**
288
+ * Creates a `FunctionParametersNode` from an ordered list of parameters.
289
+ *
290
+ * @example
291
+ * ```ts
292
+ * const empty = createFunctionParameters()
293
+ * // { kind: 'FunctionParameters', params: [] }
294
+ * ```
295
+ */
296
+ export function createFunctionParameters(props: Partial<Omit<FunctionParametersNode, 'kind'>> = {}): FunctionParametersNode {
297
+ return functionParametersDef.create(props)
298
+ }
@@ -1,7 +1,7 @@
1
1
  import type { ArrowFunctionNode, ConstNode, FunctionNode, TypeNode } from './code.ts'
2
2
  import type { ContentNode } from './content.ts'
3
3
  import type { ExportNode, FileNode, ImportNode, SourceNode } from './file.ts'
4
- import type { FunctionParamNode, ParamsTypeNode } from './function.ts'
4
+ import type { FunctionParamNode } from './function.ts'
5
5
  import type { InputNode } from './input.ts'
6
6
  import type { OperationNode } from './operation.ts'
7
7
  import type { OutputNode } from './output.ts'
@@ -15,7 +15,16 @@ export type { NodeKind } from './base.ts'
15
15
  export type { ArrowFunctionNode, BreakNode, CodeNode, ConstNode, FunctionNode, JSDocNode, JsxNode, TextNode, TypeNode } from './code.ts'
16
16
  export type { ContentNode } from './content.ts'
17
17
  export type { ExportNode, FileNode, ImportNode, SourceNode } from './file.ts'
18
- export type { FunctionNodeType, FunctionParameterNode, FunctionParametersNode, FunctionParamNode, ParameterGroupNode, ParamsTypeNode } from './function.ts'
18
+ export type {
19
+ FunctionParamKind,
20
+ FunctionParameterNode,
21
+ FunctionParametersNode,
22
+ FunctionParamNode,
23
+ IndexedAccessTypeNode,
24
+ ObjectBindingPatternNode,
25
+ TypeExpression,
26
+ TypeLiteralNode,
27
+ } from './function.ts'
19
28
  export type { StatusCode } from './http.ts'
20
29
  export type { InputMeta, InputNode } from './input.ts'
21
30
  export type { GenericOperationNode, HttpMethod, HttpOperationNode, OperationNode } from './operation.ts'
@@ -81,6 +90,5 @@ export type Node =
81
90
  | SourceNode
82
91
  | ConstNode
83
92
  | TypeNode
84
- | ParamsTypeNode
85
93
  | FunctionNode
86
94
  | ArrowFunctionNode
@@ -1,4 +1,5 @@
1
1
  import type { Streamable } from '@internals/utils'
2
+ import { defineNode } from '../node.ts'
2
3
  import type { BaseNode } from './base.ts'
3
4
  import type { OperationNode } from './operation.ts'
4
5
  import type { SchemaNode } from './schema.ts'
@@ -101,3 +102,39 @@ export type InputNode<Stream extends boolean = false> = BaseNode & {
101
102
  */
102
103
  operations: Streamable<OperationNode, Stream>
103
104
  } & (Stream extends true ? { meta?: InputMeta } : { meta: InputMeta })
105
+
106
+ /**
107
+ * Definition for the {@link InputNode}.
108
+ */
109
+ export const inputDef = defineNode<InputNode, Partial<Omit<InputNode, 'kind'>>>({
110
+ kind: 'Input',
111
+ defaults: { schemas: [], operations: [], meta: { circularNames: [], enumNames: [] } },
112
+ children: ['schemas', 'operations'],
113
+ visitorKey: 'input',
114
+ })
115
+
116
+ /**
117
+ * Creates an `InputNode`. Pass `stream: true` for the streaming variant whose `schemas` and
118
+ * `operations` are `AsyncIterable` sources and whose `meta` is optional. Otherwise it builds the
119
+ * eager variant with array `schemas`/`operations` and the defaulted `meta`.
120
+ *
121
+ * @example Eager
122
+ * ```ts
123
+ * const input = createInput()
124
+ * // { kind: 'Input', schemas: [], operations: [] }
125
+ * ```
126
+ *
127
+ * @example Streaming
128
+ * ```ts
129
+ * const node = createInput({ stream: true, schemas: schemasIterable, operations: operationsIterable, meta: { title: 'My API' } })
130
+ * ```
131
+ */
132
+ export function createInput<Stream extends boolean = false>(options: Partial<Omit<InputNode<Stream>, 'kind'>> & { stream?: Stream } = {}): InputNode<Stream> {
133
+ const { stream, ...overrides } = options
134
+ // Streaming inputs carry AsyncIterable sources, so skip the array/meta defaults that
135
+ // inputDef.create applies for the eager variant.
136
+ if (stream) {
137
+ return { kind: 'Input', ...overrides } as InputNode<Stream>
138
+ }
139
+ return inputDef.create(overrides as Partial<Omit<InputNode, 'kind'>>) as InputNode<Stream>
140
+ }
@@ -1,6 +1,7 @@
1
+ import { defineNode } from '../node.ts'
1
2
  import type { BaseNode } from './base.ts'
2
3
  import type { ParameterNode } from './parameter.ts'
3
- import type { RequestBodyNode } from './requestBody.ts'
4
+ import { createRequestBody, type RequestBodyNode, type UserRequestBody } from './requestBody.ts'
4
5
  import type { ResponseNode } from './response.ts'
5
6
 
6
7
  export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS' | 'TRACE'
@@ -105,3 +106,60 @@ export type GenericOperationNode = OperationNodeBase & {
105
106
  * `isHttpOperationNode(node)` or `node.protocol === 'http'` before reading `method`/`path`.
106
107
  */
107
108
  export type OperationNode = HttpOperationNode | GenericOperationNode
109
+
110
+ type OperationInput = {
111
+ operationId: string
112
+ method?: HttpOperationNode['method']
113
+ path?: HttpOperationNode['path']
114
+ requestBody?: UserRequestBody
115
+ [key: string]: unknown
116
+ }
117
+
118
+ /**
119
+ * Definition for the {@link OperationNode}. HTTP operations (those carrying both
120
+ * `method` and `path`) are tagged with `protocol: 'http'`, and the request body is
121
+ * normalized into a `RequestBodyNode`.
122
+ */
123
+ export const operationDef = defineNode<OperationNode, OperationInput>({
124
+ kind: 'Operation',
125
+ build: (props) => {
126
+ const { requestBody, ...rest } = props
127
+ const isHttp = rest.method !== undefined && rest.path !== undefined
128
+
129
+ return {
130
+ tags: [],
131
+ parameters: [],
132
+ responses: [],
133
+ ...rest,
134
+ ...(isHttp ? { protocol: 'http' as const } : {}),
135
+ requestBody: requestBody ? createRequestBody(requestBody) : undefined,
136
+ }
137
+ },
138
+ children: ['parameters', 'requestBody', 'responses'],
139
+ visitorKey: 'operation',
140
+ })
141
+
142
+ /**
143
+ * Creates an `OperationNode` with default empty arrays for `tags`, `parameters`, and `responses`.
144
+ *
145
+ * @example
146
+ * ```ts
147
+ * const operation = createOperation({ operationId: 'getPetById', method: 'GET', path: '/pet/{petId}' })
148
+ * // tags, parameters, and responses are []
149
+ * ```
150
+ */
151
+ export function createOperation(
152
+ props: Pick<HttpOperationNode, 'operationId' | 'method' | 'path'> &
153
+ Partial<Omit<HttpOperationNode, 'kind' | 'operationId' | 'method' | 'path' | 'requestBody'>> & {
154
+ requestBody?: UserRequestBody
155
+ },
156
+ ): HttpOperationNode
157
+ export function createOperation(
158
+ props: Pick<GenericOperationNode, 'operationId'> &
159
+ Partial<Omit<GenericOperationNode, 'kind' | 'operationId' | 'requestBody'>> & {
160
+ requestBody?: UserRequestBody
161
+ },
162
+ ): GenericOperationNode
163
+ export function createOperation(props: OperationInput): OperationNode {
164
+ return operationDef.create(props)
165
+ }
@@ -1,3 +1,4 @@
1
+ import { defineNode } from '../node.ts'
1
2
  import type { BaseNode } from './base.ts'
2
3
  import type { FileNode } from './file.ts'
3
4
 
@@ -24,3 +25,25 @@ export type OutputNode = BaseNode & {
24
25
  */
25
26
  files: Array<FileNode>
26
27
  }
28
+
29
+ /**
30
+ * Definition for the {@link OutputNode}.
31
+ */
32
+ export const outputDef = defineNode<OutputNode, Partial<Omit<OutputNode, 'kind'>>>({
33
+ kind: 'Output',
34
+ defaults: { files: [] },
35
+ visitorKey: 'output',
36
+ })
37
+
38
+ /**
39
+ * Creates an `OutputNode` with a stable default for `files`.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * const output = createOutput()
44
+ * // { kind: 'Output', files: [] }
45
+ * ```
46
+ */
47
+ export function createOutput(overrides: Partial<Omit<OutputNode, 'kind'>> = {}): OutputNode {
48
+ return outputDef.create(overrides)
49
+ }
@@ -1,3 +1,4 @@
1
+ import { defineNode, syncOptionality } from '../node.ts'
1
2
  import type { BaseNode } from './base.ts'
2
3
  import type { SchemaNode } from './schema.ts'
3
4
 
@@ -39,3 +40,35 @@ export type ParameterNode = BaseNode & {
39
40
  */
40
41
  required: boolean
41
42
  }
43
+
44
+ type UserParameterNode = Pick<ParameterNode, 'name' | 'in' | 'schema'> & Partial<Omit<ParameterNode, 'kind' | 'name' | 'in' | 'schema'>>
45
+
46
+ /**
47
+ * Definition for the {@link ParameterNode}. `required` defaults to `false` and the
48
+ * schema's `optional`/`nullish` flags are kept in sync with it.
49
+ */
50
+ export const parameterDef = defineNode<ParameterNode, UserParameterNode>({
51
+ kind: 'Parameter',
52
+ build: (props) => {
53
+ const required = props.required ?? false
54
+ return { ...props, required, schema: syncOptionality(props.schema, required) }
55
+ },
56
+ children: ['schema'],
57
+ visitorKey: 'parameter',
58
+ rebuild: true,
59
+ })
60
+
61
+ /**
62
+ * Creates a `ParameterNode`.
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * const param = createParameter({
67
+ * name: 'petId',
68
+ * in: 'path',
69
+ * required: true,
70
+ * schema: createSchema({ type: 'string' }),
71
+ * })
72
+ * ```
73
+ */
74
+ export const createParameter = parameterDef.create