@kubb/ast 5.0.0-beta.55 → 5.0.0-beta.57

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,73 +1,9 @@
1
1
  import { hash } from 'node:crypto'
2
2
  import path from 'node:path'
3
3
  import { trimExtName } from '@internals/utils'
4
- import type { InferSchemaNode } from './infer.ts'
5
- import type {
6
- ArrowFunctionNode,
7
- BreakNode,
8
- ConstNode,
9
- ContentNode,
10
- ExportNode,
11
- FileNode,
12
- FunctionNode,
13
- FunctionParameterNode,
14
- FunctionParametersNode,
15
- GenericOperationNode,
16
- HttpOperationNode,
17
- ImportNode,
18
- InputMeta,
19
- InputNode,
20
- JsxNode,
21
- Node,
22
- ObjectSchemaNode,
23
- OperationNode,
24
- OutputNode,
25
- ParameterGroupNode,
26
- ParameterNode,
27
- ParamsTypeNode,
28
- PrimitiveSchemaType,
29
- PropertyNode,
30
- RequestBodyNode,
31
- ResponseNode,
32
- SchemaNode,
33
- SourceNode,
34
- TextNode,
35
- TypeNode,
36
- } from './nodes/index.ts'
4
+ import type { FileNode, Node } from './nodes/index.ts'
37
5
  import { combineExports, combineImports, combineSources, extractStringsFromNodes } from './utils/ast.ts'
38
6
 
