@kubb/ast 5.0.0-beta.6 → 5.0.0-beta.61
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/LICENSE +17 -10
- package/README.md +51 -27
- package/dist/chunk-CNktS9qV.js +17 -0
- package/dist/defineMacro-BLIR6k-j.d.ts +475 -0
- package/dist/defineMacro-BTXvS8nI.js +106 -0
- package/dist/defineMacro-BTXvS8nI.js.map +1 -0
- package/dist/defineMacro-Bv9R_9a2.cjs +123 -0
- package/dist/defineMacro-Bv9R_9a2.cjs.map +1 -0
- package/dist/extractStringsFromNodes-Cja-xxx5.js +29 -0
- package/dist/extractStringsFromNodes-Cja-xxx5.js.map +1 -0
- package/dist/extractStringsFromNodes-DKgDjFO0.cjs +34 -0
- package/dist/extractStringsFromNodes-DKgDjFO0.cjs.map +1 -0
- package/dist/extractStringsFromNodes-p4mX1TQD.d.ts +14 -0
- package/dist/factory-CZNOGI-N.js +283 -0
- package/dist/factory-CZNOGI-N.js.map +1 -0
- package/dist/factory-DG1CVkEb.cjs +300 -0
- package/dist/factory-DG1CVkEb.cjs.map +1 -0
- package/dist/factory.cjs +29 -0
- package/dist/factory.d.ts +62 -0
- package/dist/factory.js +3 -0
- package/dist/index-BzjwdK2M.d.ts +2433 -0
- package/dist/index.cjs +444 -2180
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +94 -3408
- package/dist/index.js +395 -2101
- package/dist/index.js.map +1 -1
- package/dist/macros.cjs +117 -0
- package/dist/macros.cjs.map +1 -0
- package/dist/macros.d.ts +59 -0
- package/dist/macros.js +115 -0
- package/dist/macros.js.map +1 -0
- package/dist/operationParams-BZ07xDm0.d.ts +204 -0
- package/dist/response-KUdWiDWw.js +658 -0
- package/dist/response-KUdWiDWw.js.map +1 -0
- package/dist/response-hnSw2NKE.cjs +1027 -0
- package/dist/response-hnSw2NKE.cjs.map +1 -0
- package/dist/types-DyDzizSf.d.ts +364 -0
- package/dist/types.cjs +0 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.js +1 -0
- package/dist/utils-BLJwyza-.cjs +912 -0
- package/dist/utils-BLJwyza-.cjs.map +1 -0
- package/dist/utils-CF_-Pn_c.js +770 -0
- package/dist/utils-CF_-Pn_c.js.map +1 -0
- package/dist/utils.cjs +36 -0
- package/dist/utils.d.ts +358 -0
- package/dist/utils.js +4 -0
- package/dist/visitor-DJ6ZEJvq.js +548 -0
- package/dist/visitor-DJ6ZEJvq.js.map +1 -0
- package/dist/visitor-DpKZ9Tk0.cjs +654 -0
- package/dist/visitor-DpKZ9Tk0.cjs.map +1 -0
- package/package.json +21 -6
- package/src/constants.ts +19 -64
- package/src/dedupe.ts +239 -0
- package/src/defineMacro.ts +132 -0
- package/src/dialect.ts +53 -0
- package/src/factory.ts +67 -678
- package/src/guards.ts +10 -92
- package/src/index.ts +13 -44
- package/src/infer.ts +16 -14
- package/src/macros/index.ts +3 -0
- package/src/macros/macroDiscriminatorEnum.ts +44 -0
- package/src/macros/macroEnumName.ts +25 -0
- package/src/macros/macroSimplifyUnion.ts +50 -0
- package/src/mocks.ts +7 -127
- package/src/node.ts +128 -0
- package/src/nodes/base.ts +5 -12
- package/src/nodes/code.ts +165 -74
- package/src/nodes/content.ts +56 -0
- package/src/nodes/file.ts +97 -36
- package/src/nodes/function.ts +216 -156
- package/src/nodes/http.ts +1 -35
- package/src/nodes/index.ts +23 -15
- package/src/nodes/input.ts +140 -0
- package/src/nodes/operation.ts +122 -68
- package/src/nodes/output.ts +23 -0
- package/src/nodes/parameter.ts +33 -3
- package/src/nodes/property.ts +36 -3
- package/src/nodes/requestBody.ts +61 -0
- package/src/nodes/response.ts +58 -13
- package/src/nodes/schema.ts +93 -17
- package/src/printer.ts +48 -42
- package/src/registry.ts +75 -0
- package/src/signature.ts +207 -0
- package/src/types.ts +8 -68
- package/src/utils/codegen.ts +104 -0
- package/src/utils/extractStringsFromNodes.ts +34 -0
- package/src/utils/fileMerge.ts +184 -0
- package/src/utils/index.ts +11 -0
- package/src/utils/operationParams.ts +353 -0
- package/src/utils/refs.ts +138 -0
- package/src/utils/schemaGraph.ts +169 -0
- package/src/utils/schemaMerge.ts +34 -0
- package/src/utils/schemaTraversal.ts +86 -0
- package/src/utils/strings.ts +139 -0
- package/src/visitor.ts +227 -289
- package/dist/chunk--u3MIqq1.js +0 -8
- package/src/nodes/root.ts +0 -64
- package/src/refs.ts +0 -67
- package/src/resolvers.ts +0 -45
- package/src/transformers.ts +0 -159
- package/src/utils.ts +0 -915
package/src/factory.ts
CHANGED
|
@@ -1,510 +1,56 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { hash } from 'node:crypto'
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import { trimExtName } from '@internals/utils'
|
|
4
|
-
import type {
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
nullish: !required && nullable ? true : undefined,
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Distributive `Omit` that preserves each member of a union.
|
|
51
|
-
*
|
|
52
|
-
* @example
|
|
53
|
-
* ```ts
|
|
54
|
-
* type A = { kind: 'a'; keep: string; drop: number }
|
|
55
|
-
* type B = { kind: 'b'; keep: boolean; drop: number }
|
|
56
|
-
* type Result = DistributiveOmit<A | B, 'drop'>
|
|
57
|
-
* // -> { kind: 'a'; keep: string } | { kind: 'b'; keep: boolean }
|
|
58
|
-
* ```
|
|
59
|
-
*/
|
|
60
|
-
export type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never
|
|
61
|
-
|
|
62
|
-
type CreateSchemaObjectInput = Omit<ObjectSchemaNode, 'kind' | 'properties' | 'primitive'> & { properties?: Array<PropertyNode>; primitive?: 'object' }
|
|
63
|
-
type CreateSchemaInput = CreateSchemaObjectInput | DistributiveOmit<Exclude<SchemaNode, ObjectSchemaNode>, 'kind'>
|
|
64
|
-
type CreateSchemaOutput<T extends CreateSchemaInput> = InferSchemaNode<T> & {
|
|
65
|
-
kind: 'Schema'
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Creates an `InputNode` with stable defaults for `schemas` and `operations`.
|
|
70
|
-
*
|
|
71
|
-
* @example
|
|
72
|
-
* ```ts
|
|
73
|
-
* const input = createInput()
|
|
74
|
-
* // { kind: 'Input', schemas: [], operations: [] }
|
|
75
|
-
* ```
|
|
76
|
-
*
|
|
77
|
-
* @example
|
|
78
|
-
* ```ts
|
|
79
|
-
* const input = createInput({ schemas: [petSchema] })
|
|
80
|
-
* // keeps default operations: []
|
|
81
|
-
* ```
|
|
82
|
-
*/
|
|
83
|
-
export function createInput(overrides: Partial<Omit<InputNode, 'kind'>> = {}): InputNode {
|
|
84
|
-
return {
|
|
85
|
-
schemas: [],
|
|
86
|
-
operations: [],
|
|
87
|
-
...overrides,
|
|
88
|
-
kind: 'Input',
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Creates an `OutputNode` with a stable default for `files`.
|
|
94
|
-
*
|
|
95
|
-
* @example
|
|
96
|
-
* ```ts
|
|
97
|
-
* const output = createOutput()
|
|
98
|
-
* // { kind: 'Output', files: [] }
|
|
99
|
-
* ```
|
|
100
|
-
*
|
|
101
|
-
* @example
|
|
102
|
-
* ```ts
|
|
103
|
-
* const output = createOutput({ files: [petFile] })
|
|
104
|
-
* ```
|
|
105
|
-
*/
|
|
106
|
-
export function createOutput(overrides: Partial<Omit<OutputNode, 'kind'>> = {}): OutputNode {
|
|
107
|
-
return {
|
|
108
|
-
files: [],
|
|
109
|
-
...overrides,
|
|
110
|
-
kind: 'Output',
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Creates an `OperationNode` with default empty arrays for `tags`, `parameters`, and `responses`.
|
|
116
|
-
*
|
|
117
|
-
* @example
|
|
118
|
-
* ```ts
|
|
119
|
-
* const operation = createOperation({
|
|
120
|
-
* operationId: 'getPetById',
|
|
121
|
-
* method: 'GET',
|
|
122
|
-
* path: '/pet/{petId}',
|
|
123
|
-
* })
|
|
124
|
-
* // tags, parameters, and responses are []
|
|
125
|
-
* ```
|
|
126
|
-
*
|
|
127
|
-
* @example
|
|
128
|
-
* ```ts
|
|
129
|
-
* const operation = createOperation({
|
|
130
|
-
* operationId: 'findPets',
|
|
131
|
-
* method: 'GET',
|
|
132
|
-
* path: '/pet/findByStatus',
|
|
133
|
-
* tags: ['pet'],
|
|
134
|
-
* })
|
|
135
|
-
* ```
|
|
136
|
-
*/
|
|
137
|
-
export function createOperation(
|
|
138
|
-
props: Pick<OperationNode, 'operationId' | 'method' | 'path'> & Partial<Omit<OperationNode, 'kind' | 'operationId' | 'method' | 'path'>>,
|
|
139
|
-
): OperationNode {
|
|
140
|
-
return {
|
|
141
|
-
tags: [],
|
|
142
|
-
parameters: [],
|
|
143
|
-
responses: [],
|
|
144
|
-
...props,
|
|
145
|
-
kind: 'Operation',
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Maps schema `type` to its underlying `primitive`.
|
|
151
|
-
* Primitive types map to themselves; special string formats map to `'string'`.
|
|
152
|
-
* Complex types (`ref`, `enum`, `union`, `intersection`, `tuple`, `blob`) are left unset.
|
|
153
|
-
*/
|
|
154
|
-
const TYPE_TO_PRIMITIVE: Partial<Record<SchemaNode['type'], PrimitiveSchemaType>> = {
|
|
155
|
-
string: 'string',
|
|
156
|
-
number: 'number',
|
|
157
|
-
integer: 'integer',
|
|
158
|
-
bigint: 'bigint',
|
|
159
|
-
boolean: 'boolean',
|
|
160
|
-
null: 'null',
|
|
161
|
-
any: 'any',
|
|
162
|
-
unknown: 'unknown',
|
|
163
|
-
void: 'void',
|
|
164
|
-
never: 'never',
|
|
165
|
-
object: 'object',
|
|
166
|
-
array: 'array',
|
|
167
|
-
date: 'date',
|
|
168
|
-
uuid: 'string',
|
|
169
|
-
email: 'string',
|
|
170
|
-
url: 'string',
|
|
171
|
-
datetime: 'string',
|
|
172
|
-
time: 'string',
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Creates a `SchemaNode`, narrowed to the variant of `props.type`.
|
|
177
|
-
* For object schemas, `properties` defaults to an empty array.
|
|
178
|
-
* `primitive` is automatically inferred from `type` when not explicitly provided.
|
|
179
|
-
*
|
|
180
|
-
* @example
|
|
181
|
-
* ```ts
|
|
182
|
-
* const scalar = createSchema({ type: 'string' })
|
|
183
|
-
* // { kind: 'Schema', type: 'string', primitive: 'string' }
|
|
184
|
-
* ```
|
|
185
|
-
*
|
|
186
|
-
* @example
|
|
187
|
-
* ```ts
|
|
188
|
-
* const uuid = createSchema({ type: 'uuid' })
|
|
189
|
-
* // { kind: 'Schema', type: 'uuid', primitive: 'string' }
|
|
190
|
-
* ```
|
|
191
|
-
*
|
|
192
|
-
* @example
|
|
193
|
-
* ```ts
|
|
194
|
-
* const object = createSchema({ type: 'object' })
|
|
195
|
-
* // { kind: 'Schema', type: 'object', primitive: 'object', properties: [] }
|
|
196
|
-
* ```
|
|
197
|
-
*
|
|
198
|
-
* @example
|
|
199
|
-
* ```ts
|
|
200
|
-
* const enumSchema = createSchema({
|
|
201
|
-
* type: 'enum',
|
|
202
|
-
* primitive: 'string',
|
|
203
|
-
* enumValues: ['available', 'pending'],
|
|
204
|
-
* })
|
|
205
|
-
* ```
|
|
206
|
-
*/
|
|
207
|
-
export function createSchema<T extends CreateSchemaInput>(props: T): CreateSchemaOutput<T>
|
|
208
|
-
export function createSchema(props: CreateSchemaInput): SchemaNode
|
|
209
|
-
export function createSchema(props: CreateSchemaInput): SchemaNode {
|
|
210
|
-
const inferredPrimitive = TYPE_TO_PRIMITIVE[props.type as keyof typeof TYPE_TO_PRIMITIVE]
|
|
211
|
-
|
|
212
|
-
if (props['type'] === 'object') {
|
|
213
|
-
return {
|
|
214
|
-
properties: [],
|
|
215
|
-
primitive: 'object',
|
|
216
|
-
...props,
|
|
217
|
-
kind: 'Schema',
|
|
218
|
-
} as CreateSchemaOutput<typeof props>
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return {
|
|
222
|
-
primitive: inferredPrimitive,
|
|
223
|
-
...props,
|
|
224
|
-
kind: 'Schema',
|
|
225
|
-
} as CreateSchemaOutput<typeof props>
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
type UserPropertyNode = Pick<PropertyNode, 'name' | 'schema'> & Partial<Omit<PropertyNode, 'kind' | 'name' | 'schema'>>
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Creates a `PropertyNode`.
|
|
232
|
-
*
|
|
233
|
-
* `required` defaults to `false`.
|
|
234
|
-
* `schema.optional` and `schema.nullish` are derived from `required` and `schema.nullable`.
|
|
235
|
-
*
|
|
236
|
-
* @example
|
|
237
|
-
* ```ts
|
|
238
|
-
* const property = createProperty({
|
|
239
|
-
* name: 'status',
|
|
240
|
-
* schema: createSchema({ type: 'string' }),
|
|
241
|
-
* })
|
|
242
|
-
* // required=false, schema.optional=true
|
|
243
|
-
* ```
|
|
244
|
-
*
|
|
245
|
-
* @example
|
|
246
|
-
* ```ts
|
|
247
|
-
* const property = createProperty({
|
|
248
|
-
* name: 'status',
|
|
249
|
-
* required: true,
|
|
250
|
-
* schema: createSchema({ type: 'string', nullable: true }),
|
|
251
|
-
* })
|
|
252
|
-
* // required=true, no optional/nullish
|
|
253
|
-
* ```
|
|
254
|
-
*/
|
|
255
|
-
export function createProperty(props: UserPropertyNode): PropertyNode {
|
|
256
|
-
const required = props.required ?? false
|
|
257
|
-
|
|
258
|
-
return {
|
|
259
|
-
...props,
|
|
260
|
-
kind: 'Property',
|
|
261
|
-
required,
|
|
262
|
-
schema: syncOptionality(props.schema, required),
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Creates a `ParameterNode`.
|
|
268
|
-
*
|
|
269
|
-
* `required` defaults to `false`.
|
|
270
|
-
* Nested schema flags are set from `required` and `schema.nullable`.
|
|
271
|
-
*
|
|
272
|
-
* @example
|
|
273
|
-
* ```ts
|
|
274
|
-
* const param = createParameter({
|
|
275
|
-
* name: 'petId',
|
|
276
|
-
* in: 'path',
|
|
277
|
-
* required: true,
|
|
278
|
-
* schema: createSchema({ type: 'string' }),
|
|
279
|
-
* })
|
|
280
|
-
* ```
|
|
281
|
-
*
|
|
282
|
-
* @example
|
|
283
|
-
* ```ts
|
|
284
|
-
* const param = createParameter({
|
|
285
|
-
* name: 'status',
|
|
286
|
-
* in: 'query',
|
|
287
|
-
* schema: createSchema({ type: 'string', nullable: true }),
|
|
288
|
-
* })
|
|
289
|
-
* // required=false, schema.nullish=true
|
|
290
|
-
* ```
|
|
291
|
-
*/
|
|
292
|
-
export function createParameter(
|
|
293
|
-
props: Pick<ParameterNode, 'name' | 'in' | 'schema'> & Partial<Omit<ParameterNode, 'kind' | 'name' | 'in' | 'schema'>>,
|
|
294
|
-
): ParameterNode {
|
|
295
|
-
const required = props.required ?? false
|
|
296
|
-
return {
|
|
297
|
-
...props,
|
|
298
|
-
kind: 'Parameter',
|
|
299
|
-
required,
|
|
300
|
-
schema: syncOptionality(props.schema, required),
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* Creates a `ResponseNode`.
|
|
306
|
-
*
|
|
307
|
-
* @example
|
|
308
|
-
* ```ts
|
|
309
|
-
* const response = createResponse({
|
|
310
|
-
* statusCode: '200',
|
|
311
|
-
* description: 'Success',
|
|
312
|
-
* schema: createSchema({ type: 'object', properties: [] }),
|
|
313
|
-
* })
|
|
314
|
-
* ```
|
|
315
|
-
*/
|
|
316
|
-
export function createResponse(
|
|
317
|
-
props: Pick<ResponseNode, 'statusCode' | 'schema'> & Partial<Omit<ResponseNode, 'kind' | 'statusCode' | 'schema'>>,
|
|
318
|
-
): ResponseNode {
|
|
319
|
-
return {
|
|
320
|
-
...props,
|
|
321
|
-
kind: 'Response',
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* Creates a `FunctionParameterNode`.
|
|
327
|
-
*
|
|
328
|
-
* `optional` defaults to `false`.
|
|
329
|
-
*
|
|
330
|
-
* @example Required typed param
|
|
331
|
-
* ```ts
|
|
332
|
-
* createFunctionParameter({ name: 'petId', type: createParamsType({ variant: 'reference', name: 'string' }) })
|
|
333
|
-
* // → petId: string
|
|
334
|
-
* ```
|
|
335
|
-
*
|
|
336
|
-
* @example Optional param
|
|
337
|
-
* ```ts
|
|
338
|
-
* createFunctionParameter({ name: 'params', type: createParamsType({ variant: 'reference', name: 'QueryParams' }), optional: true })
|
|
339
|
-
* // → params?: QueryParams
|
|
340
|
-
* ```
|
|
341
|
-
*
|
|
342
|
-
* @example Param with default (implicitly optional; cannot combine with `optional: true`)
|
|
343
|
-
* ```ts
|
|
344
|
-
* createFunctionParameter({ name: 'config', type: createParamsType({ variant: 'reference', name: 'RequestConfig' }), default: '{}' })
|
|
345
|
-
* // → config: RequestConfig = {}
|
|
346
|
-
* ```
|
|
347
|
-
*/
|
|
348
|
-
export function createFunctionParameter(
|
|
349
|
-
props: { name: string; type?: ParamsTypeNode; rest?: boolean } & ({ optional: true; default?: never } | { optional?: false; default?: string }),
|
|
350
|
-
): FunctionParameterNode {
|
|
351
|
-
return {
|
|
352
|
-
optional: false,
|
|
353
|
-
...props,
|
|
354
|
-
kind: 'FunctionParameter',
|
|
355
|
-
} as FunctionParameterNode
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* Creates a {@link TypeNode} representing a language-agnostic structured type expression.
|
|
360
|
-
*
|
|
361
|
-
* Use `variant: 'struct'` for inline anonymous types and `variant: 'member'` for a single
|
|
362
|
-
* named field accessed from a group type. Each language's printer renders the variant
|
|
363
|
-
* into its own syntax (TypeScript, Python, C#, Kotlin, …).
|
|
364
|
-
*
|
|
365
|
-
* @example Reference type (TypeScript: `QueryParams`)
|
|
366
|
-
* ```ts
|
|
367
|
-
* createParamsType({ variant: 'reference', name: 'QueryParams' })
|
|
368
|
-
* ```
|
|
369
|
-
*
|
|
370
|
-
* @example Struct type (TypeScript: `{ petId: string }`)
|
|
371
|
-
* ```ts
|
|
372
|
-
* createParamsType({ variant: 'struct', properties: [{ name: 'petId', optional: false, type: createParamsType({ variant: 'reference', name: 'string' }) }] })
|
|
373
|
-
* ```
|
|
374
|
-
*
|
|
375
|
-
* @example Member type (TypeScript: `DeletePetPathParams['petId']`)
|
|
376
|
-
* ```ts
|
|
377
|
-
* createParamsType({ variant: 'member', base: 'DeletePetPathParams', key: 'petId' })
|
|
378
|
-
* ```
|
|
379
|
-
*/
|
|
380
|
-
export function createParamsType(
|
|
381
|
-
props:
|
|
382
|
-
| { variant: 'reference'; name: string }
|
|
383
|
-
| {
|
|
384
|
-
variant: 'struct'
|
|
385
|
-
properties: Array<{
|
|
386
|
-
name: string
|
|
387
|
-
optional: boolean
|
|
388
|
-
type: ParamsTypeNode
|
|
389
|
-
}>
|
|
390
|
-
}
|
|
391
|
-
| { variant: 'member'; base: string; key: string },
|
|
392
|
-
): ParamsTypeNode {
|
|
393
|
-
return { ...props, kind: 'ParamsType' } as ParamsTypeNode
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
* Creates a `ParameterGroupNode` representing a group of related parameters treated as a unit.
|
|
398
|
-
*
|
|
399
|
-
* @example Grouped param (TypeScript declaration)
|
|
400
|
-
* ```ts
|
|
401
|
-
* createParameterGroup({
|
|
402
|
-
* properties: [
|
|
403
|
-
* createFunctionParameter({ name: 'id', type: createParamsType({ variant: 'reference', name: 'string' }), optional: false }),
|
|
404
|
-
* createFunctionParameter({ name: 'name', type: createParamsType({ variant: 'reference', name: 'string' }), optional: true }),
|
|
405
|
-
* ],
|
|
406
|
-
* default: '{}',
|
|
407
|
-
* })
|
|
408
|
-
* // declaration → { id, name? }: { id: string; name?: string } = {}
|
|
409
|
-
* // call → { id, name }
|
|
410
|
-
* ```
|
|
411
|
-
*
|
|
412
|
-
* @example Inline (spread) — children emitted as individual top-level parameters
|
|
413
|
-
* ```ts
|
|
414
|
-
* createParameterGroup({
|
|
415
|
-
* properties: [createFunctionParameter({ name: 'petId', type: createParamsType({ variant: 'reference', name: 'string' }), optional: false })],
|
|
416
|
-
* inline: true,
|
|
417
|
-
* })
|
|
418
|
-
* // declaration → petId: string
|
|
419
|
-
* // call → petId
|
|
420
|
-
* ```
|
|
421
|
-
*/
|
|
422
|
-
export function createParameterGroup(
|
|
423
|
-
props: Pick<ParameterGroupNode, 'properties'> & Partial<Omit<ParameterGroupNode, 'kind' | 'properties'>>,
|
|
424
|
-
): ParameterGroupNode {
|
|
425
|
-
return {
|
|
426
|
-
...props,
|
|
427
|
-
kind: 'ParameterGroup',
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
/**
|
|
432
|
-
* Creates a `FunctionParametersNode` from an ordered list of parameters.
|
|
433
|
-
*
|
|
434
|
-
* @example
|
|
435
|
-
* ```ts
|
|
436
|
-
* createFunctionParameters({
|
|
437
|
-
* params: [
|
|
438
|
-
* createFunctionParameter({ name: 'petId', type: createParamsType({ variant: 'reference', name: 'string' }), optional: false }),
|
|
439
|
-
* createFunctionParameter({ name: 'config', type: createParamsType({ variant: 'reference', name: 'RequestConfig' }), optional: false, default: '{}' }),
|
|
440
|
-
* ],
|
|
441
|
-
* })
|
|
442
|
-
* ```
|
|
443
|
-
*
|
|
444
|
-
* @example
|
|
445
|
-
* ```ts
|
|
446
|
-
* const empty = createFunctionParameters()
|
|
447
|
-
* // { kind: 'FunctionParameters', params: [] }
|
|
448
|
-
* ```
|
|
449
|
-
*/
|
|
450
|
-
export function createFunctionParameters(props: Partial<Omit<FunctionParametersNode, 'kind'>> = {}): FunctionParametersNode {
|
|
451
|
-
return {
|
|
452
|
-
params: [],
|
|
453
|
-
...props,
|
|
454
|
-
kind: 'FunctionParameters',
|
|
4
|
+
import type { FileNode, Node } from './nodes/index.ts'
|
|
5
|
+
import { extractStringsFromNodes } from './utils/extractStringsFromNodes.ts'
|
|
6
|
+
import { combineExports, combineImports, combineSources } from './utils/fileMerge.ts'
|
|
7
|
+
|
|
8
|
+
// Node constructors, grouped under the `factory` namespace the way the TypeScript compiler exposes
|
|
9
|
+
// `ts.factory.createX`. Aggregating them here lets `export * as factory from './factory.ts'` in the
|
|
10
|
+
// barrel surface every `createX` alongside the `createFile`/`update` helpers from a single module.
|
|
11
|
+
export { createArrowFunction, createBreak, createConst, createFunction, createJsx, createText, createType } from './nodes/code.ts'
|
|
12
|
+
export { createContent } from './nodes/content.ts'
|
|
13
|
+
export { createExport, createImport, createSource } from './nodes/file.ts'
|
|
14
|
+
export { createFunctionParameter, createFunctionParameters, createIndexedAccessType, createObjectBindingPattern, createTypeLiteral } from './nodes/function.ts'
|
|
15
|
+
export { createInput } from './nodes/input.ts'
|
|
16
|
+
export { createOperation } from './nodes/operation.ts'
|
|
17
|
+
export { createOutput } from './nodes/output.ts'
|
|
18
|
+
export { createParameter } from './nodes/parameter.ts'
|
|
19
|
+
export { createProperty } from './nodes/property.ts'
|
|
20
|
+
export { createRequestBody } from './nodes/requestBody.ts'
|
|
21
|
+
export { createResponse } from './nodes/response.ts'
|
|
22
|
+
export { createSchema } from './nodes/schema.ts'
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Identity-preserving node update: returns `node` unchanged when every field in
|
|
26
|
+
* `changes` already equals (by reference) the current value, otherwise a new node
|
|
27
|
+
* with the changes applied.
|
|
28
|
+
*
|
|
29
|
+
* Mirrors the TypeScript compiler's `factory.updateX` contract, pair it with the
|
|
30
|
+
* structural sharing in {@link transform} so a no-op rewrite doesn't allocate and
|
|
31
|
+
* downstream passes can detect "nothing changed" by identity. Comparison is
|
|
32
|
+
* shallow: a structurally-equal but newly-allocated array/object counts as a change.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* update(node, { name: node.name }) // -> same `node` reference
|
|
37
|
+
* update(node, { name: 'renamed' }) // -> new node, `name` replaced
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export function update<T extends Node>(node: T, changes: Partial<T>): T {
|
|
41
|
+
for (const key in changes) {
|
|
42
|
+
if (changes[key] !== node[key as keyof T]) {
|
|
43
|
+
return { ...node, ...changes }
|
|
44
|
+
}
|
|
455
45
|
}
|
|
456
|
-
}
|
|
457
46
|
|
|
458
|
-
|
|
459
|
-
* Creates an `ImportNode` representing a language-agnostic import/dependency declaration.
|
|
460
|
-
*
|
|
461
|
-
* @example Named import
|
|
462
|
-
* ```ts
|
|
463
|
-
* createImport({ name: ['useState'], path: 'react' })
|
|
464
|
-
* // import { useState } from 'react'
|
|
465
|
-
* ```
|
|
466
|
-
*
|
|
467
|
-
* @example Type-only import
|
|
468
|
-
* ```ts
|
|
469
|
-
* createImport({ name: ['FC'], path: 'react', isTypeOnly: true })
|
|
470
|
-
* // import type { FC } from 'react'
|
|
471
|
-
* ```
|
|
472
|
-
*/
|
|
473
|
-
export function createImport(props: Omit<ImportNode, 'kind'>): ImportNode {
|
|
474
|
-
return { ...props, kind: 'Import' }
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
/**
|
|
478
|
-
* Creates an `ExportNode` representing a language-agnostic export/public API declaration.
|
|
479
|
-
*
|
|
480
|
-
* @example Named export
|
|
481
|
-
* ```ts
|
|
482
|
-
* createExport({ name: ['Pet'], path: './Pet' })
|
|
483
|
-
* // export { Pet } from './Pet'
|
|
484
|
-
* ```
|
|
485
|
-
*
|
|
486
|
-
* @example Wildcard export
|
|
487
|
-
* ```ts
|
|
488
|
-
* createExport({ path: './utils' })
|
|
489
|
-
* // export * from './utils'
|
|
490
|
-
* ```
|
|
491
|
-
*/
|
|
492
|
-
export function createExport(props: Omit<ExportNode, 'kind'>): ExportNode {
|
|
493
|
-
return { ...props, kind: 'Export' }
|
|
47
|
+
return node
|
|
494
48
|
}
|
|
495
49
|
|
|
496
50
|
/**
|
|
497
|
-
*
|
|
498
|
-
*
|
|
499
|
-
* @example
|
|
500
|
-
* ```ts
|
|
501
|
-
* createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')], isExportable: true })
|
|
502
|
-
* ```
|
|
51
|
+
* Input descriptor for {@link createFile}, before `id`, `name`, and `extname` are computed
|
|
52
|
+
* and `imports`/`exports`/`sources` are deduplicated.
|
|
503
53
|
*/
|
|
504
|
-
export function createSource(props: Omit<SourceNode, 'kind'>): SourceNode {
|
|
505
|
-
return { ...props, kind: 'Source' }
|
|
506
|
-
}
|
|
507
|
-
|
|
508
54
|
export type UserFileNode<TMeta extends object = object> = Omit<FileNode<TMeta>, 'kind' | 'id' | 'name' | 'extname' | 'imports' | 'exports' | 'sources'> &
|
|
509
55
|
Pick<Partial<FileNode<TMeta>>, 'imports' | 'exports' | 'sources'>
|
|
510
56
|
|
|
@@ -512,9 +58,9 @@ export type UserFileNode<TMeta extends object = object> = Omit<FileNode<TMeta>,
|
|
|
512
58
|
* Creates a fully resolved `FileNode` from a file input descriptor.
|
|
513
59
|
*
|
|
514
60
|
* Computes:
|
|
515
|
-
* - `id`
|
|
516
|
-
* - `name`
|
|
517
|
-
* - `extname`
|
|
61
|
+
* - `id` SHA256 hash of the file path
|
|
62
|
+
* - `name` `baseName` without extension
|
|
63
|
+
* - `extname` extension extracted from `baseName`
|
|
518
64
|
*
|
|
519
65
|
* Deduplicates:
|
|
520
66
|
* - `sources` via `combineSources`
|
|
@@ -551,13 +97,30 @@ export function createFile<TMeta extends object = object>(input: UserFileNode<TM
|
|
|
551
97
|
.filter(Boolean)
|
|
552
98
|
.join('\n\n')
|
|
553
99
|
const resolvedExports = input.exports?.length ? combineExports(input.exports) : []
|
|
554
|
-
const
|
|
100
|
+
const combinedImports = input.imports?.length ? combineImports(input.imports, resolvedExports, source || undefined) : []
|
|
101
|
+
const localNames = new Set((input.sources ?? []).map((item) => item.name).filter((name): name is string => Boolean(name)))
|
|
102
|
+
const nameOf = (item: string | { propertyName: string; name?: string }): string => (typeof item === 'string' ? item : (item.name ?? item.propertyName))
|
|
103
|
+
// Drop self-imports. Consolidating output (`mode: 'file'`) can place a symbol's
|
|
104
|
+
// definition and a cross-file import of it in the same file. The first pass catches imports that
|
|
105
|
+
// resolve to this file's own path. The second drops imports of names the file already defines,
|
|
106
|
+
// the case consolidation produces when the import path no longer matches `input.path`. Sources
|
|
107
|
+
// stay intact, so the local definition remains. Bare specifiers like `'zod'` never match a path.
|
|
108
|
+
const resolvedImports = combinedImports
|
|
109
|
+
.filter((imp) => imp.path !== input.path)
|
|
110
|
+
.flatMap((imp) => {
|
|
111
|
+
if (!Array.isArray(imp.name)) {
|
|
112
|
+
return typeof imp.name === 'string' && localNames.has(imp.name) ? [] : [imp]
|
|
113
|
+
}
|
|
114
|
+
const kept = imp.name.filter((item) => !localNames.has(nameOf(item)))
|
|
115
|
+
if (!kept.length) return []
|
|
116
|
+
return [kept.length === imp.name.length ? imp : { ...imp, name: kept }]
|
|
117
|
+
})
|
|
555
118
|
const resolvedSources = input.sources?.length ? combineSources(input.sources) : []
|
|
556
119
|
|
|
557
120
|
return {
|
|
558
121
|
kind: 'File',
|
|
559
122
|
...input,
|
|
560
|
-
id:
|
|
123
|
+
id: hash('sha256', input.path, 'hex'),
|
|
561
124
|
name: trimExtName(input.baseName),
|
|
562
125
|
extname,
|
|
563
126
|
imports: resolvedImports,
|
|
@@ -566,177 +129,3 @@ export function createFile<TMeta extends object = object>(input: UserFileNode<TM
|
|
|
566
129
|
meta: input.meta ?? ({} as TMeta),
|
|
567
130
|
}
|
|
568
131
|
}
|
|
569
|
-
|
|
570
|
-
/**
|
|
571
|
-
* Creates a `ConstNode` representing a TypeScript `const` declaration.
|
|
572
|
-
*
|
|
573
|
-
* Mirrors the `Const` component from `@kubb/renderer-jsx`.
|
|
574
|
-
* The component's `children` are represented as `nodes`.
|
|
575
|
-
*
|
|
576
|
-
* @example Simple constant
|
|
577
|
-
* ```ts
|
|
578
|
-
* createConst({ name: 'pet' })
|
|
579
|
-
* // const pet = ...
|
|
580
|
-
* ```
|
|
581
|
-
*
|
|
582
|
-
* @example Exported constant with type and `as const`
|
|
583
|
-
* ```ts
|
|
584
|
-
* createConst({ name: 'pets', export: true, type: 'Pet[]', asConst: true })
|
|
585
|
-
* // export const pets: Pet[] = ... as const
|
|
586
|
-
* ```
|
|
587
|
-
*
|
|
588
|
-
* @example With JSDoc and child nodes
|
|
589
|
-
* ```ts
|
|
590
|
-
* createConst({
|
|
591
|
-
* name: 'config',
|
|
592
|
-
* export: true,
|
|
593
|
-
* JSDoc: { comments: ['@description App configuration'] },
|
|
594
|
-
* nodes: [],
|
|
595
|
-
* })
|
|
596
|
-
* ```
|
|
597
|
-
*/
|
|
598
|
-
export function createConst(props: Omit<ConstNode, 'kind'>): ConstNode {
|
|
599
|
-
return { ...props, kind: 'Const' }
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
/**
|
|
603
|
-
* Creates a `TypeNode` representing a TypeScript `type` alias declaration.
|
|
604
|
-
*
|
|
605
|
-
* Mirrors the `Type` component from `@kubb/renderer-jsx`.
|
|
606
|
-
* The component's `children` are represented as `nodes`.
|
|
607
|
-
*
|
|
608
|
-
* @example Simple type alias
|
|
609
|
-
* ```ts
|
|
610
|
-
* createType({ name: 'Pet' })
|
|
611
|
-
* // type Pet = ...
|
|
612
|
-
* ```
|
|
613
|
-
*
|
|
614
|
-
* @example Exported type with JSDoc
|
|
615
|
-
* ```ts
|
|
616
|
-
* createType({
|
|
617
|
-
* name: 'PetStatus',
|
|
618
|
-
* export: true,
|
|
619
|
-
* JSDoc: { comments: ['@description Status of a pet'] },
|
|
620
|
-
* })
|
|
621
|
-
* // export type PetStatus = ...
|
|
622
|
-
* ```
|
|
623
|
-
*/
|
|
624
|
-
export function createType(props: Omit<TypeNode, 'kind'>): TypeNode {
|
|
625
|
-
return { ...props, kind: 'Type' }
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
/**
|
|
629
|
-
* Creates a `FunctionNode` representing a TypeScript `function` declaration.
|
|
630
|
-
*
|
|
631
|
-
* Mirrors the `Function` component from `@kubb/renderer-jsx`.
|
|
632
|
-
* The component's `children` are represented as `nodes`.
|
|
633
|
-
*
|
|
634
|
-
* @example Simple function
|
|
635
|
-
* ```ts
|
|
636
|
-
* createFunction({ name: 'getPet' })
|
|
637
|
-
* // function getPet() { ... }
|
|
638
|
-
* ```
|
|
639
|
-
*
|
|
640
|
-
* @example Exported async function with return type
|
|
641
|
-
* ```ts
|
|
642
|
-
* createFunction({ name: 'fetchPet', export: true, async: true, returnType: 'Pet' })
|
|
643
|
-
* // export async function fetchPet(): Promise<Pet> { ... }
|
|
644
|
-
* ```
|
|
645
|
-
*
|
|
646
|
-
* @example Function with generics and params
|
|
647
|
-
* ```ts
|
|
648
|
-
* createFunction({
|
|
649
|
-
* name: 'identity',
|
|
650
|
-
* export: true,
|
|
651
|
-
* generics: ['T'],
|
|
652
|
-
* params: 'value: T',
|
|
653
|
-
* returnType: 'T',
|
|
654
|
-
* })
|
|
655
|
-
* // export function identity<T>(value: T): T { ... }
|
|
656
|
-
* ```
|
|
657
|
-
*/
|
|
658
|
-
export function createFunction(props: Omit<FunctionNode, 'kind'>): FunctionNode {
|
|
659
|
-
return { ...props, kind: 'Function' }
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
/**
|
|
663
|
-
* Creates an `ArrowFunctionNode` representing a TypeScript arrow function.
|
|
664
|
-
*
|
|
665
|
-
* Mirrors the `Function.Arrow` component from `@kubb/renderer-jsx`.
|
|
666
|
-
* The component's `children` are represented as `nodes`.
|
|
667
|
-
*
|
|
668
|
-
* @example Simple arrow function
|
|
669
|
-
* ```ts
|
|
670
|
-
* createArrowFunction({ name: 'getPet' })
|
|
671
|
-
* // const getPet = () => { ... }
|
|
672
|
-
* ```
|
|
673
|
-
*
|
|
674
|
-
* @example Single-line exported arrow function
|
|
675
|
-
* ```ts
|
|
676
|
-
* createArrowFunction({ name: 'double', export: true, params: 'n: number', singleLine: true })
|
|
677
|
-
* // export const double = (n: number) => ...
|
|
678
|
-
* ```
|
|
679
|
-
*
|
|
680
|
-
* @example Async arrow function with generics
|
|
681
|
-
* ```ts
|
|
682
|
-
* createArrowFunction({
|
|
683
|
-
* name: 'fetchPet',
|
|
684
|
-
* export: true,
|
|
685
|
-
* async: true,
|
|
686
|
-
* generics: ['T'],
|
|
687
|
-
* params: 'id: string',
|
|
688
|
-
* returnType: 'T',
|
|
689
|
-
* })
|
|
690
|
-
* // export const fetchPet = async <T>(id: string): Promise<T> => { ... }
|
|
691
|
-
* ```
|
|
692
|
-
*/
|
|
693
|
-
export function createArrowFunction(props: Omit<ArrowFunctionNode, 'kind'>): ArrowFunctionNode {
|
|
694
|
-
return { ...props, kind: 'ArrowFunction' }
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
/**
|
|
698
|
-
* Creates a {@link TextNode} representing a raw string fragment in the source output.
|
|
699
|
-
*
|
|
700
|
-
* Use this instead of bare strings when building `nodes` arrays so that every
|
|
701
|
-
* entry in the array is a typed {@link CodeNode}.
|
|
702
|
-
*
|
|
703
|
-
* @example
|
|
704
|
-
* ```ts
|
|
705
|
-
* createText('return fetch(id)')
|
|
706
|
-
* // { kind: 'Text', value: 'return fetch(id)' }
|
|
707
|
-
* ```
|
|
708
|
-
*/
|
|
709
|
-
export function createText(value: string): TextNode {
|
|
710
|
-
return { value, kind: 'Text' }
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
/**
|
|
714
|
-
* Creates a {@link BreakNode} representing a line break in the source output.
|
|
715
|
-
*
|
|
716
|
-
* Corresponds to `<br/>` in JSX components. Prints as an empty string which,
|
|
717
|
-
* when joined with `\n` by `printNodes`, produces a blank line.
|
|
718
|
-
*
|
|
719
|
-
* @example
|
|
720
|
-
* ```ts
|
|
721
|
-
* createBreak()
|
|
722
|
-
* // { kind: 'Break' }
|
|
723
|
-
* ```
|
|
724
|
-
*/
|
|
725
|
-
export function createBreak(): BreakNode {
|
|
726
|
-
return { kind: 'Break' }
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
/**
|
|
730
|
-
* Creates a {@link JsxNode} representing a raw JSX fragment in the source output.
|
|
731
|
-
*
|
|
732
|
-
* Use this to embed JSX markup (including fragments `<>…</>`) directly in generated code.
|
|
733
|
-
*
|
|
734
|
-
* @example
|
|
735
|
-
* ```ts
|
|
736
|
-
* createJsx('<>\n <a href={href}>Open</a>\n</>')
|
|
737
|
-
* // { kind: 'Jsx', value: '<>\n <a href={href}>Open</a>\n</>' }
|
|
738
|
-
* ```
|
|
739
|
-
*/
|
|
740
|
-
export function createJsx(value: string): JsxNode {
|
|
741
|
-
return { value, kind: 'Jsx' }
|
|
742
|
-
}
|