@kubb/ast 5.0.0-beta.3 → 5.0.0-beta.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -190,6 +190,105 @@ declare const mediaTypes: {
190
190
  readonly videoMp4: "video/mp4";
191
191
  };
192
192
  //#endregion
193
+ //#region src/dialect.d.ts
194
+ /**
195
+ * The spec-specific decisions a schema parser makes while converting a source
196
+ * document's schemas into Kubb AST nodes.
197
+ *
198
+ * Everything else in an adapter's schema pipeline is generic JSON Schema shared
199
+ * across specs; the dialect is the one seam where a spec differs — the
200
+ * "dialect layer" analogue of a database driver targeting Postgres vs MySQL.
201
+ * Pair it with {@link dispatch}: the rule table decides *which* converter runs,
202
+ * the dialect answers the spec-specific questions inside them.
203
+ *
204
+ * The guard methods (`isReference`, `isDiscriminator`) are type predicates so
205
+ * converters narrow the schema after a check; the type parameters carry those
206
+ * narrowed types through.
207
+ *
208
+ * Scope: this is the seam for the **JSON Schema family** — OpenAPI, AsyncAPI, and
209
+ * plain JSON Schema all share `$ref`, `allOf`/`oneOf`, `enum`, and `format`, and
210
+ * differ only in these few decisions. A spec built on a different type system
211
+ * (e.g. GraphQL, with non-null wrappers, interfaces, and named-type references
212
+ * instead of `$ref`) does not implement a `SchemaDialect`; it reuses the universal
213
+ * layer directly — the `Adapter` port, the AST factories, and {@link dispatch}
214
+ * with its own rule table — to emit the same nodes.
215
+ *
216
+ * @typeParam TSchema - The adapter's schema object type (e.g. an OpenAPI `SchemaObject`).
217
+ * @typeParam TRef - The narrowed `$ref` pointer type `isReference` proves.
218
+ * @typeParam TDiscriminated - The narrowed discriminated-schema type `isDiscriminator` proves.
219
+ * @typeParam TDocument - The source document `resolveRef` resolves against.
220
+ */
221
+ type SchemaDialect<TSchema = unknown, TRef = TSchema, TDiscriminated = TSchema, TDocument = unknown> = {
222
+ /** Identifies the dialect in logs and while debugging dispatch. */name: string; /** Whether a schema should be treated as nullable. */
223
+ isNullable: (schema?: TSchema) => boolean; /** Whether a value is a `$ref` pointer object. */
224
+ isReference: (value?: unknown) => value is TRef; /** Whether a schema carries a structured discriminator (polymorphism). */
225
+ isDiscriminator: (value?: unknown) => value is TDiscriminated; /** Whether a schema represents binary data (converted to a `blob` node). */
226
+ isBinary: (schema: TSchema) => boolean; /** Resolves a local `$ref` pointer against the document, or nullish when it cannot. */
227
+ resolveRef: <TResolved>(document: TDocument, ref: string) => TResolved | null | undefined;
228
+ };
229
+ /**
230
+ * Identity helper that types a {@link SchemaDialect} for an adapter. Like
231
+ * `defineParser`, it adds no runtime behavior — it pins the dialect's type for
232
+ * inference and gives adapter authors a discoverable anchor.
233
+ *
234
+ * @example
235
+ * ```ts
236
+ * export const oasDialect = defineSchemaDialect({
237
+ * name: 'oas',
238
+ * isNullable,
239
+ * isReference,
240
+ * isDiscriminator,
241
+ * isBinary: (schema) => schema.type === 'string' && schema.contentMediaType === 'application/octet-stream',
242
+ * resolveRef,
243
+ * })
244
+ * ```
245
+ */
246
+ declare function defineSchemaDialect<TSchema, TRef, TDiscriminated, TDocument>(dialect: SchemaDialect<TSchema, TRef, TDiscriminated, TDocument>): SchemaDialect<TSchema, TRef, TDiscriminated, TDocument>;
247
+ //#endregion
248
+ //#region src/dispatch.d.ts
249
+ /**
250
+ * One entry in an ordered dispatch table: a predicate paired with a converter.
251
+ *
252
+ * @typeParam TContext - Per-input context handed to every rule. A spec adapter typically
253
+ * pre-computes this once per node (the source spec node plus derived fields like a
254
+ * normalized type or resolved options) so individual rules stay cheap predicates.
255
+ * @typeParam TNode - The node a rule produces, e.g. a Kubb AST `SchemaNode`.
256
+ */
257
+ type DispatchRule<TContext, TNode> = {
258
+ /** Identifies the rule when reading the table or debugging which branch ran. */name: string; /** Returns `true` when this rule is responsible for the given context. */
259
+ match: (context: TContext) => boolean;
260
+ /**
261
+ * Produces a node for the context, or `null` to fall through to the next rule.
262
+ *
263
+ * Returning `null` lets a broad `match` defer: e.g. "has a `format`" matches many schemas,
264
+ * but only some formats are convertible — the rest fall through to plain `type` handling.
265
+ */
266
+ convert: (context: TContext) => TNode | null;
267
+ };
268
+ /**
269
+ * Walks an ordered list of {@link DispatchRule}s and returns the first node produced.
270
+ *
271
+ * This is the shared backbone for spec adapters (OpenAPI today, AsyncAPI and others later).
272
+ * The contract an adapter follows is intentionally minimal:
273
+ *
274
+ * context → [rule.match → rule.convert] → node
275
+ *
276
+ * An adapter derives a context from a source spec node, then declares an ordered table of
277
+ * rules mapping spec shapes onto Kubb AST nodes. To add support for a new spec, write a new
278
+ * context type and a new rules table — the traversal here is reused unchanged.
279
+ *
280
+ * Order is significant: earlier rules win, so list higher-precedence or more specific shapes
281
+ * first (e.g. composition keywords before plain `type`). A rule whose `match` returns `true`
282
+ * may still `convert` to `null` to defer to later rules. When no rule produces a node this
283
+ * returns `null`, leaving the caller to apply its own fallback.
284
+ *
285
+ * @example
286
+ * ```ts
287
+ * const node = dispatch(schemaRules, schemaContext) ?? createSchema({ type: fallbackType })
288
+ * ```
289
+ */
290
+ declare function dispatch<TContext, TNode>(rules: ReadonlyArray<DispatchRule<TContext, TNode>>, context: TContext): TNode | null;
291
+ //#endregion
193
292
  //#region src/nodes/base.d.ts
194
293
  /**
195
294
  * `kind` values used by AST nodes.
@@ -199,7 +298,7 @@ declare const mediaTypes: {
199
298
  * const kind: NodeKind = 'Schema'
200
299
  * ```
201
300
  */
202
- type NodeKind = 'Input' | 'Output' | 'Operation' | 'Schema' | 'Property' | 'Parameter' | 'Response' | 'FunctionParameter' | 'ParameterGroup' | 'FunctionParameters' | 'Type' | 'ParamsType' | 'File' | 'Import' | 'Export' | 'Source' | 'Const' | 'Function' | 'ArrowFunction' | 'Text' | 'Break' | 'Jsx';
301
+ type NodeKind = 'Input' | 'Output' | 'Operation' | 'Schema' | 'Property' | 'Parameter' | 'Response' | 'RequestBody' | 'Content' | 'FunctionParameter' | 'ParameterGroup' | 'FunctionParameters' | 'Type' | 'ParamsType' | 'File' | 'Import' | 'Export' | 'Source' | 'Const' | 'Function' | 'ArrowFunction' | 'Text' | 'Break' | 'Jsx';
203
302
  /**
204
303
  * Base shape shared by all AST nodes.
205
304
  *
@@ -251,21 +350,21 @@ type ConstNode = BaseNode & {
251
350
  * Whether the declaration should be exported.
252
351
  * @default false
253
352
  */
254
- export?: boolean;
353
+ export?: boolean | null;
255
354
  /**
256
355
  * Optional explicit type annotation.
257
356
  * @example 'Pet'
258
357
  */
259
- type?: string;
358
+ type?: string | null;
260
359
  /**
261
360
  * JSDoc documentation metadata.
262
361
  */
263
- JSDoc?: JSDocNode;
362
+ JSDoc?: JSDocNode | null;
264
363
  /**
265
364
  * Whether to append `as const` to the declaration.
266
365
  * @default false
267
366
  */
268
- asConst?: boolean;
367
+ asConst?: boolean | null;
269
368
  /**
270
369
  * Child nodes representing the value of the constant (children of the `Const` component).
271
370
  * Each entry is a {@link CodeNode}; use {@link TextNode} for raw string content.
@@ -297,11 +396,11 @@ type TypeNode = BaseNode & {
297
396
  * Whether the declaration should be exported.
298
397
  * @default false
299
398
  */
300
- export?: boolean;
399
+ export?: boolean | null;
301
400
  /**
302
401
  * JSDoc documentation metadata.
303
402
  */
304
- JSDoc?: JSDocNode;
403
+ JSDoc?: JSDocNode | null;
305
404
  /**
306
405
  * Child nodes representing the type body (children of the `Type` component).
307
406
  * Each entry is a {@link CodeNode}; use {@link TextNode} for raw string content.
@@ -338,35 +437,35 @@ type FunctionNode = BaseNode & {
338
437
  * Whether the function is a default export.
339
438
  * @default false
340
439
  */
341
- default?: boolean;
440
+ default?: boolean | null;
342
441
  /**
343
442
  * Function parameter list rendered as a string (e.g. from `FunctionParams.toConstructor()`).
344
443
  */
345
- params?: string;
444
+ params?: string | null;
346
445
  /**
347
446
  * Whether the function should be exported.
348
447
  * @default false
349
448
  */
350
- export?: boolean;
449
+ export?: boolean | null;
351
450
  /**
352
451
  * Whether the function is async. When `true`, the return type is wrapped in `Promise<>`.
353
452
  * @default false
354
453
  */
355
- async?: boolean;
454
+ async?: boolean | null;
356
455
  /**
357
456
  * TypeScript generic type parameters.
358
457
  * @example ['T', 'U extends string']
359
458
  */
360
- generics?: string | string[];
459
+ generics?: string | Array<string> | null;
361
460
  /**
362
461
  * Return type annotation.
363
462
  * @example 'Pet'
364
463
  */
365
- returnType?: string;
464
+ returnType?: string | null;
366
465
  /**
367
466
  * JSDoc documentation metadata.
368
467
  */
369
- JSDoc?: JSDocNode;
468
+ JSDoc?: JSDocNode | null;
370
469
  /**
371
470
  * Child nodes representing the function body (children of the `Function` component).
372
471
  * Each entry is a {@link CodeNode}; use {@link TextNode} for raw string content.
@@ -398,40 +497,40 @@ type ArrowFunctionNode = BaseNode & {
398
497
  * Whether the function is a default export.
399
498
  * @default false
400
499
  */
401
- default?: boolean;
500
+ default?: boolean | null;
402
501
  /**
403
502
  * Function parameter list rendered as a string (e.g. from `FunctionParams.toConstructor()`).
404
503
  */
405
- params?: string;
504
+ params?: string | null;
406
505
  /**
407
506
  * Whether the arrow function should be exported.
408
507
  * @default false
409
508
  */
410
- export?: boolean;
509
+ export?: boolean | null;
411
510
  /**
412
511
  * Whether the arrow function is async. When `true`, the return type is wrapped in `Promise<>`.
413
512
  * @default false
414
513
  */
415
- async?: boolean;
514
+ async?: boolean | null;
416
515
  /**
417
516
  * TypeScript generic type parameters.
418
517
  * @example ['T', 'U extends string']
419
518
  */
420
- generics?: string | string[];
519
+ generics?: string | Array<string> | null;
421
520
  /**
422
521
  * Return type annotation.
423
522
  * @example 'Pet'
424
523
  */
425
- returnType?: string;
524
+ returnType?: string | null;
426
525
  /**
427
526
  * JSDoc documentation metadata.
428
527
  */
429
- JSDoc?: JSDocNode;
528
+ JSDoc?: JSDocNode | null;
430
529
  /**
431
530
  * Render the arrow function body as a single-line expression.
432
531
  * @default false
433
532
  */
434
- singleLine?: boolean;
533
+ singleLine?: boolean | null;
435
534
  /**
436
535
  * Child nodes representing the function body (children of the `Function.Arrow` component).
437
536
  * Each entry is a {@link CodeNode}; use {@link TextNode} for raw string content.
@@ -510,1079 +609,1123 @@ type JsxNode = BaseNode & {
510
609
  */
511
610
  type CodeNode = ConstNode | TypeNode | FunctionNode | ArrowFunctionNode | TextNode | BreakNode | JsxNode;
512
611
  //#endregion
513
- //#region src/nodes/file.d.ts
514
- /**
515
- * Supported file extensions.
516
- */
517
- type Extname = '.ts' | '.js' | '.tsx' | '.json' | `.${string}`;
518
- type ImportName = string | Array<string | {
519
- propertyName: string;
520
- name?: string;
521
- }>;
612
+ //#region src/nodes/property.d.ts
522
613
  /**
523
- * Represents a language-agnostic import/dependency declaration.
524
- *
525
- * @example Named import (TypeScript: `import { useState } from 'react'`)
526
- * ```ts
527
- * createImport({ name: ['useState'], path: 'react' })
528
- * ```
529
- *
530
- * @example Default import (TypeScript: `import React from 'react'`)
531
- * ```ts
532
- * createImport({ name: 'React', path: 'react' })
533
- * ```
534
- *
535
- * @example Type-only import (TypeScript: `import type { FC } from 'react'`)
536
- * ```ts
537
- * createImport({ name: ['FC'], path: 'react', isTypeOnly: true })
538
- * ```
614
+ * AST node representing one named object property.
539
615
  *
540
- * @example Namespace import (TypeScript: `import * as React from 'react'`)
616
+ * @example
541
617
  * ```ts
542
- * createImport({ name: 'React', path: 'react', isNameSpace: true })
618
+ * const property: PropertyNode = {
619
+ * kind: 'Property',
620
+ * name: 'id',
621
+ * schema: createSchema({ type: 'integer' }),
622
+ * required: true,
623
+ * }
543
624
  * ```
544
625
  */