39
- /**
40
- * Updates a schema's `optional` and `nullish` flags from a parent's `required`
41
- * value and the schema's own `nullable`. Mirrors how OpenAPI parameters and
42
- * object properties combine "required" and "nullable" into a single AST.
43
- *
44
- * - Non-required + non-nullable → `optional: true`.
45
- * - Non-required + nullable → `nullish: true`.
46
- * - Required → both flags cleared.
47
- */
48
- export function syncOptionality(schema: SchemaNode, required: boolean): SchemaNode {
49
- const nullable = schema.nullable ?? false
50
-
51
- return {
52
- ...schema,
53
- optional: !required && !nullable ? true : undefined,
54
- nullish: !required && nullable ? true : undefined,
55
- }
56
- }
57
-
58
- /**
59
- * Distributive `Omit` that preserves each member of a union.
60
- *
61
- * @example
62
- * ```ts
63
- * type A = { kind: 'a'; keep: string; drop: number }
64
- * type B = { kind: 'b'; keep: boolean; drop: number }
65
- * type Result = DistributiveOmit<A | B, 'drop'>
66
- * // -> { kind: 'a'; keep: string } | { kind: 'b'; keep: boolean }
67
- * ```
68
- */
69
- export type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never
70
-
71
7
  /**
72
8
  * Identity-preserving node update: returns `node` unchanged when every field in
73
9
  * `changes` already equals (by reference) the current value, otherwise a new node
@@ -94,532 +30,10 @@ export function update<T extends Node>(node: T, changes: Partial<T>): T {
94
30
  return node
95
31
  }
96
32
 
97
- type CreateSchemaObjectInput = Omit<ObjectSchemaNode, 'kind' | 'properties' | 'primitive'> & { properties?: Array<PropertyNode>; primitive?: 'object' }
98
- type CreateSchemaInput = CreateSchemaObjectInput | DistributiveOmit<Exclude<SchemaNode, ObjectSchemaNode>, 'kind'>
99
- type CreateSchemaOutput<T extends CreateSchemaInput> = InferSchemaNode<T> & {
100
- kind: 'Schema'
101
- }
102
-
103
- /**
104
- * Creates an `InputNode` with stable defaults for `schemas` and `operations`.
105
- *
106
- * @example
107
- * ```ts
108
- * const input = createInput()
109
- * // { kind: 'Input', schemas: [], operations: [] }
110
- * ```
111
- *
112
- * @example
113
- * ```ts
114
- * const input = createInput({ schemas: [petSchema] })
115
- * // keeps default operations: []
116
- * ```
117
- */
118
- export function createInput(overrides: Partial<Omit<InputNode, 'kind'>> = {}): InputNode {
119
- return {
120
- schemas: [],
121
- operations: [],
122
- meta: { circularNames: [], enumNames: [] },
123
- ...overrides,
124
- kind: 'Input',
125
- }
126
- }
127
-
128
- /**
129
- * Creates a streaming `InputNode<true>` from pre-built `AsyncIterable` sources.
130
- *
131
- * @example
132
- * ```ts
133
- * const node = createStreamInput(schemasIterable, operationsIterable, { title: 'My API' })
134
- * ```
135
- */
136
- export function createStreamInput(schemas: AsyncIterable<SchemaNode>, operations: AsyncIterable<OperationNode>, meta?: InputMeta): InputNode<true> {
137
- return { kind: 'Input', schemas, operations, meta }
138
- }
139
-
140
- /**
141
- * Creates an `OutputNode` with a stable default for `files`.
142
- *
143
- * @example
144
- * ```ts
145
- * const output = createOutput()
146
- * // { kind: 'Output', files: [] }
147
- * ```
148
- *
149
- * @example
150
- * ```ts
151
- * const output = createOutput({ files: [petFile] })
152
- * ```
153
- */
154
- export function createOutput(overrides: Partial<Omit<OutputNode, 'kind'>> = {}): OutputNode {
155
- return {
156
- files: [],
157
- ...overrides,
158
- kind: 'Output',
159
- }
160
- }
161
-
162
- /**
163
- * Creates an `OperationNode` with default empty arrays for `tags`, `parameters`, and `responses`.
164
- *
165
- * @example
166
- * ```ts
167
- * const operation = createOperation({
168
- * operationId: 'getPetById',
169
- * method: 'GET',
170
- * path: '/pet/{petId}',
171
- * })
172
- * // tags, parameters, and responses are []
173
- * ```
174
- *
175
- * @example
176
- * ```ts
177
- * const operation = createOperation({
178
- * operationId: 'findPets',
179
- * method: 'GET',
180
- * path: '/pet/findByStatus',
181
- * tags: ['pet'],
182
- * })
183
- * ```
184
- */
185
- /**
186
- * Loosely-typed content entry accepted by the builders, normalized into a {@link ContentNode}.
187
- */
188
- type UserContent = Omit<ContentNode, 'kind'>
189
-
190
- /**
191
- * Creates a `ContentNode` for a single request-body or response content type.
192
- */
193
- function createContent(props: UserContent): ContentNode {
194
- return {
195
- ...props,
196
- kind: 'Content',
197
- }
198
- }
199
-
200
- /**
201
- * Loosely-typed request body accepted by `createOperation`, normalized into a {@link RequestBodyNode}.
202
- */
203
- type UserRequestBody = Omit<RequestBodyNode, 'kind' | 'content'> & {
204
- content?: Array<UserContent>
205
- }
206
-
207
- /**
208
- * Creates a `RequestBodyNode`, normalizing each content entry into a `ContentNode`.
209
- */
210
- function createRequestBody(props: UserRequestBody): RequestBodyNode {
211
- return {
212
- ...props,
213
- kind: 'RequestBody',
214
- content: props.content?.map(createContent),
215
- }
216
- }
217
-
218
- export function createOperation(
219
- props: Pick<HttpOperationNode, 'operationId' | 'method' | 'path'> &
220
- Partial<Omit<HttpOperationNode, 'kind' | 'operationId' | 'method' | 'path' | 'requestBody'>> & {
221
- requestBody?: UserRequestBody
222
- },
223
- ): HttpOperationNode
224
- export function createOperation(
225
- props: Pick<GenericOperationNode, 'operationId'> &
226
- Partial<Omit<GenericOperationNode, 'kind' | 'operationId' | 'requestBody'>> & {
227
- requestBody?: UserRequestBody
228
- },
229
- ): GenericOperationNode
230
- export function createOperation(props: {
231
- operationId: string
232
- method?: HttpOperationNode['method']
233
- path?: HttpOperationNode['path']
234
- requestBody?: UserRequestBody
235
- [key: string]: unknown
236
- }): OperationNode {
237
- const { requestBody, ...rest } = props
238
- const isHttp = rest.method !== undefined && rest.path !== undefined
239
-
240
- return {
241
- tags: [],
242
- parameters: [],
243
- responses: [],
244
- ...rest,
245
- ...(isHttp ? { protocol: 'http' } : {}),
246
- kind: 'Operation',
247
- requestBody: requestBody ? createRequestBody(requestBody) : undefined,
248
- } as OperationNode
249
- }
250
-
251
- /**
252
- * Maps schema `type` to its underlying `primitive`.
253
- * Primitive types map to themselves. Special string formats map to `'string'`.
254
- * Complex types (`ref`, `enum`, `union`, `intersection`, `tuple`, `blob`) are left unset.
255
- */
256
- const TYPE_TO_PRIMITIVE: Partial<Record<SchemaNode['type'], PrimitiveSchemaType>> = {
257
- string: 'string',
258
- number: 'number',
259
- integer: 'integer',
260
- bigint: 'bigint',
261
- boolean: 'boolean',
262
- null: 'null',
263
- any: 'any',
264
- unknown: 'unknown',
265
- void: 'void',
266
- never: 'never',
267
- object: 'object',
268
- array: 'array',
269
- date: 'date',
270
- uuid: 'string',
271
- email: 'string',
272
- url: 'string',
273
- datetime: 'string',
274
- time: 'string',
275
- }
276
-
277
- /**
278
- * Creates a `SchemaNode`, narrowed to the variant of `props.type`.
279
- * For object schemas, `properties` defaults to an empty array.
280
- * `primitive` is automatically inferred from `type` when not explicitly provided.
281
- *
282
- * @example
283
- * ```ts
284
- * const scalar = createSchema({ type: 'string' })
285
- * // { kind: 'Schema', type: 'string', primitive: 'string' }
286
- * ```
287
- *
288
- * @example
289
- * ```ts
290
- * const uuid = createSchema({ type: 'uuid' })
291
- * // { kind: 'Schema', type: 'uuid', primitive: 'string' }
292
- * ```
293
- *
294
- * @example
295
- * ```ts
296
- * const object = createSchema({ type: 'object' })
297
- * // { kind: 'Schema', type: 'object', primitive: 'object', properties: [] }
298
- * ```
299
- *
300
- * @example
301
- * ```ts
302
- * const enumSchema = createSchema({
303
- * type: 'enum',
304
- * primitive: 'string',
305
- * enumValues: ['available', 'pending'],
306
- * })
307
- * ```
308
- */
309
- export function createSchema<T extends CreateSchemaInput>(props: T): CreateSchemaOutput<T>
310
- export function createSchema(props: CreateSchemaInput): SchemaNode
311
- export function createSchema(props: CreateSchemaInput): SchemaNode {
312
- const inferredPrimitive = TYPE_TO_PRIMITIVE[props.type as keyof typeof TYPE_TO_PRIMITIVE]
313
-
314
- if (props['type'] === 'object') {
315
- return {
316
- properties: [],
317
- primitive: 'object',
318
- ...props,
319
- kind: 'Schema',
320
- } as CreateSchemaOutput<typeof props>
321
- }
322
-
323
- return {
324
- primitive: inferredPrimitive,
325
- ...props,
326
- kind: 'Schema',
327
- } as CreateSchemaOutput<typeof props>
328
- }
329
-
330
- type UserPropertyNode = Pick<PropertyNode, 'name' | 'schema'> & Partial<Omit<PropertyNode, 'kind' | 'name' | 'schema'>>
331
-
332
- /**
333
- * Creates a `PropertyNode`.
334
- *
335
- * `required` defaults to `false`.
336
- * `schema.optional` and `schema.nullish` are derived from `required` and `schema.nullable`.
337
- *
338
- * @example
339
- * ```ts
340
- * const property = createProperty({
341
- * name: 'status',
342
- * schema: createSchema({ type: 'string' }),
343
- * })
344
- * // required=false, schema.optional=true
345
- * ```
346
- *
347
- * @example
348
- * ```ts
349
- * const property = createProperty({
350
- * name: 'status',
351
- * required: true,
352
- * schema: createSchema({ type: 'string', nullable: true }),
353
- * })
354
- * // required=true, no optional/nullish
355
- * ```
356
- */
357
- export function createProperty(props: UserPropertyNode): PropertyNode {
358
- const required = props.required ?? false
359
-
360
- return {
361
- ...props,
362
- kind: 'Property',
363
- required,
364
- schema: syncOptionality(props.schema, required),
365
- }
366
- }
367
-
368
- /**
369
- * Creates a `ParameterNode`.
370
- *
371
- * `required` defaults to `false`.
372
- * Nested schema flags are set from `required` and `schema.nullable`.
373
- *
374
- * @example
375
- * ```ts
376
- * const param = createParameter({
377
- * name: 'petId',
378
- * in: 'path',
379
- * required: true,
380
- * schema: createSchema({ type: 'string' }),
381
- * })
382
- * ```
383
- *
384
- * @example
385
- * ```ts
386
- * const param = createParameter({
387
- * name: 'status',
388
- * in: 'query',
389
- * schema: createSchema({ type: 'string', nullable: true }),
390
- * })
391
- * // required=false, schema.nullish=true
392
- * ```
393
- */
394
- export function createParameter(
395
- props: Pick<ParameterNode, 'name' | 'in' | 'schema'> & Partial<Omit<ParameterNode, 'kind' | 'name' | 'in' | 'schema'>>,
396
- ): ParameterNode {
397
- const required = props.required ?? false
398
- return {
399
- ...props,
400
- kind: 'Parameter',
401
- required,
402
- schema: syncOptionality(props.schema, required),
403
- }
404
- }
405
-
406
33
  /**
407
- * Creates a `ResponseNode`.
408
- *
409
- * Response body schemas live inside `content`. For convenience a single legacy `schema`
410
- * (with optional `mediaType`/`keysToOmit`) is normalized into one `content` entry, so the same
411
- * schema is never stored both at the node root and inside `content`.
412
- *
413
- * @example
414
- * ```ts
415
- * const response = createResponse({
416
- * statusCode: '200',
417
- * content: [{ contentType: 'application/json', schema: createSchema({ type: 'object', properties: [] }) }],
418
- * })
419
- * ```
34
+ * Input descriptor for {@link createFile}, before `id`, `name`, and `extname` are computed
35
+ * and `imports`/`exports`/`sources` are deduplicated.
420
36
  */
