@kubb/ast 5.0.0-alpha.4 → 5.0.0-alpha.41

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