545
- type ImportNode = BaseNode & {
546
- kind: 'Import';
547
- /**
548
- * Import name(s) to be used.
549
- * @example ['useState']
550
- * @example 'React'
551
- */
552
- name: ImportName;
626
+ type PropertyNode = BaseNode & {
553
627
  /**
554
- * Path for the import.
555
- * @example '@kubb/core'
628
+ * Node kind.
556
629
  */
557
- path: string;
630
+ kind: 'Property';
558
631
  /**
559
- * Add type-only import prefix.
560
- * - `true` generates `import type { Type } from './path'`
561
- * - `false` generates `import { Type } from './path'`
562
- * @default false
632
+ * Property key.
563
633
  */
564
- isTypeOnly?: boolean;
634
+ name: string;
565
635
  /**
566
- * Import entire module as namespace.
567
- * - `true` generates `import * as Name from './path'`
568
- * - `false` generates standard import
569
- * @default false
636
+ * Property schema.
570
637
  */
571
- isNameSpace?: boolean;
638
+ schema: SchemaNode;
572
639
  /**
573
- * When set, the import path is resolved relative to this root.
640
+ * Whether the property is required.
574
641
  */
575
- root?: string;
642
+ required: boolean;
576
643
  };
644
+ //#endregion
645
+ //#region src/nodes/schema.d.ts
646
+ type PrimitiveSchemaType =
577
647
  /**
578
- * Represents a language-agnostic export/public API declaration.
579
- *
580
- * @example Named export (TypeScript: `export { Pets } from './Pets'`)
581
- * ```ts
582
- * createExport({ name: ['Pets'], path: './Pets' })
583
- * ```
584
- *
585
- * @example Type-only export (TypeScript: `export type { Pet } from './Pet'`)
586
- * ```ts
587
- * createExport({ name: ['Pet'], path: './Pet', isTypeOnly: true })
588
- * ```
589
- *
590
- * @example Wildcard export (TypeScript: `export * from './utils'`)
591
- * ```ts
592
- * createExport({ path: './utils' })
593
- * ```
594
- *
595
- * @example Namespace alias (TypeScript: `export * as utils from './utils'`)
596
- * ```ts
597
- * createExport({ name: 'utils', path: './utils', asAlias: true })
598
- * ```
648
+ * Text value.
599
649
  */
600
- type ExportNode = BaseNode & {
601
- kind: 'Export';
650
+ 'string'
651
+ /**
652
+ * Floating-point number.
653
+ */
654
+ | 'number'
655
+ /**
656
+ * Integer number.
657
+ */
658
+ | 'integer'
659
+ /**
660
+ * Big integer number.
661
+ */
662
+ | 'bigint'
663
+ /**
664
+ * Boolean value.
665
+ */
666
+ | 'boolean'
667
+ /**
668
+ * Null value.
669
+ */
670
+ | 'null'
671
+ /**
672
+ * Any value.
673
+ */
674
+ | 'any'
675
+ /**
676
+ * Unknown value.
677
+ */
678
+ | 'unknown'
679
+ /**
680
+ * No value (`void`).
681
+ */
682
+ | 'void'
683
+ /**
684
+ * Never value.
685
+ */
686
+ | 'never'
687
+ /**
688
+ * Object value.
689
+ */
690
+ | 'object'
691
+ /**
692
+ * Array value.
693
+ */
694
+ | 'array'
695
+ /**
696
+ * Date value.
697
+ */
698
+ | 'date';
699
+ /**
700
+ * Composite schema types.
701
+ */
702
+ type ComplexSchemaType = 'tuple' | 'union' | 'intersection' | 'enum';
703
+ /**
704
+ * Schema types that need special handling in generators.
705
+ */
706
+ type SpecialSchemaType = 'ref' | 'datetime' | 'time' | 'uuid' | 'email' | 'url' | 'ipv4' | 'ipv6' | 'blob';
707
+ /**
708
+ * All schema type strings.
709
+ */
710
+ type SchemaType = PrimitiveSchemaType | ComplexSchemaType | SpecialSchemaType;
711
+ /**
712
+ * Scalar schema types without extra object/array/ref structure.
713
+ */
714
+ type ScalarSchemaType = Exclude<SchemaType, 'object' | 'array' | 'tuple' | 'union' | 'intersection' | 'enum' | 'ref' | 'datetime' | 'date' | 'time' | 'string' | 'number' | 'integer' | 'bigint' | 'url' | 'uuid' | 'email'>;
715
+ /**
716
+ * Fields shared by all schema nodes.
717
+ */
718
+ type SchemaNodeBase = BaseNode & {
602
719
  /**
603
- * Export name(s) to be used. When omitted, generates a wildcard export.
604
- * @example ['useState']
605
- * @example 'React'
720
+ * Node kind.
606
721
  */
607
- name?: string | Array<string>;
722
+ kind: 'Schema';
608
723
  /**
609
- * Path for the export.
610
- * @example '@kubb/core'
724
+ * Schema name for named definitions (for example, `"Pet"`).
725
+ * Inline schemas omit this field.
726
+ * `null` means kubb has processed this and determined there is no applicable name.
727
+ * `undefined` means the name has not been set yet.
611
728
  */
612
- path: string;
729
+ name?: string | null;
613
730
  /**
614
- * Add type-only export prefix.
615
- * - `true` generates `export type { Type } from './path'`
616
- * - `false` generates `export { Type } from './path'`
617
- * @default false
731
+ * Short schema title.
618
732
  */
619
- isTypeOnly?: boolean;
733
+ title?: string;
620
734
  /**
621
- * Export as an aliased namespace.
622
- * - `true` generates `export * as aliasName from './path'`
623
- * - `false` generates a standard export
624
- * @default false
735
+ * Schema description text.
625
736
  */
626
- asAlias?: boolean;
627
- };
628
- /**
629
- * Represents a fragment of source code within a file.
630
- *
631
- * @example Named exportable source
632
- * ```ts
633
- * createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')], isExportable: true, isIndexable: true })
634
- * ```
635
- *
636
- * @example Inline unnamed code block
637
- * ```ts
638
- * createSource({ nodes: [createText('const x = 1')] })
639
- * ```
640
- */
641
- type SourceNode = BaseNode & {
642
- kind: 'Source';
737
+ description?: string;
643
738
  /**
644
- * Optional name identifying this source (used for deduplication and barrel generation).
739
+ * Whether `null` is allowed.
645
740
  */
646
- name?: string;
741
+ nullable?: boolean;
647
742
  /**
648
- * Mark this source as a type-only export.
649
- * @default false
743
+ * Whether the field is optional.
650
744
  */
651
- isTypeOnly?: boolean;
745
+ optional?: boolean;
652
746
  /**
653
- * Include `export` keyword in the generated source.
654
- * @default false
747
+ * Both optional and nullable (`optional` + `nullable`).
655
748
  */
656
- isExportable?: boolean;
749
+ nullish?: boolean;
657
750
  /**
658
- * Include this source in barrel/index file generation.
659
- * @default false
751
+ * Whether the schema is deprecated.
660
752
  */
661
- isIndexable?: boolean;
753
+ deprecated?: boolean;
662
754
  /**
663
- * Structured child nodes representing the content of this source fragment, in DOM order.
664
- * Each entry is a {@link CodeNode}; use {@link TextNode} for raw string content.
755
+ * Whether the schema is read-only.
665
756
  */
666
- nodes?: Array<CodeNode>;
667
- };
668
- /**
669
- * Represents a fully resolved file in the AST.
670
- *
671
- * Created via `createFile()`, which computes the `id`, `name`, and `extname` from the input
672
- * and deduplicates `imports`, `exports`, and `sources`.
673
- *
674
- * @example
675
- * ```ts
676
- * const file = createFile({
677
- * baseName: 'petStore.ts',
678
- * path: 'src/models/petStore.ts',
679
- * sources: [createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')], isExportable: true })],
680
- * imports: [createImport({ name: ['z'], path: 'zod' })],
681
- * exports: [createExport({ name: ['Pet'], path: './petStore' })],
682
- * })
683
- * // file.id = SHA256 hash of the path
684
- * // file.name = 'petStore'
685
- * // file.extname = '.ts'
686
- * ```
687
- */
688
- type FileNode<TMeta extends object = object> = BaseNode & {
689
- kind: 'File';
757
+ readOnly?: boolean;
690
758
  /**
691
- * Unique identifier derived from a SHA256 hash of the file path.
692
- * @default hash
759
+ * Whether the schema is write-only.
693
760
  */
694
- id: string;
761
+ writeOnly?: boolean;
695
762
  /**
696
- * File name without extension, derived from `baseName`.
697
- * @link https://nodejs.org/api/path.html#pathformatpathobject
763
+ * Default value.
698
764
  */
699
- name: string;
765
+ default?: unknown;
700
766
  /**
701
- * File base name, including extension.
702
- * Based on UNIX basename: `${name}${extname}`
703
- * @link https://nodejs.org/api/path.html#pathbasenamepath-suffix
767
+ * Example value.
704
768
  */
705
- baseName: `${string}.${string}`;
769
+ example?: unknown;
706
770
  /**
707
- * Full qualified path to the file.
771
+ * Base primitive type.
772
+ * For example, this is `'string'` for a `uuid` schema.
708
773
  */
709
- path: string;
774
+ primitive?: PrimitiveSchemaType;
710
775
  /**
711
- * File extension extracted from `baseName`.
776
+ * Schema `format` value.
712
777
  */
713
- extname: Extname;
778
+ format?: string;
779
+ };
780
+ /**
781
+ * Object schema with ordered properties.
782
+ *
783
+ * @example
784
+ * ```ts
785
+ * const objectSchema: ObjectSchemaNode = {
786
+ * kind: 'Schema',
787
+ * type: 'object',
788
+ * properties: [],
789
+ * }
790
+ * ```
791
+ */
792
+ type ObjectSchemaNode = SchemaNodeBase & {
714
793
  /**
715
- * Deduplicated list of source code fragments.
794
+ * Schema type discriminator.
716
795
  */
717
- sources: Array<SourceNode>;
796
+ type: 'object';
718
797
  /**
719
- * Deduplicated list of import declarations.
798
+ * Primitive type always `'object'` for object schemas.
720
799
  */
721
- imports: Array<ImportNode>;
800
+ primitive: 'object';
722
801
  /**
723
- * Deduplicated list of export declarations.
802
+ * Ordered object properties.
724
803
  */
725
- exports: Array<ExportNode>;
804
+ properties: Array<PropertyNode>;
726
805
  /**
727
- * Optional metadata attached to this file (used by plugins for barrel generation etc.).
806
+ * Additional object properties behavior:
807
+ * - `true`: allow any value
808
+ * - `false`: reject unknown properties (maps to `.strict()` in Zod)
809
+ * - `SchemaNode`: allow values that match that schema
810
+ * - `undefined`: no additional properties constraint (open object)
728
811
  */
729
- meta?: TMeta;
812
+ additionalProperties?: SchemaNode | boolean;
730
813
  /**
731
- * Optional banner prepended to the generated file content.
814
+ * Pattern-based property schemas.
732
815
  */
733
- banner?: string;
816
+ patternProperties?: Record<string, SchemaNode>;
734
817
  /**
735
- * Optional footer appended to the generated file content.
818
+ * Minimum number of properties allowed.
819
+ */
820
+ minProperties?: number;
821
+ /**
822
+ * Maximum number of properties allowed.
736
823
  */
737
- footer?: string;
824
+ maxProperties?: number;
738
825
  };
739
- //#endregion
740
- //#region src/nodes/function.d.ts
741
826
  /**
742
- * AST node representing a language-agnostic type expression used as a function parameter
743
- * type annotation. Each language printer renders the variant into its own syntax.
744
- *
745
- * - `struct` — an inline anonymous type grouping named fields.
746
- * TypeScript renders as `{ petId: string; name?: string }`.
747
- * - `member` — a single named field accessed from a named group type.
748
- * TypeScript renders as `PathParams['petId']`.
749
- *
750
- * @example Reference variant
751
- * ```ts
752
- * createParamsType({ variant: 'reference', name: 'QueryParams' })
753
- * // QueryParams
754
- * ```
755
- *
756
- * @example Struct variant
757
- * ```ts
758
- * createParamsType({ variant: 'struct', properties: [{ name: 'petId', optional: false, type: createParamsType({ variant: 'reference', name: 'string' }) }] })
759
- * // { petId: string }
760
- * ```
827
+ * Array-like schema (`array` or `tuple`).
761
828
  *
762
- * @example Member variant
829
+ * @example
763
830
  * ```ts
764
- * createParamsType({ variant: 'member', base: 'PathParams', key: 'petId' })
765
- * // PathParams['petId']
831
+ * const arraySchema: ArraySchemaNode = {
832
+ * kind: 'Schema',
833
+ * type: 'array',
834
+ * items: [],
835
+ * }
766
836
  * ```
767
837
  */
768
- type ParamsTypeNode = BaseNode & {
838
+ type ArraySchemaNode = SchemaNodeBase & {
769
839
  /**
770
- * Node kind.
840
+ * Schema type discriminator (`array` or `tuple`).
771
841
  */
772
- kind: 'ParamsType';
773
- } & ({
842
+ type: 'array' | 'tuple';
774
843
  /**
775
- * Reference variant — a plain type name or identifier.
776
- * TypeScript renders as-is, e.g. `string`, `QueryParams`, `Partial<Config>`.
844
+ * Item schemas.
777
845
  */
778
- variant: 'reference';
846
+ items?: Array<SchemaNode>;
779
847
  /**
780
- * The full type name string, e.g. `'string'`, `'QueryParams'`, `'Partial<Config>'`.
848
+ * Tuple rest-item schema for elements beyond positional `items`.
781
849
  */
782
- name: string;
783
- } | {
850
+ rest?: SchemaNode;
784
851
  /**
785
- * Struct variant an inline anonymous type grouping named fields.
786
- * TypeScript renders as `{ key: Type; other?: OtherType }`.
852
+ * Minimum item count (or tuple length).
787
853
  */
788
- variant: 'struct';
854
+ min?: number;
789
855
  /**
790
- * Properties of the struct type.
856
+ * Maximum item count (or tuple length).
791
857
  */
792
- properties: Array<{
793
- name: string;
794
- optional: boolean;
795
- type: ParamsTypeNode;
796
- }>;
797
- } | {
858
+ max?: number;
798
859
  /**
799
- * Member variant a single named field accessed from a group type.
800
- * TypeScript renders as `Base['key']`.
860
+ * Whether all items must be unique.
801
861
  */
802
- variant: 'member';
862
+ unique?: boolean;
863
+ };
864
+ /**
865
+ * Shared shape for union and intersection schemas.
866
+ */
867
+ type CompositeSchemaNodeBase = SchemaNodeBase & {
803
868
  /**
804
- * Base type name, e.g. `'DeletePetPathParams'`.
869
+ * Member schemas.
805
870
  */
806
- base: string;
871
+ members?: Array<SchemaNode>;
872
+ };
873
+ /**
874
+ * Union schema, often from `oneOf` or `anyOf`.
875
+ *
876
+ * @example
877
+ * ```ts
878
+ * const unionSchema: UnionSchemaNode = {
879
+ * kind: 'Schema',
880
+ * type: 'union',
881
+ * members: [],
882
+ * }
883
+ * ```
884
+ */
885
+ type UnionSchemaNode = CompositeSchemaNodeBase & {
807
886
  /**
808
- * The field name to access, e.g. `'petId'`.
887
+ * Schema type discriminator.
809
888
  */
810
- key: string;
811
- });
889
+ type: 'union';
890
+ /**
891
+ * Discriminator property name from OpenAPI `discriminator.propertyName`.
892
+ */
893
+ discriminatorPropertyName?: string;
894
+ /**
895
+ * Logical strategy applied to union members: 'one' means exactly one member must be valid (from `oneOf`),
896
+ * 'any' means any number of members can be valid (from `anyOf`).
897
+ */
898
+ strategy?: 'one' | 'any';
899
+ };
812
900
  /**
813
- * AST node for one function parameter.
814
- *
815
- * @example Required parameter
816
- * `name: Type`
817
- *
818
- * @example Optional parameter
819
- * `name?: Type`
820
- *
821
- * @example Parameter with default value
822
- * `name: Type = defaultValue`
901
+ * Intersection schema, often from `allOf`.
823
902
  *
824
- * @example Rest parameter
825
- * `...name: Type[]`
903
+ * @example
904
+ * ```ts
905
+ * const intersectionSchema: IntersectionSchemaNode = {
906
+ * kind: 'Schema',
907
+ * type: 'intersection',
908
+ * members: [],
909
+ * }
910
+ * ```
826
911
  */
827
- type FunctionParameterNode = BaseNode & {
912
+ type IntersectionSchemaNode = CompositeSchemaNodeBase & {
828
913
  /**
829
- * Node kind.
914
+ * Schema type discriminator.
830
915
  */
831
- kind: 'FunctionParameter';
916
+ type: 'intersection';
917
+ };
918
+ /**
919
+ * One named enum item.
920
+ */
921
+ type EnumValueNode = {
832
922
  /**
833
- * Parameter name in the generated signature.
923
+ * Enum item name.
834
924
  */
835
925
  name: string;
836
926
  /**
837
- * Type annotation as a structured {@link ParamsTypeNode}.
838
- * Omit for untyped output.
839
- *
840
- * @example Reference type node
841
- * `{ kind: 'ParamsType', variant: 'reference', name: 'string' }` → `petId: string`
842
- *
843
- * @example Struct type node
844
- * `{ kind: 'ParamsType', variant: 'struct', properties: [...] }` → `{ key: Type; other?: OtherType }`
845
- *
846
- * @example Member type node
847
- * `{ kind: 'ParamsType', variant: 'member', base: 'PathParams', key: 'petId' }` → `PathParams['petId']`
927
+ * Enum item value.
848
928
  */
849
- type?: ParamsTypeNode;
929
+ value: string | number | boolean;
850
930
  /**
851
- * When `true` the parameter is emitted as a rest parameter.
852
- *
853
- * @example Rest parameter
854
- * `...name: Type[]`
931
+ * Primitive type of the enum value.
855
932
  */
856
- rest?: boolean;
857
- }
858
- /**
859
- * Optional parameter — rendered with `?` and may be omitted by the caller.
860
- * Cannot be combined with `default` because a defaulted parameter is already optional.
861
- */
862
- & ({
863
- optional: true;
864
- default?: never;
865
- }
933
+ primitive: Extract<PrimitiveSchemaType, 'string' | 'number' | 'boolean'>;
934
+ };
866
935
  /**
867
- * Required parameter, or a parameter with a default value.
936
+ * Enum schema node.
868
937
  *
869
- * @example Required
870
- * `name: Type`
871
- *
872
- * @example With default
873
- * `name: Type = default`
874
- */
875
- | {
876
- optional?: false;
877
- default?: string;
878
- });
879
- /**
880
- * AST node for a group of related function parameters treated as a single unit.
881
- *
882
- * Each language printer decides how to render this group:
883
- * - TypeScript/JS: destructured object `{ key1, key2 }: { key1: Type1; key2: Type2 } = {}`
884
- * - Python: keyword-only args or a typed dict parameter
885
- * - C# / Kotlin: named record / data-class parameter
886
- *
887
- * When `inline` is `true`, the group is spread as individual top-level parameters
888
- * rather than wrapped in a single grouped construct.
889
- *
890
- * @example Grouped destructuring
891
- * `{ id, name }: { id: string; name: string } = {}`
892
- *
893
- * @example Inline (spread as individual parameters)
894
- * `id: string, name: string`
938
+ * @example
939
+ * ```ts
940
+ * const enumSchema: EnumSchemaNode = {
941
+ * kind: 'Schema',
942
+ * type: 'enum',
943
+ * enumValues: ['a', 'b'],
944
+ * }
945
+ * ```
895
946
  */
896
- type ParameterGroupNode = BaseNode & {
947
+ type EnumSchemaNode = SchemaNodeBase & {
897
948
  /**
898
- * Node kind.
949
+ * Schema type discriminator.
899
950
  */
900
- kind: 'ParameterGroup';
951
+ type: 'enum';
901
952
  /**
902
- * The individual parameters that form the group.
903
- * Rendered as a destructured object or spread inline when `inline` is `true`.
953
+ * Enum values in simple form.
904
954
  */
905
- properties: Array<FunctionParameterNode>;
955
+ enumValues?: Array<string | number | boolean | null>;
906
956
  /**
907
- * Optional explicit type annotation for the whole group.
908
- * When absent, printers auto-compute it from `properties`.
957
+ * Enum values in named form.
958
+ * If present, this is used instead of `enumValues`.
909
959
  */
910
- type?: ParamsTypeNode;
960
+ namedEnumValues?: Array<EnumValueNode>;
961
+ };
962
+ /**
963
+ * Reference schema that points to another schema definition.
964
+ *
965
+ * @example
966
+ * ```ts
967
+ * const refSchema: RefSchemaNode = {
968
+ * kind: 'Schema',
969
+ * type: 'ref',
970
+ * ref: '#/components/schemas/Pet',
971
+ * }
972
+ * ```
973
+ */
974
+ type RefSchemaNode = SchemaNodeBase & {
911
975
  /**
912
- * When `true`, `properties` are emitted as individual top-level parameters instead of
913
- * being wrapped in a single grouped construct.
914
- *
915
- * @default false
976
+ * Schema type discriminator.
916
977
  */
917
- inline?: boolean;
978
+ type: 'ref';
918
979
  /**
919
- * Whether the group as a whole is optional.
920
- * If omitted, printers infer this from child properties.
980
+ * Referenced schema name.
981
+ * `null` means Kubb has processed this and determined there is no applicable name.
921
982
  */
922
- optional?: boolean;
983
+ name?: string | null;
923
984
  /**
924
- * Default value for the group, written verbatim after `=`.
925
- * Commonly `'{}'` to allow omitting the argument entirely.
985
+ * Original `$ref` path, for example, `#/components/schemas/Order`.
986
+ * Used to resolve names later.
926
987
  */
927
- default?: string;
928
- };
929
- /**
930
- * AST node for a complete function parameter list.
931
- *
932
- * Printers are responsible for sorting (`required` → `optional` → `defaulted`).
933
- * Nodes are plain immutable data.
934
- *
935
- * Renders differently depending on the output mode:
936
- * - `declaration` → `(id: string, config: Config = {})` — function declaration parameters
937
- * - `call` → `(id, { method, url })` — function call arguments
938
- * - `keys` → `{ id, config }` — key names only (for destructuring)
939
- * - `values` → `{ id: id, config: config }` — key → value pairs
940
- */
941
- type FunctionParametersNode = BaseNode & {
988
+ ref?: string;
942
989
  /**
943
- * Node kind.
990
+ * Pattern copied from a sibling `pattern` field.
944
991
  */
945
- kind: 'FunctionParameters';
992
+ pattern?: string;
946
993
  /**
947
- * Ordered parameter nodes.
994
+ * The fully-parsed schema that this ref resolves to.
995
+ * Populated during OAS parsing when the referenced definition can be resolved.
996
+ * `null` when the ref cannot be resolved or is part of a circular chain.
997
+ * `undefined` when resolution has not been attempted.
998
+ *
999
+ * Useful for inspecting the referenced schema's structure (e.g. `primitive`, `properties`)
1000
+ * without following the reference manually.
948
1001
  */
949
- params: ReadonlyArray<FunctionParameterNode | ParameterGroupNode>;
1002
+ schema?: SchemaNode | null;
950
1003
  };
951
1004
  /**
952
- * Union of all function-parameter AST node variants used by the function-parameter printer.
953
- */
954
- type FunctionParamNode = FunctionParameterNode | ParameterGroupNode | FunctionParametersNode | ParamsTypeNode;
955
- /**
956
- * Handler map keys — one per `FunctionParamNode` kind.
957
- */
958
- type FunctionNodeType = 'functionParameter' | 'parameterGroup' | 'functionParameters' | 'paramsType';
959
- //#endregion
960
- //#region src/nodes/property.d.ts
961
- /**
962
- * AST node representing one named object property.
1005
+ * Datetime schema.
963
1006
  *
964
1007
  * @example
965
1008
  * ```ts
966
- * const property: PropertyNode = {
967
- * kind: 'Property',
968
- * name: 'id',
969
- * schema: createSchema({ type: 'integer' }),
970
- * required: true,
971
- * }
1009
+ * const datetimeSchema: DatetimeSchemaNode = { kind: 'Schema', type: 'datetime' }
972
1010
  * ```
973
1011
  */
974
- type PropertyNode = BaseNode & {
975
- /**
976
- * Node kind.
977
- */
978
- kind: 'Property';
1012
+ type DatetimeSchemaNode = SchemaNodeBase & {
979
1013
  /**
980
- * Property key.
1014
+ * Schema type discriminator.
981
1015
  */
982
- name: string;
1016
+ type: 'datetime';
983
1017
  /**
984
- * Property schema.
1018
+ * Whether the datetime includes a timezone offset (`dateType: 'stringOffset'`).
985
1019
  */
986
- schema: SchemaNode;
1020
+ offset?: boolean;
987
1021
  /**
988
- * Whether the property is required.
1022
+ * Whether the datetime is local (no timezone, `dateType: 'stringLocal'`).
989
1023
  */
990
- required: boolean;
1024
+ local?: boolean;
991
1025
  };
992
- //#endregion
993
- //#region src/nodes/schema.d.ts
994
- type PrimitiveSchemaType =
995
1026
  /**
996
- * Text value.
997
- */
998
- 'string'
999
- /**
1000
- * Floating-point number.
1001
- */
1002
- | 'number'
1003
- /**
1004
- * Integer number.
1005
- */
1006
- | 'integer'
1007
- /**
1008
- * Big integer number.
1009
- */
1010
- | 'bigint'
1011
- /**
1012
- * Boolean value.
1013
- */
1014
- | 'boolean'
1015
- /**
1016
- * Null value.
1017
- */
1018
- | 'null'
1019
- /**
1020
- * Any value.
1021
- */
1022
- | 'any'
1023
- /**
1024
- * Unknown value.
1025
- */
1026
- | 'unknown'
1027
- /**
1028
- * No value (`void`).
1029
- */
1030
- | 'void'
1031
- /**
1032
- * Never value.
1033
- */
1034
- | 'never'
1035
- /**
1036
- * Object value.
1037
- */
1038
- | 'object'
1039
- /**
1040
- * Array value.
1041
- */
1042
- | 'array'
1043
- /**
1044
- * Date value.
1045
- */
1046
- | 'date';
1047
- /**
1048
- * Composite schema types.
1049
- */
1050
- type ComplexSchemaType = 'tuple' | 'union' | 'intersection' | 'enum';
1051
- /**
1052
- * Schema types that need special handling in generators.
1027
+ * Shared base for `date` and `time` schemas.
1053
1028
  */
1054
- type SpecialSchemaType = 'ref' | 'datetime' | 'time' | 'uuid' | 'email' | 'url' | 'ipv4' | 'ipv6' | 'blob';
1029
+ type TemporalSchemaNodeBase<T extends 'date' | 'time'> = SchemaNodeBase & {
1030
+ /**
1031
+ * Schema type discriminator.
1032
+ */
1033
+ type: T;
1034
+ /**
1035
+ * Output representation in generated code.
1036
+ */
1037
+ representation: 'date' | 'string';
1038
+ };
1055
1039
  /**
1056
- * All schema type strings.
1040
+ * Date schema node.
1041
+ *
1042
+ * @example
1043
+ * ```ts
1044
+ * const dateSchema: DateSchemaNode = { kind: 'Schema', type: 'date', representation: 'string' }
1045
+ * ```
1057
1046
  */
1058
- type SchemaType = PrimitiveSchemaType | ComplexSchemaType | SpecialSchemaType;
1047
+ type DateSchemaNode = TemporalSchemaNodeBase<'date'>;
1059
1048
  /**
1060
- * Scalar schema types without extra object/array/ref structure.
1049
+ * Time schema node.
1050
+ *
1051
+ * @example
1052
+ * ```ts
1053
+ * const timeSchema: TimeSchemaNode = { kind: 'Schema', type: 'time', representation: 'string' }
1054
+ * ```
1061
1055
  */
1062
- type ScalarSchemaType = Exclude<SchemaType, 'object' | 'array' | 'tuple' | 'union' | 'intersection' | 'enum' | 'ref' | 'datetime' | 'date' | 'time' | 'string' | 'number' | 'integer' | 'bigint' | 'url' | 'uuid' | 'email'>;
1056
+ type TimeSchemaNode = TemporalSchemaNodeBase<'time'>;
1063
1057
  /**
1064
- * Fields shared by all schema nodes.
1058
+ * String schema node.
1059
+ *
1060
+ * @example
1061
+ * ```ts
1062
+ * const stringSchema: StringSchemaNode = { kind: 'Schema', type: 'string' }
1063
+ * ```
1065
1064
  */
1066
- type SchemaNodeBase = BaseNode & {
1067
- /**
1068
- * Node kind.
1069
- */
1070
- kind: 'Schema';
1071
- /**
1072
- * Schema name for named definitions (for example, `"Pet"`).
1073
- * Inline schemas omit this field.
1074
- * `null` means kubb has processed this and determined there is no applicable name.
1075
- * `undefined` means the name has not been set yet.
1076
- */
1077
- name?: string | null;
1078
- /**
1079
- * Short schema title.
1080
- */
1081
- title?: string;
1065
+ type StringSchemaNode = SchemaNodeBase & {
1082
1066
  /**
1083
- * Schema description text.
1067
+ * Schema type discriminator.
1084
1068
  */
1085
- description?: string;
1069
+ type: 'string';
1086
1070
  /**
1087
- * Whether `null` is allowed.
1071
+ * Minimum string length.
1088
1072
  */
1089
- nullable?: boolean;
1073
+ min?: number;
1090
1074
  /**
1091
- * Whether the field is optional.
1075
+ * Maximum string length.
1092
1076
  */
1093
- optional?: boolean;
1077
+ max?: number;
1094
1078
  /**
1095
- * Both optional and nullable (`optional` + `nullable`).
1079
+ * Regex pattern.
1096
1080
  */
1097
- nullish?: boolean;
1081
+ pattern?: string;
1082
+ };
1083
+ /**
1084
+ * Numeric schema (`number`, `integer`, or `bigint`).
1085
+ *
1086
+ * @example
1087
+ * ```ts
1088
+ * const numberSchema: NumberSchemaNode = { kind: 'Schema', type: 'number' }
1089
+ * ```
1090
+ */
1091
+ type NumberSchemaNode = SchemaNodeBase & {
1098
1092
  /**
1099
- * Whether the schema is deprecated.
1093
+ * Schema type discriminator.
1100
1094
  */
1101
- deprecated?: boolean;
1095
+ type: 'number' | 'integer' | 'bigint';
1102
1096
  /**
1103
- * Whether the schema is read-only.
1097
+ * Minimum value.
1104
1098
  */
1105
- readOnly?: boolean;
1099
+ min?: number;
1106
1100
  /**
1107
- * Whether the schema is write-only.
1101
+ * Maximum value.
1108
1102
  */
1109
- writeOnly?: boolean;
1103
+ max?: number;
1110
1104
  /**
1111
- * Default value.
1105
+ * Exclusive minimum value.
1112
1106
  */
1113
- default?: unknown;
1107
+ exclusiveMinimum?: number;
1114
1108
  /**
1115
- * Example value.
1109
+ * Exclusive maximum value.
1116
1110
  */
1117
- example?: unknown;
1111
+ exclusiveMaximum?: number;
1118
1112
  /**
1119
- * Base primitive type.
1120
- * For example, this is `'string'` for a `uuid` schema.
1113
+ * The value must be a multiple of this number.
1121
1114
  */
1122
- primitive?: PrimitiveSchemaType;
1115
+ multipleOf?: number;
1123
1116
  };
1124
1117
  /**
1125
- * Object schema with ordered properties.
1118
+ * Scalar schema with no extra constraints.
1126
1119
  *
1127
1120
  * @example
1128
1121
  * ```ts
1129
- * const objectSchema: ObjectSchemaNode = {
1130
- * kind: 'Schema',
1131
- * type: 'object',
1132
- * properties: [],
1133
- * }
1122
+ * const anySchema: ScalarSchemaNode = { kind: 'Schema', type: 'any' }
1134
1123
  * ```
1135
1124
  */
1136
- type ObjectSchemaNode = SchemaNodeBase & {
1125
+ type ScalarSchemaNode = SchemaNodeBase & {
1137
1126
  /**
1138
1127
  * Schema type discriminator.
1139
1128
  */
1140
- type: 'object';
1141
- /**
1142
- * Primitive type — always `'object'` for object schemas.
1143
- */
1144
- primitive: 'object';
1145
- /**
1146
- * Ordered object properties.
1147
- */
1148
- properties: Array<PropertyNode>;
1129
+ type: ScalarSchemaType;
1130
+ };
1131
+ /**
1132
+ * URL schema node.
1133
+ * Can include an OpenAPI-style path template for template literal types.
1134
+ *
1135
+ * @example
1136
+ * ```ts
1137
+ * const urlSchema: UrlSchemaNode = { kind: 'Schema', type: 'url', path: '/pets/{petId}' }
1138
+ * ```
1139
+ */
1140
+ type UrlSchemaNode = SchemaNodeBase & {
1149
1141
  /**
1150
- * Additional object properties behavior:
1151
- * - `true`: allow any value
1152
- * - `false`: reject unknown properties (maps to `.strict()` in Zod)
1153
- * - `SchemaNode`: allow values that match that schema
1154
- * - `undefined`: no additional properties constraint (open object)
1142
+ * Schema type discriminator.
1155
1143
  */
1156
- additionalProperties?: SchemaNode | boolean;
1144
+ type: 'url';
1157
1145
  /**
1158
- * Pattern-based property schemas.
1146
+ * OpenAPI-style path template, for example, `'/pets/{petId}'`.
1159
1147
  */
1160
- patternProperties?: Record<string, SchemaNode>;
1148
+ path?: string;
1161
1149
  /**
1162
- * Minimum number of properties allowed.
1150
+ * Minimum string length.
1163
1151
  */
1164
- minProperties?: number;
1152
+ min?: number;
1165
1153
  /**
1166
- * Maximum number of properties allowed.
1154
+ * Maximum string length.
1167
1155
  */
1168
- maxProperties?: number;
1156
+ max?: number;
1169
1157
  };
1170
1158
  /**
1171
- * Array-like schema (`array` or `tuple`).
1159
+ * Format-string schema for string-based formats that support length constraints.
1172
1160
  *
1173
1161
  * @example
1174
1162
  * ```ts
1175
- * const arraySchema: ArraySchemaNode = {
1176
- * kind: 'Schema',
1177
- * type: 'array',
1178
- * items: [],
1179
- * }
1163
+ * const uuidSchema: FormatStringSchemaNode = { kind: 'Schema', type: 'uuid', min: 36, max: 36 }
1180
1164
  * ```
1181
1165
  */
1182
- type ArraySchemaNode = SchemaNodeBase & {
1183
- /**
1184
- * Schema type discriminator (`array` or `tuple`).
1185
- */
1186
- type: 'array' | 'tuple';
1187
- /**
1188
- * Item schemas.
1189
- */
1190
- items?: Array<SchemaNode>;
1166
+ type FormatStringSchemaNode = SchemaNodeBase & {
1191
1167
  /**
1192
- * Tuple rest-item schema for elements beyond positional `items`.
1168
+ * Schema type discriminator.
1193
1169
  */
1194
- rest?: SchemaNode;
1170
+ type: 'uuid' | 'email';
1195
1171
  /**
1196
- * Minimum item count (or tuple length).
1172
+ * Minimum string length.
1197
1173
  */
1198
1174
  min?: number;
1199
1175
  /**
1200
- * Maximum item count (or tuple length).
1176
+ * Maximum string length.
1201
1177
  */
1202
1178
  max?: number;
1179
+ };
1180
+ /**
1181
+ * IPv4 address schema node.
1182
+ *
1183
+ * @example
1184
+ * ```ts
1185
+ * const ipv4Schema: Ipv4SchemaNode = { kind: 'Schema', type: 'ipv4' }
1186
+ * ```
1187
+ */
1188
+ type Ipv4SchemaNode = SchemaNodeBase & {
1203
1189
  /**
1204
- * Whether all items must be unique.
1190
+ * Schema type discriminator.
1205
1191
  */
1206
- unique?: boolean;
1192
+ type: 'ipv4';
1193
+ };
1194
+ /**
1195
+ * IPv6 address schema node.
1196
+ *
1197
+ * @example
1198
+ * ```ts
1199
+ * const ipv6Schema: Ipv6SchemaNode = { kind: 'Schema', type: 'ipv6' }
1200
+ * ```
1201
+ */
1202
+ type Ipv6SchemaNode = SchemaNodeBase & {
1203
+ /**
1204
+ * Schema type discriminator.
1205
+ */
1206
+ type: 'ipv6';
1207
+ };
1208
+ /**
1209
+ * Mapping from schema type literals to concrete schema node types.
1210
+ * Used by `narrowSchema`.
1211
+ */
1212
+ type SchemaNodeByType = {
1213
+ object: ObjectSchemaNode;
1214
+ array: ArraySchemaNode;
1215
+ tuple: ArraySchemaNode;
1216
+ union: UnionSchemaNode;
1217
+ intersection: IntersectionSchemaNode;
1218
+ enum: EnumSchemaNode;
1219
+ ref: RefSchemaNode;
1220
+ datetime: DatetimeSchemaNode;
1221
+ date: DateSchemaNode;
1222
+ time: TimeSchemaNode;
1223
+ string: StringSchemaNode;
1224
+ number: NumberSchemaNode;
1225
+ integer: NumberSchemaNode;
1226
+ bigint: NumberSchemaNode;
1227
+ boolean: ScalarSchemaNode;
1228
+ null: ScalarSchemaNode;
1229
+ any: ScalarSchemaNode;
1230
+ unknown: ScalarSchemaNode;
1231
+ void: ScalarSchemaNode;
1232
+ never: ScalarSchemaNode;
1233
+ uuid: FormatStringSchemaNode;
1234
+ email: FormatStringSchemaNode;
1235
+ url: UrlSchemaNode;
1236
+ ipv4: Ipv4SchemaNode;
1237
+ ipv6: Ipv6SchemaNode;
1238
+ blob: ScalarSchemaNode;
1207
1239
  };
1208
1240
  /**
1209
- * Shared shape for union and intersection schemas.
1241
+ * Union of all schema node types.
1210
1242
  */
1211
- type CompositeSchemaNodeBase = SchemaNodeBase & {
1212
- /**
1213
- * Member schemas.
1214
- */
1215
- members?: Array<SchemaNode>;
1216
- };
1243
+ type SchemaNode = ObjectSchemaNode | ArraySchemaNode | UnionSchemaNode | IntersectionSchemaNode | EnumSchemaNode | RefSchemaNode | DatetimeSchemaNode | DateSchemaNode | TimeSchemaNode | StringSchemaNode | NumberSchemaNode | UrlSchemaNode | FormatStringSchemaNode | Ipv4SchemaNode | Ipv6SchemaNode | ScalarSchemaNode;
1244
+ //#endregion
1245
+ //#region src/nodes/content.d.ts
1217
1246
  /**
1218
- * Union schema, often from `oneOf` or `anyOf`.
1247
+ * AST node representing one content-type entry of a request body or response.
1248
+ *
1249
+ * One entry per content type declared in the spec (e.g. `application/json`,
1250
+ * `multipart/form-data`), each carrying its own body schema.
1219
1251
  *
1220
1252
  * @example
1221
1253
  * ```ts
1222
- * const unionSchema: UnionSchemaNode = {
1223
- * kind: 'Schema',
1224
- * type: 'union',
1225
- * members: [],
1254
+ * const content: ContentNode = {
1255
+ * kind: 'Content',
1256
+ * contentType: 'application/json',
1257
+ * schema: createSchema({ type: 'string' }),
1226
1258
  * }
1227
1259
  * ```
1228
1260
  */
1229
- type UnionSchemaNode = CompositeSchemaNodeBase & {
1261
+ type ContentNode = BaseNode & {
1230
1262
  /**
1231
- * Schema type discriminator.
1263
+ * Node kind.
1232
1264
  */
1233
- type: 'union';
1265
+ kind: 'Content';
1234
1266
  /**
1235
- * Discriminator property name from OpenAPI `discriminator.propertyName`.
1267
+ * The content type for this entry (e.g. `'application/json'`).
1236
1268
  */
1237
- discriminatorPropertyName?: string;
1269
+ contentType: string;
1238
1270
  /**
1239
- * Logical strategy applied to union members: 'one' means exactly one member must be valid (from `oneOf`),
1240
- * 'any' means any number of members can be valid (from `anyOf`).
1271
+ * Body schema for this content type.
1241
1272
  */
1242
- strategy?: 'one' | 'any';
1273
+ schema?: SchemaNode;
1274
+ /**
1275
+ * Property keys to exclude from the generated type via `Omit<Type, Keys>`.
1276
+ * Set when a referenced schema has `readOnly`/`writeOnly` fields that should be omitted.
1277
+ */
1278
+ keysToOmit?: Array<string> | null;
1243
1279
  };
1280
+ //#endregion
1281
+ //#region src/nodes/file.d.ts
1244
1282
  /**
1245
- * Intersection schema, often from `allOf`.
1283
+ * Supported file extensions.
1284
+ */
1285
+ type Extname = '.ts' | '.js' | '.tsx' | '.json' | `.${string}`;
1286
+ type ImportName = string | Array<string | {
1287
+ propertyName: string;
1288
+ name?: string;
1289
+ }>;
1290
+ /**
1291
+ * Represents a language-agnostic import/dependency declaration.
1246
1292
  *
1247
- * @example
1293
+ * @example Named import (TypeScript: `import { useState } from 'react'`)
1248
1294
  * ```ts
1249
- * const intersectionSchema: IntersectionSchemaNode = {
1250
- * kind: 'Schema',
1251
- * type: 'intersection',
1252
- * members: [],
1253
- * }
1295
+ * createImport({ name: ['useState'], path: 'react' })
1296
+ * ```
1297
+ *
1298
+ * @example Default import (TypeScript: `import React from 'react'`)
1299
+ * ```ts
1300
+ * createImport({ name: 'React', path: 'react' })
1301
+ * ```
1302
+ *
1303
+ * @example Type-only import (TypeScript: `import type { FC } from 'react'`)
1304
+ * ```ts
1305
+ * createImport({ name: ['FC'], path: 'react', isTypeOnly: true })
1306
+ * ```
1307
+ *
1308
+ * @example Namespace import (TypeScript: `import * as React from 'react'`)
1309
+ * ```ts
1310
+ * createImport({ name: 'React', path: 'react', isNameSpace: true })
1254
1311
  * ```
1255
1312
  */
1256
- type IntersectionSchemaNode = CompositeSchemaNodeBase & {
1313
+ type ImportNode = BaseNode & {
1314
+ kind: 'Import';
1257
1315
  /**
1258
- * Schema type discriminator.
1316
+ * Import name(s) to be used.
1317
+ * @example ['useState']
1318
+ * @example 'React'
1259
1319
  */
1260
- type: 'intersection';
1261
- };
1262
- /**
1263
- * One named enum item.
1264
- */
1265
- type EnumValueNode = {
1320
+ name: ImportName;
1266
1321
  /**
1267
- * Enum item name.
1322
+ * Path for the import.
1323
+ * @example '@kubb/core'
1268
1324
  */
1269
- name: string;
1325
+ path: string;
1270
1326
  /**
1271
- * Enum item value.
1327
+ * Add type-only import prefix.
1328
+ * - `true` generates `import type { Type } from './path'`
1329
+ * - `false` generates `import { Type } from './path'`
1330
+ * @default false
1272
1331
  */
1273
- value: string | number | boolean;
1332
+ isTypeOnly?: boolean | null;
1274
1333
  /**
1275
- * Primitive type of the enum value.
1334
+ * Import entire module as namespace.
1335
+ * - `true` generates `import * as Name from './path'`
1336
+ * - `false` generates standard import
1337
+ * @default false
1276
1338
  */
1277
- primitive: Extract<PrimitiveSchemaType, 'string' | 'number' | 'boolean'>;
1339
+ isNameSpace?: boolean | null;
1340
+ /**
1341
+ * When set, the import path is resolved relative to this root.
1342
+ */
1343
+ root?: string | null;
1278
1344
  };
1279
1345
  /**
1280
- * Enum schema node.
1346
+ * Represents a language-agnostic export/public API declaration.
1281
1347
  *
1282
- * @example
1348
+ * @example Named export (TypeScript: `export { Pets } from './Pets'`)
1283
1349
  * ```ts
1284
- * const enumSchema: EnumSchemaNode = {
1285
- * kind: 'Schema',
1286
- * type: 'enum',
1287
- * enumValues: ['a', 'b'],
1288
- * }
1350
+ * createExport({ name: ['Pets'], path: './Pets' })
1351
+ * ```
1352
+ *
1353
+ * @example Type-only export (TypeScript: `export type { Pet } from './Pet'`)
1354
+ * ```ts
1355
+ * createExport({ name: ['Pet'], path: './Pet', isTypeOnly: true })
1356
+ * ```
1357
+ *
1358
+ * @example Wildcard export (TypeScript: `export * from './utils'`)
1359
+ * ```ts
1360
+ * createExport({ path: './utils' })
1361
+ * ```
1362
+ *
1363
+ * @example Namespace alias (TypeScript: `export * as utils from './utils'`)
1364
+ * ```ts
1365
+ * createExport({ name: 'utils', path: './utils', asAlias: true })
1289
1366
  * ```
1290
1367
  */
1291
- type EnumSchemaNode = SchemaNodeBase & {
1368
+ type ExportNode = BaseNode & {
1369
+ kind: 'Export';
1292
1370
  /**
1293
- * Schema type discriminator.
1371
+ * Export name(s) to be used. When omitted, generates a wildcard export.
1372
+ * @example ['useState']
1373
+ * @example 'React'
1294
1374
  */
1295
- type: 'enum';
1375
+ name?: string | Array<string> | null;
1296
1376
  /**
1297
- * Enum values in simple form.
1377
+ * Path for the export.
1378
+ * @example '@kubb/core'
1298
1379
  */
1299
- enumValues?: Array<string | number | boolean | null>;
1380
+ path: string;
1300
1381
  /**
1301
- * Enum values in named form.
1302
- * If present, this is used instead of `enumValues`.
1382
+ * Add type-only export prefix.
1383
+ * - `true` generates `export type { Type } from './path'`
1384
+ * - `false` generates `export { Type } from './path'`
1385
+ * @default false
1303
1386
  */
1304
- namedEnumValues?: Array<EnumValueNode>;
1387
+ isTypeOnly?: boolean | null;
1388
+ /**
1389
+ * Export as an aliased namespace.
1390
+ * - `true` generates `export * as aliasName from './path'`
1391
+ * - `false` generates a standard export
1392
+ * @default false
1393
+ */
1394
+ asAlias?: boolean | null;
1305
1395
  };
1306
1396
  /**
1307
- * Reference schema that points to another schema definition.
1397
+ * Represents a fragment of source code within a file.
1308
1398
  *
1309
- * @example
1399
+ * @example Named exportable source
1310
1400
  * ```ts
1311
- * const refSchema: RefSchemaNode = {
1312
- * kind: 'Schema',
1313
- * type: 'ref',
1314
- * ref: '#/components/schemas/Pet',
1315
- * }
1401
+ * createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')], isExportable: true, isIndexable: true })
1402
+ * ```
1403
+ *
1404
+ * @example Inline unnamed code block
1405
+ * ```ts
1406
+ * createSource({ nodes: [createText('const x = 1')] })
1316
1407
  * ```
1317
1408
  */
1318
- type RefSchemaNode = SchemaNodeBase & {
1409
+ type SourceNode = BaseNode & {
1410
+ kind: 'Source';
1319
1411
  /**
1320
- * Schema type discriminator.
1412
+ * Optional name identifying this source (used for deduplication and barrel generation).
1321
1413
  */
1322
- type: 'ref';
1414
+ name?: string | null;
1323
1415
  /**
1324
- * Referenced schema name.
1416
+ * Mark this source as a type-only export.
1417
+ * @default false
1325
1418
  */
1326
- name?: string;
1419
+ isTypeOnly?: boolean | null;
1327
1420
  /**
1328
- * Original `$ref` path, for example, `#/components/schemas/Order`.
1329
- * Used to resolve names later.
1421
+ * Include `export` keyword in the generated source.
1422
+ * @default false
1330
1423
  */
1331
- ref?: string;
1424
+ isExportable?: boolean | null;
1332
1425
  /**
1333
- * Pattern copied from a sibling `pattern` field.
1426
+ * Include this source in barrel/index file generation.
1427
+ * @default false
1334
1428
  */
1335
- pattern?: string;
1429
+ isIndexable?: boolean | null;
1336
1430
  /**
1337
- * The fully-parsed schema that this ref resolves to.
1338
- * Populated during OAS parsing when the referenced definition can be resolved.
1339
- * `undefined` when the ref cannot be resolved or is part of a circular chain.
1340
- *
1341
- * Useful for inspecting the referenced schema's structure (e.g. `primitive`, `properties`)
1342
- * without following the reference manually.
1431
+ * Structured child nodes representing the content of this source fragment, in DOM order.
1432
+ * Each entry is a {@link CodeNode}; use {@link TextNode} for raw string content.
1343
1433
  */
1344
- schema?: SchemaNode;
1434
+ nodes?: Array<CodeNode>;
1345
1435
  };
1346
1436
  /**
1347
- * Datetime schema.
1437
+ * Represents a fully resolved file in the AST.
1438
+ *
1439
+ * Created via `createFile()`, which computes the `id`, `name`, and `extname` from the input
1440
+ * and deduplicates `imports`, `exports`, and `sources`.
1348
1441
  *
1349
1442
  * @example
1350
1443
  * ```ts
1351
- * const datetimeSchema: DatetimeSchemaNode = { kind: 'Schema', type: 'datetime' }
1444
+ * const file = createFile({
1445
+ * baseName: 'petStore.ts',
1446
+ * path: 'src/models/petStore.ts',
1447
+ * sources: [createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')], isExportable: true })],
1448
+ * imports: [createImport({ name: ['z'], path: 'zod' })],
1449
+ * exports: [createExport({ name: ['Pet'], path: './petStore' })],
1450
+ * })
1451
+ * // file.id = SHA256 hash of the path
1452
+ * // file.name = 'petStore'
1453
+ * // file.extname = '.ts'
1352
1454
  * ```
1353
1455
  */
1354
- type DatetimeSchemaNode = SchemaNodeBase & {
1456
+ type FileNode<TMeta extends object = object> = BaseNode & {
1457
+ kind: 'File';
1355
1458
  /**
1356
- * Schema type discriminator.
1459
+ * Unique identifier derived from a SHA256 hash of the file path. Computed
1460
+ * by `createFile`; callers do not need to provide it.
1357
1461
  */
1358
- type: 'datetime';
1462
+ id: string;
1359
1463
  /**
1360
- * Whether the datetime includes a timezone offset (`dateType: 'stringOffset'`).
1464
+ * File name without extension, derived from `baseName`.
1465
+ * @link https://nodejs.org/api/path.html#pathformatpathobject
1361
1466
  */
1362
- offset?: boolean;
1467
+ name: string;
1468
+ /**
1469
+ * File base name, including extension.
1470
+ * Based on UNIX basename: `${name}${extname}`
1471
+ * @link https://nodejs.org/api/path.html#pathbasenamepath-suffix
1472
+ */
1473
+ baseName: `${string}.${string}`;
1474
+ /**
1475
+ * Full qualified path to the file.
1476
+ */
1477
+ path: string;
1478
+ /**
1479
+ * File extension extracted from `baseName`.
1480
+ */
1481
+ extname: Extname;
1482
+ /**
1483
+ * Deduplicated list of source code fragments.
1484
+ */
1485
+ sources: Array<SourceNode>;
1486
+ /**
1487
+ * Deduplicated list of import declarations.
1488
+ */
1489
+ imports: Array<ImportNode>;
1490
+ /**
1491
+ * Deduplicated list of export declarations.
1492
+ */
1493
+ exports: Array<ExportNode>;
1363
1494
  /**
1364
- * Whether the datetime is local (no timezone, `dateType: 'stringLocal'`).
1495
+ * Optional metadata attached to this file (used by plugins for barrel generation etc.).
1365
1496
  */
1366
- local?: boolean;
1367
- };
1368
- /**
1369
- * Shared base for `date` and `time` schemas.
1370
- */
1371
- type TemporalSchemaNodeBase<T extends 'date' | 'time'> = SchemaNodeBase & {
1497
+ meta?: TMeta;
1372
1498
  /**
1373
- * Schema type discriminator.
1499
+ * Optional banner prepended to the generated file content.
1500
+ * Accepts `null` so `resolver.resolveBanner()` results can be passed directly.
1374
1501
  */
1375
- type: T;
1502
+ banner?: string | null;
1376
1503
  /**
1377
- * Output representation in generated code.
1504
+ * Optional footer appended to the generated file content.
1505
+ * Accepts `null` so `resolver.resolveFooter()` results can be passed directly.
1378
1506
  */
1379
- representation: 'date' | 'string';
1507
+ footer?: string | null;
1380
1508
  };
1509
+ //#endregion
1510
+ //#region src/nodes/function.d.ts
1381
1511
  /**
1382
- * Date schema node.
1512
+ * AST node representing a language-agnostic type expression used as a function parameter
1513
+ * type annotation. Each language printer renders the variant into its own syntax.
1383
1514
  *
1384
- * @example
1515
+ * - `struct` — an inline anonymous type grouping named fields.
1516
+ * TypeScript renders as `{ petId: string; name?: string }`.
1517
+ * - `member` — a single named field accessed from a named group type.
1518
+ * TypeScript renders as `PathParams['petId']`.
1519
+ *
1520
+ * @example Reference variant
1385
1521
  * ```ts
1386
- * const dateSchema: DateSchemaNode = { kind: 'Schema', type: 'date', representation: 'string' }
1522
+ * createParamsType({ variant: 'reference', name: 'QueryParams' })
1523
+ * // QueryParams
1387
1524
  * ```
1388
- */
1389
- type DateSchemaNode = TemporalSchemaNodeBase<'date'>;
1390
- /**
1391
- * Time schema node.
1392
1525
  *
1393
- * @example
1526
+ * @example Struct variant
1394
1527
  * ```ts
1395
- * const timeSchema: TimeSchemaNode = { kind: 'Schema', type: 'time', representation: 'string' }
1528
+ * createParamsType({ variant: 'struct', properties: [{ name: 'petId', optional: false, type: createParamsType({ variant: 'reference', name: 'string' }) }] })
1529
+ * // { petId: string }
1396
1530
  * ```
1397
- */
1398
- type TimeSchemaNode = TemporalSchemaNodeBase<'time'>;
1399
- /**
1400
- * String schema node.
1401
1531
  *
1402
- * @example
1532
+ * @example Member variant
1403
1533
  * ```ts
1404
- * const stringSchema: StringSchemaNode = { kind: 'Schema', type: 'string' }
1534
+ * createParamsType({ variant: 'member', base: 'PathParams', key: 'petId' })
1535
+ * // PathParams['petId']
1405
1536
  * ```
1406
1537
  */
1407
- type StringSchemaNode = SchemaNodeBase & {
1408
- /**
1409
- * Schema type discriminator.
1410
- */
1411
- type: 'string';
1412
- /**
1413
- * Minimum string length.
1414
- */
1415
- min?: number;
1538
+ type ParamsTypeNode = BaseNode & {
1416
1539
  /**
1417
- * Maximum string length.
1540
+ * Node kind.
1418
1541
  */
1419
- max?: number;
1542
+ kind: 'ParamsType';
1543
+ } & ({
1420
1544
  /**
1421
- * Regex pattern.
1545
+ * Reference variant — a plain type name or identifier.
1546
+ * TypeScript renders as-is, e.g. `string`, `QueryParams`, `Partial<Config>`.
1422
1547
  */
1423
- pattern?: string;
1424
- };
1425
- /**
1426
- * Numeric schema (`number`, `integer`, or `bigint`).
1427
- *
1428
- * @example
1429
- * ```ts
1430
- * const numberSchema: NumberSchemaNode = { kind: 'Schema', type: 'number' }
1431
- * ```
1432
- */
1433
- type NumberSchemaNode = SchemaNodeBase & {
1548
+ variant: 'reference';
1434
1549
  /**
1435
- * Schema type discriminator.
1550
+ * The full type name string, e.g. `'string'`, `'QueryParams'`, `'Partial<Config>'`.
1436
1551
  */
1437
- type: 'number' | 'integer' | 'bigint';
1552
+ name: string;
1553
+ } | {
1438
1554
  /**
1439
- * Minimum value.
1555
+ * Struct variant — an inline anonymous type grouping named fields.
1556
+ * TypeScript renders as `{ key: Type; other?: OtherType }`.
1440
1557
  */
1441
- min?: number;
1558
+ variant: 'struct';
1442
1559
  /**
1443
- * Maximum value.
1560
+ * Properties of the struct type.
1444
1561
  */
1445
- max?: number;
1562
+ properties: Array<{
1563
+ name: string;
1564
+ optional: boolean;
1565
+ type: ParamsTypeNode;
1566
+ }>;
1567
+ } | {
1446
1568
  /**
1447
- * Exclusive minimum value.
1569
+ * Member variant — a single named field accessed from a group type.
1570
+ * TypeScript renders as `Base['key']`.
1448
1571
  */
1449
- exclusiveMinimum?: number;
1572
+ variant: 'member';
1450
1573
  /**
1451
- * Exclusive maximum value.
1574
+ * Base type name, e.g. `'DeletePetPathParams'`.
1452
1575
  */
1453
- exclusiveMaximum?: number;
1576
+ base: string;
1454
1577
  /**
1455
- * The value must be a multiple of this number.
1578
+ * The field name to access, e.g. `'petId'`.
1456
1579
  */
1457
- multipleOf?: number;
1458
- };
1580
+ key: string;
1581
+ });
1459
1582
  /**
1460
- * Scalar schema with no extra constraints.
1583
+ * AST node for one function parameter.
1461
1584
  *
1462
- * @example
1463
- * ```ts
1464
- * const anySchema: ScalarSchemaNode = { kind: 'Schema', type: 'any' }
1465
- * ```
1466
- */
1467
- type ScalarSchemaNode = SchemaNodeBase & {
1468
- /**
1469
- * Schema type discriminator.
1470
- */
1471
- type: ScalarSchemaType;
1472
- };
1473
- /**
1474
- * URL schema node.
1475
- * Can include an OpenAPI-style path template for template literal types.
1585
+ * @example Required parameter
1586
+ * `name: Type`
1476
1587
  *
1477
- * @example
1478
- * ```ts
1479
- * const urlSchema: UrlSchemaNode = { kind: 'Schema', type: 'url', path: '/pets/{petId}' }
1480
- * ```
1588
+ * @example Optional parameter
1589
+ * `name?: Type`
1590
+ *
1591
+ * @example Parameter with default value
1592
+ * `name: Type = defaultValue`
1593
+ *
1594
+ * @example Rest parameter
1595
+ * `...name: Type[]`
1481
1596
  */
1482
- type UrlSchemaNode = SchemaNodeBase & {
1597
+ type FunctionParameterNode = BaseNode & {
1483
1598
  /**
1484
- * Schema type discriminator.
1599
+ * Node kind.
1485
1600
  */
1486
- type: 'url';
1601
+ kind: 'FunctionParameter';
1487
1602
  /**
1488
- * OpenAPI-style path template, for example, `'/pets/{petId}'`.
1603
+ * Parameter name in the generated signature.
1489
1604
  */
1490
- path?: string;
1605
+ name: string;
1491
1606
  /**
1492
- * Minimum string length.
1607
+ * Type annotation as a structured {@link ParamsTypeNode}.
1608
+ * Omit for untyped output.
1609
+ *
1610
+ * @example Reference type node
1611
+ * `{ kind: 'ParamsType', variant: 'reference', name: 'string' }` → `petId: string`
1612
+ *
1613
+ * @example Struct type node
1614
+ * `{ kind: 'ParamsType', variant: 'struct', properties: [...] }` → `{ key: Type; other?: OtherType }`
1615
+ *
1616
+ * @example Member type node
1617
+ * `{ kind: 'ParamsType', variant: 'member', base: 'PathParams', key: 'petId' }` → `PathParams['petId']`
1493
1618
  */
1494
- min?: number;
1619
+ type?: ParamsTypeNode;
1495
1620
  /**
1496
- * Maximum string length.
1621
+ * When `true` the parameter is emitted as a rest parameter.
1622
+ *
1623
+ * @example Rest parameter
1624
+ * `...name: Type[]`
1497
1625
  */
1498
- max?: number;
1499
- };
1626
+ rest?: boolean;
1627
+ }
1500
1628
  /**
1501
- * Format-string schema for string-based formats that support length constraints.
1629
+ * Optional parameter rendered with `?` and may be omitted by the caller.
1630
+ * Cannot be combined with `default` because a defaulted parameter is already optional.
1631
+ */
1632
+ & ({
1633
+ optional: true;
1634
+ default?: never;
1635
+ }
1636
+ /**
1637
+ * Required parameter, or a parameter with a default value.
1502
1638
  *
1503
- * @example
1504
- * ```ts
1505
- * const uuidSchema: FormatStringSchemaNode = { kind: 'Schema', type: 'uuid', min: 36, max: 36 }
1506
- * ```
1639
+ * @example Required
1640
+ * `name: Type`
1641
+ *
1642
+ * @example With default
1643
+ * `name: Type = default`
1507
1644
  */
1508
- type FormatStringSchemaNode = SchemaNodeBase & {
1645
+ | {
1646
+ optional?: false;
1647
+ default?: string;
1648
+ });
1649
+ /**
1650
+ * AST node for a group of related function parameters treated as a single unit.
1651
+ *
1652
+ * Each language printer decides how to render this group:
1653
+ * - TypeScript/JS: destructured object `{ key1, key2 }: { key1: Type1; key2: Type2 } = {}`
1654
+ * - Python: keyword-only args or a typed dict parameter
1655
+ * - C# / Kotlin: named record / data-class parameter
1656
+ *
1657
+ * When `inline` is `true`, the group is spread as individual top-level parameters
1658
+ * rather than wrapped in a single grouped construct.
1659
+ *
1660
+ * @example Grouped destructuring
1661
+ * `{ id, name }: { id: string; name: string } = {}`
1662
+ *
1663
+ * @example Inline (spread as individual parameters)
1664
+ * `id: string, name: string`
1665
+ */
1666
+ type ParameterGroupNode = BaseNode & {
1509
1667
  /**
1510
- * Schema type discriminator.
1668
+ * Node kind.
1511
1669
  */
1512
- type: 'uuid' | 'email';
1670
+ kind: 'ParameterGroup';
1513
1671
  /**
1514
- * Minimum string length.
1672
+ * The individual parameters that form the group.
1673
+ * Rendered as a destructured object or spread inline when `inline` is `true`.
1515
1674
  */
1516
- min?: number;
1675
+ properties: Array<FunctionParameterNode>;
1517
1676
  /**
1518
- * Maximum string length.
1677
+ * Optional explicit type annotation for the whole group.
1678
+ * When absent, printers auto-compute it from `properties`.
1519
1679
  */
1520
- max?: number;
1521
- };
1522
- /**
1523
- * IPv4 address schema node.
1524
- *
1525
- * @example
1526
- * ```ts
1527
- * const ipv4Schema: Ipv4SchemaNode = { kind: 'Schema', type: 'ipv4' }
1528
- * ```
1529
- */
1530
- type Ipv4SchemaNode = SchemaNodeBase & {
1680
+ type?: ParamsTypeNode;
1531
1681
  /**
1532
- * Schema type discriminator.
1682
+ * When `true`, `properties` are emitted as individual top-level parameters instead of
1683
+ * being wrapped in a single grouped construct.
1684
+ *
1685
+ * @default false
1686
+ */
1687
+ inline?: boolean;
1688
+ /**
1689
+ * Whether the group as a whole is optional.
1690
+ * If omitted, printers infer this from child properties.
1691
+ */
1692
+ optional?: boolean;
1693
+ /**
1694
+ * Default value for the group, written verbatim after `=`.
1695
+ * Commonly `'{}'` to allow omitting the argument entirely.
1533
1696
  */
1534
- type: 'ipv4';
1697
+ default?: string;
1535
1698
  };
1536
1699
  /**
1537
- * IPv6 address schema node.
1700
+ * AST node for a complete function parameter list.
1538
1701
  *
1539
- * @example
1540
- * ```ts
1541
- * const ipv6Schema: Ipv6SchemaNode = { kind: 'Schema', type: 'ipv6' }
1542
- * ```
1702
+ * Printers are responsible for sorting (`required` → `optional` → `defaulted`).
1703
+ * Nodes are plain immutable data.
1704
+ *
1705
+ * Renders differently depending on the output mode:
1706
+ * - `declaration` → `(id: string, config: Config = {})` — function declaration parameters
1707
+ * - `call` → `(id, { method, url })` — function call arguments
1708
+ * - `keys` → `{ id, config }` — key names only (for destructuring)
1709
+ * - `values` → `{ id: id, config: config }` — key → value pairs
1543
1710
  */
1544
- type Ipv6SchemaNode = SchemaNodeBase & {
1711
+ type FunctionParametersNode = BaseNode & {
1545
1712
  /**
1546
- * Schema type discriminator.
1713
+ * Node kind.
1547
1714
  */
1548
- type: 'ipv6';
1715
+ kind: 'FunctionParameters';
1716
+ /**
1717
+ * Ordered parameter nodes.
1718
+ */
1719
+ params: ReadonlyArray<FunctionParameterNode | ParameterGroupNode>;
1549
1720
  };
1550
1721
  /**
1551
- * Mapping from schema type literals to concrete schema node types.
1552
- * Used by `narrowSchema`.
1722
+ * Union of all function-parameter AST node variants used by the function-parameter printer.
1553
1723
  */
1554
- type SchemaNodeByType = {
1555
- object: ObjectSchemaNode;
1556
- array: ArraySchemaNode;
1557
- tuple: ArraySchemaNode;
1558
- union: UnionSchemaNode;
1559
- intersection: IntersectionSchemaNode;
1560
- enum: EnumSchemaNode;
1561
- ref: RefSchemaNode;
1562
- datetime: DatetimeSchemaNode;
1563
- date: DateSchemaNode;
1564
- time: TimeSchemaNode;
1565
- string: StringSchemaNode;
1566
- number: NumberSchemaNode;
1567
- integer: NumberSchemaNode;
1568
- bigint: NumberSchemaNode;
1569
- boolean: ScalarSchemaNode;
1570
- null: ScalarSchemaNode;
1571
- any: ScalarSchemaNode;
1572
- unknown: ScalarSchemaNode;
1573
- void: ScalarSchemaNode;
1574
- never: ScalarSchemaNode;
1575
- uuid: FormatStringSchemaNode;
1576
- email: FormatStringSchemaNode;
1577
- url: UrlSchemaNode;
1578
- ipv4: Ipv4SchemaNode;
1579
- ipv6: Ipv6SchemaNode;
1580
- blob: ScalarSchemaNode;
1581
- };
1724
+ type FunctionParamNode = FunctionParameterNode | ParameterGroupNode | FunctionParametersNode | ParamsTypeNode;
1582
1725
  /**
1583
- * Union of all schema node types.
1726
+ * Handler map keys one per `FunctionParamNode` kind.
1584
1727
  */
1585
- type SchemaNode = ObjectSchemaNode | ArraySchemaNode | UnionSchemaNode | IntersectionSchemaNode | EnumSchemaNode | RefSchemaNode | DatetimeSchemaNode | DateSchemaNode | TimeSchemaNode | StringSchemaNode | NumberSchemaNode | UrlSchemaNode | FormatStringSchemaNode | Ipv4SchemaNode | Ipv6SchemaNode | ScalarSchemaNode;
1728
+ type FunctionNodeType = 'functionParameter' | 'parameterGroup' | 'functionParameters' | 'paramsType';
1586
1729
  //#endregion
1587
1730
  //#region src/nodes/parameter.d.ts
1588
1731
  type ParameterLocation = 'path' | 'query' | 'header' | 'cookie';
@@ -1655,12 +1798,16 @@ type MediaType = 'application/json' | 'application/xml' | 'application/x-www-for
1655
1798
  /**
1656
1799
  * AST node representing one operation response variant.
1657
1800
  *
1801
+ * Mirrors {@link OperationNode.requestBody}: the response body schemas live exclusively inside
1802
+ * the `content` array (one entry per content type), so the same schema is never duplicated at the
1803
+ * node root and inside `content`.
1804
+ *
1658
1805
  * @example
1659
1806
  * ```ts
1660
1807
  * const response: ResponseNode = {
1661
1808
  * kind: 'Response',
1662
1809
  * statusCode: '200',
1663
- * schema: createSchema({ type: 'string' }),
1810
+ * content: [{ contentType: 'application/json', schema: createSchema({ type: 'string' }) }],
1664
1811
  * }
1665
1812
  * ```
1666
1813
  */
@@ -1678,56 +1825,80 @@ type ResponseNode = BaseNode & {
1678
1825
  */
1679
1826
  description?: string;
1680
1827
  /**
1681
- * Response body schema.
1682
- */
1683
- schema: SchemaNode;
1684
- /**
1685
- * Response media type.
1686
- */
1687
- mediaType?: MediaType | null;
1688
- /**
1689
- * Property keys to exclude from the generated type via `Omit<Type, Keys>`.
1690
- * Set when a referenced schema has `writeOnly` fields that should not appear in response types.
1828
+ * All available content type entries for this response.
1829
+ *
1830
+ * When the adapter `contentType` option is set, this array contains exactly one entry for that
1831
+ * content type. Otherwise it contains one entry per content type declared in the spec, so that
1832
+ * plugins can generate a union of response types (e.g. `application/json` and `application/xml`).
1833
+ * Body-less responses keep a single entry whose `schema` is the empty/`void` placeholder.
1834
+ *
1835
+ * @example
1836
+ * ```ts
1837
+ * // spec response declares both application/json and application/xml
1838
+ * response.content[0].contentType // 'application/json'
1839
+ * response.content[1].contentType // 'application/xml'
1840
+ * ```
1691
1841
  */
1692
- keysToOmit?: Array<string>;
1842
+ content?: Array<ContentNode>;
1693
1843
  };
1694
1844
  //#endregion
1695
1845
  //#region src/nodes/operation.d.ts
1696
1846
  type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS' | 'TRACE';
1697
1847
  /**
1698
- * AST node representing one API operation.
1848
+ * Transport an operation belongs to.
1849
+ */
1850
+ type OperationProtocol = 'http';
1851
+ /**
1852
+ * AST node representing an operation request body.
1853
+ *
1854
+ * Body schemas live exclusively inside the `content` array (one entry per content type),
1855
+ * mirroring {@link ResponseNode}.
1699
1856
  *
1700
1857
  * @example
1701
1858
  * ```ts
1702
- * const operation: OperationNode = {
1703
- * kind: 'Operation',
1704
- * operationId: 'listPets',
1705
- * method: 'GET',
1706
- * path: '/pets',
1707
- * tags: [],
1708
- * parameters: [],
1709
- * responses: [],
1859
+ * const requestBody: RequestBodyNode = {
1860
+ * kind: 'RequestBody',
1861
+ * required: true,
1862
+ * content: [{ kind: 'Content', contentType: 'application/json', schema: createSchema({ type: 'string' }) }],
1710
1863
  * }
1711
1864
  * ```
1712
1865
  */
1713
- type OperationNode = BaseNode & {
1866
+ type RequestBodyNode = BaseNode & {
1714
1867
  /**
1715
1868
  * Node kind.
1716
1869
  */
1717
- kind: 'Operation';
1870
+ kind: 'RequestBody';
1718
1871
  /**
1719
- * Operation identifier, usually from OpenAPI `operationId`.
1872
+ * Human-readable request body description.
1720
1873
  */
1721
- operationId: string;
1874
+ description?: string;
1722
1875
  /**
1723
- * HTTP Method like 'GET'
1876
+ * Whether the request body is required (`requestBody.required: true` in the spec).
1877
+ * When `false` or absent, the generated `data` parameter should be optional.
1724
1878
  */
1725
- method: HttpMethod;
1879
+ required?: boolean;
1726
1880
  /**
1727
- * OpenAPI-style path string, for example `/pets/{petId}`.
1728
- * Path parameters retain the `{param}` notation from the original spec.
1881
+ * All available content type entries for this request body.
1882
+ *
1883
+ * When the adapter `contentType` option is set, this array contains exactly one entry for
1884
+ * that content type. Otherwise it contains one entry per content type declared in the spec,
1885
+ * so that plugins can generate code for every variant (e.g. separate hooks for
1886
+ * `application/json` and `multipart/form-data`).
1729
1887
  */
1730
- path: string;
1888
+ content?: Array<ContentNode>;
1889
+ };
1890
+ /**
1891
+ * Fields shared by every operation, regardless of transport.
1892
+ */
1893
+ type OperationNodeBase = BaseNode & {
1894
+ /**
1895
+ * Node kind.
1896
+ */
1897
+ kind: 'Operation';
1898
+ /**
1899
+ * Operation identifier, usually from OpenAPI `operationId`.
1900
+ */
1901
+ operationId: string;
1731
1902
  /**
1732
1903
  * Group labels for the operation.
1733
1904
  * Usually copied from OpenAPI `tags`.
@@ -1750,54 +1921,64 @@ type OperationNode = BaseNode & {
1750
1921
  */
1751
1922
  parameters: Array<ParameterNode>;
1752
1923
  /**
1753
- * Request body metadata for the operation.
1924
+ * Request body for the operation.
1754
1925
  */
1755
- requestBody?: {
1756
- /**
1757
- * Human-readable request body description.
1758
- */
1759
- description?: string;
1760
- /**
1761
- * Whether the request body is required (`requestBody.required: true` in the spec).
1762
- * When `false` or absent, the generated `data` parameter should be optional.
1763
- */
1764
- required?: boolean;
1765
- /**
1766
- * All available content type entries for this request body.
1767
- *
1768
- * When the adapter `contentType` option is set, this array contains exactly one entry for
1769
- * that content type. Otherwise it contains one entry per content type declared in the spec,
1770
- * so that plugins can generate code for every variant (e.g. separate hooks for
1771
- * `application/json` and `multipart/form-data`).
1772
- *
1773
- * @example
1774
- * ```ts
1775
- * // spec has both application/json and multipart/form-data
1776
- * requestBody.content[0].contentType // 'application/json'
1777
- * requestBody.content[1].contentType // 'multipart/form-data'
1778
- * ```
1779
- */
1780
- content?: Array<{
1781
- /**
1782
- * The content type for this entry (e.g. `'application/json'`).
1783
- */
1784
- contentType: string;
1785
- /**
1786
- * Request body schema for this content type.
1787
- */
1788
- schema?: SchemaNode;
1789
- /**
1790
- * Property keys to exclude from the generated request body type via `Omit<Type, Keys>`.
1791
- * Set when a referenced schema has `readOnly` fields that should be omitted in request types.
1792
- */
1793
- keysToOmit?: Array<string>;
1794
- }>;
1795
- };
1926
+ requestBody?: RequestBodyNode;
1796
1927
  /**
1797
1928
  * Operation responses.
1798
1929
  */
1799
1930
  responses: Array<ResponseNode>;
1800
1931
  };
1932
+ /**
1933
+ * Operation served over HTTP/REST (OpenAPI). `method` and `path` are guaranteed.
1934
+ *
1935
+ * @example
1936
+ * ```ts
1937
+ * const operation: HttpOperationNode = {
1938
+ * kind: 'Operation',
1939
+ * operationId: 'listPets',
1940
+ * protocol: 'http',
1941
+ * method: 'GET',
1942
+ * path: '/pets',
1943
+ * tags: [],
1944
+ * parameters: [],
1945
+ * responses: [],
1946
+ * }
1947
+ * ```
1948
+ */
1949
+ type HttpOperationNode = OperationNodeBase & {
1950
+ /**
1951
+ * Transport the operation belongs to.
1952
+ */
1953
+ protocol?: 'http';
1954
+ /**
1955
+ * HTTP method like `'GET'`.
1956
+ */
1957
+ method: HttpMethod;
1958
+ /**
1959
+ * OpenAPI-style path string, for example `/pets/{petId}`, with `{param}` notation preserved.
1960
+ */
1961
+ path: string;
1962
+ };
1963
+ /**
1964
+ * Operation for a non-HTTP transport. HTTP-only fields are forbidden.
1965
+ */
1966
+ type GenericOperationNode = OperationNodeBase & {
1967
+ /**
1968
+ * Transport the operation belongs to.
1969
+ */
1970
+ protocol?: Exclude<OperationProtocol, 'http'>;
1971
+ method?: never;
1972
+ path?: never;
1973
+ };
1974
+ /**
1975
+ * AST node representing one API operation.
1976
+ *
1977
+ * Discriminated on `protocol`: an {@link HttpOperationNode} (`protocol: 'http'`) guarantees
1978
+ * `method` and `path`, while a {@link GenericOperationNode} omits them. Narrow with
1979
+ * `isHttpOperationNode(node)` or `node.protocol === 'http'` before reading `method`/`path`.
1980
+ */
1981
+ type OperationNode = HttpOperationNode | GenericOperationNode;
1801
1982
  //#endregion
1802
1983
  //#region src/nodes/output.d.ts
1803
1984
  /**
@@ -1826,32 +2007,62 @@ type OutputNode = BaseNode & {
1826
2007
  //#endregion
1827
2008
  //#region src/nodes/root.d.ts
1828
2009
  /**
1829
- * Basic metadata for an API document.
1830
- * Adapters fill fields that exist in their source format.
2010
+ * Metadata for an API document, populated by the adapter and available to every generator.
2011
+ *
2012
+ * All fields are plain JSON-serializable values — no `Set`, no `Map`, no class instances.
2013
+ * Computed fields (`circularNames`, `enumNames`) are pre-calculated once during the adapter
2014
+ * pre-scan so generators never need to iterate the full schema list themselves.
1831
2015
  *
1832
2016
  * @example
1833
2017
  * ```ts
1834
- * const meta: InputMeta = { title: 'Pet API', version: '1.0.0' }
2018
+ * const meta: InputMeta = { title: 'Pet Store', version: '1.0.0', baseURL: 'https://petstore.swagger.io/v2', circularNames: [], enumNames: [] }
1835
2019
  * ```
1836
2020
  */
1837
2021
  type InputMeta = {
1838
2022
  /**
1839
- * API title (from `info.title` in OAS/AsyncAPI).
2023
+ * API title from `info.title` in the source document.
1840
2024
  */
1841
2025
  title?: string;
1842
2026
  /**
1843
- * API description (from `info.description` in OAS/AsyncAPI).
2027
+ * API description from `info.description` in the source document.
1844
2028
  */
1845
2029
  description?: string;
1846
2030
  /**
1847
- * API version string (from `info.version` in OAS/AsyncAPI).
2031
+ * API version string from `info.version` in the source document.
1848
2032
  */
1849
2033
  version?: string;
1850
2034
  /**
1851
- * Resolved API base URL.
1852
- * For OpenAPI and AsyncAPI, this comes from the selected server URL.
2035
+ * Resolved base URL from the first matching server entry in the source document.
1853
2036
  */
1854
- baseURL?: string;
2037
+ baseURL?: string | null;
2038
+ /**
2039
+ * Names of schemas that participate in a circular reference chain.
2040
+ * Computed once during the adapter pre-scan — use this instead of calling
2041
+ * `findCircularSchemas` per generator call.
2042
+ *
2043
+ * Convert to a `Set` once at the start of a generator, not per-schema,
2044
+ * to keep lookup O(1) without repeated allocations.
2045
+ *
2046
+ * @example Wrap a circular schema in z.lazy()
2047
+ * ```ts
2048
+ * const circular = new Set(meta.circularNames)
2049
+ * if (circular.has(schema.name)) { ... }
2050
+ * ```
2051
+ */
2052
+ circularNames: ReadonlyArray<string>;
2053
+ /**
2054
+ * Names of schemas whose type is `enum`.
2055
+ * Computed once during the adapter pre-scan — use this instead of filtering
2056
+ * schemas per generator call.
2057
+ *
2058
+ * Convert to a `Set` once at the start of a generator when you need repeated
2059
+ * membership checks, rather than calling `.includes()` per schema.
2060
+ *
2061
+ * @example Check if a referenced schema is an enum
2062
+ * `const enums = new Set(meta.enumNames)`
2063
+ * `const isEnum = enums.has(schemaName)`
2064
+ */
2065
+ enumNames: ReadonlyArray<string>;
1855
2066
  };
1856
2067
  /**
1857
2068
  * Input AST node that contains all schemas and operations for one API document.
@@ -1880,7 +2091,38 @@ type InputNode = BaseNode & {
1880
2091
  */
1881
2092
  operations: Array<OperationNode>;
1882
2093
  /**
1883
- * Optional document metadata populated by the adapter.
2094
+ * Document metadata populated by the adapter.
2095
+ */
2096
+ meta: InputMeta;
2097
+ };
2098
+ /**
2099
+ * Streaming variant of `InputNode` for memory-efficient processing of large API specs.
2100
+ *
2101
+ * `schemas` and `operations` are `AsyncIterable` rather than arrays — each `for await`
2102
+ * loop creates a fresh parse pass from the cached in-memory document, so multiple
2103
+ * consumers (plugins) can iterate independently without keeping all nodes in memory.
2104
+ *
2105
+ * @example
2106
+ * ```ts
2107
+ * for await (const schema of inputStreamNode.schemas) {
2108
+ * // only this one SchemaNode is live here; previous ones are GC-eligible
2109
+ * }
2110
+ * ```
2111
+ */
2112
+ type InputStreamNode = {
2113
+ kind: 'Input';
2114
+ /**
2115
+ * Lazily parsed schema nodes. Each `for await` creates a fresh parse pass, so
2116
+ * multiple plugins can iterate independently without sharing state.
2117
+ */
2118
+ schemas: AsyncIterable<SchemaNode>;
2119
+ /**
2120
+ * Lazily parsed operation nodes. Each `for await` creates a fresh parse pass, so
2121
+ * multiple plugins can iterate independently without sharing state.
2122
+ */
2123
+ operations: AsyncIterable<OperationNode>;
2124
+ /**
2125
+ * Document metadata available immediately, before the first yielded node.
1884
2126
  */
1885
2127
  meta?: InputMeta;
1886
2128
  };
@@ -1905,7 +2147,7 @@ type InputNode = BaseNode & {
1905
2147
  * }
1906
2148
  * ```
1907
2149
  */
1908
- type Node = InputNode | OutputNode | OperationNode | SchemaNode | PropertyNode | ParameterNode | ResponseNode | FunctionParamNode | FileNode | ImportNode | ExportNode | SourceNode | ConstNode | TypeNode | ParamsTypeNode | FunctionNode | ArrowFunctionNode;
2150
+ type Node = InputNode | OutputNode | OperationNode | SchemaNode | PropertyNode | ParameterNode | ResponseNode | RequestBodyNode | ContentNode | FunctionParamNode | FileNode | ImportNode | ExportNode | SourceNode | ConstNode | TypeNode | ParamsTypeNode | FunctionNode | ArrowFunctionNode;
1909
2151
  //#endregion
1910
2152
  //#region src/infer.d.ts
1911
2153
  /**
@@ -1913,15 +2155,25 @@ type Node = InputNode | OutputNode | OperationNode | SchemaNode | PropertyNode |
1913
2155
  */
1914
2156
  type ParserOptions = {
1915
2157
  /**
1916
- * How `format: 'date-time'` schemas are represented. `false` falls through to a plain string.
2158
+ * How `format: 'date-time'` schemas are represented downstream.
2159
+ * - `false` falls through to a plain `string` (no validation).
2160
+ * - `'string'` emits a datetime string node.
2161
+ * - `'stringOffset'` emits a datetime node with timezone offset.
2162
+ * - `'stringLocal'` emits a local datetime node.
2163
+ * - `'date'` emits a `date` node (JavaScript `Date` object).
1917
2164
  */
1918
2165
  dateType: false | 'string' | 'stringOffset' | 'stringLocal' | 'date';
1919
2166
  /**
1920
- * Whether `type: 'integer'` and `format: 'int64'` produce `number` or `bigint` nodes.
2167
+ * How `type: 'integer'` (and `format: 'int64'`) maps to TypeScript.
2168
+ * - `'number'` fits most JSON APIs; loses precision above `Number.MAX_SAFE_INTEGER`.
2169
+ * - `'bigint'` is exact for 64-bit IDs, but does not round-trip through JSON.
2170
+ *
2171
+ * @default 'number'
1921
2172
  */
1922
2173
  integerType?: 'number' | 'bigint';
1923
2174
  /**
1924
- * AST type used when no schema type can be inferred.
2175
+ * AST type used when a schema's type cannot be inferred from the spec
2176
+ * (`additionalProperties: true`, missing `type`, ...).
1925
2177
  */
1926
2178
  unknownType: 'any' | 'unknown' | 'void';
1927
2179
  /**
@@ -1929,7 +2181,8 @@ type ParserOptions = {
1929
2181
  */
1930
2182
  emptySchemaType: 'any' | 'unknown' | 'void';
1931
2183
  /**
1932
- * Suffix appended to derived enum names when building property schema names.
2184
+ * Suffix appended to derived enum names when Kubb has to invent one
2185
+ * (typically for inline enums on object properties).
1933
2186
  */
1934
2187
  enumSuffix: 'enum' | (string & {});
1935
2188
  };
@@ -1957,7 +2210,7 @@ type SchemaNodeMap<TDateType extends ParserOptions['dateType'] = 'string'> = [[{
1957
2210
  allOf: ReadonlyArray<unknown>;
1958
2211
  properties: object;
1959
2212
  }, IntersectionSchemaNode], [{
1960
- allOf: readonly [unknown, unknown, ...unknown[]];
2213
+ allOf: readonly [unknown, unknown, ...Array<unknown>];
1961
2214
  }, IntersectionSchemaNode], [{
1962
2215
  allOf: ReadonlyArray<unknown>;
1963
2216
  }, SchemaNode], [{
@@ -2050,10 +2303,13 @@ type InferSchema<TSchema extends object, TDateType extends ParserOptions['dateTy
2050
2303
  //#endregion
2051
2304
  //#region src/factory.d.ts
2052
2305
  /**
2053
- * Syncs property/parameter schema optionality flags from `required` and `schema.nullable`.
2306
+ * Updates a schema's `optional` and `nullish` flags from a parent's `required`
2307
+ * value and the schema's own `nullable`. Mirrors how OpenAPI parameters and
2308
+ * object properties combine "required" and "nullable" into a single AST.
2054
2309
  *
2055
- * - `optional` is set for non-required, non-nullable schemas.
2056
- * - `nullish` is set for non-required, nullable schemas.
2310
+ * - Non-required + non-nullable → `optional: true`.
2311
+ * - Non-required + nullable `nullish: true`.
2312
+ * - Required → both flags cleared.
2057
2313
  */
2058
2314
  declare function syncOptionality(schema: SchemaNode, required: boolean): SchemaNode;
2059
2315
  /**
@@ -2068,6 +2324,23 @@ declare function syncOptionality(schema: SchemaNode, required: boolean): SchemaN
2068
2324
  * ```
2069
2325
  */
2070
2326
  type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
2327
+ /**
2328
+ * Identity-preserving node update: returns `node` unchanged when every field in
2329
+ * `changes` already equals (by reference) the current value, otherwise a new node
2330
+ * with the changes applied.
2331
+ *
2332
+ * Mirrors the TypeScript compiler's `factory.updateX` contract — pair it with the
2333
+ * structural sharing in {@link transform} so a no-op rewrite doesn't allocate and
2334
+ * downstream passes can detect "nothing changed" by identity. Comparison is
2335
+ * shallow: a structurally-equal but newly-allocated array/object counts as a change.
2336
+ *
2337
+ * @example
2338
+ * ```ts
2339
+ * update(node, { name: node.name }) // -> same `node` reference
2340
+ * update(node, { name: 'renamed' }) // -> new node, `name` replaced
2341
+ * ```
2342
+ */
2343
+ declare function update<T extends Node>(node: T, changes: Partial<T>): T;
2071
2344
  type CreateSchemaObjectInput = Omit<ObjectSchemaNode, 'kind' | 'properties' | 'primitive'> & {
2072
2345
  properties?: Array<PropertyNode>;
2073
2346
  primitive?: 'object';
@@ -2092,6 +2365,15 @@ type CreateSchemaOutput<T extends CreateSchemaInput> = InferSchemaNode<T> & {
2092
2365
  * ```
2093
2366
  */
2094
2367
  declare function createInput(overrides?: Partial<Omit<InputNode, 'kind'>>): InputNode;
2368
+ /**
2369
+ * Creates an `InputStreamNode` from pre-built `AsyncIterable` sources.
2370
+ *
2371
+ * @example
2372
+ * ```ts
2373
+ * const node = createStreamInput(schemasIterable, operationsIterable, { title: 'My API' })
2374
+ * ```
2375
+ */
2376
+ declare function createStreamInput(schemas: AsyncIterable<SchemaNode>, operations: AsyncIterable<OperationNode>, meta?: InputMeta): InputStreamNode;
2095
2377
  /**
2096
2378
  * Creates an `OutputNode` with a stable default for `files`.
2097
2379
  *
@@ -2130,7 +2412,30 @@ declare function createOutput(overrides?: Partial<Omit<OutputNode, 'kind'>>): Ou
2130
2412
  * })
2131
2413
  * ```
2132
2414
  */
2133
- declare function createOperation(props: Pick<OperationNode, 'operationId' | 'method' | 'path'> & Partial<Omit<OperationNode, 'kind' | 'operationId' | 'method' | 'path'>>): OperationNode;
2415
+ /**
2416
+ * Loosely-typed content entry accepted by the builders, normalized into a {@link ContentNode}.
2417
+ */
2418
+ type UserContent = Omit<ContentNode, 'kind'>;
2419
+ /**
2420
+ * Creates a `ContentNode` for a single request-body or response content type.
2421
+ */
2422
+ declare function createContent(props: UserContent): ContentNode;
2423
+ /**
2424
+ * Loosely-typed request body accepted by `createOperation`, normalized into a {@link RequestBodyNode}.
2425
+ */
2426
+ type UserRequestBody = Omit<RequestBodyNode, 'kind' | 'content'> & {
2427
+ content?: Array<UserContent>;
2428
+ };
2429
+ /**
2430
+ * Creates a `RequestBodyNode`, normalizing each content entry into a `ContentNode`.
2431
+ */
2432
+ declare function createRequestBody(props: UserRequestBody): RequestBodyNode;
2433
+ declare function createOperation(props: Pick<HttpOperationNode, 'operationId' | 'method' | 'path'> & Partial<Omit<HttpOperationNode, 'kind' | 'operationId' | 'method' | 'path' | 'requestBody'>> & {
2434
+ requestBody?: UserRequestBody;
2435
+ }): HttpOperationNode;
2436
+ declare function createOperation(props: Pick<GenericOperationNode, 'operationId'> & Partial<Omit<GenericOperationNode, 'kind' | 'operationId' | 'requestBody'>> & {
2437
+ requestBody?: UserRequestBody;
2438
+ }): GenericOperationNode;
2134
2439
  /**
2135
2440
  * Creates a `SchemaNode`, narrowed to the variant of `props.type`.
2136
2441
  * For object schemas, `properties` defaults to an empty array.
@@ -2222,16 +2527,24 @@ declare function createParameter(props: Pick<ParameterNode, 'name' | 'in' | 'sch
2222
2527
  /**
2223
2528
  * Creates a `ResponseNode`.
2224
2529
  *
2530
+ * Response body schemas live inside `content`. For convenience a single legacy `schema`
2531
+ * (with optional `mediaType`/`keysToOmit`) is normalized into one `content` entry, so the same
2532
+ * schema is never stored both at the node root and inside `content`.
2533
+ *
2225
2534
  * @example
2226
2535
  * ```ts
2227
2536
  * const response = createResponse({
2228
2537
  * statusCode: '200',
2229
- * description: 'Success',
2230
- * schema: createSchema({ type: 'object', properties: [] }),
2538
+ * content: [{ contentType: 'application/json', schema: createSchema({ type: 'object', properties: [] }) }],
2231
2539
  * })
2232
2540
  * ```
2233
2541
  */
2234
- declare function createResponse(props: Pick<ResponseNode, 'statusCode' | 'schema'> & Partial<Omit<ResponseNode, 'kind' | 'statusCode' | 'schema'>>): ResponseNode;
2542
+ declare function createResponse(props: Pick<ResponseNode, 'statusCode'> & Partial<Omit<ResponseNode, 'kind' | 'statusCode' | 'content'>> & {
2543
+ content?: Array<UserContent>;
2544
+ schema?: SchemaNode;
2545
+ mediaType?: string | null;
2546
+ keysToOmit?: Array<string> | null;
2547
+ }): ResponseNode;
2235
2548
  /**
2236
2549
  * Creates a `FunctionParameterNode`.
2237
2550
  *
@@ -2583,10 +2896,10 @@ declare function createJsx(value: string): JsxNode;
2583
2896
  * @example
2584
2897
  * ```ts
2585
2898
  * const schema = createSchema({ type: 'string' })
2586
- * const stringNode = narrowSchema(schema, 'string') // StringSchemaNode | undefined
2899
+ * const stringNode = narrowSchema(schema, 'string') // StringSchemaNode | null
2587
2900
  * ```
2588
2901
  */
2589
- declare function narrowSchema<T extends SchemaNode['type']>(node: SchemaNode | undefined, type: T): SchemaNodeByType[T] | undefined;
2902
+ declare function narrowSchema<T extends SchemaNode['type']>(node: SchemaNode | undefined, type: T): SchemaNodeByType[T] | null;
2590
2903
  /**
2591
2904
  * Returns `true` when the input is an `InputNode`.
2592
2905
  *
@@ -2620,6 +2933,17 @@ declare const isOutputNode: (node: unknown) => node is OutputNode;
2620
2933
  * ```
2621
2934
  */
2622
2935
  declare const isOperationNode: (node: unknown) => node is OperationNode;
2936
+ /**
2937
+ * Narrows an `OperationNode` to an `HttpOperationNode`, guaranteeing `method` and `path`.
2938
+ *
2939
+ * @example
2940
+ * ```ts
2941
+ * if (isHttpOperationNode(node)) {
2942
+ * console.log(node.method, node.path)
2943
+ * }
2944
+ * ```
2945
+ */
2946
+ declare function isHttpOperationNode(node: OperationNode): node is HttpOperationNode;
2623
2947
  /**
2624
2948
  * Returns `true` when the input is a `SchemaNode`.
2625
2949
  *
@@ -2651,7 +2975,7 @@ type PrinterHandlerContext<TOutput, TOptions extends object> = {
2651
2975
  * Recursively transform a nested `SchemaNode` to `TOutput` using the node-level handlers.
2652
2976
  * Use `this.transform` inside `nodes` handlers and inside the `print` override.
2653
2977
  */
2654
- transform: (node: SchemaNode) => TOutput | null | undefined;
2978
+ transform: (node: SchemaNode) => TOutput | null;
2655
2979
  /**
2656
2980
  * Options for this printer instance.
2657
2981
  */
@@ -2669,7 +2993,7 @@ type PrinterHandlerContext<TOutput, TOptions extends object> = {
2669
2993
  * }
2670
2994
  * ```
2671
2995
  */
2672
- type PrinterHandler<TOutput, TOptions extends object, T extends SchemaType = SchemaType> = (this: PrinterHandlerContext<TOutput, TOptions>, node: SchemaNodeByType[T]) => TOutput | null | undefined;
2996
+ type PrinterHandler<TOutput, TOptions extends object, T extends SchemaType = SchemaType> = (this: PrinterHandlerContext<TOutput, TOptions>, node: SchemaNodeByType[T]) => TOutput | null;
2673
2997
  /**
2674
2998
  * Partial map of per-node-type handler overrides for a printer.
2675
2999
  *
@@ -2732,13 +3056,13 @@ type Printer<T extends PrinterFactoryOptions = PrinterFactoryOptions> = {
2732
3056
  * Always dispatches through the `nodes` map; never calls the `print` override.
2733
3057
  * Use this when you need the raw output (e.g. `ts.TypeNode`) without declaration wrapping.
2734
3058
  */
2735
- transform: (node: SchemaNode) => T['output'] | null | undefined;
3059
+ transform: (node: SchemaNode) => T['output'] | null;
2736
3060
  /**
2737
3061
  * Public printer. If the builder provides a root-level `print`, this calls that
2738
3062
  * higher-level function (which may produce full declarations).
2739
3063
  * Otherwise, falls back to the node-level dispatcher.
2740
3064
  */
2741
- print: (node: SchemaNode) => T['printOutput'] | null | undefined;
3065
+ print: (node: SchemaNode) => T['printOutput'] | null;
2742
3066
  };
2743
3067
  /**
2744
3068
  * Builder function passed to `definePrinter`.
@@ -2769,22 +3093,27 @@ type PrinterBuilder<T extends PrinterFactoryOptions> = (options: T['options']) =
2769
3093
  print?: (this: PrinterHandlerContext<T['output'], T['options']>, node: SchemaNode) => T['printOutput'] | null;
2770
3094
  };
2771
3095
  /**
2772
- * Creates a schema printer factory.
2773
- *
2774
- * This function wraps a builder and makes options optional at call sites.
3096
+ * Defines a schema printer: a function that takes a `SchemaNode` and emits
3097
+ * code in your target language. Each plugin that produces code from schemas
3098
+ * (TypeScript types, Zod schemas, Faker factories) ships a printer built
3099
+ * with this helper.
2775
3100
  *
2776
3101
  * The builder receives resolved options and returns:
2777
- * - `name` — a unique identifier for the printer
2778
- * - `options` — options stored on the returned printer instance
2779
- * - `nodes` — a map of `SchemaType` → handler functions that convert a `SchemaNode` to `TOutput`
2780
- * - `print` _(optional)_ — top-level override exposed as `printer.print`
2781
- * - Inside this function, use `this.transform(node)` to dispatch to the `nodes` map
2782
- * - This keeps recursion safe and avoids self-calls
2783
3102
  *
2784
- * When no `print` override is provided, `printer.print` falls back to `printer.transform` (the node-level dispatcher).
3103
+ * - `name` unique identifier for the printer.
3104
+ * - `options` — stored on the returned printer instance.
3105
+ * - `nodes` — map of `SchemaType` → handler. Handlers return the rendered
3106
+ * output (a string, a TypeScript AST node, ...) for that schema type.
3107
+ * - `print` (optional) — top-level override exposed as `printer.print`.
3108
+ * Use `this.transform(node)` inside it to dispatch to `nodes` recursively.
3109
+ *
3110
+ * Without a `print` override, `printer.print` falls back to `printer.transform`
3111
+ * (the node-level dispatcher).
2785
3112
  *
2786
- * @example Basic usage — Zod schema printer
3113
+ * @example Tiny Zod printer
2787
3114
  * ```ts
3115
+ * import { definePrinter, type PrinterFactoryOptions } from '@kubb/ast'
3116
+ *
2788
3117
  * type PrinterZod = PrinterFactoryOptions<'zod', { strict?: boolean }, string>
2789
3118
  *
2790
3119
  * export const zodPrinter = definePrinter<PrinterZod>((options) => ({
@@ -2793,7 +3122,9 @@ type PrinterBuilder<T extends PrinterFactoryOptions> = (options: T['options']) =
2793
3122
  * nodes: {
2794
3123
  * string: () => 'z.string()',
2795
3124
  * object(node) {
2796
- * const props = node.properties.map(p => `${p.name}: ${this.transform(p.schema)}`).join(', ')
3125
+ * const props = node.properties
3126
+ * .map((p) => `${p.name}: ${this.transform(p.schema)}`)
3127
+ * .join(', ')
2797
3128
  * return `z.object({ ${props} })`
2798
3129
  * },
2799
3130
  * },
@@ -2811,22 +3142,22 @@ declare function definePrinter<T extends PrinterFactoryOptions = PrinterFactoryO
2811
3142
  * )
2812
3143
  * ```
2813
3144
  */
2814
- declare function createPrinterFactory<TNode, TKey extends string, TNodeByKey extends Partial<Record<TKey, TNode>>>(getKey: (node: TNode) => TKey | undefined): <T extends PrinterFactoryOptions>(build: (options: T["options"]) => {
3145
+ declare function createPrinterFactory<TNode, TKey extends string, TNodeByKey extends Partial<Record<TKey, TNode>>>(getKey: (node: TNode) => TKey | null): <T extends PrinterFactoryOptions>(build: (options: T["options"]) => {
2815
3146
  name: T["name"];
2816
3147
  options: T["options"];
2817
3148
  nodes: Partial<{ [K in TKey]: (this: {
2818
- transform: (node: TNode) => T["output"] | null | undefined;
3149
+ transform: (node: TNode) => T["output"] | null;
2819
3150
  options: T["options"];
2820
- }, node: TNodeByKey[K]) => T["output"] | null | undefined }>;
3151
+ }, node: TNodeByKey[K]) => T["output"] | null }>;
2821
3152
  print?: (this: {
2822
- transform: (node: TNode) => T["output"] | null | undefined;
3153
+ transform: (node: TNode) => T["output"] | null;
2823
3154
  options: T["options"];
2824
- }, node: TNode) => T["printOutput"] | null | undefined;
3155
+ }, node: TNode) => T["printOutput"] | null;
2825
3156
  }) => (options?: T["options"]) => {
2826
3157
  name: T["name"];
2827
3158
  options: T["options"];
2828
- transform: (node: TNode) => T["output"] | null | undefined;
2829
- print: (node: TNode) => T["printOutput"] | null | undefined;
3159
+ transform: (node: TNode) => T["output"] | null;
3160
+ print: (node: TNode) => T["printOutput"] | null;
2830
3161
  };
2831
3162
  //#endregion
2832
3163
  //#region src/refs.d.ts
@@ -2860,7 +3191,7 @@ declare function collectImports<TImport>({
2860
3191
  }: {
2861
3192
  node: SchemaNode;
2862
3193
  nameMapping: Map<string, string>;
2863
- resolve: (schemaName: string) => TImport | undefined;
3194
+ resolve: (schemaName: string) => TImport | null;
2864
3195
  }): Array<TImport>;
2865
3196
  //#endregion
2866
3197
  //#region src/transformers.d.ts
@@ -2901,6 +3232,7 @@ declare function setDiscriminatorEnum({
2901
3232
  * ])
2902
3233
  * ```
2903
3234
  */
3235
+ declare function mergeAdjacentObjectsLazy(members: Iterable<SchemaNode>): Generator<SchemaNode, void, undefined>;
2904
3236
  declare function mergeAdjacentObjects(members: Array<SchemaNode>): Array<SchemaNode>;
2905
3237
  /**
2906
3238
  * Removes enum members that are covered by broader scalar primitives in the same union.
@@ -2923,7 +3255,7 @@ declare function setEnumName(propNode: SchemaNode, parentName: string | null | u
2923
3255
  *
2924
3256
  * `ParentOf` uses this map to find parent types.
2925
3257
  */
2926
- type ParentNodeMap = [[InputNode, undefined], [OutputNode, undefined], [OperationNode, InputNode], [SchemaNode, InputNode | OperationNode | SchemaNode | PropertyNode | ParameterNode | ResponseNode], [PropertyNode, SchemaNode], [ParameterNode, OperationNode], [ResponseNode, OperationNode]];
3258
+ type ParentNodeMap = [[InputNode, undefined], [OutputNode, undefined], [OperationNode, InputNode], [RequestBodyNode, OperationNode], [ContentNode, RequestBodyNode | ResponseNode], [SchemaNode, InputNode | ContentNode | SchemaNode | PropertyNode | ParameterNode], [PropertyNode, SchemaNode], [ParameterNode, OperationNode], [ResponseNode, OperationNode]];
2927
3259
  /**
2928
3260
  * Resolves the parent node type for a given AST node type.
2929
3261
  *
@@ -2970,25 +3302,40 @@ type VisitorContext<T extends Node = Node> = {
2970
3302
  parent?: ParentOf<T>;
2971
3303
  };
2972
3304
  /**
2973
- * Synchronous visitor used by `transform`.
3305
+ * Synchronous visitor consumed by `transform`. Each optional callback runs
3306
+ * for the matching node type. Return a new node to replace it, or `undefined`
3307
+ * to leave it untouched.
2974
3308
  *
2975
- * @example
3309
+ * Plugins typically expose `transformer` so users can supply a `Visitor` that
3310
+ * rewrites operation IDs, drops descriptions, or otherwise tweaks the AST
3311
+ * before printing.
3312
+ *
3313
+ * @example Prefix every operationId
2976
3314
  * ```ts
2977
3315
  * const visitor: Visitor = {
2978
3316
  * operation(node) {
2979
- * return { ...node, operationId: `x_${node.operationId}` }
3317
+ * return { ...node, operationId: `api_${node.operationId}` }
3318
+ * },
3319
+ * }
3320
+ * ```
3321
+ *
3322
+ * @example Strip schema descriptions
3323
+ * ```ts
3324
+ * const visitor: Visitor = {
3325
+ * schema(node) {
3326
+ * return { ...node, description: undefined }
2980
3327
  * },
2981
3328
  * }
2982
3329
  * ```
2983
3330
  */
2984
3331
  type Visitor = {
2985
- input?(node: InputNode, context: VisitorContext<InputNode>): void | InputNode;
2986
- output?(node: OutputNode, context: VisitorContext<OutputNode>): void | OutputNode;
2987
- operation?(node: OperationNode, context: VisitorContext<OperationNode>): void | OperationNode;
2988
- schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): void | SchemaNode;
2989
- property?(node: PropertyNode, context: VisitorContext<PropertyNode>): void | PropertyNode;
2990
- parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): void | ParameterNode;
2991
- response?(node: ResponseNode, context: VisitorContext<ResponseNode>): void | ResponseNode;
3332
+ input?(node: InputNode, context: VisitorContext<InputNode>): undefined | null | InputNode;
3333
+ output?(node: OutputNode, context: VisitorContext<OutputNode>): undefined | null | OutputNode;
3334
+ operation?(node: OperationNode, context: VisitorContext<OperationNode>): undefined | null | OperationNode;
3335
+ schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): undefined | null | SchemaNode;
3336
+ property?(node: PropertyNode, context: VisitorContext<PropertyNode>): undefined | null | PropertyNode;
3337
+ parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): undefined | null | ParameterNode;
3338
+ response?(node: ResponseNode, context: VisitorContext<ResponseNode>): undefined | null | ResponseNode;
2992
3339
  };
2993
3340
  /**
2994
3341
  * Utility type for values that can be returned directly or asynchronously.
@@ -3007,13 +3354,13 @@ type MaybePromise<T> = T | Promise<T>;
3007
3354
  * ```
3008
3355
  */
3009
3356
  type AsyncVisitor = {
3010
- input?(node: InputNode, context: VisitorContext<InputNode>): MaybePromise<void | InputNode>;
3011
- output?(node: OutputNode, context: VisitorContext<OutputNode>): MaybePromise<void | OutputNode>;
3012
- operation?(node: OperationNode, context: VisitorContext<OperationNode>): MaybePromise<void | OperationNode>;
3013
- schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): MaybePromise<void | SchemaNode>;
3014
- property?(node: PropertyNode, context: VisitorContext<PropertyNode>): MaybePromise<void | PropertyNode>;
3015
- parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): MaybePromise<void | ParameterNode>;
3016
- response?(node: ResponseNode, context: VisitorContext<ResponseNode>): MaybePromise<void | ResponseNode>;
3357
+ input?(node: InputNode, context: VisitorContext<InputNode>): MaybePromise<undefined | null | InputNode>;
3358
+ output?(node: OutputNode, context: VisitorContext<OutputNode>): MaybePromise<undefined | null | OutputNode>;
3359
+ operation?(node: OperationNode, context: VisitorContext<OperationNode>): MaybePromise<undefined | null | OperationNode>;
3360
+ schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): MaybePromise<undefined | null | SchemaNode>;
3361
+ property?(node: PropertyNode, context: VisitorContext<PropertyNode>): MaybePromise<undefined | null | PropertyNode>;
3362
+ parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): MaybePromise<undefined | null | ParameterNode>;
3363
+ response?(node: ResponseNode, context: VisitorContext<ResponseNode>): MaybePromise<undefined | null | ResponseNode>;
3017
3364
  };
3018
3365
  /**
3019
3366
  * Visitor used by `collect`.
@@ -3028,13 +3375,13 @@ type AsyncVisitor = {
3028
3375
  * ```
3029
3376
  */
3030
3377
  type CollectVisitor<T> = {
3031
- input?(node: InputNode, context: VisitorContext<InputNode>): T | undefined;
3032
- output?(node: OutputNode, context: VisitorContext<OutputNode>): T | undefined;
3033
- operation?(node: OperationNode, context: VisitorContext<OperationNode>): T | undefined;
3034
- schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): T | undefined;
3035
- property?(node: PropertyNode, context: VisitorContext<PropertyNode>): T | undefined;
3036
- parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): T | undefined;
3037
- response?(node: ResponseNode, context: VisitorContext<ResponseNode>): T | undefined;
3378
+ input?(node: InputNode, context: VisitorContext<InputNode>): T | null | undefined;
3379
+ output?(node: OutputNode, context: VisitorContext<OutputNode>): T | null | undefined;
3380
+ operation?(node: OperationNode, context: VisitorContext<OperationNode>): T | null | undefined;
3381
+ schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): T | null | undefined;
3382
+ property?(node: PropertyNode, context: VisitorContext<PropertyNode>): T | null | undefined;
3383
+ parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): T | null | undefined;
3384
+ response?(node: ResponseNode, context: VisitorContext<ResponseNode>): T | null | undefined;
3038
3385
  };
3039
3386
  /**
3040
3387
  * Options for `transform`.
@@ -3101,11 +3448,14 @@ type CollectOptions<T> = CollectVisitor<T> & {
3101
3448
  parent?: Node;
3102
3449
  };
3103
3450
  /**
3104
- * Depth-first traversal for side effects. Visitor return values are ignored.
3105
- * Sibling nodes at each level are visited concurrently up to `options.concurrency`
3106
- * (default: `WALK_CONCURRENCY`).
3451
+ * Async depth-first traversal for side effects. Visitor return values are
3452
+ * ignored. Use `transform` when you want to rewrite nodes.
3107
3453
  *
3108
- * @example
3454
+ * Sibling nodes at each depth run concurrently up to `options.concurrency`
3455
+ * (defaults to `WALK_CONCURRENCY`). Higher values overlap I/O-bound visitor
3456
+ * work; lower values reduce memory pressure.
3457
+ *
3458
+ * @example Log every operation
3109
3459
  * ```ts
3110
3460
  * await walk(root, {
3111
3461
  * operation(node) {
@@ -3114,20 +3464,20 @@ type CollectOptions<T> = CollectVisitor<T> & {
3114
3464
  * })
3115
3465
  * ```
3116
3466
  *
3117
- * @example
3467
+ * @example Only visit the root node
3118
3468
  * ```ts
3119
- * // Visit only the current node
3120
- * await walk(root, { depth: 'shallow', root: () => {} })
3469
+ * await walk(root, { depth: 'shallow', input: () => {} })
3121
3470
  * ```
3122
3471
  */
3123
3472
  declare function walk(node: Node, options: WalkOptions): Promise<void>;
3124
3473
  /**
3125
- * Runs a depth-first immutable transform.
3474
+ * Synchronous depth-first transform. Each visitor callback gets a chance to
3475
+ * return a replacement node; `undefined` keeps the original.
3126
3476
  *
3127
- * If a visitor returns a node, it replaces the current node.
3128
- * If it returns `undefined`, the current node stays the same.
3477
+ * The transform is immutable. The original tree is not mutated; a new tree
3478
+ * is returned. Use `depth: 'shallow'` to skip recursion into children.
3129
3479
  *
3130
- * @example
3480
+ * @example Prefix every operationId
3131
3481
  * ```ts
3132
3482
  * const next = transform(root, {
3133
3483
  * operation(node) {
@@ -3136,10 +3486,12 @@ declare function walk(node: Node, options: WalkOptions): Promise<void>;
3136
3486
  * })
3137
3487
  * ```
3138
3488
  *
3139
- * @example
3489
+ * @example Replace only the root node
3140
3490
  * ```ts
3141
- * // Shallow mode: only transform the input node
3142
- * const next = transform(root, { depth: 'shallow', root: (node) => node })
3491
+ * const next = transform(root, {
3492
+ * depth: 'shallow',
3493
+ * input: (node) => ({ ...node, meta: { ...node.meta, title: 'Rewritten' } }),
3494
+ * })
3143
3495
  * ```
3144
3496
  */
3145
3497
  declare function transform(node: InputNode, options: TransformOptions): InputNode;
@@ -3151,23 +3503,33 @@ declare function transform(node: ParameterNode, options: TransformOptions): Para
3151
3503
  declare function transform(node: ResponseNode, options: TransformOptions): ResponseNode;
3152
3504
  declare function transform(node: Node, options: TransformOptions): Node;
3153
3505
  /**
3154
- * Runs a depth-first synchronous collection pass.
3506
+ * Lazy depth-first collection pass. Yields every non-null value returned by
3507
+ * the visitor callbacks. Use `collect` for the eager array form.
3155
3508
  *
3156
- * Non-`undefined` values returned by visitor callbacks are appended to the result.
3157
- *
3158
- * @example
3509
+ * @example Collect every operationId
3159
3510
  * ```ts
3160
- * const ids = collect(root, {
3511
+ * const ids: string[] = []
3512
+ * for (const id of collectLazy<string>(root, {
3161
3513
  * operation(node) {
3162
3514
  * return node.operationId
3163
3515
  * },
3164
- * })
3516
+ * })) {
3517
+ * ids.push(id)
3518
+ * }
3165
3519
  * ```
3520
+ */
3521
+ declare function collectLazy<T>(node: Node, options: CollectOptions<T>): Generator<T, void, undefined>;
3522
+ /**
3523
+ * Eager depth-first collection pass. Returns an array of every non-null value
3524
+ * the visitor callbacks return.
3166
3525
  *
3167
- * @example
3526
+ * @example Collect every operationId
3168
3527
  * ```ts
3169
- * // Collect from only the current node
3170
- * const values = collect(root, { depth: 'shallow', root: () => 'root' })
3528
+ * const ids = collect<string>(root, {
3529
+ * operation(node) {
3530
+ * return node.operationId
3531
+ * },
3532
+ * })
3171
3533
  * ```
3172
3534
  */
3173
3535
  declare function collect<T>(node: Node, options: CollectOptions<T>): Array<T>;
@@ -3194,13 +3556,6 @@ declare function syncSchemaRef(node: SchemaNode): SchemaNode;
3194
3556
  * types, returns `true` only when `representation` is `'string'` rather than `'date'`.
3195
3557
  */
3196
3558
  declare function isStringType(node: SchemaNode): boolean;
3197
- /**
3198
- * Applies casing rules to parameter names and returns a new parameter array.
3199
- *
3200
- * Use this before passing parameters to schema builders so output property keys match
3201
- * the desired casing while preserving `OperationNode.parameters` for other consumers.
3202
- * The input array is not mutated. When `casing` is not set, the original array is returned unchanged.
3203
- */
3204
3559
  declare function caseParams(params: Array<ParameterNode>, casing: 'camelcase' | undefined): Array<ParameterNode>;
3205
3560
  /**
3206
3561
  * Creates a single-property object schema used as a discriminator literal.
@@ -3361,7 +3716,7 @@ declare function extractStringsFromNodes(nodes: Array<CodeNode> | undefined): st
3361
3716
  /**
3362
3717
  * Resolves the schema name of a ref node, falling back through `ref` → `name` → nested `schema.name`.
3363
3718
  *
3364
- * Returns `undefined` for non-ref nodes or when no name can be resolved. Use this to get a schema's
3719
+ * Returns `null` for non-ref nodes or when no name can be resolved. Use this to get a schema's
3365
3720
  * identifier for type definitions or error messages.
3366
3721
  *
3367
3722
  * @example
@@ -3370,56 +3725,8 @@ declare function extractStringsFromNodes(nodes: Array<CodeNode> | undefined): st
3370
3725
  * // => 'Pet'
3371
3726
  * ```
3372
3727
  */
3373
- declare function resolveRefName(node: SchemaNode | undefined): string | undefined;
3374
- /**
3375
- * Collects every named schema referenced (transitively) from a node via ref edges.
3376
- *
3377
- * Refs are followed by name only — the resolved `node.schema` is not traversed inline.
3378
- * Use this to determine schema dependencies, build reference graphs, or detect what schemas need to be emitted.
3379
- *
3380
- * @example Collect refs from a single schema
3381
- * ```ts
3382
- * const names = collectReferencedSchemaNames(petSchema)
3383
- * // → Set { 'Category', 'Tag' }
3384
- * ```
3385
- *
3386
- * @example Accumulate refs from multiple schemas into one set
3387
- * ```ts
3388
- * const out = new Set<string>()
3389
- * for (const schema of schemas) {
3390
- * collectReferencedSchemaNames(schema, out)
3391
- * }
3392
- * ```
3393
- */
3728
+ declare function resolveRefName(node: SchemaNode | undefined): string | null;
3394
3729
  declare function collectReferencedSchemaNames(node: SchemaNode | undefined, out?: Set<string>): Set<string>;
3395
- /**
3396
- * Collects the names of all top-level schemas transitively used by a set of operations.
3397
- *
3398
- * An operation uses a schema when any of its parameters, request body content, or responses
3399
- * reference it — directly or indirectly through other named schemas.
3400
- * The walk is iterative and safe against reference cycles.
3401
- *
3402
- * Use this together with `include` filters to determine which schemas from `components/schemas`
3403
- * are reachable from the allowed operations, so that schemas used only by excluded operations
3404
- * are not generated.
3405
- *
3406
- * @example Only generate schemas referenced by included operations
3407
- * ```ts
3408
- * const includedOps = inputNode.operations.filter(op => resolver.resolveOptions(op, { options, include }) !== null)
3409
- * const allowed = collectUsedSchemaNames(includedOps, inputNode.schemas)
3410
- *
3411
- * for (const schema of inputNode.schemas) {
3412
- * if (schema.name && !allowed.has(schema.name)) continue
3413
- * // … generate schema
3414
- * }
3415
- * ```
3416
- *
3417
- * @example Check whether a specific schema is needed
3418
- * ```ts
3419
- * const allowed = collectUsedSchemaNames(includedOps, inputNode.schemas)
3420
- * allowed.has('OrderStatus') // false when no included operation references OrderStatus
3421
- * ```
3422
- */
3423
3730
  declare function collectUsedSchemaNames(operations: ReadonlyArray<OperationNode>, schemas: ReadonlyArray<SchemaNode>): Set<string>;
3424
3731
  /**
3425
3732
  * Identifies all schemas that participate in circular dependency chains, including direct self-loops.
@@ -3447,5 +3754,5 @@ declare function containsCircularRef(node: SchemaNode | undefined, {
3447
3754
  excludeName?: string;
3448
3755
  }): boolean;
3449
3756
  //#endregion
3450
- export { type ArraySchemaNode, type ArrowFunctionNode, AsyncVisitor, type BaseNode, type BreakNode, type CodeNode, CollectOptions, CollectVisitor, type ComplexSchemaType, type ConstNode, type DateSchemaNode, type DatetimeSchemaNode, DistributiveOmit, type EnumSchemaNode, type EnumValueNode, type ExportNode, type FileNode, type FormatStringSchemaNode, type FunctionNode, type FunctionNodeType, type FunctionParamNode, type FunctionParameterNode, type FunctionParametersNode, type HttpMethod, type HttpStatusCode, type ImportNode, InferSchema, InferSchemaNode, type InputMeta, type InputNode, type IntersectionSchemaNode, type Ipv4SchemaNode, type Ipv6SchemaNode, type JSDocNode, type JsxNode, type MediaType, Node, type NodeKind, type NumberSchemaNode, type ObjectSchemaNode, type OperationNode, OperationParamsResolver, type OutputNode, type ParameterGroupNode, type ParameterLocation, type ParameterNode, type ParamsTypeNode, ParentOf, ParserOptions, type PrimitiveSchemaType, Printer, PrinterFactoryOptions, PrinterPartial, type PropertyNode, RefMap, type RefSchemaNode, type ResponseNode, ScalarPrimitive, type ScalarSchemaNode, type ScalarSchemaType, type SchemaNode, type SchemaNodeByType, type SchemaType, type SourceNode, type SpecialSchemaType, type StatusCode, type StringSchemaNode, type TextNode, type TimeSchemaNode, TransformOptions, type TypeDeclarationNode, type TypeNode, type UnionSchemaNode, type UrlSchemaNode, UserFileNode, Visitor, VisitorContext, VisitorDepth, WalkOptions, caseParams, childName, collect, collectImports, collectReferencedSchemaNames, collectUsedSchemaNames, containsCircularRef, createArrowFunction, createBreak, createConst, createDiscriminantNode, createExport, createFile, createFunction, createFunctionParameter, createFunctionParameters, createImport, createInput, createJsx, createOperation, createOperationParams, createOutput, createParameter, createParameterGroup, createParamsType, createPrinterFactory, createProperty, createResponse, createSchema, createSource, createText, createType, definePrinter, enumPropName, extractRefName, extractStringsFromNodes, findCircularSchemas, findDiscriminator, httpMethods, isInputNode, isOperationNode, isOutputNode, isScalarPrimitive, isSchemaNode, isStringType, mediaTypes, mergeAdjacentObjects, narrowSchema, nodeKinds, resolveRefName, schemaTypes, setDiscriminatorEnum, setEnumName, simplifyUnion, syncOptionality, syncSchemaRef, transform, walk };
3757
+ export { type ArraySchemaNode, type ArrowFunctionNode, AsyncVisitor, type BaseNode, type BreakNode, type CodeNode, CollectOptions, CollectVisitor, type ComplexSchemaType, type ConstNode, type DateSchemaNode, type DatetimeSchemaNode, DispatchRule, DistributiveOmit, type EnumSchemaNode, type EnumValueNode, type ExportNode, type FileNode, type FormatStringSchemaNode, type FunctionNode, type FunctionNodeType, type FunctionParamNode, type FunctionParameterNode, type FunctionParametersNode, type GenericOperationNode, type HttpMethod, type HttpOperationNode, type HttpStatusCode, type ImportNode, InferSchema, InferSchemaNode, type InputMeta, type InputNode, type InputStreamNode, type IntersectionSchemaNode, type Ipv4SchemaNode, type Ipv6SchemaNode, type JSDocNode, type JsxNode, type MediaType, Node, type NodeKind, type NumberSchemaNode, type ObjectSchemaNode, type OperationNode, type OperationNodeBase, OperationParamsResolver, type OperationProtocol, type OutputNode, type ParameterGroupNode, type ParameterLocation, type ParameterNode, type ParamsTypeNode, ParentOf, ParserOptions, type PrimitiveSchemaType, Printer, PrinterFactoryOptions, PrinterPartial, type PropertyNode, RefMap, type RefSchemaNode, type ResponseNode, ScalarPrimitive, type ScalarSchemaNode, type ScalarSchemaType, SchemaDialect, type SchemaNode, type SchemaNodeByType, type SchemaType, type SourceNode, type SpecialSchemaType, type StatusCode, type StringSchemaNode, type TextNode, type TimeSchemaNode, TransformOptions, type TypeDeclarationNode, type TypeNode, type UnionSchemaNode, type UrlSchemaNode, UserFileNode, Visitor, VisitorContext, VisitorDepth, WalkOptions, caseParams, childName, collect, collectImports, collectLazy, collectReferencedSchemaNames, collectUsedSchemaNames, containsCircularRef, createArrowFunction, createBreak, createConst, createContent, createDiscriminantNode, createExport, createFile, createFunction, createFunctionParameter, createFunctionParameters, createImport, createInput, createJsx, createOperation, createOperationParams, createOutput, createParameter, createParameterGroup, createParamsType, createPrinterFactory, createProperty, createRequestBody, createResponse, createSchema, createSource, createStreamInput, createText, createType, definePrinter, defineSchemaDialect, dispatch, enumPropName, extractRefName, extractStringsFromNodes, findCircularSchemas, findDiscriminator, httpMethods, isHttpOperationNode, isInputNode, isOperationNode, isOutputNode, isScalarPrimitive, isSchemaNode, isStringType, mediaTypes, mergeAdjacentObjects, mergeAdjacentObjectsLazy, narrowSchema, nodeKinds, resolveRefName, schemaTypes, setDiscriminatorEnum, setEnumName, simplifyUnion, syncOptionality, syncSchemaRef, transform, update, walk };
3451
3758
  //# sourceMappingURL=index.d.ts.map