421
- export function createResponse(
422
- props: Pick<ResponseNode, 'statusCode'> &
423
- Partial<Omit<ResponseNode, 'kind' | 'statusCode' | 'content'>> & {
424
- content?: Array<UserContent>
425
- schema?: SchemaNode
426
- mediaType?: string | null
427
- keysToOmit?: Array<string> | null
428
- },
429
- ): ResponseNode {
430
- const { schema, mediaType, keysToOmit, content, ...rest } = props
431
- const entries = content ?? (schema ? [{ contentType: mediaType ?? 'application/json', schema, keysToOmit: keysToOmit ?? null }] : undefined)
432
-
433
- return {
434
- ...rest,
435
- kind: 'Response',
436
- content: entries?.map(createContent),
437
- }
438
- }
439
-
440
- /**
441
- * Creates a `FunctionParameterNode`.
442
- *
443
- * `optional` defaults to `false`.
444
- *
445
- * @example Required typed param
446
- * ```ts
447
- * createFunctionParameter({ name: 'petId', type: createParamsType({ variant: 'reference', name: 'string' }) })
448
- * // → petId: string
449
- * ```
450
- *
451
- * @example Optional param
452
- * ```ts
453
- * createFunctionParameter({ name: 'params', type: createParamsType({ variant: 'reference', name: 'QueryParams' }), optional: true })
454
- * // → params?: QueryParams
455
- * ```
456
- *
457
- * @example Param with default (implicitly optional. Cannot combine with `optional: true`)
458
- * ```ts
459
- * createFunctionParameter({ name: 'config', type: createParamsType({ variant: 'reference', name: 'RequestConfig' }), default: '{}' })
460
- * // → config: RequestConfig = {}
461
- * ```
462
- */
463
- export function createFunctionParameter(
464
- props: { name: string; type?: ParamsTypeNode; rest?: boolean } & ({ optional: true; default?: never } | { optional?: false; default?: string }),
465
- ): FunctionParameterNode {
466
- return {
467
- optional: false,
468
- ...props,
469
- kind: 'FunctionParameter',
470
- } as FunctionParameterNode
471
- }
472
-
473
- /**
474
- * Creates a {@link TypeNode} representing a language-agnostic structured type expression.
475
- *
476
- * Use `variant: 'struct'` for inline anonymous types and `variant: 'member'` for a single
477
- * named field accessed from a group type. Each language's printer renders the variant
478
- * into its own syntax (TypeScript, Python, C#, Kotlin, …).
479
- *
480
- * @example Reference type (TypeScript: `QueryParams`)
481
- * ```ts
482
- * createParamsType({ variant: 'reference', name: 'QueryParams' })
483
- * ```
484
- *
485
- * @example Struct type (TypeScript: `{ petId: string }`)
486
- * ```ts
487
- * createParamsType({ variant: 'struct', properties: [{ name: 'petId', optional: false, type: createParamsType({ variant: 'reference', name: 'string' }) }] })
488
- * ```
489
- *
490
- * @example Member type (TypeScript: `DeletePetPathParams['petId']`)
491
- * ```ts
492
- * createParamsType({ variant: 'member', base: 'DeletePetPathParams', key: 'petId' })
493
- * ```
494
- */
495
- export function createParamsType(
496
- props:
497
- | { variant: 'reference'; name: string }
498
- | {
499
- variant: 'struct'
500
- properties: Array<{
501
- name: string
502
- optional: boolean
503
- type: ParamsTypeNode
504
- }>
505
- }
506
- | { variant: 'member'; base: string; key: string },
507
- ): ParamsTypeNode {
508
- return { ...props, kind: 'ParamsType' } as ParamsTypeNode
509
- }
510
-
511
- /**
512
- * Creates a `ParameterGroupNode` representing a group of related parameters treated as a unit.
513
- *
514
- * @example Grouped param (TypeScript declaration)
515
- * ```ts
516
- * createParameterGroup({
517
- * properties: [
518
- * createFunctionParameter({ name: 'id', type: createParamsType({ variant: 'reference', name: 'string' }), optional: false }),
519
- * createFunctionParameter({ name: 'name', type: createParamsType({ variant: 'reference', name: 'string' }), optional: true }),
520
- * ],
521
- * default: '{}',
522
- * })
523
- * // declaration → { id, name? }: { id: string; name?: string } = {}
524
- * // call → { id, name }
525
- * ```
526
- *
527
- * @example Inline (spread), children emitted as individual top-level parameters
528
- * ```ts
529
- * createParameterGroup({
530
- * properties: [createFunctionParameter({ name: 'petId', type: createParamsType({ variant: 'reference', name: 'string' }), optional: false })],
531
- * inline: true,
532
- * })
533
- * // declaration → petId: string
534
- * // call → petId
535
- * ```
536
- */
537
- export function createParameterGroup(
538
- props: Pick<ParameterGroupNode, 'properties'> & Partial<Omit<ParameterGroupNode, 'kind' | 'properties'>>,
539
- ): ParameterGroupNode {
540
- return {
541
- ...props,
542
- kind: 'ParameterGroup',
543
- }
544
- }
545
-
546
- /**
547
- * Creates a `FunctionParametersNode` from an ordered list of parameters.
548
- *
549
- * @example
550
- * ```ts
551
- * createFunctionParameters({
552
- * params: [
553
- * createFunctionParameter({ name: 'petId', type: createParamsType({ variant: 'reference', name: 'string' }), optional: false }),
554
- * createFunctionParameter({ name: 'config', type: createParamsType({ variant: 'reference', name: 'RequestConfig' }), optional: false, default: '{}' }),
555
- * ],
556
- * })
557
- * ```
558
- *
559
- * @example
560
- * ```ts
561
- * const empty = createFunctionParameters()
562
- * // { kind: 'FunctionParameters', params: [] }
563
- * ```
564
- */
565
- export function createFunctionParameters(props: Partial<Omit<FunctionParametersNode, 'kind'>> = {}): FunctionParametersNode {
566
- return {
567
- params: [],
568
- ...props,
569
- kind: 'FunctionParameters',
570
- }
571
- }
572
-
573
- /**
574
- * Creates an `ImportNode` representing a language-agnostic import/dependency declaration.
575
- *
576
- * @example Named import
577
- * ```ts
578
- * createImport({ name: ['useState'], path: 'react' })
579
- * // import { useState } from 'react'
580
- * ```
581
- *
582
- * @example Type-only import
583
- * ```ts
584
- * createImport({ name: ['FC'], path: 'react', isTypeOnly: true })
585
- * // import type { FC } from 'react'
586
- * ```
587
- */
588
- export function createImport(props: Omit<ImportNode, 'kind'>): ImportNode {
589
- return { ...props, kind: 'Import' }
590
- }
591
-
592
- /**
593
- * Creates an `ExportNode` representing a language-agnostic export/public API declaration.
594
- *
595
- * @example Named export
596
- * ```ts
597
- * createExport({ name: ['Pet'], path: './Pet' })
598
- * // export { Pet } from './Pet'
599
- * ```
600
- *
601
- * @example Wildcard export
602
- * ```ts
603
- * createExport({ path: './utils' })
604
- * // export * from './utils'
605
- * ```
606
- */
607
- export function createExport(props: Omit<ExportNode, 'kind'>): ExportNode {
608
- return { ...props, kind: 'Export' }
609
- }
610
-
611
- /**
612
- * Creates a `SourceNode` representing a fragment of source code within a file.
613
- *
614
- * @example
615
- * ```ts
616
- * createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')], isExportable: true })
617
- * ```
618
- */
619
- export function createSource(props: Omit<SourceNode, 'kind'>): SourceNode {
620
- return { ...props, kind: 'Source' }
621
- }
622
-
623
37
  export type UserFileNode<TMeta extends object = object> = Omit<FileNode<TMeta>, 'kind' | 'id' | 'name' | 'extname' | 'imports' | 'exports' | 'sources'> &
624
38
  Pick<Partial<FileNode<TMeta>>, 'imports' | 'exports' | 'sources'>
625
39
 
@@ -698,177 +112,3 @@ export function createFile<TMeta extends object = object>(input: UserFileNode<TM
698
112
  meta: input.meta ?? ({} as TMeta),
699
113
  }
700
114
  }
701
-
702
- /**
703
- * Creates a `ConstNode` representing a TypeScript `const` declaration.
704
- *
705
- * Mirrors the `Const` component from `@kubb/renderer-jsx`.
706
- * The component's `children` are represented as `nodes`.
707
- *
708
- * @example Simple constant
709
- * ```ts
710
- * createConst({ name: 'pet' })
711
- * // const pet = ...
712
- * ```
713
- *
714
- * @example Exported constant with type and `as const`
715
- * ```ts
716
- * createConst({ name: 'pets', export: true, type: 'Pet[]', asConst: true })
717
- * // export const pets: Pet[] = ... as const
718
- * ```
719
- *
720
- * @example With JSDoc and child nodes
721
- * ```ts
722
- * createConst({
723
- * name: 'config',
724
- * export: true,
725
- * JSDoc: { comments: ['@description App configuration'] },
726
- * nodes: [],
727
- * })
728
- * ```
729
- */
730
- export function createConst(props: Omit<ConstNode, 'kind'>): ConstNode {
731
- return { ...props, kind: 'Const' }
732
- }
733
-
734
- /**
735
- * Creates a `TypeNode` representing a TypeScript `type` alias declaration.
736
- *
737
- * Mirrors the `Type` component from `@kubb/renderer-jsx`.
738
- * The component's `children` are represented as `nodes`.
739
- *
740
- * @example Simple type alias
741
- * ```ts
742
- * createType({ name: 'Pet' })
743
- * // type Pet = ...
744
- * ```
745
- *
746
- * @example Exported type with JSDoc
747
- * ```ts
748
- * createType({
749
- * name: 'PetStatus',
750
- * export: true,
751
- * JSDoc: { comments: ['@description Status of a pet'] },
752
- * })
753
- * // export type PetStatus = ...
754
- * ```
755
- */
756
- export function createType(props: Omit<TypeNode, 'kind'>): TypeNode {
757
- return { ...props, kind: 'Type' }
758
- }
759
-
760
- /**
761
- * Creates a `FunctionNode` representing a TypeScript `function` declaration.
762
- *
763
- * Mirrors the `Function` component from `@kubb/renderer-jsx`.
764
- * The component's `children` are represented as `nodes`.
765
- *
766
- * @example Simple function
767
- * ```ts
768
- * createFunction({ name: 'getPet' })
769
- * // function getPet() { ... }
770
- * ```
771
- *
772
- * @example Exported async function with return type
773
- * ```ts
774
- * createFunction({ name: 'fetchPet', export: true, async: true, returnType: 'Pet' })
775
- * // export async function fetchPet(): Promise<Pet> { ... }
776
- * ```
777
- *
778
- * @example Function with generics and params
779
- * ```ts
780
- * createFunction({
781
- * name: 'identity',
782
- * export: true,
783
- * generics: ['T'],
784
- * params: 'value: T',
785
- * returnType: 'T',
786
- * })
787
- * // export function identity<T>(value: T): T { ... }
788
- * ```
789
- */
790
- export function createFunction(props: Omit<FunctionNode, 'kind'>): FunctionNode {
791
- return { ...props, kind: 'Function' }
792
- }
793
-
794
- /**
795
- * Creates an `ArrowFunctionNode` representing a TypeScript arrow function.
796
- *
797
- * Mirrors the `Function.Arrow` component from `@kubb/renderer-jsx`.
798
- * The component's `children` are represented as `nodes`.
799
- *
800
- * @example Simple arrow function
801
- * ```ts
802
- * createArrowFunction({ name: 'getPet' })
803
- * // const getPet = () => { ... }
804
- * ```
805
- *
806
- * @example Single-line exported arrow function
807
- * ```ts
808
- * createArrowFunction({ name: 'double', export: true, params: 'n: number', singleLine: true })
809
- * // export const double = (n: number) => ...
810
- * ```
811
- *
812
- * @example Async arrow function with generics
813
- * ```ts
814
- * createArrowFunction({
815
- * name: 'fetchPet',
816
- * export: true,
817
- * async: true,
818
- * generics: ['T'],
819
- * params: 'id: string',
820
- * returnType: 'T',
821
- * })
822
- * // export const fetchPet = async <T>(id: string): Promise<T> => { ... }
823
- * ```
824
- */
825
- export function createArrowFunction(props: Omit<ArrowFunctionNode, 'kind'>): ArrowFunctionNode {
826
- return { ...props, kind: 'ArrowFunction' }
827
- }
828
-
829
- /**
830
- * Creates a {@link TextNode} representing a raw string fragment in the source output.
831
- *
832
- * Use this instead of bare strings when building `nodes` arrays so that every
833
- * entry in the array is a typed {@link CodeNode}.
834
- *
835
- * @example
836
- * ```ts
837
- * createText('return fetch(id)')
838
- * // { kind: 'Text', value: 'return fetch(id)' }
839
- * ```
840
- */
841
- export function createText(value: string): TextNode {
842
- return { value, kind: 'Text' }
843
- }
844
-
845
- /**
846
- * Creates a {@link BreakNode} representing a line break in the source output.
847
- *
848
- * Corresponds to `<br/>` in JSX components. Prints as an empty string which,
849
- * when joined with `\n` by `printNodes`, produces a blank line.
850
- *
851
- * @example
852
- * ```ts
853
- * createBreak()
854
- * // { kind: 'Break' }
855
- * ```
856
- */
857
- export function createBreak(): BreakNode {
858
- return { kind: 'Break' }
859
- }
860
-
861
- /**
862
- * Creates a {@link JsxNode} representing a raw JSX fragment in the source output.
863
- *
864
- * Use this to embed JSX markup (including fragments `<>…</>`) directly in generated code.
865
- *
866
- * @example
867
- * ```ts
868
- * createJsx('<>\n <a href={href}>Open</a>\n</>')
869
- * // { kind: 'Jsx', value: '<>\n <a href={href}>Open</a>\n</>' }
870
- * ```
871
- */
872
- export function createJsx(value: string): JsxNode {
873
- return { value, kind: 'Jsx' }
874
- }