🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@kubb/ast

Package Overview
Dependencies
Maintainers
1
Versions
181
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@kubb/ast - npm Package Compare versions

Comparing version
5.0.0-beta.70
to
5.0.0-beta.71
+114
dist/defineMacro-5Dvct8k_.cjs
const require_visitor = require("./visitor-CQdSiClY.cjs");
//#region src/defineMacro.ts
/**
* Sort weight for an `enforce` hint. `pre` sorts before unmarked items and `post` after, so a plain
* list keeps its authored order.
*/
function enforceWeight(enforce) {
if (enforce === "pre") return 0;
if (enforce === "post") return 2;
return 1;
}
/**
* Types a macro for inference and a single construction site, mirroring `definePlugin`.
* Adds no runtime behavior.
*
* @example
* ```ts
* const macroUntagged = defineMacro({
* name: 'untagged',
* operation(node) {
* return node.tags?.length ? undefined : { ...node, tags: ['untagged'] }
* },
* })
* ```
*/
function defineMacro(macro) {
return macro;
}
/**
* Runs every macro's callback for one node kind in order, chaining the result so each macro sees
* the previous macro's output. Returns `undefined` when nothing changed, so `transform` keeps the
* original reference (structural sharing).
*/
function chain({ macros, key, node, context }) {
let current = node;
for (const macro of macros) {
const callback = macro[key];
if (!callback) continue;
if (macro.when && !macro.when(current)) continue;
const next = callback(current, context);
if (next != null) current = next;
}
return current === node ? void 0 : current;
}
/**
* Folds an ordered list of macros into a single {@link Visitor} that `transform` (and the per-plugin
* transform layer in `@kubb/core`) can run. Macros are stable-sorted by `enforce`, then applied
* sequentially per node so later macros see earlier output. This differs from a plain visitor, which
* has no names, ordering, or composition.
*
* @example
* ```ts
* const visitor = composeMacros([macroSimplifyUnion, macroDiscriminatorEnum])
* const next = transform(root, visitor)
* ```
*/
function composeMacros(macros) {
const ordered = [...macros].sort((a, b) => enforceWeight(a.enforce) - enforceWeight(b.enforce));
const visitor = {};
for (const key of require_visitor.visitorKeys) {
if (!ordered.some((macro) => typeof macro[key] === "function")) continue;
const callback = (node, context) => chain({
macros: ordered,
key,
node,
context
});
visitor[key] = callback;
}
return visitor;
}
/**
* Runs a list of macros over a node tree and returns the rewritten tree. Keeps `transform`'s
* structural sharing, so an empty or no-op macro list returns the same reference. Pass
* `depth: 'shallow'` to rewrite the root node only.
*
* @example
* ```ts
* const next = applyMacros(root, [macroIntegerToString])
* ```
*
* @example Apply to the root node only
* ```ts
* const named = applyMacros(node, [macroEnumName({ parentName, propName, enumSuffix })], { depth: 'shallow' })
* ```
*/
function applyMacros(root, macros, options) {
if (macros.length === 0) return root;
return require_visitor.transform(root, {
...composeMacros(macros),
...options
});
}
//#endregion
Object.defineProperty(exports, "applyMacros", {
enumerable: true,
get: function() {
return applyMacros;
}
});
Object.defineProperty(exports, "composeMacros", {
enumerable: true,
get: function() {
return composeMacros;
}
});
Object.defineProperty(exports, "defineMacro", {
enumerable: true,
get: function() {
return defineMacro;
}
});
//# sourceMappingURL=defineMacro-5Dvct8k_.cjs.map
{"version":3,"file":"defineMacro-5Dvct8k_.cjs","names":["visitorKeys","transform"],"sources":["../src/defineMacro.ts"],"sourcesContent":["import type { VisitorDepth } from './constants.ts'\nimport type { VisitorKey } from './defineNode.ts'\nimport { visitorKeys } from './defineNode.ts'\nimport type { Node } from './nodes/index.ts'\nimport type { Visitor, VisitorContext } from './visitor.ts'\nimport { transform } from './visitor.ts'\n\n/**\n * Ordering hint shared by macros and plugins. `pre` runs before unmarked items, `post` after,\n * and `undefined` keeps declaration order.\n */\nexport type Enforce = 'pre' | 'post'\n\n/**\n * Sort weight for an `enforce` hint. `pre` sorts before unmarked items and `post` after, so a plain\n * list keeps its authored order.\n */\nfunction enforceWeight(enforce?: Enforce): number {\n if (enforce === 'pre') return 0\n if (enforce === 'post') return 2\n return 1\n}\n\n/**\n * A named, composable transform over the Kubb AST. It carries the same per-kind callbacks as a\n * {@link Visitor} (`schema`, `operation`, …), plus a `name`, an optional `enforce` order, and an\n * optional `when` gate. Macros run on the shared AST, so the same macro works across every adapter\n * and output target. Exports follow the `macro<Name>` convention, mirroring plugins (`pluginTs`).\n */\nexport type Macro = Visitor & {\n /**\n * Macro identifier used to tell macros apart, for example `'simplify-union'`.\n */\n name: string\n /**\n * Ordering hint. `pre` macros run before unmarked macros, `post` macros run after.\n * Ordering within a bucket follows list order.\n */\n enforce?: Enforce\n /**\n * Gate checked against the current node before any callback runs. When it returns `false`\n * the macro is skipped for that node.\n */\n when?: (node: Node) => boolean\n}\n\n/**\n * Types a macro for inference and a single construction site, mirroring `definePlugin`.\n * Adds no runtime behavior.\n *\n * @example\n * ```ts\n * const macroUntagged = defineMacro({\n * name: 'untagged',\n * operation(node) {\n * return node.tags?.length ? undefined : { ...node, tags: ['untagged'] }\n * },\n * })\n * ```\n */\nexport function defineMacro(macro: Macro): Macro {\n return macro\n}\n\ntype MacroCallback = (node: Node, context: VisitorContext) => Node | null | undefined\n\ntype ChainProps = {\n macros: ReadonlyArray<Macro>\n key: VisitorKey\n node: Node\n context: VisitorContext\n}\n\n/**\n * Runs every macro's callback for one node kind in order, chaining the result so each macro sees\n * the previous macro's output. Returns `undefined` when nothing changed, so `transform` keeps the\n * original reference (structural sharing).\n */\nfunction chain({ macros, key, node, context }: ChainProps): Node | undefined {\n let current = node\n\n for (const macro of macros) {\n const callback = macro[key] as MacroCallback | undefined\n if (!callback) continue\n if (macro.when && !macro.when(current)) continue\n\n const next = callback(current, context)\n if (next != null) current = next\n }\n\n return current === node ? undefined : current\n}\n\n/**\n * Folds an ordered list of macros into a single {@link Visitor} that `transform` (and the per-plugin\n * transform layer in `@kubb/core`) can run. Macros are stable-sorted by `enforce`, then applied\n * sequentially per node so later macros see earlier output. This differs from a plain visitor, which\n * has no names, ordering, or composition.\n *\n * @example\n * ```ts\n * const visitor = composeMacros([macroSimplifyUnion, macroDiscriminatorEnum])\n * const next = transform(root, visitor)\n * ```\n */\nexport function composeMacros(macros: ReadonlyArray<Macro>): Visitor {\n const ordered = [...macros].sort((a, b) => enforceWeight(a.enforce) - enforceWeight(b.enforce))\n\n const visitor: Visitor = {}\n for (const key of visitorKeys) {\n if (!ordered.some((macro) => typeof macro[key] === 'function')) continue\n\n const callback = (node: Node, context: VisitorContext) => chain({ macros: ordered, key, node, context })\n ;(visitor as Record<VisitorKey, MacroCallback>)[key] = callback\n }\n\n return visitor\n}\n\n/**\n * Runs a list of macros over a node tree and returns the rewritten tree. Keeps `transform`'s\n * structural sharing, so an empty or no-op macro list returns the same reference. Pass\n * `depth: 'shallow'` to rewrite the root node only.\n *\n * @example\n * ```ts\n * const next = applyMacros(root, [macroIntegerToString])\n * ```\n *\n * @example Apply to the root node only\n * ```ts\n * const named = applyMacros(node, [macroEnumName({ parentName, propName, enumSuffix })], { depth: 'shallow' })\n * ```\n */\nexport function applyMacros<TNode extends Node>(root: TNode, macros: ReadonlyArray<Macro>, options?: { depth?: VisitorDepth }): TNode {\n if (macros.length === 0) return root\n\n return transform(root, { ...composeMacros(macros), ...options }) as TNode\n}\n"],"mappings":";;;;;;AAiBA,SAAS,cAAc,SAA2B;CAChD,IAAI,YAAY,OAAO,OAAO;CAC9B,IAAI,YAAY,QAAQ,OAAO;CAC/B,OAAO;AACT;;;;;;;;;;;;;;;AAuCA,SAAgB,YAAY,OAAqB;CAC/C,OAAO;AACT;;;;;;AAgBA,SAAS,MAAM,EAAE,QAAQ,KAAK,MAAM,WAAyC;CAC3E,IAAI,UAAU;CAEd,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,WAAW,MAAM;EACvB,IAAI,CAAC,UAAU;EACf,IAAI,MAAM,QAAQ,CAAC,MAAM,KAAK,OAAO,GAAG;EAExC,MAAM,OAAO,SAAS,SAAS,OAAO;EACtC,IAAI,QAAQ,MAAM,UAAU;CAC9B;CAEA,OAAO,YAAY,OAAO,KAAA,IAAY;AACxC;;;;;;;;;;;;;AAcA,SAAgB,cAAc,QAAuC;CACnE,MAAM,UAAU,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,GAAG,MAAM,cAAc,EAAE,OAAO,IAAI,cAAc,EAAE,OAAO,CAAC;CAE9F,MAAM,UAAmB,CAAC;CAC1B,KAAK,MAAM,OAAOA,gBAAAA,aAAa;EAC7B,IAAI,CAAC,QAAQ,MAAM,UAAU,OAAO,MAAM,SAAS,UAAU,GAAG;EAEhE,MAAM,YAAY,MAAY,YAA4B,MAAM;GAAE,QAAQ;GAAS;GAAK;GAAM;EAAQ,CAAC;EACtG,QAA+C,OAAO;CACzD;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;AAiBA,SAAgB,YAAgC,MAAa,QAA8B,SAA2C;CACpI,IAAI,OAAO,WAAW,GAAG,OAAO;CAEhC,OAAOC,gBAAAA,UAAU,MAAM;EAAE,GAAG,cAAc,MAAM;EAAG,GAAG;CAAQ,CAAC;AACjE"}
import { n as __name } from "./rolldown-runtime-CNktS9qV.js";
import { C as ParameterNode, Et as PropertyNode, _t as SchemaNode, f as OperationNode, h as ResponseNode, n as OutputNode, o as InputNode, rt as ContentNode, t as Node, y as RequestBodyNode } from "./index-DJEyS5y6.js";
//#region src/constants.d.ts
/**
* Traversal depth for AST visitor utilities.
*
* - `'shallow'` visits only the immediate node, skipping children.
* - `'deep'` recursively visits all descendant nodes.
*/
type VisitorDepth = 'shallow' | 'deep';
/**
* Schema type discriminators used by all AST schema nodes.
*
* Each value is a stable discriminator across the AST (for example `schema.type === schemaTypes.object`).
*/
declare const schemaTypes: {
/**
* Text value.
*/
readonly string: "string";
/**
* Floating-point number (`float`, `double`).
*/
readonly number: "number";
/**
* Whole number (`int32`). Use `bigint` for `int64`.
*/
readonly integer: "integer";
/**
* 64-bit integer (`int64`). Only used when `integerType` is set to `'bigint'`.
*/
readonly bigint: "bigint";
/**
* Boolean value.
*/
readonly boolean: "boolean";
/**
* Explicit null value.
*/
readonly null: "null";
/**
* Any value (no type restriction).
*/
readonly any: "any";
/**
* Unknown value (must be narrowed before usage).
*/
readonly unknown: "unknown";
/**
* No return value (`void`).
*/
readonly void: "void";
/**
* Object with named properties.
*/
readonly object: "object";
/**
* Sequential list of items.
*/
readonly array: "array";
/**
* Fixed-length list with position-specific items.
*/
readonly tuple: "tuple";
/**
* "One of" multiple schema members.
*/
readonly union: "union";
/**
* "All of" multiple schema members.
*/
readonly intersection: "intersection";
/**
* Enum schema.
*/
readonly enum: "enum";
/**
* Reference to another schema.
*/
readonly ref: "ref";
/**
* Calendar date (for example `2026-03-24`).
*/
readonly date: "date";
/**
* Date-time value (for example `2026-03-24T09:00:00Z`).
*/
readonly datetime: "datetime";
/**
* Time-only value (for example `09:00:00`).
*/
readonly time: "time";
/**
* UUID value.
*/
readonly uuid: "uuid";
/**
* Email address value.
*/
readonly email: "email";
/**
* URL value.
*/
readonly url: "url";
/**
* IPv4 address value.
*/
readonly ipv4: "ipv4";
/**
* IPv6 address value.
*/
readonly ipv6: "ipv6";
/**
* Binary/blob value.
*/
readonly blob: "blob";
/**
* Impossible value (`never`).
*/
readonly never: "never";
};
//#endregion
//#region src/visitor.d.ts
/**
* Ordered mapping of `[NodeType, ParentType]` pairs.
*
* `ParentOf` uses this map to find parent types.
*/
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]];
/**
* Resolves the parent node type for a given AST node type.
*
* Visitor context relies on this so `ctx.parent` is typed for each callback.
*
* @example
* ```ts
* type InputParent = ParentOf<InputNode>
* // undefined
* ```
*
* @example
* ```ts
* type PropertyParent = ParentOf<PropertyNode>
* // SchemaNode
* ```
*
* @example
* ```ts
* type SchemaParent = ParentOf<SchemaNode>
* // InputNode | ContentNode | SchemaNode | PropertyNode | ParameterNode
* ```
*/
type ParentOf<T extends Node, TEntries extends ReadonlyArray<[Node, unknown]> = ParentNodeMap> = TEntries extends [infer TEntry extends [Node, unknown], ...infer TRest extends ReadonlyArray<[Node, unknown]>] ? T extends TEntry[0] ? TEntry[1] : ParentOf<T, TRest> : Node;
/**
* Traversal context passed as the second argument to every visitor callback.
* `parent` is typed from the current node type.
*
* @example
* ```ts
* const visitor: Visitor = {
* schema(node, { parent }) {
* // parent type is narrowed by node kind
* },
* }
* ```
*/
type VisitorContext<T extends Node = Node> = {
/**
* Parent node of the currently visited node.
* For `InputNode`, this is `undefined`.
*/
parent?: ParentOf<T>;
};
/**
* Synchronous visitor consumed by `transform`. Each optional callback runs
* for the matching node type. Return a new node to replace it, or `undefined`
* to leave it untouched.
*
* Plugins typically expose `transformer` so users can supply a `Visitor` that
* rewrites the AST before printing.
*
* @example Prefix every operationId
* ```ts
* const visitor: Visitor = {
* operation(node) {
* return { ...node, operationId: `api_${node.operationId}` }
* },
* }
* ```
*
* @example Strip schema descriptions
* ```ts
* const visitor: Visitor = {
* schema(node) {
* return { ...node, description: undefined }
* },
* }
* ```
*/
type Visitor = {
input?(node: InputNode, context: VisitorContext<InputNode>): undefined | null | InputNode;
output?(node: OutputNode, context: VisitorContext<OutputNode>): undefined | null | OutputNode;
operation?(node: OperationNode, context: VisitorContext<OperationNode>): undefined | null | OperationNode;
schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): undefined | null | SchemaNode;
property?(node: PropertyNode, context: VisitorContext<PropertyNode>): undefined | null | PropertyNode;
parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): undefined | null | ParameterNode;
response?(node: ResponseNode, context: VisitorContext<ResponseNode>): undefined | null | ResponseNode;
};
/**
* A visitor callback result that may be sync or async.
*/
type MaybePromise<T> = T | Promise<T>;
/**
* Async visitor for `walk`. Synchronous `Visitor` objects are compatible.
*
* @example
* ```ts
* const visitor: AsyncVisitor = {
* async operation(node) {
* await Promise.resolve(node.operationId)
* },
* }
* ```
*/
type AsyncVisitor = {
input?(node: InputNode, context: VisitorContext<InputNode>): MaybePromise<undefined | null | InputNode>;
output?(node: OutputNode, context: VisitorContext<OutputNode>): MaybePromise<undefined | null | OutputNode>;
operation?(node: OperationNode, context: VisitorContext<OperationNode>): MaybePromise<undefined | null | OperationNode>;
schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): MaybePromise<undefined | null | SchemaNode>;
property?(node: PropertyNode, context: VisitorContext<PropertyNode>): MaybePromise<undefined | null | PropertyNode>;
parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): MaybePromise<undefined | null | ParameterNode>;
response?(node: ResponseNode, context: VisitorContext<ResponseNode>): MaybePromise<undefined | null | ResponseNode>;
};
/**
* Visitor used by `collect`.
*
* @example
* ```ts
* const visitor: CollectVisitor<string> = {
* operation(node) {
* return node.operationId
* },
* }
* ```
*/
type CollectVisitor<T> = {
input?(node: InputNode, context: VisitorContext<InputNode>): T | null | undefined;
output?(node: OutputNode, context: VisitorContext<OutputNode>): T | null | undefined;
operation?(node: OperationNode, context: VisitorContext<OperationNode>): T | null | undefined;
schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): T | null | undefined;
property?(node: PropertyNode, context: VisitorContext<PropertyNode>): T | null | undefined;
parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): T | null | undefined;
response?(node: ResponseNode, context: VisitorContext<ResponseNode>): T | null | undefined;
};
/**
* Options for `transform`.
*
* @example
* ```ts
* const options: TransformOptions = { depth: 'deep', schema: (node) => node }
* ```
*
* @example
* ```ts
* // Only transform the current node, not nested children
* const options: TransformOptions = { depth: 'shallow', schema: (node) => node }
* ```
*/
type TransformOptions = Visitor & {
/**
* Traversal depth.
* @default 'deep'
*/
depth?: VisitorDepth;
/**
* Internal parent override used during recursion.
*/
parent?: Node;
};
/**
* Options for `walk`.
*
* @example
* ```ts
* const options: WalkOptions = { depth: 'deep', concurrency: 10, root: () => {} }
* ```
*/
type WalkOptions = AsyncVisitor & {
/**
* Traversal depth.
* @default 'deep'
*/
depth?: VisitorDepth;
/**
* Maximum number of sibling nodes visited concurrently.
* @default 30
*/
concurrency?: number;
};
/**
* Options for `collect`.
*
* @example
* ```ts
* const options: CollectOptions<string> = { depth: 'shallow', schema: () => undefined }
* ```
*/
type CollectOptions<T> = CollectVisitor<T> & {
/**
* Traversal depth.
* @default 'deep'
*/
depth?: VisitorDepth;
/**
* Internal parent override used during recursion.
*/
parent?: Node;
};
/**
* Async depth-first traversal for side effects. Visitor return values are
* ignored. Use `transform` when you want to rewrite nodes.
*
* Sibling nodes at each depth run concurrently up to `options.concurrency`
* (defaults to `WALK_CONCURRENCY`). Higher values overlap I/O-bound visitor
* work. Lower values reduce memory pressure.
*
* @example Log every operation
* ```ts
* await walk(root, {
* operation(node) {
* console.log(node.operationId)
* },
* })
* ```
*
* @example Only visit the root node
* ```ts
* await walk(root, { depth: 'shallow', input: () => {} })
* ```
*/
declare function walk(node: Node, options: WalkOptions): Promise<void>;
/**
* Synchronous depth-first transform. Each visitor callback can return a
* replacement node. Returning `undefined` keeps the original.
*
* The original tree is never mutated, a new tree is returned. Pass
* `depth: 'shallow'` to skip recursion into children.
*
* @example Prefix every operationId
* ```ts
* const next = transform(root, {
* operation(node) {
* return { ...node, operationId: `prefixed_${node.operationId}` }
* },
* })
* ```
*
* @example Replace only the root node
* ```ts
* const next = transform(root, {
* depth: 'shallow',
* input: (node) => ({ ...node, meta: { ...node.meta, title: 'Rewritten' } }),
* })
* ```
*/
declare function transform(node: InputNode, options: TransformOptions): InputNode;
declare function transform(node: OutputNode, options: TransformOptions): OutputNode;
declare function transform(node: OperationNode, options: TransformOptions): OperationNode;
declare function transform(node: SchemaNode, options: TransformOptions): SchemaNode;
declare function transform(node: PropertyNode, options: TransformOptions): PropertyNode;
declare function transform(node: ParameterNode, options: TransformOptions): ParameterNode;
declare function transform(node: ResponseNode, options: TransformOptions): ResponseNode;
declare function transform(node: Node, options: TransformOptions): Node;
/**
* Eager depth-first collection pass. Gathers every non-null value the visitor
* callbacks return into an array.
*
* @example Collect every operationId
* ```ts
* const ids = collect<string>(root, {
* operation(node) {
* return node.operationId
* },
* })
* ```
*/
declare function collect<T>(node: Node, options: CollectOptions<T>): Array<T>;
//#endregion
//#region src/defineMacro.d.ts
/**
* Ordering hint shared by macros and plugins. `pre` runs before unmarked items, `post` after,
* and `undefined` keeps declaration order.
*/
type Enforce = 'pre' | 'post';
/**
* A named, composable transform over the Kubb AST. It carries the same per-kind callbacks as a
* {@link Visitor} (`schema`, `operation`, …), plus a `name`, an optional `enforce` order, and an
* optional `when` gate. Macros run on the shared AST, so the same macro works across every adapter
* and output target. Exports follow the `macro<Name>` convention, mirroring plugins (`pluginTs`).
*/
type Macro = Visitor & {
/**
* Macro identifier used to tell macros apart, for example `'simplify-union'`.
*/
name: string;
/**
* Ordering hint. `pre` macros run before unmarked macros, `post` macros run after.
* Ordering within a bucket follows list order.
*/
enforce?: Enforce;
/**
* Gate checked against the current node before any callback runs. When it returns `false`
* the macro is skipped for that node.
*/
when?: (node: Node) => boolean;
};
/**
* Types a macro for inference and a single construction site, mirroring `definePlugin`.
* Adds no runtime behavior.
*
* @example
* ```ts
* const macroUntagged = defineMacro({
* name: 'untagged',
* operation(node) {
* return node.tags?.length ? undefined : { ...node, tags: ['untagged'] }
* },
* })
* ```
*/
declare function defineMacro(macro: Macro): Macro;
/**
* Folds an ordered list of macros into a single {@link Visitor} that `transform` (and the per-plugin
* transform layer in `@kubb/core`) can run. Macros are stable-sorted by `enforce`, then applied
* sequentially per node so later macros see earlier output. This differs from a plain visitor, which
* has no names, ordering, or composition.
*
* @example
* ```ts
* const visitor = composeMacros([macroSimplifyUnion, macroDiscriminatorEnum])
* const next = transform(root, visitor)
* ```
*/
declare function composeMacros(macros: ReadonlyArray<Macro>): Visitor;
/**
* Runs a list of macros over a node tree and returns the rewritten tree. Keeps `transform`'s
* structural sharing, so an empty or no-op macro list returns the same reference. Pass
* `depth: 'shallow'` to rewrite the root node only.
*
* @example
* ```ts
* const next = applyMacros(root, [macroIntegerToString])
* ```
*
* @example Apply to the root node only
* ```ts
* const named = applyMacros(node, [macroEnumName({ parentName, propName, enumSuffix })], { depth: 'shallow' })
* ```
*/
declare function applyMacros<TNode extends Node>(root: TNode, macros: ReadonlyArray<Macro>, options?: {
depth?: VisitorDepth;
}): TNode;
//#endregion
export { defineMacro as a, VisitorContext as c, walk as d, schemaTypes as f, composeMacros as i, collect as l, Macro as n, ParentOf as o, applyMacros as r, Visitor as s, Enforce as t, transform as u };
//# sourceMappingURL=defineMacro-BXpTwp0y.d.ts.map
import "./rolldown-runtime-CNktS9qV.js";
import { r as transform, st as visitorKeys } from "./visitor-dcVC5TOW.js";
//#region src/defineMacro.ts
/**
* Sort weight for an `enforce` hint. `pre` sorts before unmarked items and `post` after, so a plain
* list keeps its authored order.
*/
function enforceWeight(enforce) {
if (enforce === "pre") return 0;
if (enforce === "post") return 2;
return 1;
}
/**
* Types a macro for inference and a single construction site, mirroring `definePlugin`.
* Adds no runtime behavior.
*
* @example
* ```ts
* const macroUntagged = defineMacro({
* name: 'untagged',
* operation(node) {
* return node.tags?.length ? undefined : { ...node, tags: ['untagged'] }
* },
* })
* ```
*/
function defineMacro(macro) {
return macro;
}
/**
* Runs every macro's callback for one node kind in order, chaining the result so each macro sees
* the previous macro's output. Returns `undefined` when nothing changed, so `transform` keeps the
* original reference (structural sharing).
*/
function chain({ macros, key, node, context }) {
let current = node;
for (const macro of macros) {
const callback = macro[key];
if (!callback) continue;
if (macro.when && !macro.when(current)) continue;
const next = callback(current, context);
if (next != null) current = next;
}
return current === node ? void 0 : current;
}
/**
* Folds an ordered list of macros into a single {@link Visitor} that `transform` (and the per-plugin
* transform layer in `@kubb/core`) can run. Macros are stable-sorted by `enforce`, then applied
* sequentially per node so later macros see earlier output. This differs from a plain visitor, which
* has no names, ordering, or composition.
*
* @example
* ```ts
* const visitor = composeMacros([macroSimplifyUnion, macroDiscriminatorEnum])
* const next = transform(root, visitor)
* ```
*/
function composeMacros(macros) {
const ordered = [...macros].sort((a, b) => enforceWeight(a.enforce) - enforceWeight(b.enforce));
const visitor = {};
for (const key of visitorKeys) {
if (!ordered.some((macro) => typeof macro[key] === "function")) continue;
const callback = (node, context) => chain({
macros: ordered,
key,
node,
context
});
visitor[key] = callback;
}
return visitor;
}
/**
* Runs a list of macros over a node tree and returns the rewritten tree. Keeps `transform`'s
* structural sharing, so an empty or no-op macro list returns the same reference. Pass
* `depth: 'shallow'` to rewrite the root node only.
*
* @example
* ```ts
* const next = applyMacros(root, [macroIntegerToString])
* ```
*
* @example Apply to the root node only
* ```ts
* const named = applyMacros(node, [macroEnumName({ parentName, propName, enumSuffix })], { depth: 'shallow' })
* ```
*/
function applyMacros(root, macros, options) {
if (macros.length === 0) return root;
return transform(root, {
...composeMacros(macros),
...options
});
}
//#endregion
export { composeMacros as n, defineMacro as r, applyMacros as t };
//# sourceMappingURL=defineMacro-VfsvblGi.js.map
{"version":3,"file":"defineMacro-VfsvblGi.js","names":[],"sources":["../src/defineMacro.ts"],"sourcesContent":["import type { VisitorDepth } from './constants.ts'\nimport type { VisitorKey } from './defineNode.ts'\nimport { visitorKeys } from './defineNode.ts'\nimport type { Node } from './nodes/index.ts'\nimport type { Visitor, VisitorContext } from './visitor.ts'\nimport { transform } from './visitor.ts'\n\n/**\n * Ordering hint shared by macros and plugins. `pre` runs before unmarked items, `post` after,\n * and `undefined` keeps declaration order.\n */\nexport type Enforce = 'pre' | 'post'\n\n/**\n * Sort weight for an `enforce` hint. `pre` sorts before unmarked items and `post` after, so a plain\n * list keeps its authored order.\n */\nfunction enforceWeight(enforce?: Enforce): number {\n if (enforce === 'pre') return 0\n if (enforce === 'post') return 2\n return 1\n}\n\n/**\n * A named, composable transform over the Kubb AST. It carries the same per-kind callbacks as a\n * {@link Visitor} (`schema`, `operation`, …), plus a `name`, an optional `enforce` order, and an\n * optional `when` gate. Macros run on the shared AST, so the same macro works across every adapter\n * and output target. Exports follow the `macro<Name>` convention, mirroring plugins (`pluginTs`).\n */\nexport type Macro = Visitor & {\n /**\n * Macro identifier used to tell macros apart, for example `'simplify-union'`.\n */\n name: string\n /**\n * Ordering hint. `pre` macros run before unmarked macros, `post` macros run after.\n * Ordering within a bucket follows list order.\n */\n enforce?: Enforce\n /**\n * Gate checked against the current node before any callback runs. When it returns `false`\n * the macro is skipped for that node.\n */\n when?: (node: Node) => boolean\n}\n\n/**\n * Types a macro for inference and a single construction site, mirroring `definePlugin`.\n * Adds no runtime behavior.\n *\n * @example\n * ```ts\n * const macroUntagged = defineMacro({\n * name: 'untagged',\n * operation(node) {\n * return node.tags?.length ? undefined : { ...node, tags: ['untagged'] }\n * },\n * })\n * ```\n */\nexport function defineMacro(macro: Macro): Macro {\n return macro\n}\n\ntype MacroCallback = (node: Node, context: VisitorContext) => Node | null | undefined\n\ntype ChainProps = {\n macros: ReadonlyArray<Macro>\n key: VisitorKey\n node: Node\n context: VisitorContext\n}\n\n/**\n * Runs every macro's callback for one node kind in order, chaining the result so each macro sees\n * the previous macro's output. Returns `undefined` when nothing changed, so `transform` keeps the\n * original reference (structural sharing).\n */\nfunction chain({ macros, key, node, context }: ChainProps): Node | undefined {\n let current = node\n\n for (const macro of macros) {\n const callback = macro[key] as MacroCallback | undefined\n if (!callback) continue\n if (macro.when && !macro.when(current)) continue\n\n const next = callback(current, context)\n if (next != null) current = next\n }\n\n return current === node ? undefined : current\n}\n\n/**\n * Folds an ordered list of macros into a single {@link Visitor} that `transform` (and the per-plugin\n * transform layer in `@kubb/core`) can run. Macros are stable-sorted by `enforce`, then applied\n * sequentially per node so later macros see earlier output. This differs from a plain visitor, which\n * has no names, ordering, or composition.\n *\n * @example\n * ```ts\n * const visitor = composeMacros([macroSimplifyUnion, macroDiscriminatorEnum])\n * const next = transform(root, visitor)\n * ```\n */\nexport function composeMacros(macros: ReadonlyArray<Macro>): Visitor {\n const ordered = [...macros].sort((a, b) => enforceWeight(a.enforce) - enforceWeight(b.enforce))\n\n const visitor: Visitor = {}\n for (const key of visitorKeys) {\n if (!ordered.some((macro) => typeof macro[key] === 'function')) continue\n\n const callback = (node: Node, context: VisitorContext) => chain({ macros: ordered, key, node, context })\n ;(visitor as Record<VisitorKey, MacroCallback>)[key] = callback\n }\n\n return visitor\n}\n\n/**\n * Runs a list of macros over a node tree and returns the rewritten tree. Keeps `transform`'s\n * structural sharing, so an empty or no-op macro list returns the same reference. Pass\n * `depth: 'shallow'` to rewrite the root node only.\n *\n * @example\n * ```ts\n * const next = applyMacros(root, [macroIntegerToString])\n * ```\n *\n * @example Apply to the root node only\n * ```ts\n * const named = applyMacros(node, [macroEnumName({ parentName, propName, enumSuffix })], { depth: 'shallow' })\n * ```\n */\nexport function applyMacros<TNode extends Node>(root: TNode, macros: ReadonlyArray<Macro>, options?: { depth?: VisitorDepth }): TNode {\n if (macros.length === 0) return root\n\n return transform(root, { ...composeMacros(macros), ...options }) as TNode\n}\n"],"mappings":";;;;;;;AAiBA,SAAS,cAAc,SAA2B;CAChD,IAAI,YAAY,OAAO,OAAO;CAC9B,IAAI,YAAY,QAAQ,OAAO;CAC/B,OAAO;AACT;;;;;;;;;;;;;;;AAuCA,SAAgB,YAAY,OAAqB;CAC/C,OAAO;AACT;;;;;;AAgBA,SAAS,MAAM,EAAE,QAAQ,KAAK,MAAM,WAAyC;CAC3E,IAAI,UAAU;CAEd,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,WAAW,MAAM;EACvB,IAAI,CAAC,UAAU;EACf,IAAI,MAAM,QAAQ,CAAC,MAAM,KAAK,OAAO,GAAG;EAExC,MAAM,OAAO,SAAS,SAAS,OAAO;EACtC,IAAI,QAAQ,MAAM,UAAU;CAC9B;CAEA,OAAO,YAAY,OAAO,KAAA,IAAY;AACxC;;;;;;;;;;;;;AAcA,SAAgB,cAAc,QAAuC;CACnE,MAAM,UAAU,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,GAAG,MAAM,cAAc,EAAE,OAAO,IAAI,cAAc,EAAE,OAAO,CAAC;CAE9F,MAAM,UAAmB,CAAC;CAC1B,KAAK,MAAM,OAAO,aAAa;EAC7B,IAAI,CAAC,QAAQ,MAAM,UAAU,OAAO,MAAM,SAAS,UAAU,GAAG;EAEhE,MAAM,YAAY,MAAY,YAA4B,MAAM;GAAE,QAAQ;GAAS;GAAK;GAAM;EAAQ,CAAC;EACtG,QAA+C,OAAO;CACzD;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;AAiBA,SAAgB,YAAgC,MAAa,QAA8B,SAA2C;CACpI,IAAI,OAAO,WAAW,GAAG,OAAO;CAEhC,OAAO,UAAU,MAAM;EAAE,GAAG,cAAc,MAAM;EAAG,GAAG;CAAQ,CAAC;AACjE"}

Sorry, the diff of this file is too big to display

import { n as __name } from "./rolldown-runtime-CNktS9qV.js";
import { C as ParameterNode, O as FunctionParameterNode, f as OperationNode, k as FunctionParametersNode } from "./index-DJEyS5y6.js";
//#region src/utils/operationParams.d.ts
/**
* Applies casing rules to parameter names and returns a new array without mutating the input.
*
* Run it before handing parameters to schema builders so output property keys get the right casing
* while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the
* original array is returned unchanged.
*/
declare function caseParams(params: Array<ParameterNode>, casing: 'camelcase' | undefined): Array<ParameterNode>;
/**
* Resolver interface for {@link createOperationParams}.
*
* `ResolverTs` from `@kubb/plugin-ts` satisfies this interface and can be passed directly.
*/
type OperationParamsResolver = {
/**
* Resolves the type name for an individual parameter.
*
* @example Individual path parameter name
* `resolver.resolveParamName(node, param) // → 'DeletePetPathPetId'`
*/
resolveParamName(node: OperationNode, param: ParameterNode): string;
/**
* Resolves the request body type name.
*
* @example Request body type name
* `resolver.resolveDataName(node) // → 'CreatePetData'`
*/
resolveDataName(node: OperationNode): string;
/**
* Resolves the grouped path parameters type name.
* When the return value equals `resolveParamName`, no indexed access is emitted.
*
* @example Grouped path params type name
* `resolver.resolvePathParamsName(node, param) // → 'DeletePetPathParams'`
*/
resolvePathParamsName(node: OperationNode, param: ParameterNode): string;
/**
* Resolves the grouped query parameters type name.
* When the return value equals `resolveParamName`, an inline struct type is emitted instead.
*
* @example Grouped query params type name
* `resolver.resolveQueryParamsName(node, param) // → 'FindPetsByStatusQueryParams'`
*/
resolveQueryParamsName(node: OperationNode, param: ParameterNode): string;
/**
* Resolves the grouped header parameters type name.
* When the return value equals `resolveParamName`, an inline struct type is emitted instead.
*
* @example Grouped header params type name
* `resolver.resolveHeaderParamsName(node, param) // → 'DeletePetHeaderParams'`
*/
resolveHeaderParamsName(node: OperationNode, param: ParameterNode): string;
};
/**
* Options for {@link createOperationParams}.
*/
type CreateOperationParamsOptions = {
/**
* How all operation parameters are grouped in the function signature.
* - `'object'` wraps all params into a single destructured object `{ petId, data, params }`
* - `'inline'` emits each param category as a separate top-level parameter
*/
paramsType: 'object' | 'inline';
/**
* How path parameters are emitted when `paramsType` is `'inline'`.
* - `'object'` groups them as `{ petId, storeId }: PathParams`
* - `'inline'` spreads them as individual parameters `petId: string, storeId: string`
* - `'inlineSpread'` emits a single rest parameter `...pathParams: PathParams`
*/
pathParamsType: 'object' | 'inline' | 'inlineSpread';
/**
* Converts parameter names to camelCase before output.
*/
paramsCasing?: 'camelcase';
/**
* Resolver for parameter and request body type names.
* Pass `ResolverTs` from `@kubb/plugin-ts` directly.
* When omitted, falls back to the schema primitive or `'unknown'`.
*/
resolver?: OperationParamsResolver;
/**
* Default value for the path parameters binding when `pathParamsType` is `'object'`.
* Falls back to `'{}'` when all path params are optional.
*/
pathParamsDefault?: string;
/**
* Extra parameters appended after the standard operation parameters.
*
* @example Plugin-specific trailing parameter
* ```ts
* extraParams: [createFunctionParameter({ name: 'options', type: 'Partial<RequestOptions>', default: '{}' })]
* ```
*/
extraParams?: Array<FunctionParameterNode>;
/**
* Override the default parameter names used for body, query, header, and rest-path groups.
*
* Useful when targeting languages or frameworks with different naming conventions.
*
* @default { data: 'data', params: 'params', headers: 'headers', path: 'pathParams' }
*/
paramNames?: {
/**
* Name for the request body parameter.
* @default 'data'
*/
data?: string;
/**
* Name for the query parameters group parameter.
* @default 'params'
*/
params?: string;
/**
* Name for the header parameters group parameter.
* @default 'headers'
*/
headers?: string;
/**
* Name for the rest path-parameters parameter when `pathParamsType` is `'inlineSpread'`.
* @default 'pathParams'
*/
path?: string;
};
/**
* Transforms every resolved type name before it lands in a parameter node, for framework-level
* type wrappers.
*
* @example Vue Query, wrap every parameter type with `MaybeRefOrGetter`
* `typeWrapper: (t) => \`MaybeRefOrGetter<${t}>\``
*/
typeWrapper?: (type: string) => string;
};
/**
* Converts an `OperationNode` into function parameters for code generation.
*
* Centralizes parameter grouping logic for all plugins. `paramsType` chooses between one
* destructured object parameter (`object`) and separate top-level parameters (`inline`), while
* `pathParamsType` controls how path params render in inline mode. Provide a `resolver` for type
* name resolution and `extraParams` for plugin-specific trailing parameters such as an `options` object.
*/
declare function createOperationParams(node: OperationNode, options: CreateOperationParamsOptions): FunctionParametersNode;
//#endregion
export { caseParams as n, createOperationParams as r, OperationParamsResolver as t };
//# sourceMappingURL=operationParams-BaY12i2I.d.ts.map
import "./rolldown-runtime-CNktS9qV.js";
import { U as pascalCase, lt as narrowSchema, o as createSchema } from "./visitor-dcVC5TOW.js";
//#region src/utils/refs.ts
const plainStringTypes = new Set([
"string",
"uuid",
"email",
"url",
"datetime"
]);
/**
* Returns the last path segment of a reference string.
*
* @example
* `extractRefName('#/components/schemas/Pet') // 'Pet'`
*/
function extractRefName(ref) {
return ref.split("/").at(-1) ?? ref;
}
/**
* Resolves the schema name of a ref node. Uses the last segment of `ref` when set, otherwise falls
* back to `name` then nested `schema.name`.
*
* Returns `null` for non-ref nodes or when no name resolves.
*
* @example
* `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Pet' }) // 'Pet'`
*/
function resolveRefName(node) {
if (!node || node.type !== "ref") return null;
if (node.ref) return extractRefName(node.ref) ?? node.name ?? node.schema?.name ?? null;
return node.name ?? node.schema?.name ?? null;
}
/**
* Builds a PascalCase child schema name by joining a parent name and property name.
* Returns `null` when there is no parent to nest under.
*
* @example Nested under a parent
* `childName('Order', 'shipping_address') // 'OrderShippingAddress'`
*
* @example No parent
* `childName(undefined, 'params') // null`
*/
function childName(parentName, propName) {
return parentName ? pascalCase([parentName, propName].join(" ")) : null;
}
/**
* Builds a PascalCase enum name from the parent name, property name, and a suffix, skipping any
* empty parts.
*
* @example
* `enumPropName('Order', 'status', 'enum') // 'OrderStatusEnum'`
*/
function enumPropName(parentName, propName, enumSuffix) {
return pascalCase([
parentName,
propName,
enumSuffix
].filter(Boolean).join(" "));
}
/**
* Merges a ref node with its resolved schema, giving usage-site fields precedence.
*
* Every field set on the ref node except `kind`, `type`, `name`, `ref`, and `schema` overrides the
* same field in the resolved `node.schema` (for example `description`, `nullable`, `readOnly`,
* `deprecated`). Fields left `undefined` on the ref do not shadow the resolved schema. Non-ref
* nodes and refs without a resolved `schema` are returned unchanged.
*
* @example
* ```ts
* const ref = createSchema({ type: 'ref', ref: '#/components/schemas/Pet', description: 'A cute pet' })
* const merged = syncSchemaRef(ref) // merges with resolved Pet schema
* ```
*/
function syncSchemaRef(node) {
const ref = narrowSchema(node, "ref");
if (!ref) return node;
if (!ref.schema) return node;
const { kind: _kind, type: _type, name: _name, ref: _ref, schema: _schema, ...overrides } = ref;
const definedOverrides = Object.fromEntries(Object.entries(overrides).filter(([, v]) => v !== void 0));
return createSchema({
...ref.schema,
...definedOverrides
});
}
/**
* Type guard that returns `true` when a schema emits as a plain `string` type.
*
* Covers `string`, `uuid`, `email`, `url`, and `datetime` types. For `date` and `time`
* types, returns `true` only when `representation` is `'string'` rather than `'date'`.
*/
function isStringType(node) {
if (plainStringTypes.has(node.type)) return true;
const temporal = narrowSchema(node, "date") ?? narrowSchema(node, "time");
if (temporal) return temporal.representation !== "date";
return false;
}
/**
* Derives a {@link ParamGroupType} for a query or header group from the resolver.
*
* Returns `null` when there is no resolver, no params, or the group name equals the
* individual param name (so there is no real group to emit).
*/
function resolveGroupType({ node, params, group, resolver }) {
if (!resolver || !params.length) return null;
const firstParam = params[0];
const groupName = (group === "query" ? resolver.resolveQueryParamsName : resolver.resolveHeaderParamsName).call(resolver, node, firstParam);
if (groupName === resolver.resolveParamName(node, firstParam)) return null;
return {
type: groupName,
optional: params.every((p) => !p.required)
};
}
//#endregion
export { resolveGroupType as a, isStringType as i, enumPropName as n, resolveRefName as o, extractRefName as r, syncSchemaRef as s, childName as t };
//# sourceMappingURL=refs-D18OeCgb.js.map
{"version":3,"file":"refs-D18OeCgb.js","names":[],"sources":["../src/utils/refs.ts"],"sourcesContent":["import { pascalCase } from '@internals/utils'\nimport { narrowSchema } from '../guards.ts'\nimport type { OperationNode, ParameterNode, SchemaNode } from '../nodes/index.ts'\nimport { createSchema, type SchemaType } from '../nodes/schema.ts'\nimport type { OperationParamsResolver, ParamGroupType } from './operationParams.ts'\n\nconst plainStringTypes = new Set<SchemaType>(['string', 'uuid', 'email', 'url', 'datetime'] as const)\n\n/**\n * Returns the last path segment of a reference string.\n *\n * @example\n * `extractRefName('#/components/schemas/Pet') // 'Pet'`\n */\nexport function extractRefName(ref: string): string {\n return ref.split('/').at(-1) ?? ref\n}\n\n/**\n * Resolves the schema name of a ref node. Uses the last segment of `ref` when set, otherwise falls\n * back to `name` then nested `schema.name`.\n *\n * Returns `null` for non-ref nodes or when no name resolves.\n *\n * @example\n * `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Pet' }) // 'Pet'`\n */\nexport function resolveRefName(node: SchemaNode | undefined): string | null {\n if (!node || node.type !== 'ref') return null\n if (node.ref) return extractRefName(node.ref) ?? node.name ?? node.schema?.name ?? null\n\n return node.name ?? node.schema?.name ?? null\n}\n\n/**\n * Builds a PascalCase child schema name by joining a parent name and property name.\n * Returns `null` when there is no parent to nest under.\n *\n * @example Nested under a parent\n * `childName('Order', 'shipping_address') // 'OrderShippingAddress'`\n *\n * @example No parent\n * `childName(undefined, 'params') // null`\n */\nexport function childName(parentName: string | null | undefined, propName: string): string | null {\n return parentName ? pascalCase([parentName, propName].join(' ')) : null\n}\n\n/**\n * Builds a PascalCase enum name from the parent name, property name, and a suffix, skipping any\n * empty parts.\n *\n * @example\n * `enumPropName('Order', 'status', 'enum') // 'OrderStatusEnum'`\n */\nexport function enumPropName(parentName: string | null | undefined, propName: string, enumSuffix: string): string {\n return pascalCase([parentName, propName, enumSuffix].filter(Boolean).join(' '))\n}\n\n/**\n * Merges a ref node with its resolved schema, giving usage-site fields precedence.\n *\n * Every field set on the ref node except `kind`, `type`, `name`, `ref`, and `schema` overrides the\n * same field in the resolved `node.schema` (for example `description`, `nullable`, `readOnly`,\n * `deprecated`). Fields left `undefined` on the ref do not shadow the resolved schema. Non-ref\n * nodes and refs without a resolved `schema` are returned unchanged.\n *\n * @example\n * ```ts\n * const ref = createSchema({ type: 'ref', ref: '#/components/schemas/Pet', description: 'A cute pet' })\n * const merged = syncSchemaRef(ref) // merges with resolved Pet schema\n * ```\n */\nexport function syncSchemaRef(node: SchemaNode): SchemaNode {\n const ref = narrowSchema(node, 'ref')\n\n if (!ref) return node\n if (!ref.schema) return node\n\n const { kind: _kind, type: _type, name: _name, ref: _ref, schema: _schema, ...overrides } = ref\n\n // Filter out undefined override values so they don't shadow the resolved schema's fields.\n const definedOverrides = Object.fromEntries(Object.entries(overrides).filter(([, v]) => v !== undefined))\n\n return createSchema({ ...ref.schema, ...definedOverrides })\n}\n\n/**\n * Type guard that returns `true` when a schema emits as a plain `string` type.\n *\n * Covers `string`, `uuid`, `email`, `url`, and `datetime` types. For `date` and `time`\n * types, returns `true` only when `representation` is `'string'` rather than `'date'`.\n */\nexport function isStringType(node: SchemaNode): boolean {\n if (plainStringTypes.has(node.type)) {\n return true\n }\n\n const temporal = narrowSchema(node, 'date') ?? narrowSchema(node, 'time')\n if (temporal) {\n return temporal.representation !== 'date'\n }\n\n return false\n}\n\n/**\n * Derives a {@link ParamGroupType} for a query or header group from the resolver.\n *\n * Returns `null` when there is no resolver, no params, or the group name equals the\n * individual param name (so there is no real group to emit).\n */\nexport function resolveGroupType({\n node,\n params,\n group,\n resolver,\n}: {\n node: OperationNode\n params: Array<ParameterNode>\n group: 'query' | 'header'\n resolver: OperationParamsResolver | undefined\n}): ParamGroupType | null {\n if (!resolver || !params.length) {\n return null\n }\n const firstParam = params[0]!\n const groupMethod = group === 'query' ? resolver.resolveQueryParamsName : resolver.resolveHeaderParamsName\n const groupName = groupMethod.call(resolver, node, firstParam)\n if (groupName === resolver.resolveParamName(node, firstParam)) {\n return null\n }\n return { type: groupName, optional: params.every((p) => !p.required) }\n}\n"],"mappings":";;;AAMA,MAAM,mBAAmB,IAAI,IAAgB;CAAC;CAAU;CAAQ;CAAS;CAAO;AAAU,CAAU;;;;;;;AAQpG,SAAgB,eAAe,KAAqB;CAClD,OAAO,IAAI,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK;AAClC;;;;;;;;;;AAWA,SAAgB,eAAe,MAA6C;CAC1E,IAAI,CAAC,QAAQ,KAAK,SAAS,OAAO,OAAO;CACzC,IAAI,KAAK,KAAK,OAAO,eAAe,KAAK,GAAG,KAAK,KAAK,QAAQ,KAAK,QAAQ,QAAQ;CAEnF,OAAO,KAAK,QAAQ,KAAK,QAAQ,QAAQ;AAC3C;;;;;;;;;;;AAYA,SAAgB,UAAU,YAAuC,UAAiC;CAChG,OAAO,aAAa,WAAW,CAAC,YAAY,QAAQ,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI;AACrE;;;;;;;;AASA,SAAgB,aAAa,YAAuC,UAAkB,YAA4B;CAChH,OAAO,WAAW;EAAC;EAAY;EAAU;CAAU,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC;AAChF;;;;;;;;;;;;;;;AAgBA,SAAgB,cAAc,MAA8B;CAC1D,MAAM,MAAM,aAAa,MAAM,KAAK;CAEpC,IAAI,CAAC,KAAK,OAAO;CACjB,IAAI,CAAC,IAAI,QAAQ,OAAO;CAExB,MAAM,EAAE,MAAM,OAAO,MAAM,OAAO,MAAM,OAAO,KAAK,MAAM,QAAQ,SAAS,GAAG,cAAc;CAG5F,MAAM,mBAAmB,OAAO,YAAY,OAAO,QAAQ,SAAS,CAAC,CAAC,QAAQ,GAAG,OAAO,MAAM,KAAA,CAAS,CAAC;CAExG,OAAO,aAAa;EAAE,GAAG,IAAI;EAAQ,GAAG;CAAiB,CAAC;AAC5D;;;;;;;AAQA,SAAgB,aAAa,MAA2B;CACtD,IAAI,iBAAiB,IAAI,KAAK,IAAI,GAChC,OAAO;CAGT,MAAM,WAAW,aAAa,MAAM,MAAM,KAAK,aAAa,MAAM,MAAM;CACxE,IAAI,UACF,OAAO,SAAS,mBAAmB;CAGrC,OAAO;AACT;;;;;;;AAQA,SAAgB,iBAAiB,EAC/B,MACA,QACA,OACA,YAMwB;CACxB,IAAI,CAAC,YAAY,CAAC,OAAO,QACvB,OAAO;CAET,MAAM,aAAa,OAAO;CAE1B,MAAM,aADc,UAAU,UAAU,SAAS,yBAAyB,SAAS,wBAAA,CACrD,KAAK,UAAU,MAAM,UAAU;CAC7D,IAAI,cAAc,SAAS,iBAAiB,MAAM,UAAU,GAC1D,OAAO;CAET,OAAO;EAAE,MAAM;EAAW,UAAU,OAAO,OAAO,MAAM,CAAC,EAAE,QAAQ;CAAE;AACvE"}
const require_visitor = require("./visitor-CQdSiClY.cjs");
//#region src/utils/refs.ts
const plainStringTypes = new Set([
"string",
"uuid",
"email",
"url",
"datetime"
]);
/**
* Returns the last path segment of a reference string.
*
* @example
* `extractRefName('#/components/schemas/Pet') // 'Pet'`
*/
function extractRefName(ref) {
return ref.split("/").at(-1) ?? ref;
}
/**
* Resolves the schema name of a ref node. Uses the last segment of `ref` when set, otherwise falls
* back to `name` then nested `schema.name`.
*
* Returns `null` for non-ref nodes or when no name resolves.
*
* @example
* `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Pet' }) // 'Pet'`
*/
function resolveRefName(node) {
if (!node || node.type !== "ref") return null;
if (node.ref) return extractRefName(node.ref) ?? node.name ?? node.schema?.name ?? null;
return node.name ?? node.schema?.name ?? null;
}
/**
* Builds a PascalCase child schema name by joining a parent name and property name.
* Returns `null` when there is no parent to nest under.
*
* @example Nested under a parent
* `childName('Order', 'shipping_address') // 'OrderShippingAddress'`
*
* @example No parent
* `childName(undefined, 'params') // null`
*/
function childName(parentName, propName) {
return parentName ? require_visitor.pascalCase([parentName, propName].join(" ")) : null;
}
/**
* Builds a PascalCase enum name from the parent name, property name, and a suffix, skipping any
* empty parts.
*
* @example
* `enumPropName('Order', 'status', 'enum') // 'OrderStatusEnum'`
*/
function enumPropName(parentName, propName, enumSuffix) {
return require_visitor.pascalCase([
parentName,
propName,
enumSuffix
].filter(Boolean).join(" "));
}
/**
* Merges a ref node with its resolved schema, giving usage-site fields precedence.
*
* Every field set on the ref node except `kind`, `type`, `name`, `ref`, and `schema` overrides the
* same field in the resolved `node.schema` (for example `description`, `nullable`, `readOnly`,
* `deprecated`). Fields left `undefined` on the ref do not shadow the resolved schema. Non-ref
* nodes and refs without a resolved `schema` are returned unchanged.
*
* @example
* ```ts
* const ref = createSchema({ type: 'ref', ref: '#/components/schemas/Pet', description: 'A cute pet' })
* const merged = syncSchemaRef(ref) // merges with resolved Pet schema
* ```
*/
function syncSchemaRef(node) {
const ref = require_visitor.narrowSchema(node, "ref");
if (!ref) return node;
if (!ref.schema) return node;
const { kind: _kind, type: _type, name: _name, ref: _ref, schema: _schema, ...overrides } = ref;
const definedOverrides = Object.fromEntries(Object.entries(overrides).filter(([, v]) => v !== void 0));
return require_visitor.createSchema({
...ref.schema,
...definedOverrides
});
}
/**
* Type guard that returns `true` when a schema emits as a plain `string` type.
*
* Covers `string`, `uuid`, `email`, `url`, and `datetime` types. For `date` and `time`
* types, returns `true` only when `representation` is `'string'` rather than `'date'`.
*/
function isStringType(node) {
if (plainStringTypes.has(node.type)) return true;
const temporal = require_visitor.narrowSchema(node, "date") ?? require_visitor.narrowSchema(node, "time");
if (temporal) return temporal.representation !== "date";
return false;
}
/**
* Derives a {@link ParamGroupType} for a query or header group from the resolver.
*
* Returns `null` when there is no resolver, no params, or the group name equals the
* individual param name (so there is no real group to emit).
*/
function resolveGroupType({ node, params, group, resolver }) {
if (!resolver || !params.length) return null;
const firstParam = params[0];
const groupName = (group === "query" ? resolver.resolveQueryParamsName : resolver.resolveHeaderParamsName).call(resolver, node, firstParam);
if (groupName === resolver.resolveParamName(node, firstParam)) return null;
return {
type: groupName,
optional: params.every((p) => !p.required)
};
}
//#endregion
Object.defineProperty(exports, "childName", {
enumerable: true,
get: function() {
return childName;
}
});
Object.defineProperty(exports, "enumPropName", {
enumerable: true,
get: function() {
return enumPropName;
}
});
Object.defineProperty(exports, "extractRefName", {
enumerable: true,
get: function() {
return extractRefName;
}
});
Object.defineProperty(exports, "isStringType", {
enumerable: true,
get: function() {
return isStringType;
}
});
Object.defineProperty(exports, "resolveGroupType", {
enumerable: true,
get: function() {
return resolveGroupType;
}
});
Object.defineProperty(exports, "resolveRefName", {
enumerable: true,
get: function() {
return resolveRefName;
}
});
Object.defineProperty(exports, "syncSchemaRef", {
enumerable: true,
get: function() {
return syncSchemaRef;
}
});
//# sourceMappingURL=refs-DuP3_Leg.cjs.map
{"version":3,"file":"refs-DuP3_Leg.cjs","names":["pascalCase","narrowSchema","createSchema"],"sources":["../src/utils/refs.ts"],"sourcesContent":["import { pascalCase } from '@internals/utils'\nimport { narrowSchema } from '../guards.ts'\nimport type { OperationNode, ParameterNode, SchemaNode } from '../nodes/index.ts'\nimport { createSchema, type SchemaType } from '../nodes/schema.ts'\nimport type { OperationParamsResolver, ParamGroupType } from './operationParams.ts'\n\nconst plainStringTypes = new Set<SchemaType>(['string', 'uuid', 'email', 'url', 'datetime'] as const)\n\n/**\n * Returns the last path segment of a reference string.\n *\n * @example\n * `extractRefName('#/components/schemas/Pet') // 'Pet'`\n */\nexport function extractRefName(ref: string): string {\n return ref.split('/').at(-1) ?? ref\n}\n\n/**\n * Resolves the schema name of a ref node. Uses the last segment of `ref` when set, otherwise falls\n * back to `name` then nested `schema.name`.\n *\n * Returns `null` for non-ref nodes or when no name resolves.\n *\n * @example\n * `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Pet' }) // 'Pet'`\n */\nexport function resolveRefName(node: SchemaNode | undefined): string | null {\n if (!node || node.type !== 'ref') return null\n if (node.ref) return extractRefName(node.ref) ?? node.name ?? node.schema?.name ?? null\n\n return node.name ?? node.schema?.name ?? null\n}\n\n/**\n * Builds a PascalCase child schema name by joining a parent name and property name.\n * Returns `null` when there is no parent to nest under.\n *\n * @example Nested under a parent\n * `childName('Order', 'shipping_address') // 'OrderShippingAddress'`\n *\n * @example No parent\n * `childName(undefined, 'params') // null`\n */\nexport function childName(parentName: string | null | undefined, propName: string): string | null {\n return parentName ? pascalCase([parentName, propName].join(' ')) : null\n}\n\n/**\n * Builds a PascalCase enum name from the parent name, property name, and a suffix, skipping any\n * empty parts.\n *\n * @example\n * `enumPropName('Order', 'status', 'enum') // 'OrderStatusEnum'`\n */\nexport function enumPropName(parentName: string | null | undefined, propName: string, enumSuffix: string): string {\n return pascalCase([parentName, propName, enumSuffix].filter(Boolean).join(' '))\n}\n\n/**\n * Merges a ref node with its resolved schema, giving usage-site fields precedence.\n *\n * Every field set on the ref node except `kind`, `type`, `name`, `ref`, and `schema` overrides the\n * same field in the resolved `node.schema` (for example `description`, `nullable`, `readOnly`,\n * `deprecated`). Fields left `undefined` on the ref do not shadow the resolved schema. Non-ref\n * nodes and refs without a resolved `schema` are returned unchanged.\n *\n * @example\n * ```ts\n * const ref = createSchema({ type: 'ref', ref: '#/components/schemas/Pet', description: 'A cute pet' })\n * const merged = syncSchemaRef(ref) // merges with resolved Pet schema\n * ```\n */\nexport function syncSchemaRef(node: SchemaNode): SchemaNode {\n const ref = narrowSchema(node, 'ref')\n\n if (!ref) return node\n if (!ref.schema) return node\n\n const { kind: _kind, type: _type, name: _name, ref: _ref, schema: _schema, ...overrides } = ref\n\n // Filter out undefined override values so they don't shadow the resolved schema's fields.\n const definedOverrides = Object.fromEntries(Object.entries(overrides).filter(([, v]) => v !== undefined))\n\n return createSchema({ ...ref.schema, ...definedOverrides })\n}\n\n/**\n * Type guard that returns `true` when a schema emits as a plain `string` type.\n *\n * Covers `string`, `uuid`, `email`, `url`, and `datetime` types. For `date` and `time`\n * types, returns `true` only when `representation` is `'string'` rather than `'date'`.\n */\nexport function isStringType(node: SchemaNode): boolean {\n if (plainStringTypes.has(node.type)) {\n return true\n }\n\n const temporal = narrowSchema(node, 'date') ?? narrowSchema(node, 'time')\n if (temporal) {\n return temporal.representation !== 'date'\n }\n\n return false\n}\n\n/**\n * Derives a {@link ParamGroupType} for a query or header group from the resolver.\n *\n * Returns `null` when there is no resolver, no params, or the group name equals the\n * individual param name (so there is no real group to emit).\n */\nexport function resolveGroupType({\n node,\n params,\n group,\n resolver,\n}: {\n node: OperationNode\n params: Array<ParameterNode>\n group: 'query' | 'header'\n resolver: OperationParamsResolver | undefined\n}): ParamGroupType | null {\n if (!resolver || !params.length) {\n return null\n }\n const firstParam = params[0]!\n const groupMethod = group === 'query' ? resolver.resolveQueryParamsName : resolver.resolveHeaderParamsName\n const groupName = groupMethod.call(resolver, node, firstParam)\n if (groupName === resolver.resolveParamName(node, firstParam)) {\n return null\n }\n return { type: groupName, optional: params.every((p) => !p.required) }\n}\n"],"mappings":";;AAMA,MAAM,mBAAmB,IAAI,IAAgB;CAAC;CAAU;CAAQ;CAAS;CAAO;AAAU,CAAU;;;;;;;AAQpG,SAAgB,eAAe,KAAqB;CAClD,OAAO,IAAI,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK;AAClC;;;;;;;;;;AAWA,SAAgB,eAAe,MAA6C;CAC1E,IAAI,CAAC,QAAQ,KAAK,SAAS,OAAO,OAAO;CACzC,IAAI,KAAK,KAAK,OAAO,eAAe,KAAK,GAAG,KAAK,KAAK,QAAQ,KAAK,QAAQ,QAAQ;CAEnF,OAAO,KAAK,QAAQ,KAAK,QAAQ,QAAQ;AAC3C;;;;;;;;;;;AAYA,SAAgB,UAAU,YAAuC,UAAiC;CAChG,OAAO,aAAaA,gBAAAA,WAAW,CAAC,YAAY,QAAQ,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI;AACrE;;;;;;;;AASA,SAAgB,aAAa,YAAuC,UAAkB,YAA4B;CAChH,OAAOA,gBAAAA,WAAW;EAAC;EAAY;EAAU;CAAU,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC;AAChF;;;;;;;;;;;;;;;AAgBA,SAAgB,cAAc,MAA8B;CAC1D,MAAM,MAAMC,gBAAAA,aAAa,MAAM,KAAK;CAEpC,IAAI,CAAC,KAAK,OAAO;CACjB,IAAI,CAAC,IAAI,QAAQ,OAAO;CAExB,MAAM,EAAE,MAAM,OAAO,MAAM,OAAO,MAAM,OAAO,KAAK,MAAM,QAAQ,SAAS,GAAG,cAAc;CAG5F,MAAM,mBAAmB,OAAO,YAAY,OAAO,QAAQ,SAAS,CAAC,CAAC,QAAQ,GAAG,OAAO,MAAM,KAAA,CAAS,CAAC;CAExG,OAAOC,gBAAAA,aAAa;EAAE,GAAG,IAAI;EAAQ,GAAG;CAAiB,CAAC;AAC5D;;;;;;;AAQA,SAAgB,aAAa,MAA2B;CACtD,IAAI,iBAAiB,IAAI,KAAK,IAAI,GAChC,OAAO;CAGT,MAAM,WAAWD,gBAAAA,aAAa,MAAM,MAAM,KAAKA,gBAAAA,aAAa,MAAM,MAAM;CACxE,IAAI,UACF,OAAO,SAAS,mBAAmB;CAGrC,OAAO;AACT;;;;;;;AAQA,SAAgB,iBAAiB,EAC/B,MACA,QACA,OACA,YAMwB;CACxB,IAAI,CAAC,YAAY,CAAC,OAAO,QACvB,OAAO;CAET,MAAM,aAAa,OAAO;CAE1B,MAAM,aADc,UAAU,UAAU,SAAS,yBAAyB,SAAS,wBAAA,CACrD,KAAK,UAAU,MAAM,UAAU;CAC7D,IAAI,cAAc,SAAS,iBAAiB,MAAM,UAAU,GAC1D,OAAO;CAET,OAAO;EAAE,MAAM;EAAW,UAAU,OAAO,OAAO,MAAM,CAAC,EAAE,QAAQ;CAAE;AACvE"}
import { n as __name } from "./rolldown-runtime-CNktS9qV.js";
import { _t as SchemaNode, vt as SchemaNodeByType, yt as SchemaType } from "./index-DJEyS5y6.js";
//#region src/defineDialect.d.ts
/**
* The spec-specific questions a schema parser answers while turning a source document into Kubb
* AST nodes. The rest of the pipeline is generic JSON Schema, so this is the one seam where
* OpenAPI, AsyncAPI, and plain JSON Schema differ.
*/
type SchemaDialect<TSchema = unknown, TRef = TSchema, TDiscriminated = TSchema, TDocument = unknown> = {
/**
* Whether the schema is nullable.
*/
isNullable(schema?: TSchema): boolean;
/**
* Whether the value is a `$ref` pointer.
*/
isReference(value?: unknown): value is TRef;
/**
* Whether the schema carries a discriminator for polymorphism.
*/
isDiscriminator(value?: unknown): value is TDiscriminated;
/**
* Whether the schema is binary data, converted to a `blob` node.
*/
isBinary(schema: TSchema): boolean;
/**
* Resolves a local `$ref` against the document, or nullish when it cannot.
*/
resolveRef<TResolved>(document: TDocument, ref: string): TResolved | null | undefined;
};
/**
* A spec adapter's dialect. `name` identifies it in logs and diagnostics, and `schema` holds the
* spec-specific schema questions the parser answers.
*/
type Dialect<TSchema = unknown, TRef = TSchema, TDiscriminated = TSchema, TDocument = unknown> = {
/**
* Identifies the dialect in logs and diagnostics.
*/
name: string;
/**
* The spec-specific schema behavior. See {@link SchemaDialect}.
*/
schema: SchemaDialect<TSchema, TRef, TDiscriminated, TDocument>;
};
/**
* Types a {@link Dialect} for an adapter. Adds no runtime behavior and only pins the
* dialect's type for inference.
*
* @example
* ```ts
* export const oasDialect = defineDialect({
* name: 'oas',
* schema: {
* isNullable,
* isReference,
* isDiscriminator,
* isBinary: (schema) => schema.type === 'string' && schema.contentMediaType === 'application/octet-stream',
* resolveRef,
* },
* })
* ```
*/
declare function defineDialect<TSchema, TRef, TDiscriminated, TDocument>(dialect: Dialect<TSchema, TRef, TDiscriminated, TDocument>): Dialect<TSchema, TRef, TDiscriminated, TDocument>;
//#endregion
//#region src/createPrinter.d.ts
/**
* Runtime context passed as `this` to printer handlers.
*
* `this.transform` dispatches to node-level handlers from `nodes`.
*
* @example
* ```ts
* const context: PrinterHandlerContext<string, {}> = {
* options: {},
* transform: () => 'value',
* }
* ```
*/
type PrinterHandlerContext<TOutput, TOptions extends object> = {
/**
* Recursively transform a nested `SchemaNode` to `TOutput` using the node-level handlers.
* Use `this.transform` inside `nodes` handlers and inside the `print` override.
*/
transform: (node: SchemaNode) => TOutput | null;
/**
* Options for this printer instance.
*/
options: TOptions;
};
/**
* Handler for one schema node type.
*
* Use a regular function (not an arrow function) if you need `this`.
*
* @example
* ```ts
* const handler: PrinterHandler<string, {}, 'string'> = function () {
* return 'string'
* }
* ```
*/
type PrinterHandler<TOutput, TOptions extends object, T extends SchemaType = SchemaType> = (this: PrinterHandlerContext<TOutput, TOptions>, node: SchemaNodeByType[T]) => TOutput | null;
/**
* Partial map of per-node-type handler overrides for a printer.
*
* Each key is a `SchemaType` string (e.g. `'date'`, `'string'`).
* Supply only the handlers you want to replace. The printer's built-in
* defaults fill in the rest.
*
* @example
* ```ts
* pluginZod({
* printer: {
* nodes: {
* date(): string {
* return 'z.string().date()'
* },
* } satisfies PrinterPartial<string, PrinterZodOptions>,
* },
* })
* ```
*/
type PrinterPartial<TOutput, TOptions extends object> = Partial<{ [K in SchemaType]: PrinterHandler<TOutput, TOptions, K> }>;
/**
* Generic shape used by `definePrinter`.
*
* - `TName` unique string identifier (e.g. `'zod'`, `'ts'`)
* - `TOptions` options passed to and stored on the printer instance
* - `TOutput` the type emitted by node handlers
* - `TPrintOutput` type returned by public `print` (defaults to `TOutput`)
*
* @example
* ```ts
* type MyPrinter = PrinterFactoryOptions<'my', { strict: boolean }, string>
* ```
*/
type PrinterFactoryOptions<TName extends string = string, TOptions extends object = object, TOutput = unknown, TPrintOutput = TOutput> = {
name: TName;
options: TOptions;
output: TOutput;
printOutput: TPrintOutput;
};
/**
* Printer instance returned by a printer factory.
*
* @example
* ```ts
* const printer = definePrinter((options: {}) => ({ name: 'x', options, nodes: {} }))({})
* ```
*/
type Printer<T extends PrinterFactoryOptions = PrinterFactoryOptions> = {
/**
* Unique identifier supplied at creation time.
*/
name: T['name'];
/**
* Options for this printer instance.
*/
options: T['options'];
/**
* Node-level dispatcher, converts a `SchemaNode` directly to `TOutput` using the `nodes` handlers.
* Always dispatches through the `nodes` map. Never calls the `print` override.
* Reach for it when you need the raw output (e.g. `ts.TypeNode`) without declaration wrapping.
*/
transform: (node: SchemaNode) => T['output'] | null;
/**
* Public printer. If the builder provides a root-level `print`, this calls that
* higher-level function (which may produce full declarations).
* Otherwise, falls back to the node-level dispatcher.
*/
print: (node: SchemaNode) => T['printOutput'] | null;
};
/**
* Builder function passed to `definePrinter`.
*
* It receives resolved options and returns:
* - `name`
* - `options`
* - `nodes` handlers
* - optional top-level `print` override
*
* @example
* ```ts
* const build = (options: {}) => ({ name: 'x' as const, options, nodes: {} })
* ```
*/
type PrinterBuilder<T extends PrinterFactoryOptions> = (options: T['options']) => {
name: T['name'];
/**
* Options to store on the printer.
*/
options: T['options'];
nodes: Partial<{ [K in SchemaType]: PrinterHandler<T['output'], T['options'], K> }>;
/**
* Optional root-level print override. When provided, becomes the public `printer.print`.
* Use `this.transform(node)` inside this function to dispatch to the node-level handlers (`nodes`),
* not the override itself, so recursion is safe.
*/
print?: (this: PrinterHandlerContext<T['output'], T['options']>, node: SchemaNode) => T['printOutput'] | null;
};
/**
* Creates a schema printer: a function that takes a `SchemaNode` and emits
* code in your target language. Each plugin that produces code from schemas
* (TypeScript types, Zod schemas, Faker factories) ships a printer built
* with this helper.
*
* The builder receives resolved options and returns:
*
* - `name` unique identifier for the printer.
* - `options` stored on the returned printer instance.
* - `nodes` map of `SchemaType` → handler. Handlers return the rendered
* output (a string, a TypeScript AST node, ...) for that schema type.
* - `print` (optional), top-level override exposed as `printer.print`.
* Use `this.transform(node)` inside it to dispatch to `nodes` recursively.
*
* Without a `print` override, `printer.print` falls back to `printer.transform`
* (the node-level dispatcher).
*
* @example Tiny Zod printer
* ```ts
* import { createPrinter, type PrinterFactoryOptions } from '@kubb/ast'
*
* type PrinterZod = PrinterFactoryOptions<'zod', { strict?: boolean }, string>
*
* export const zodPrinter = createPrinter<PrinterZod>((options) => ({
* name: 'zod',
* options: { strict: options.strict ?? true },
* nodes: {
* string: () => 'z.string()',
* object(node) {
* const props = node.properties
* .map((p) => `${p.name}: ${this.transform(p.schema)}`)
* .join(', ')
* return `z.object({ ${props} })`
* },
* },
* }))
* ```
*/
declare function createPrinter<T extends PrinterFactoryOptions = PrinterFactoryOptions>(build: PrinterBuilder<T>): (options?: T['options']) => Printer<T>;
//#endregion
export { Dialect as a, createPrinter as i, PrinterFactoryOptions as n, SchemaDialect as o, PrinterPartial as r, defineDialect as s, Printer as t };
//# sourceMappingURL=types-BsP1SK9j.d.ts.map
//#region \0rolldown/runtime.js
var __create = Object.create;
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", {
value,
configurable: true
});
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __exportAll = (all, no_symbols) => {
let target = {};
for (var name in all) __defProp(target, name, {
get: all[name],
enumerable: true
});
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
return target;
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
key = keys[i];
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: ((k) => from[k]).bind(null, key),
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
value: mod,
enumerable: true
}) : target, mod));
//#endregion
let node_crypto = require("node:crypto");
let node_path = require("node:path");
node_path = __toESM(node_path, 1);
//#region src/constants.ts
const visitorDepths = {
shallow: "shallow",
deep: "deep"
};
/**
* Schema type discriminators used by all AST schema nodes.
*
* Each value is a stable discriminator across the AST (for example `schema.type === schemaTypes.object`).
*/
const schemaTypes = {
/**
* Text value.
*/
string: "string",
/**
* Floating-point number (`float`, `double`).
*/
number: "number",
/**
* Whole number (`int32`). Use `bigint` for `int64`.
*/
integer: "integer",
/**
* 64-bit integer (`int64`). Only used when `integerType` is set to `'bigint'`.
*/
bigint: "bigint",
/**
* Boolean value.
*/
boolean: "boolean",
/**
* Explicit null value.
*/
null: "null",
/**
* Any value (no type restriction).
*/
any: "any",
/**
* Unknown value (must be narrowed before usage).
*/
unknown: "unknown",
/**
* No return value (`void`).
*/
void: "void",
/**
* Object with named properties.
*/
object: "object",
/**
* Sequential list of items.
*/
array: "array",
/**
* Fixed-length list with position-specific items.
*/
tuple: "tuple",
/**
* "One of" multiple schema members.
*/
union: "union",
/**
* "All of" multiple schema members.
*/
intersection: "intersection",
/**
* Enum schema.
*/
enum: "enum",
/**
* Reference to another schema.
*/
ref: "ref",
/**
* Calendar date (for example `2026-03-24`).
*/
date: "date",
/**
* Date-time value (for example `2026-03-24T09:00:00Z`).
*/
datetime: "datetime",
/**
* Time-only value (for example `09:00:00`).
*/
time: "time",
/**
* UUID value.
*/
uuid: "uuid",
/**
* Email address value.
*/
email: "email",
/**
* URL value.
*/
url: "url",
/**
* IPv4 address value.
*/
ipv4: "ipv4",
/**
* IPv6 address value.
*/
ipv6: "ipv6",
/**
* Binary/blob value.
*/
blob: "blob",
/**
* Impossible value (`never`).
*/
never: "never"
};
/**
* One indentation level, derived from {@link INDENT_SIZE}.
*/
const INDENT = Array.from({ length: 2 }, () => " ").join("");
//#endregion
//#region src/guards.ts
/**
* Narrows a `SchemaNode` to the variant that matches `type`.
*
* @example
* ```ts
* const schema = createSchema({ type: 'string' })
* const stringNode = narrowSchema(schema, 'string') // StringSchemaNode | null
* ```
*/
function narrowSchema(node, type) {
return node?.type === type ? node : null;
}
/**
* Narrows an `OperationNode` to an `HttpOperationNode` so `method` and `path` are present.
*
* @example
* ```ts
* if (isHttpOperationNode(node)) {
* console.log(node.method, node.path)
* }
* ```
*/
function isHttpOperationNode(node) {
return node.protocol === "http" || node.method !== void 0 && node.path !== void 0;
}
//#endregion
//#region src/defineNode.ts
/**
* Visitor callback names, one per traversable node kind, in traversal order.
* Kept in sync with the keys of `Visitor` in `visitor.ts`.
*/
const visitorKeys = [
"input",
"output",
"operation",
"schema",
"property",
"parameter",
"response"
];
/**
* Builds a type guard that matches nodes of the given `kind`.
*/
function isKind(kind) {
return (node) => node?.kind === kind;
}
/**
* Defines a node once and derives its `create` builder, `is` guard, and traversal
* metadata. `create` merges `defaults`, the `build` hook (or the raw input), and the
* `kind`, so node construction lives in one place without scattered `as` casts.
*
* @example Simple node
* ```ts
* const importDef = defineNode<ImportNode>({ kind: 'Import' })
* const createImport = importDef.create
* ```
*
* @example Node with a build hook
* ```ts
* const propertyDef = defineNode<PropertyNode, UserPropertyNode>({
* kind: 'Property',
* build: (props) => ({ ...props, required: props.required ?? false }),
* children: ['schema'],
* visitorKey: 'property',
* })
* ```
*/
function defineNode(config) {
const { kind, defaults, build, children, visitorKey } = config;
function create(input) {
const base = build ? build(input) : input;
return {
...defaults,
...base,
kind
};
}
return {
kind,
create,
is: isKind(kind),
children,
visitorKey
};
}
//#endregion
//#region src/nodes/code.ts
/**
* Definition for the {@link ConstNode}.
*/
const constDef = defineNode({ kind: "Const" });
/**
* Definition for the {@link TypeNode}.
*/
const typeDef = defineNode({ kind: "Type" });
/**
* Definition for the {@link FunctionNode}.
*/
const functionDef = defineNode({ kind: "Function" });
/**
* Definition for the {@link ArrowFunctionNode}.
*/
const arrowFunctionDef = defineNode({ kind: "ArrowFunction" });
/**
* Definition for the {@link TextNode}.
*/
const textDef = defineNode({
kind: "Text",
build: (value) => ({ value })
});
/**
* Definition for the {@link BreakNode}.
*/
const breakDef = defineNode({
kind: "Break",
build: () => ({})
});
/**
* Definition for the {@link JsxNode}.
*/
const jsxDef = defineNode({
kind: "Jsx",
build: (value) => ({ value })
});
/**
* Creates a `ConstNode` representing a TypeScript `const` declaration.
*
* @example Exported constant with type and `as const`
* ```ts
* createConst({ name: 'pets', export: true, type: 'Pet[]', asConst: true })
* // export const pets: Pet[] = ... as const
* ```
*/
const createConst = constDef.create;
/**
* Creates a `TypeNode` representing a TypeScript `type` alias declaration.
*
* @example
* ```ts
* createType({ name: 'Pet', export: true })
* // export type Pet = ...
* ```
*/
const createType = typeDef.create;
/**
* Creates a `FunctionNode` representing a TypeScript `function` declaration.
*
* @example
* ```ts
* createFunction({ name: 'fetchPet', export: true, async: true, returnType: 'Pet' })
* // export async function fetchPet(): Promise<Pet> { ... }
* ```
*/
const createFunction = functionDef.create;
/**
* Creates an `ArrowFunctionNode` representing a TypeScript arrow function.
*
* @example
* ```ts
* createArrowFunction({ name: 'double', export: true, params: 'n: number', singleLine: true })
* // export const double = (n: number) => ...
* ```
*/
const createArrowFunction = arrowFunctionDef.create;
/**
* Creates a {@link TextNode} representing a raw string fragment in the source output.
*
* @example
* ```ts
* createText('return fetch(id)')
* // { kind: 'Text', value: 'return fetch(id)' }
* ```
*/
const createText = textDef.create;
/**
* Creates a {@link BreakNode} representing a line break in the source output.
*
* @example
* ```ts
* createBreak()
* // { kind: 'Break' }
* ```
*/
function createBreak() {
return breakDef.create();
}
/**
* Creates a {@link JsxNode} representing a raw JSX fragment in the source output.
*
* @example
* ```ts
* createJsx('<>\n <a href={href}>Open</a>\n</>')
* // { kind: 'Jsx', value: '<>\n <a href={href}>Open</a>\n</>' }
* ```
*/
const createJsx = jsxDef.create;
//#endregion
//#region src/nodes/content.ts
/**
* Definition for the {@link ContentNode}.
*/
const contentDef = defineNode({
kind: "Content",
children: ["schema"]
});
/**
* Creates a `ContentNode` for a single request-body or response content type.
*/
const createContent = contentDef.create;
//#endregion
//#region ../../internals/utils/src/casing.ts
/**
* Shared implementation for camelCase and PascalCase conversion.
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
* and capitalizes each word according to `pascal`.
*
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
*/
function toCamelOrPascal(text, pascal) {
return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
if (word.length > 1 && word === word.toUpperCase()) return word;
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
}).join("").replace(/[^a-zA-Z0-9]/g, "");
}
/**
* Converts `text` to camelCase.
*
* @example Word boundaries
* `camelCase('hello-world') // 'helloWorld'`
*
* @example With a prefix
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
*/
function camelCase(text, { prefix = "", suffix = "" } = {}) {
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
}
/**
* Converts `text` to PascalCase.
*
* @example Word boundaries
* `pascalCase('hello-world') // 'HelloWorld'`
*
* @example With a suffix
* `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`
*/
function pascalCase(text, { prefix = "", suffix = "" } = {}) {
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
}
//#endregion
//#region ../../internals/utils/src/fs.ts
/**
* Strips the file extension from a path or file name.
* Only removes the last `.ext` segment when the dot is not part of a directory name.
*
* @example
* trimExtName('petStore.ts') // 'petStore'
* trimExtName('/src/models/pet.ts') // '/src/models/pet'
* trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet'
* trimExtName('noExtension') // 'noExtension'
*/
function trimExtName(text) {
const dotIndex = text.lastIndexOf(".");
if (dotIndex > 0 && !text.includes("/", dotIndex)) return text.slice(0, dotIndex);
return text;
}
//#endregion
//#region src/utils/extractStringsFromNodes.ts
/**
* Extracts all string content from a `CodeNode` tree recursively.
*
* Collects text node values, identifier references in string fields (`params`, `generics`, `returnType`, `type`),
* and nested node content. Used to build the full source string for import filtering.
*/
function extractStringsFromNodes(nodes) {
if (!nodes?.length) return "";
return nodes.map((node) => {
if (typeof node === "string") return node;
if (node.kind === "Text") return node.value;
if (node.kind === "Break") return "";
if (node.kind === "Jsx") return node.value;
const parts = [];
if ("params" in node && node.params) parts.push(node.params);
if ("generics" in node && node.generics) parts.push(Array.isArray(node.generics) ? node.generics.join(", ") : node.generics);
if ("returnType" in node && node.returnType) parts.push(node.returnType);
if ("type" in node && typeof node.type === "string") parts.push(node.type);
const nested = extractStringsFromNodes(node.nodes);
if (nested) parts.push(nested);
return parts.join("\n");
}).filter(Boolean).join("\n");
}
//#endregion
//#region src/utils/fileMerge.ts
function sourceKey(source) {
return `${source.name ?? extractStringsFromNodes(source.nodes)}:${source.isExportable ?? false}:${source.isTypeOnly ?? false}`;
}
function pathTypeKey(path, isTypeOnly) {
return `${path}:${isTypeOnly ?? false}`;
}
function exportKey(path, name, isTypeOnly, asAlias) {
return `${path}:${name ?? ""}:${isTypeOnly ?? false}:${asAlias ?? ""}`;
}
function importKey(path, name, isTypeOnly) {
return `${path}:${name ?? ""}:${isTypeOnly ?? false}`;
}
/**
* Computes a multi-level sort key for exports and imports:
* non-array names first (wildcards/namespace aliases). Type-only before value. Alphabetical path. Unnamed before named.
*/
function sortKey(node) {
const isArray = Array.isArray(node.name) ? "1" : "0";
const typeOnly = node.isTypeOnly ? "0" : "1";
const hasName = node.name != null ? "1" : "0";
const name = Array.isArray(node.name) ? node.name.toSorted().join("\0") : node.name ?? "";
return `${isArray}:${typeOnly}:${node.path}:${hasName}:${name}`;
}
/**
* Deduplicates `SourceNode` objects by `name + isExportable + isTypeOnly`, keeping the first of each
* key. Unnamed sources fall back to their extracted node strings as the name part of the key. Returns
* the deduplicated array in original order.
*/
function combineSources(sources) {
const seen = /* @__PURE__ */ new Map();
for (const source of sources) {
const key = sourceKey(source);
if (!seen.has(key)) seen.set(key, source);
}
return [...seen.values()];
}
/**
* Merges `incoming` names into `existing`, preserving order and dropping duplicates.
*
* Shared by `combineExports` and `combineImports` for the same-path name-merge case.
*/
function mergeNameArrays(existing, incoming) {
const merged = new Set(existing);
for (const name of incoming) merged.add(name);
return [...merged];
}
/**
* Deduplicates and merges `ExportNode` objects by path and type.
*
* Named exports with the same path and `isTypeOnly` flag have their names merged into a single export.
* Non-array exports are deduplicated by exact identity. Returns a sorted, deduplicated array.
*/
function combineExports(exports) {
const result = [];
const namedByPath = /* @__PURE__ */ new Map();
const seen = /* @__PURE__ */ new Set();
const keyed = exports.map((node) => ({
node,
key: sortKey(node)
}));
keyed.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
for (const { node: curr } of keyed) {
const { name, path, isTypeOnly, asAlias } = curr;
if (Array.isArray(name)) {
if (!name.length) continue;
const key = pathTypeKey(path, isTypeOnly);
const existing = namedByPath.get(key);
if (existing && Array.isArray(existing.name)) existing.name = mergeNameArrays(existing.name, name);
else {
const newItem = {
...curr,
name: [...new Set(name)]
};
result.push(newItem);
namedByPath.set(key, newItem);
}
} else {
const key = exportKey(path, name, isTypeOnly, asAlias);
if (!seen.has(key)) {
result.push(curr);
seen.add(key);
}
}
}
return result;
}
/**
* Deduplicates and merges `ImportNode` objects, filtering out unused imports.
*
* Retains imports that are referenced in `source` or re-exported. Imports with the same path and
* `isTypeOnly` flag have their names merged. Returns a sorted, deduplicated, filtered array.
*/
function combineImports(imports, exports, source) {
const exportedNames = new Set(exports.flatMap((e) => Array.isArray(e.name) ? e.name : e.name ? [e.name] : []));
const isUsed = (importName) => !source || source.includes(importName) || exportedNames.has(importName);
const importNameMemo = /* @__PURE__ */ new Map();
const canonicalizeName = (n) => {
if (typeof n === "string") return n;
const key = `${n.propertyName}:${n.name ?? ""}`;
if (!importNameMemo.has(key)) importNameMemo.set(key, n);
return importNameMemo.get(key);
};
const pathsWithUsedNamedImport = /* @__PURE__ */ new Set();
for (const node of imports) {
if (!Array.isArray(node.name)) continue;
if (node.name.some((item) => typeof item === "string" ? isUsed(item) : isUsed(item.name ?? item.propertyName))) pathsWithUsedNamedImport.add(node.path);
}
const result = [];
const namedByPath = /* @__PURE__ */ new Map();
const seen = /* @__PURE__ */ new Set();
const keyed = imports.map((node) => ({
node,
key: sortKey(node)
}));
keyed.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
for (const { node: curr } of keyed) {
if (curr.path === curr.root) continue;
const { path, isTypeOnly } = curr;
let { name } = curr;
if (Array.isArray(name)) {
name = [...new Set(name.map(canonicalizeName))].filter((item) => typeof item === "string" ? isUsed(item) : isUsed(item.name ?? item.propertyName));
if (!name.length) continue;
const key = pathTypeKey(path, isTypeOnly);
const existing = namedByPath.get(key);
if (existing && Array.isArray(existing.name)) existing.name = mergeNameArrays(existing.name, name);
else {
const newItem = {
...curr,
name
};
result.push(newItem);
namedByPath.set(key, newItem);
}
} else {
if (name && !isUsed(name) && !pathsWithUsedNamedImport.has(path)) continue;
const key = importKey(path, name, isTypeOnly);
if (!seen.has(key)) {
result.push(curr);
seen.add(key);
}
}
}
return result;
}
//#endregion
//#region src/nodes/file.ts
/**
* Definition for the {@link ImportNode}.
*/
const importDef = defineNode({ kind: "Import" });
/**
* Definition for the {@link ExportNode}.
*/
const exportDef = defineNode({ kind: "Export" });
/**
* Definition for the {@link SourceNode}.
*/
const sourceDef = defineNode({ kind: "Source" });
/**
* Definition for the {@link FileNode}. The fully resolved builder lives in
* `createFile`, so this definition only supplies the guard.
*/
const fileDef = defineNode({ kind: "File" });
/**
* Creates an `ImportNode` representing a language-agnostic import/dependency declaration.
*
* @example Named import
* ```ts
* createImport({ name: ['useState'], path: 'react' })
* // import { useState } from 'react'
* ```
*/
const createImport = importDef.create;
/**
* Creates an `ExportNode` representing a language-agnostic export/public API declaration.
*
* @example Named export
* ```ts
* createExport({ name: ['Pet'], path: './Pet' })
* // export { Pet } from './Pet'
* ```
*/
const createExport = exportDef.create;
/**
* Creates a `SourceNode` representing a fragment of source code within a file.
*
* @example
* ```ts
* createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')], isExportable: true })
* ```
*/
const createSource = sourceDef.create;
/**
* Creates a fully resolved `FileNode` from a file input descriptor.
*
* Computes:
* - `id` SHA256 hash of the file path
* - `name` `baseName` without extension
* - `extname` extension extracted from `baseName`
*
* Deduplicates:
* - `sources` via `combineSources`
* - `exports` via `combineExports`
* - `imports` via `combineImports` (also filters unused imports)
*
* @throws {Error} when `baseName` has no extension.
*
* @example
* ```ts
* const file = createFile({
* baseName: 'petStore.ts',
* path: 'src/models/petStore.ts',
* sources: [createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')] })],
* imports: [createImport({ name: ['z'], path: 'zod' })],
* exports: [createExport({ name: ['Pet'], path: './petStore' })],
* })
* // file.id = SHA256 hash of 'src/models/petStore.ts'
* // file.name = 'petStore'
* // file.extname = '.ts'
* ```
*
* @example Copy a real file into the output verbatim
* ```ts
* const file = createFile({
* baseName: 'client.ts',
* path: 'src/gen/client.ts',
* copy: '/abs/path/to/templates/client.ts',
* })
* ```
*/
function createFile(input) {
const extname = node_path.default.extname(input.baseName) || (input.baseName.startsWith(".") ? input.baseName : "");
if (!extname) throw new Error(`No extname found for ${input.baseName}`);
const source = (input.sources ?? []).flatMap((item) => item.nodes ?? []).map((node) => extractStringsFromNodes([node])).filter(Boolean).join("\n\n");
const resolvedExports = input.exports?.length ? combineExports(input.exports) : [];
const combinedImports = input.imports?.length ? combineImports(input.imports, resolvedExports, source || void 0) : [];
const localNames = new Set((input.sources ?? []).map((item) => item.name).filter((name) => Boolean(name)));
const nameOf = (item) => typeof item === "string" ? item : item.name ?? item.propertyName;
const resolvedImports = combinedImports.filter((imp) => imp.path !== input.path).flatMap((imp) => {
if (!Array.isArray(imp.name)) return typeof imp.name === "string" && localNames.has(imp.name) ? [] : [imp];
const kept = imp.name.filter((item) => !localNames.has(nameOf(item)));
if (!kept.length) return [];
return [kept.length === imp.name.length ? imp : {
...imp,
name: kept
}];
});
const resolvedSources = input.sources?.length ? combineSources(input.sources) : [];
return {
kind: "File",
...input,
id: (0, node_crypto.hash)("sha256", input.path, "hex"),
name: trimExtName(input.baseName),
extname,
imports: resolvedImports,
exports: resolvedExports,
sources: resolvedSources,
meta: input.meta ?? {}
};
}
//#endregion
//#region src/nodes/function.ts
/**
* Definition for the {@link TypeLiteralNode}.
*/
const typeLiteralDef = defineNode({ kind: "TypeLiteral" });
/**
* Definition for the {@link IndexedAccessTypeNode}.
*/
const indexedAccessTypeDef = defineNode({ kind: "IndexedAccessType" });
/**
* Definition for the {@link ObjectBindingPatternNode}.
*/
const objectBindingPatternDef = defineNode({ kind: "ObjectBindingPattern" });
/**
* Definition for the {@link FunctionParameterNode}. `optional` defaults to `false`.
* Passing `properties` builds a destructured group: an {@link ObjectBindingPatternNode} name
* paired with a {@link TypeLiteralNode} type.
*/
const functionParameterDef = defineNode({
kind: "FunctionParameter",
build: (input) => {
if ("properties" in input) return {
name: createObjectBindingPattern({ elements: input.properties.map((p) => ({ name: p.name })) }),
type: createTypeLiteral({ members: input.properties.map((p) => ({
name: p.name,
type: p.type,
optional: p.optional ?? false
})) }),
optional: input.optional ?? false,
...input.default !== void 0 ? { default: input.default } : {}
};
return {
optional: false,
...input
};
}
});
/**
* Definition for the {@link FunctionParametersNode}.
*/
const functionParametersDef = defineNode({
kind: "FunctionParameters",
defaults: { params: [] }
});
/**
* Creates a {@link TypeLiteralNode} representing an inline anonymous object type.
*
* @example
* ```ts
* createTypeLiteral({ members: [{ name: 'petId', type: 'string', optional: false }] })
* // { petId: string }
* ```
*/
const createTypeLiteral = typeLiteralDef.create;
/**
* Creates an {@link IndexedAccessTypeNode} representing a single field accessed from a named type.
*
* @example
* ```ts
* createIndexedAccessType({ target: 'DeletePetPathParams', key: 'petId' })
* // DeletePetPathParams['petId']
* ```
*/
const createIndexedAccessType = indexedAccessTypeDef.create;
/**
* Creates an {@link ObjectBindingPatternNode} for a destructured parameter binding.
*
* @example
* ```ts
* createObjectBindingPattern({ elements: [{ name: 'id' }, { name: 'name' }] })
* // { id, name }
* ```
*/
const createObjectBindingPattern = objectBindingPatternDef.create;
/**
* Creates a `FunctionParameterNode`. `optional` defaults to `false`.
*
* @example Optional param
* ```ts
* createFunctionParameter({ name: 'params', type: 'QueryParams', optional: true })
* // → params?: QueryParams
* ```
*
* @example Destructured group
* ```ts
* createFunctionParameter({ properties: [{ name: 'id', type: 'string' }, { name: 'name', type: 'string', optional: true }], default: '{}' })
* // → { id, name }: { id: string; name?: string } = {}
* ```
*
* @example Destructured group typed from a single reference
* ```ts
* createFunctionParameter({ name: createObjectBindingPattern({ elements: [{ name: 'path' }] }), type: "Omit<Config, 'url'>", default: '{}' })
* // → { path }: Omit<Config, 'url'> = {}
* ```
*/
const createFunctionParameter = functionParameterDef.create;
/**
* Creates a `FunctionParametersNode` from an ordered list of parameters.
*
* @example
* ```ts
* const empty = createFunctionParameters()
* // { kind: 'FunctionParameters', params: [] }
* ```
*/
function createFunctionParameters(props = {}) {
return functionParametersDef.create(props);
}
//#endregion
//#region src/nodes/input.ts
/**
* Definition for the {@link InputNode}.
*/
const inputDef = defineNode({
kind: "Input",
defaults: {
schemas: [],
operations: [],
meta: {
circularNames: [],
enumNames: []
}
},
children: ["schemas", "operations"],
visitorKey: "input"
});
/**
* Creates an `InputNode`. Pass `stream: true` for the streaming variant whose `schemas` and
* `operations` are `AsyncIterable` sources. Otherwise it builds the eager variant with array
* `schemas`/`operations`. Both variants get the defaulted `meta`.
*
* @example Eager
* ```ts
* const input = createInput()
* // { kind: 'Input', schemas: [], operations: [] }
* ```
*
* @example Streaming
* ```ts
* const node = createInput({ stream: true, schemas: schemasIterable, operations: operationsIterable, meta: { title: 'My API' } })
* ```
*/
function createInput(options = {}) {
const { stream, ...overrides } = options;
if (stream) return {
kind: "Input",
meta: {
circularNames: [],
enumNames: []
},
...overrides
};
return inputDef.create(overrides);
}
//#endregion
//#region src/nodes/requestBody.ts
/**
* Definition for the {@link RequestBodyNode}. Content entries are built upfront with
* {@link createContent}, mirroring how `parameters` and `responses` take prebuilt nodes.
*/
const requestBodyDef = defineNode({
kind: "RequestBody",
children: ["content"]
});
/**
* Creates a `RequestBodyNode`.
*/
const createRequestBody = requestBodyDef.create;
//#endregion
//#region src/nodes/operation.ts
/**
* Definition for the {@link OperationNode}. HTTP operations (those carrying both
* `method` and `path`) are tagged with `protocol: 'http'`, and the request body is
* normalized into a `RequestBodyNode`.
*/
const operationDef = defineNode({
kind: "Operation",
build: (props) => {
const { requestBody, ...rest } = props;
const isHttp = rest.method !== void 0 && rest.path !== void 0;
return {
tags: [],
parameters: [],
responses: [],
...rest,
...isHttp ? { protocol: "http" } : {},
requestBody: requestBody ? createRequestBody(requestBody) : void 0
};
},
children: [
"parameters",
"requestBody",
"responses"
],
visitorKey: "operation"
});
function createOperation(props) {
return operationDef.create(props);
}
//#endregion
//#region src/nodes/output.ts
/**
* Definition for the {@link OutputNode}.
*/
const outputDef = defineNode({
kind: "Output",
defaults: { files: [] },
visitorKey: "output"
});
/**
* Creates an `OutputNode` with a stable default for `files`.
*
* @example
* ```ts
* const output = createOutput()
* // { kind: 'Output', files: [] }
* ```
*/
function createOutput(overrides = {}) {
return outputDef.create(overrides);
}
//#endregion
//#region src/optionality.ts
/**
* Generic JSON Schema optionality: a non-required field is optional, and a
* non-required nullable field is nullish.
*/
function optionality(schema, required) {
const nullable = schema.nullable ?? false;
return {
...schema,
optional: !required && !nullable ? true : void 0,
nullish: !required && nullable ? true : void 0
};
}
//#endregion
//#region src/nodes/parameter.ts
/**
* Definition for the {@link ParameterNode}. `required` defaults to `false`, and the schema's
* `optional`/`nullish` flags are derived from it through {@link optionality}.
*/
const parameterDef = defineNode({
kind: "Parameter",
build: (props) => {
const required = props.required ?? false;
return {
...props,
required,
schema: optionality(props.schema, required)
};
},
children: ["schema"],
visitorKey: "parameter"
});
/**
* Creates a `ParameterNode`.
*
* @example
* ```ts
* const param = createParameter({
* name: 'petId',
* in: 'path',
* required: true,
* schema: createSchema({ type: 'string' }),
* })
* ```
*/
const createParameter = parameterDef.create;
//#endregion
//#region src/nodes/property.ts
/**
* Definition for the {@link PropertyNode}. `required` defaults to `false`, and the schema's
* `optional`/`nullish` flags are derived from it through {@link optionality}.
*/
const propertyDef = defineNode({
kind: "Property",
build: (props) => {
const required = props.required ?? false;
return {
...props,
required,
schema: optionality(props.schema, required)
};
},
children: ["schema"],
visitorKey: "property"
});
/**
* Creates a `PropertyNode`.
*
* @example
* ```ts
* const property = createProperty({
* name: 'status',
* required: true,
* schema: createSchema({ type: 'string', nullable: true }),
* })
* // required=true, no optional/nullish
* ```
*/
const createProperty = propertyDef.create;
//#endregion
//#region src/nodes/response.ts
/**
* Definition for the {@link ResponseNode}. A single legacy `schema` (with optional
* `mediaType`/`keysToOmit`) is normalized into one `content` entry.
*/
const responseDef = defineNode({
kind: "Response",
build: (props) => {
const { schema, mediaType, keysToOmit, content, ...rest } = props;
const entries = content ?? (schema ? [createContent({
contentType: mediaType ?? "application/json",
schema,
keysToOmit: keysToOmit ?? null
})] : void 0);
return {
...rest,
content: entries
};
},
children: ["content"],
visitorKey: "response"
});
/**
* Creates a `ResponseNode`.
*
* @example
* ```ts
* const response = createResponse({
* statusCode: '200',
* content: [createContent({ contentType: 'application/json', schema: createSchema({ type: 'object', properties: [] }) })],
* })
* ```
*/
const createResponse = responseDef.create;
//#endregion
//#region src/nodes/schema.ts
/**
* Maps schema `type` to its underlying `primitive`.
* Primitive types map to themselves and special string formats map to `'string'`.
* Any type not listed here (such as `ref`, `enum`, `union`, `intersection`, `tuple`, `ipv4`, `ipv6`, `blob`) has no `primitive`.
*/
const TYPE_TO_PRIMITIVE = {
string: "string",
number: "number",
integer: "integer",
bigint: "bigint",
boolean: "boolean",
null: "null",
any: "any",
unknown: "unknown",
void: "void",
never: "never",
object: "object",
array: "array",
date: "date",
uuid: "string",
email: "string",
url: "string",
datetime: "string",
time: "string"
};
/**
* Definition for the {@link SchemaNode}. Object schemas default `properties` to an
* empty array, and `primitive` is inferred from `type` when not explicitly provided.
*/
const schemaDef = defineNode({
kind: "Schema",
build: (props) => {
if (props.type === "object") return {
properties: [],
primitive: "object",
...props
};
return {
primitive: TYPE_TO_PRIMITIVE[props.type],
...props
};
},
children: [
"properties",
"items",
"members",
"additionalProperties"
],
visitorKey: "schema"
});
function createSchema(props) {
return schemaDef.create(props);
}
//#endregion
//#region src/registry.ts
/**
* Every node definition. Adding a node means adding its `defineNode` to one
* `nodes/*.ts` file and listing it here. The visitor tables in `visitor.ts` derive from it.
*/
const nodeDefs = [
inputDef,
outputDef,
operationDef,
requestBodyDef,
contentDef,
responseDef,
schemaDef,
propertyDef,
parameterDef,
functionParameterDef,
functionParametersDef,
typeLiteralDef,
indexedAccessTypeDef,
objectBindingPatternDef,
constDef,
typeDef,
functionDef,
arrowFunctionDef,
textDef,
breakDef,
jsxDef,
importDef,
exportDef,
sourceDef,
fileDef
];
//#endregion
//#region src/visitor.ts
/**
* Child node fields per node kind, in traversal order (Babel's `VISITOR_KEYS`).
* Derived from each definition's `children`.
*/
const VISITOR_KEYS = Object.fromEntries(nodeDefs.flatMap((def) => def.children ? [[def.kind, def.children]] : []));
/**
* Maps a node kind to the matching visitor callback name. Derived from each
* definition's `visitorKey`.
*/
const VISITOR_KEY_BY_KIND = Object.fromEntries(nodeDefs.flatMap((def) => def.visitorKey ? [[def.kind, def.visitorKey]] : []));
/**
* Creates a small async concurrency limiter.
*
* At most `concurrency` tasks are in flight at once. Extra tasks are queued.
*
* @example
* ```ts
* const limit = createLimit(2)
* for (const task of [taskA, taskB, taskC]) {
* await limit(() => task())
* }
* // only 2 tasks run at the same time
* ```
*/
function createLimit(concurrency) {
let active = 0;
const queue = [];
function next() {
if (active < concurrency && queue.length > 0) {
active++;
queue.shift()();
}
}
return function limit(fn) {
return new Promise((resolve, reject) => {
queue.push(() => {
Promise.resolve(fn()).then(resolve, reject).finally(() => {
active--;
next();
});
});
next();
});
};
}
const visitorKeysByKind = VISITOR_KEYS;
/**
* Returns `true` when `value` is an AST node (an object carrying a `kind`).
*/
function isNode(value) {
return typeof value === "object" && value !== null && "kind" in value;
}
/**
* Returns the immediate traversable children of `node` based on {@link VISITOR_KEYS}.
*
* `Schema` children are only included when `recurse` is `true`. Shallow mode skips them.
*
* @example
* ```ts
* const children = getChildren(operationNode, true)
* // returns parameters, the request body, and responses
* ```
*/
function* getChildren(node, recurse) {
if (node.kind === "Schema" && !recurse) return;
const keys = visitorKeysByKind[node.kind];
if (!keys) return;
const record = node;
for (const key of keys) {
const value = record[key];
if (Array.isArray(value)) {
for (const item of value) if (isNode(item)) yield item;
} else if (isNode(value)) yield value;
}
}
/**
* Runs the visitor callback that matches `node.kind` with the traversal
* context. The result is a replacement node, a collected value, or `undefined`
* when no callback is registered for the kind.
*
* Shared by `walk`, `transform`, and `collectLazy` so node-kind dispatch lives
* in one place. `TResult` is the caller's expected return: the same node type
* for `transform`, the collected value type for `collectLazy`, ignored for `walk`.
*/
function applyVisitor(node, visitor, parent) {
const key = VISITOR_KEY_BY_KIND[node.kind];
if (!key) return void 0;
const fn = visitor[key];
return fn?.(node, { parent });
}
/**
* Async depth-first traversal for side effects. Visitor return values are
* ignored. Use `transform` when you want to rewrite nodes.
*
* Sibling nodes at each depth run concurrently up to `options.concurrency`
* (defaults to `WALK_CONCURRENCY`). Higher values overlap I/O-bound visitor
* work. Lower values reduce memory pressure.
*
* @example Log every operation
* ```ts
* await walk(root, {
* operation(node) {
* console.log(node.operationId)
* },
* })
* ```
*
* @example Only visit the root node
* ```ts
* await walk(root, { depth: 'shallow', input: () => {} })
* ```
*/
async function walk(node, options) {
return _walk(node, options, (options.depth ?? visitorDepths.deep) === visitorDepths.deep, createLimit(options.concurrency ?? 30), void 0);
}
async function _walk(node, visitor, recurse, limit, parent) {
await limit(() => applyVisitor(node, visitor, parent));
const children = Array.from(getChildren(node, recurse));
if (children.length === 0) return;
await Promise.all(children.map((child) => _walk(child, visitor, recurse, limit, node)));
}
function transform(node, options) {
const { depth, parent, ...visitor } = options;
const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep;
return transformChildren(applyVisitor(node, visitor, parent) ?? node, options, recurse);
}
/**
* Immutably rebuilds a node's children using {@link VISITOR_KEYS}, transforming
* each child node and leaving non-node values (e.g. `additionalProperties: true`) intact.
* `Schema` children are skipped in shallow mode.
*/
function transformChildren(node, options, recurse) {
if (node.kind === "Schema" && !recurse) return node;
const keys = visitorKeysByKind[node.kind];
if (!keys) return node;
const record = node;
const childOptions = {
...options,
parent: node
};
let updates;
for (const key of keys) {
if (!(key in record)) continue;
const value = record[key];
if (Array.isArray(value)) {
let changed = false;
const mapped = value.map((item) => {
if (!isNode(item)) return item;
const next = transform(item, childOptions);
if (next !== item) changed = true;
return next;
});
if (changed) (updates ??= {})[key] = mapped;
} else if (isNode(value)) {
const next = transform(value, childOptions);
if (next !== value) (updates ??= {})[key] = next;
}
}
return updates ? {
...node,
...updates
} : node;
}
/**
* Lazy depth-first collection pass. Yields every non-null value returned by
* the visitor callbacks. Use `collect` for the eager array form.
*
* @example Collect every operationId
* ```ts
* const ids: string[] = []
* for (const id of collectLazy<string>(root, {
* operation(node) {
* return node.operationId
* },
* })) {
* ids.push(id)
* }
* ```
*/
function* collectLazy(node, options) {
const { depth, parent, ...visitor } = options;
const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep;
const v = applyVisitor(node, visitor, parent);
if (v != null) yield v;
for (const child of getChildren(node, recurse)) yield* collectLazy(child, {
...options,
parent: node
});
}
/**
* Eager depth-first collection pass. Gathers every non-null value the visitor
* callbacks return into an array.
*
* @example Collect every operationId
* ```ts
* const ids = collect<string>(root, {
* operation(node) {
* return node.operationId
* },
* })
* ```
*/
function collect(node, options) {
return Array.from(collectLazy(node, options));
}
//#endregion
Object.defineProperty(exports, "INDENT", {
enumerable: true,
get: function() {
return INDENT;
}
});
Object.defineProperty(exports, "__exportAll", {
enumerable: true,
get: function() {
return __exportAll;
}
});
Object.defineProperty(exports, "__name", {
enumerable: true,
get: function() {
return __name;
}
});
Object.defineProperty(exports, "arrowFunctionDef", {
enumerable: true,
get: function() {
return arrowFunctionDef;
}
});
Object.defineProperty(exports, "breakDef", {
enumerable: true,
get: function() {
return breakDef;
}
});
Object.defineProperty(exports, "camelCase", {
enumerable: true,
get: function() {
return camelCase;
}
});
Object.defineProperty(exports, "collect", {
enumerable: true,
get: function() {
return collect;
}
});
Object.defineProperty(exports, "collectLazy", {
enumerable: true,
get: function() {
return collectLazy;
}
});
Object.defineProperty(exports, "constDef", {
enumerable: true,
get: function() {
return constDef;
}
});
Object.defineProperty(exports, "contentDef", {
enumerable: true,
get: function() {
return contentDef;
}
});
Object.defineProperty(exports, "createArrowFunction", {
enumerable: true,
get: function() {
return createArrowFunction;
}
});
Object.defineProperty(exports, "createBreak", {
enumerable: true,
get: function() {
return createBreak;
}
});
Object.defineProperty(exports, "createConst", {
enumerable: true,
get: function() {
return createConst;
}
});
Object.defineProperty(exports, "createContent", {
enumerable: true,
get: function() {
return createContent;
}
});
Object.defineProperty(exports, "createExport", {
enumerable: true,
get: function() {
return createExport;
}
});
Object.defineProperty(exports, "createFile", {
enumerable: true,
get: function() {
return createFile;
}
});
Object.defineProperty(exports, "createFunction", {
enumerable: true,
get: function() {
return createFunction;
}
});
Object.defineProperty(exports, "createFunctionParameter", {
enumerable: true,
get: function() {
return createFunctionParameter;
}
});
Object.defineProperty(exports, "createFunctionParameters", {
enumerable: true,
get: function() {
return createFunctionParameters;
}
});
Object.defineProperty(exports, "createImport", {
enumerable: true,
get: function() {
return createImport;
}
});
Object.defineProperty(exports, "createIndexedAccessType", {
enumerable: true,
get: function() {
return createIndexedAccessType;
}
});
Object.defineProperty(exports, "createInput", {
enumerable: true,
get: function() {
return createInput;
}
});
Object.defineProperty(exports, "createJsx", {
enumerable: true,
get: function() {
return createJsx;
}
});
Object.defineProperty(exports, "createObjectBindingPattern", {
enumerable: true,
get: function() {
return createObjectBindingPattern;
}
});
Object.defineProperty(exports, "createOperation", {
enumerable: true,
get: function() {
return createOperation;
}
});
Object.defineProperty(exports, "createOutput", {
enumerable: true,
get: function() {
return createOutput;
}
});
Object.defineProperty(exports, "createParameter", {
enumerable: true,
get: function() {
return createParameter;
}
});
Object.defineProperty(exports, "createProperty", {
enumerable: true,
get: function() {
return createProperty;
}
});
Object.defineProperty(exports, "createRequestBody", {
enumerable: true,
get: function() {
return createRequestBody;
}
});
Object.defineProperty(exports, "createResponse", {
enumerable: true,
get: function() {
return createResponse;
}
});
Object.defineProperty(exports, "createSchema", {
enumerable: true,
get: function() {
return createSchema;
}
});
Object.defineProperty(exports, "createSource", {
enumerable: true,
get: function() {
return createSource;
}
});
Object.defineProperty(exports, "createText", {
enumerable: true,
get: function() {
return createText;
}
});
Object.defineProperty(exports, "createType", {
enumerable: true,
get: function() {
return createType;
}
});
Object.defineProperty(exports, "createTypeLiteral", {
enumerable: true,
get: function() {
return createTypeLiteral;
}
});
Object.defineProperty(exports, "defineNode", {
enumerable: true,
get: function() {
return defineNode;
}
});
Object.defineProperty(exports, "exportDef", {
enumerable: true,
get: function() {
return exportDef;
}
});
Object.defineProperty(exports, "extractStringsFromNodes", {
enumerable: true,
get: function() {
return extractStringsFromNodes;
}
});
Object.defineProperty(exports, "fileDef", {
enumerable: true,
get: function() {
return fileDef;
}
});
Object.defineProperty(exports, "functionDef", {
enumerable: true,
get: function() {
return functionDef;
}
});
Object.defineProperty(exports, "functionParameterDef", {
enumerable: true,
get: function() {
return functionParameterDef;
}
});
Object.defineProperty(exports, "functionParametersDef", {
enumerable: true,
get: function() {
return functionParametersDef;
}
});
Object.defineProperty(exports, "importDef", {
enumerable: true,
get: function() {
return importDef;
}
});
Object.defineProperty(exports, "indexedAccessTypeDef", {
enumerable: true,
get: function() {
return indexedAccessTypeDef;
}
});
Object.defineProperty(exports, "inputDef", {
enumerable: true,
get: function() {
return inputDef;
}
});
Object.defineProperty(exports, "isHttpOperationNode", {
enumerable: true,
get: function() {
return isHttpOperationNode;
}
});
Object.defineProperty(exports, "jsxDef", {
enumerable: true,
get: function() {
return jsxDef;
}
});
Object.defineProperty(exports, "narrowSchema", {
enumerable: true,
get: function() {
return narrowSchema;
}
});
Object.defineProperty(exports, "nodeDefs", {
enumerable: true,
get: function() {
return nodeDefs;
}
});
Object.defineProperty(exports, "objectBindingPatternDef", {
enumerable: true,
get: function() {
return objectBindingPatternDef;
}
});
Object.defineProperty(exports, "operationDef", {
enumerable: true,
get: function() {
return operationDef;
}
});
Object.defineProperty(exports, "optionality", {
enumerable: true,
get: function() {
return optionality;
}
});
Object.defineProperty(exports, "outputDef", {
enumerable: true,
get: function() {
return outputDef;
}
});
Object.defineProperty(exports, "parameterDef", {
enumerable: true,
get: function() {
return parameterDef;
}
});
Object.defineProperty(exports, "pascalCase", {
enumerable: true,
get: function() {
return pascalCase;
}
});
Object.defineProperty(exports, "propertyDef", {
enumerable: true,
get: function() {
return propertyDef;
}
});
Object.defineProperty(exports, "requestBodyDef", {
enumerable: true,
get: function() {
return requestBodyDef;
}
});
Object.defineProperty(exports, "responseDef", {
enumerable: true,
get: function() {
return responseDef;
}
});
Object.defineProperty(exports, "schemaDef", {
enumerable: true,
get: function() {
return schemaDef;
}
});
Object.defineProperty(exports, "schemaTypes", {
enumerable: true,
get: function() {
return schemaTypes;
}
});
Object.defineProperty(exports, "sourceDef", {
enumerable: true,
get: function() {
return sourceDef;
}
});
Object.defineProperty(exports, "textDef", {
enumerable: true,
get: function() {
return textDef;
}
});
Object.defineProperty(exports, "transform", {
enumerable: true,
get: function() {
return transform;
}
});
Object.defineProperty(exports, "typeDef", {
enumerable: true,
get: function() {
return typeDef;
}
});
Object.defineProperty(exports, "typeLiteralDef", {
enumerable: true,
get: function() {
return typeLiteralDef;
}
});
Object.defineProperty(exports, "visitorKeys", {
enumerable: true,
get: function() {
return visitorKeys;
}
});
Object.defineProperty(exports, "walk", {
enumerable: true,
get: function() {
return walk;
}
});
//# sourceMappingURL=visitor-CQdSiClY.cjs.map

Sorry, the diff of this file is too big to display

import "./rolldown-runtime-CNktS9qV.js";
import { hash } from "node:crypto";
import path from "node:path";
//#region src/constants.ts
const visitorDepths = {
shallow: "shallow",
deep: "deep"
};
/**
* Schema type discriminators used by all AST schema nodes.
*
* Each value is a stable discriminator across the AST (for example `schema.type === schemaTypes.object`).
*/
const schemaTypes = {
/**
* Text value.
*/
string: "string",
/**
* Floating-point number (`float`, `double`).
*/
number: "number",
/**
* Whole number (`int32`). Use `bigint` for `int64`.
*/
integer: "integer",
/**
* 64-bit integer (`int64`). Only used when `integerType` is set to `'bigint'`.
*/
bigint: "bigint",
/**
* Boolean value.
*/
boolean: "boolean",
/**
* Explicit null value.
*/
null: "null",
/**
* Any value (no type restriction).
*/
any: "any",
/**
* Unknown value (must be narrowed before usage).
*/
unknown: "unknown",
/**
* No return value (`void`).
*/
void: "void",
/**
* Object with named properties.
*/
object: "object",
/**
* Sequential list of items.
*/
array: "array",
/**
* Fixed-length list with position-specific items.
*/
tuple: "tuple",
/**
* "One of" multiple schema members.
*/
union: "union",
/**
* "All of" multiple schema members.
*/
intersection: "intersection",
/**
* Enum schema.
*/
enum: "enum",
/**
* Reference to another schema.
*/
ref: "ref",
/**
* Calendar date (for example `2026-03-24`).
*/
date: "date",
/**
* Date-time value (for example `2026-03-24T09:00:00Z`).
*/
datetime: "datetime",
/**
* Time-only value (for example `09:00:00`).
*/
time: "time",
/**
* UUID value.
*/
uuid: "uuid",
/**
* Email address value.
*/
email: "email",
/**
* URL value.
*/
url: "url",
/**
* IPv4 address value.
*/
ipv4: "ipv4",
/**
* IPv6 address value.
*/
ipv6: "ipv6",
/**
* Binary/blob value.
*/
blob: "blob",
/**
* Impossible value (`never`).
*/
never: "never"
};
/**
* One indentation level, derived from {@link INDENT_SIZE}.
*/
const INDENT = Array.from({ length: 2 }, () => " ").join("");
//#endregion
//#region src/guards.ts
/**
* Narrows a `SchemaNode` to the variant that matches `type`.
*
* @example
* ```ts
* const schema = createSchema({ type: 'string' })
* const stringNode = narrowSchema(schema, 'string') // StringSchemaNode | null
* ```
*/
function narrowSchema(node, type) {
return node?.type === type ? node : null;
}
/**
* Narrows an `OperationNode` to an `HttpOperationNode` so `method` and `path` are present.
*
* @example
* ```ts
* if (isHttpOperationNode(node)) {
* console.log(node.method, node.path)
* }
* ```
*/
function isHttpOperationNode(node) {
return node.protocol === "http" || node.method !== void 0 && node.path !== void 0;
}
//#endregion
//#region src/defineNode.ts
/**
* Visitor callback names, one per traversable node kind, in traversal order.
* Kept in sync with the keys of `Visitor` in `visitor.ts`.
*/
const visitorKeys = [
"input",
"output",
"operation",
"schema",
"property",
"parameter",
"response"
];
/**
* Builds a type guard that matches nodes of the given `kind`.
*/
function isKind(kind) {
return (node) => node?.kind === kind;
}
/**
* Defines a node once and derives its `create` builder, `is` guard, and traversal
* metadata. `create` merges `defaults`, the `build` hook (or the raw input), and the
* `kind`, so node construction lives in one place without scattered `as` casts.
*
* @example Simple node
* ```ts
* const importDef = defineNode<ImportNode>({ kind: 'Import' })
* const createImport = importDef.create
* ```
*
* @example Node with a build hook
* ```ts
* const propertyDef = defineNode<PropertyNode, UserPropertyNode>({
* kind: 'Property',
* build: (props) => ({ ...props, required: props.required ?? false }),
* children: ['schema'],
* visitorKey: 'property',
* })
* ```
*/
function defineNode(config) {
const { kind, defaults, build, children, visitorKey } = config;
function create(input) {
const base = build ? build(input) : input;
return {
...defaults,
...base,
kind
};
}
return {
kind,
create,
is: isKind(kind),
children,
visitorKey
};
}
//#endregion
//#region src/nodes/code.ts
/**
* Definition for the {@link ConstNode}.
*/
const constDef = defineNode({ kind: "Const" });
/**
* Definition for the {@link TypeNode}.
*/
const typeDef = defineNode({ kind: "Type" });
/**
* Definition for the {@link FunctionNode}.
*/
const functionDef = defineNode({ kind: "Function" });
/**
* Definition for the {@link ArrowFunctionNode}.
*/
const arrowFunctionDef = defineNode({ kind: "ArrowFunction" });
/**
* Definition for the {@link TextNode}.
*/
const textDef = defineNode({
kind: "Text",
build: (value) => ({ value })
});
/**
* Definition for the {@link BreakNode}.
*/
const breakDef = defineNode({
kind: "Break",
build: () => ({})
});
/**
* Definition for the {@link JsxNode}.
*/
const jsxDef = defineNode({
kind: "Jsx",
build: (value) => ({ value })
});
/**
* Creates a `ConstNode` representing a TypeScript `const` declaration.
*
* @example Exported constant with type and `as const`
* ```ts
* createConst({ name: 'pets', export: true, type: 'Pet[]', asConst: true })
* // export const pets: Pet[] = ... as const
* ```
*/
const createConst = constDef.create;
/**
* Creates a `TypeNode` representing a TypeScript `type` alias declaration.
*
* @example
* ```ts
* createType({ name: 'Pet', export: true })
* // export type Pet = ...
* ```
*/
const createType = typeDef.create;
/**
* Creates a `FunctionNode` representing a TypeScript `function` declaration.
*
* @example
* ```ts
* createFunction({ name: 'fetchPet', export: true, async: true, returnType: 'Pet' })
* // export async function fetchPet(): Promise<Pet> { ... }
* ```
*/
const createFunction = functionDef.create;
/**
* Creates an `ArrowFunctionNode` representing a TypeScript arrow function.
*
* @example
* ```ts
* createArrowFunction({ name: 'double', export: true, params: 'n: number', singleLine: true })
* // export const double = (n: number) => ...
* ```
*/
const createArrowFunction = arrowFunctionDef.create;
/**
* Creates a {@link TextNode} representing a raw string fragment in the source output.
*
* @example
* ```ts
* createText('return fetch(id)')
* // { kind: 'Text', value: 'return fetch(id)' }
* ```
*/
const createText = textDef.create;
/**
* Creates a {@link BreakNode} representing a line break in the source output.
*
* @example
* ```ts
* createBreak()
* // { kind: 'Break' }
* ```
*/
function createBreak() {
return breakDef.create();
}
/**
* Creates a {@link JsxNode} representing a raw JSX fragment in the source output.
*
* @example
* ```ts
* createJsx('<>\n <a href={href}>Open</a>\n</>')
* // { kind: 'Jsx', value: '<>\n <a href={href}>Open</a>\n</>' }
* ```
*/
const createJsx = jsxDef.create;
//#endregion
//#region src/nodes/content.ts
/**
* Definition for the {@link ContentNode}.
*/
const contentDef = defineNode({
kind: "Content",
children: ["schema"]
});
/**
* Creates a `ContentNode` for a single request-body or response content type.
*/
const createContent = contentDef.create;
//#endregion
//#region ../../internals/utils/src/casing.ts
/**
* Shared implementation for camelCase and PascalCase conversion.
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
* and capitalizes each word according to `pascal`.
*
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
*/
function toCamelOrPascal(text, pascal) {
return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
if (word.length > 1 && word === word.toUpperCase()) return word;
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
}).join("").replace(/[^a-zA-Z0-9]/g, "");
}
/**
* Converts `text` to camelCase.
*
* @example Word boundaries
* `camelCase('hello-world') // 'helloWorld'`
*
* @example With a prefix
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
*/
function camelCase(text, { prefix = "", suffix = "" } = {}) {
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
}
/**
* Converts `text` to PascalCase.
*
* @example Word boundaries
* `pascalCase('hello-world') // 'HelloWorld'`
*
* @example With a suffix
* `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`
*/
function pascalCase(text, { prefix = "", suffix = "" } = {}) {
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
}
//#endregion
//#region ../../internals/utils/src/fs.ts
/**
* Strips the file extension from a path or file name.
* Only removes the last `.ext` segment when the dot is not part of a directory name.
*
* @example
* trimExtName('petStore.ts') // 'petStore'
* trimExtName('/src/models/pet.ts') // '/src/models/pet'
* trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet'
* trimExtName('noExtension') // 'noExtension'
*/
function trimExtName(text) {
const dotIndex = text.lastIndexOf(".");
if (dotIndex > 0 && !text.includes("/", dotIndex)) return text.slice(0, dotIndex);
return text;
}
//#endregion
//#region src/utils/extractStringsFromNodes.ts
/**
* Extracts all string content from a `CodeNode` tree recursively.
*
* Collects text node values, identifier references in string fields (`params`, `generics`, `returnType`, `type`),
* and nested node content. Used to build the full source string for import filtering.
*/
function extractStringsFromNodes(nodes) {
if (!nodes?.length) return "";
return nodes.map((node) => {
if (typeof node === "string") return node;
if (node.kind === "Text") return node.value;
if (node.kind === "Break") return "";
if (node.kind === "Jsx") return node.value;
const parts = [];
if ("params" in node && node.params) parts.push(node.params);
if ("generics" in node && node.generics) parts.push(Array.isArray(node.generics) ? node.generics.join(", ") : node.generics);
if ("returnType" in node && node.returnType) parts.push(node.returnType);
if ("type" in node && typeof node.type === "string") parts.push(node.type);
const nested = extractStringsFromNodes(node.nodes);
if (nested) parts.push(nested);
return parts.join("\n");
}).filter(Boolean).join("\n");
}
//#endregion
//#region src/utils/fileMerge.ts
function sourceKey(source) {
return `${source.name ?? extractStringsFromNodes(source.nodes)}:${source.isExportable ?? false}:${source.isTypeOnly ?? false}`;
}
function pathTypeKey(path, isTypeOnly) {
return `${path}:${isTypeOnly ?? false}`;
}
function exportKey(path, name, isTypeOnly, asAlias) {
return `${path}:${name ?? ""}:${isTypeOnly ?? false}:${asAlias ?? ""}`;
}
function importKey(path, name, isTypeOnly) {
return `${path}:${name ?? ""}:${isTypeOnly ?? false}`;
}
/**
* Computes a multi-level sort key for exports and imports:
* non-array names first (wildcards/namespace aliases). Type-only before value. Alphabetical path. Unnamed before named.
*/
function sortKey(node) {
const isArray = Array.isArray(node.name) ? "1" : "0";
const typeOnly = node.isTypeOnly ? "0" : "1";
const hasName = node.name != null ? "1" : "0";
const name = Array.isArray(node.name) ? node.name.toSorted().join("\0") : node.name ?? "";
return `${isArray}:${typeOnly}:${node.path}:${hasName}:${name}`;
}
/**
* Deduplicates `SourceNode` objects by `name + isExportable + isTypeOnly`, keeping the first of each
* key. Unnamed sources fall back to their extracted node strings as the name part of the key. Returns
* the deduplicated array in original order.
*/
function combineSources(sources) {
const seen = /* @__PURE__ */ new Map();
for (const source of sources) {
const key = sourceKey(source);
if (!seen.has(key)) seen.set(key, source);
}
return [...seen.values()];
}
/**
* Merges `incoming` names into `existing`, preserving order and dropping duplicates.
*
* Shared by `combineExports` and `combineImports` for the same-path name-merge case.
*/
function mergeNameArrays(existing, incoming) {
const merged = new Set(existing);
for (const name of incoming) merged.add(name);
return [...merged];
}
/**
* Deduplicates and merges `ExportNode` objects by path and type.
*
* Named exports with the same path and `isTypeOnly` flag have their names merged into a single export.
* Non-array exports are deduplicated by exact identity. Returns a sorted, deduplicated array.
*/
function combineExports(exports) {
const result = [];
const namedByPath = /* @__PURE__ */ new Map();
const seen = /* @__PURE__ */ new Set();
const keyed = exports.map((node) => ({
node,
key: sortKey(node)
}));
keyed.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
for (const { node: curr } of keyed) {
const { name, path, isTypeOnly, asAlias } = curr;
if (Array.isArray(name)) {
if (!name.length) continue;
const key = pathTypeKey(path, isTypeOnly);
const existing = namedByPath.get(key);
if (existing && Array.isArray(existing.name)) existing.name = mergeNameArrays(existing.name, name);
else {
const newItem = {
...curr,
name: [...new Set(name)]
};
result.push(newItem);
namedByPath.set(key, newItem);
}
} else {
const key = exportKey(path, name, isTypeOnly, asAlias);
if (!seen.has(key)) {
result.push(curr);
seen.add(key);
}
}
}
return result;
}
/**
* Deduplicates and merges `ImportNode` objects, filtering out unused imports.
*
* Retains imports that are referenced in `source` or re-exported. Imports with the same path and
* `isTypeOnly` flag have their names merged. Returns a sorted, deduplicated, filtered array.
*/
function combineImports(imports, exports, source) {
const exportedNames = new Set(exports.flatMap((e) => Array.isArray(e.name) ? e.name : e.name ? [e.name] : []));
const isUsed = (importName) => !source || source.includes(importName) || exportedNames.has(importName);
const importNameMemo = /* @__PURE__ */ new Map();
const canonicalizeName = (n) => {
if (typeof n === "string") return n;
const key = `${n.propertyName}:${n.name ?? ""}`;
if (!importNameMemo.has(key)) importNameMemo.set(key, n);
return importNameMemo.get(key);
};
const pathsWithUsedNamedImport = /* @__PURE__ */ new Set();
for (const node of imports) {
if (!Array.isArray(node.name)) continue;
if (node.name.some((item) => typeof item === "string" ? isUsed(item) : isUsed(item.name ?? item.propertyName))) pathsWithUsedNamedImport.add(node.path);
}
const result = [];
const namedByPath = /* @__PURE__ */ new Map();
const seen = /* @__PURE__ */ new Set();
const keyed = imports.map((node) => ({
node,
key: sortKey(node)
}));
keyed.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
for (const { node: curr } of keyed) {
if (curr.path === curr.root) continue;
const { path, isTypeOnly } = curr;
let { name } = curr;
if (Array.isArray(name)) {
name = [...new Set(name.map(canonicalizeName))].filter((item) => typeof item === "string" ? isUsed(item) : isUsed(item.name ?? item.propertyName));
if (!name.length) continue;
const key = pathTypeKey(path, isTypeOnly);
const existing = namedByPath.get(key);
if (existing && Array.isArray(existing.name)) existing.name = mergeNameArrays(existing.name, name);
else {
const newItem = {
...curr,
name
};
result.push(newItem);
namedByPath.set(key, newItem);
}
} else {
if (name && !isUsed(name) && !pathsWithUsedNamedImport.has(path)) continue;
const key = importKey(path, name, isTypeOnly);
if (!seen.has(key)) {
result.push(curr);
seen.add(key);
}
}
}
return result;
}
//#endregion
//#region src/nodes/file.ts
/**
* Definition for the {@link ImportNode}.
*/
const importDef = defineNode({ kind: "Import" });
/**
* Definition for the {@link ExportNode}.
*/
const exportDef = defineNode({ kind: "Export" });
/**
* Definition for the {@link SourceNode}.
*/
const sourceDef = defineNode({ kind: "Source" });
/**
* Definition for the {@link FileNode}. The fully resolved builder lives in
* `createFile`, so this definition only supplies the guard.
*/
const fileDef = defineNode({ kind: "File" });
/**
* Creates an `ImportNode` representing a language-agnostic import/dependency declaration.
*
* @example Named import
* ```ts
* createImport({ name: ['useState'], path: 'react' })
* // import { useState } from 'react'
* ```
*/
const createImport = importDef.create;
/**
* Creates an `ExportNode` representing a language-agnostic export/public API declaration.
*
* @example Named export
* ```ts
* createExport({ name: ['Pet'], path: './Pet' })
* // export { Pet } from './Pet'
* ```
*/
const createExport = exportDef.create;
/**
* Creates a `SourceNode` representing a fragment of source code within a file.
*
* @example
* ```ts
* createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')], isExportable: true })
* ```
*/
const createSource = sourceDef.create;
/**
* Creates a fully resolved `FileNode` from a file input descriptor.
*
* Computes:
* - `id` SHA256 hash of the file path
* - `name` `baseName` without extension
* - `extname` extension extracted from `baseName`
*
* Deduplicates:
* - `sources` via `combineSources`
* - `exports` via `combineExports`
* - `imports` via `combineImports` (also filters unused imports)
*
* @throws {Error} when `baseName` has no extension.
*
* @example
* ```ts
* const file = createFile({
* baseName: 'petStore.ts',
* path: 'src/models/petStore.ts',
* sources: [createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')] })],
* imports: [createImport({ name: ['z'], path: 'zod' })],
* exports: [createExport({ name: ['Pet'], path: './petStore' })],
* })
* // file.id = SHA256 hash of 'src/models/petStore.ts'
* // file.name = 'petStore'
* // file.extname = '.ts'
* ```
*
* @example Copy a real file into the output verbatim
* ```ts
* const file = createFile({
* baseName: 'client.ts',
* path: 'src/gen/client.ts',
* copy: '/abs/path/to/templates/client.ts',
* })
* ```
*/
function createFile(input) {
const extname = path.extname(input.baseName) || (input.baseName.startsWith(".") ? input.baseName : "");
if (!extname) throw new Error(`No extname found for ${input.baseName}`);
const source = (input.sources ?? []).flatMap((item) => item.nodes ?? []).map((node) => extractStringsFromNodes([node])).filter(Boolean).join("\n\n");
const resolvedExports = input.exports?.length ? combineExports(input.exports) : [];
const combinedImports = input.imports?.length ? combineImports(input.imports, resolvedExports, source || void 0) : [];
const localNames = new Set((input.sources ?? []).map((item) => item.name).filter((name) => Boolean(name)));
const nameOf = (item) => typeof item === "string" ? item : item.name ?? item.propertyName;
const resolvedImports = combinedImports.filter((imp) => imp.path !== input.path).flatMap((imp) => {
if (!Array.isArray(imp.name)) return typeof imp.name === "string" && localNames.has(imp.name) ? [] : [imp];
const kept = imp.name.filter((item) => !localNames.has(nameOf(item)));
if (!kept.length) return [];
return [kept.length === imp.name.length ? imp : {
...imp,
name: kept
}];
});
const resolvedSources = input.sources?.length ? combineSources(input.sources) : [];
return {
kind: "File",
...input,
id: hash("sha256", input.path, "hex"),
name: trimExtName(input.baseName),
extname,
imports: resolvedImports,
exports: resolvedExports,
sources: resolvedSources,
meta: input.meta ?? {}
};
}
//#endregion
//#region src/nodes/function.ts
/**
* Definition for the {@link TypeLiteralNode}.
*/
const typeLiteralDef = defineNode({ kind: "TypeLiteral" });
/**
* Definition for the {@link IndexedAccessTypeNode}.
*/
const indexedAccessTypeDef = defineNode({ kind: "IndexedAccessType" });
/**
* Definition for the {@link ObjectBindingPatternNode}.
*/
const objectBindingPatternDef = defineNode({ kind: "ObjectBindingPattern" });
/**
* Definition for the {@link FunctionParameterNode}. `optional` defaults to `false`.
* Passing `properties` builds a destructured group: an {@link ObjectBindingPatternNode} name
* paired with a {@link TypeLiteralNode} type.
*/
const functionParameterDef = defineNode({
kind: "FunctionParameter",
build: (input) => {
if ("properties" in input) return {
name: createObjectBindingPattern({ elements: input.properties.map((p) => ({ name: p.name })) }),
type: createTypeLiteral({ members: input.properties.map((p) => ({
name: p.name,
type: p.type,
optional: p.optional ?? false
})) }),
optional: input.optional ?? false,
...input.default !== void 0 ? { default: input.default } : {}
};
return {
optional: false,
...input
};
}
});
/**
* Definition for the {@link FunctionParametersNode}.
*/
const functionParametersDef = defineNode({
kind: "FunctionParameters",
defaults: { params: [] }
});
/**
* Creates a {@link TypeLiteralNode} representing an inline anonymous object type.
*
* @example
* ```ts
* createTypeLiteral({ members: [{ name: 'petId', type: 'string', optional: false }] })
* // { petId: string }
* ```
*/
const createTypeLiteral = typeLiteralDef.create;
/**
* Creates an {@link IndexedAccessTypeNode} representing a single field accessed from a named type.
*
* @example
* ```ts
* createIndexedAccessType({ target: 'DeletePetPathParams', key: 'petId' })
* // DeletePetPathParams['petId']
* ```
*/
const createIndexedAccessType = indexedAccessTypeDef.create;
/**
* Creates an {@link ObjectBindingPatternNode} for a destructured parameter binding.
*
* @example
* ```ts
* createObjectBindingPattern({ elements: [{ name: 'id' }, { name: 'name' }] })
* // { id, name }
* ```
*/
const createObjectBindingPattern = objectBindingPatternDef.create;
/**
* Creates a `FunctionParameterNode`. `optional` defaults to `false`.
*
* @example Optional param
* ```ts
* createFunctionParameter({ name: 'params', type: 'QueryParams', optional: true })
* // → params?: QueryParams
* ```
*
* @example Destructured group
* ```ts
* createFunctionParameter({ properties: [{ name: 'id', type: 'string' }, { name: 'name', type: 'string', optional: true }], default: '{}' })
* // → { id, name }: { id: string; name?: string } = {}
* ```
*
* @example Destructured group typed from a single reference
* ```ts
* createFunctionParameter({ name: createObjectBindingPattern({ elements: [{ name: 'path' }] }), type: "Omit<Config, 'url'>", default: '{}' })
* // → { path }: Omit<Config, 'url'> = {}
* ```
*/
const createFunctionParameter = functionParameterDef.create;
/**
* Creates a `FunctionParametersNode` from an ordered list of parameters.
*
* @example
* ```ts
* const empty = createFunctionParameters()
* // { kind: 'FunctionParameters', params: [] }
* ```
*/
function createFunctionParameters(props = {}) {
return functionParametersDef.create(props);
}
//#endregion
//#region src/nodes/input.ts
/**
* Definition for the {@link InputNode}.
*/
const inputDef = defineNode({
kind: "Input",
defaults: {
schemas: [],
operations: [],
meta: {
circularNames: [],
enumNames: []
}
},
children: ["schemas", "operations"],
visitorKey: "input"
});
/**
* Creates an `InputNode`. Pass `stream: true` for the streaming variant whose `schemas` and
* `operations` are `AsyncIterable` sources. Otherwise it builds the eager variant with array
* `schemas`/`operations`. Both variants get the defaulted `meta`.
*
* @example Eager
* ```ts
* const input = createInput()
* // { kind: 'Input', schemas: [], operations: [] }
* ```
*
* @example Streaming
* ```ts
* const node = createInput({ stream: true, schemas: schemasIterable, operations: operationsIterable, meta: { title: 'My API' } })
* ```
*/
function createInput(options = {}) {
const { stream, ...overrides } = options;
if (stream) return {
kind: "Input",
meta: {
circularNames: [],
enumNames: []
},
...overrides
};
return inputDef.create(overrides);
}
//#endregion
//#region src/nodes/requestBody.ts
/**
* Definition for the {@link RequestBodyNode}. Content entries are built upfront with
* {@link createContent}, mirroring how `parameters` and `responses` take prebuilt nodes.
*/
const requestBodyDef = defineNode({
kind: "RequestBody",
children: ["content"]
});
/**
* Creates a `RequestBodyNode`.
*/
const createRequestBody = requestBodyDef.create;
//#endregion
//#region src/nodes/operation.ts
/**
* Definition for the {@link OperationNode}. HTTP operations (those carrying both
* `method` and `path`) are tagged with `protocol: 'http'`, and the request body is
* normalized into a `RequestBodyNode`.
*/
const operationDef = defineNode({
kind: "Operation",
build: (props) => {
const { requestBody, ...rest } = props;
const isHttp = rest.method !== void 0 && rest.path !== void 0;
return {
tags: [],
parameters: [],
responses: [],
...rest,
...isHttp ? { protocol: "http" } : {},
requestBody: requestBody ? createRequestBody(requestBody) : void 0
};
},
children: [
"parameters",
"requestBody",
"responses"
],
visitorKey: "operation"
});
function createOperation(props) {
return operationDef.create(props);
}
//#endregion
//#region src/nodes/output.ts
/**
* Definition for the {@link OutputNode}.
*/
const outputDef = defineNode({
kind: "Output",
defaults: { files: [] },
visitorKey: "output"
});
/**
* Creates an `OutputNode` with a stable default for `files`.
*
* @example
* ```ts
* const output = createOutput()
* // { kind: 'Output', files: [] }
* ```
*/
function createOutput(overrides = {}) {
return outputDef.create(overrides);
}
//#endregion
//#region src/optionality.ts
/**
* Generic JSON Schema optionality: a non-required field is optional, and a
* non-required nullable field is nullish.
*/
function optionality(schema, required) {
const nullable = schema.nullable ?? false;
return {
...schema,
optional: !required && !nullable ? true : void 0,
nullish: !required && nullable ? true : void 0
};
}
//#endregion
//#region src/nodes/parameter.ts
/**
* Definition for the {@link ParameterNode}. `required` defaults to `false`, and the schema's
* `optional`/`nullish` flags are derived from it through {@link optionality}.
*/
const parameterDef = defineNode({
kind: "Parameter",
build: (props) => {
const required = props.required ?? false;
return {
...props,
required,
schema: optionality(props.schema, required)
};
},
children: ["schema"],
visitorKey: "parameter"
});
/**
* Creates a `ParameterNode`.
*
* @example
* ```ts
* const param = createParameter({
* name: 'petId',
* in: 'path',
* required: true,
* schema: createSchema({ type: 'string' }),
* })
* ```
*/
const createParameter = parameterDef.create;
//#endregion
//#region src/nodes/property.ts
/**
* Definition for the {@link PropertyNode}. `required` defaults to `false`, and the schema's
* `optional`/`nullish` flags are derived from it through {@link optionality}.
*/
const propertyDef = defineNode({
kind: "Property",
build: (props) => {
const required = props.required ?? false;
return {
...props,
required,
schema: optionality(props.schema, required)
};
},
children: ["schema"],
visitorKey: "property"
});
/**
* Creates a `PropertyNode`.
*
* @example
* ```ts
* const property = createProperty({
* name: 'status',
* required: true,
* schema: createSchema({ type: 'string', nullable: true }),
* })
* // required=true, no optional/nullish
* ```
*/
const createProperty = propertyDef.create;
//#endregion
//#region src/nodes/response.ts
/**
* Definition for the {@link ResponseNode}. A single legacy `schema` (with optional
* `mediaType`/`keysToOmit`) is normalized into one `content` entry.
*/
const responseDef = defineNode({
kind: "Response",
build: (props) => {
const { schema, mediaType, keysToOmit, content, ...rest } = props;
const entries = content ?? (schema ? [createContent({
contentType: mediaType ?? "application/json",
schema,
keysToOmit: keysToOmit ?? null
})] : void 0);
return {
...rest,
content: entries
};
},
children: ["content"],
visitorKey: "response"
});
/**
* Creates a `ResponseNode`.
*
* @example
* ```ts
* const response = createResponse({
* statusCode: '200',
* content: [createContent({ contentType: 'application/json', schema: createSchema({ type: 'object', properties: [] }) })],
* })
* ```
*/
const createResponse = responseDef.create;
//#endregion
//#region src/nodes/schema.ts
/**
* Maps schema `type` to its underlying `primitive`.
* Primitive types map to themselves and special string formats map to `'string'`.
* Any type not listed here (such as `ref`, `enum`, `union`, `intersection`, `tuple`, `ipv4`, `ipv6`, `blob`) has no `primitive`.
*/
const TYPE_TO_PRIMITIVE = {
string: "string",
number: "number",
integer: "integer",
bigint: "bigint",
boolean: "boolean",
null: "null",
any: "any",
unknown: "unknown",
void: "void",
never: "never",
object: "object",
array: "array",
date: "date",
uuid: "string",
email: "string",
url: "string",
datetime: "string",
time: "string"
};
/**
* Definition for the {@link SchemaNode}. Object schemas default `properties` to an
* empty array, and `primitive` is inferred from `type` when not explicitly provided.
*/
const schemaDef = defineNode({
kind: "Schema",
build: (props) => {
if (props.type === "object") return {
properties: [],
primitive: "object",
...props
};
return {
primitive: TYPE_TO_PRIMITIVE[props.type],
...props
};
},
children: [
"properties",
"items",
"members",
"additionalProperties"
],
visitorKey: "schema"
});
function createSchema(props) {
return schemaDef.create(props);
}
//#endregion
//#region src/registry.ts
/**
* Every node definition. Adding a node means adding its `defineNode` to one
* `nodes/*.ts` file and listing it here. The visitor tables in `visitor.ts` derive from it.
*/
const nodeDefs = [
inputDef,
outputDef,
operationDef,
requestBodyDef,
contentDef,
responseDef,
schemaDef,
propertyDef,
parameterDef,
functionParameterDef,
functionParametersDef,
typeLiteralDef,
indexedAccessTypeDef,
objectBindingPatternDef,
constDef,
typeDef,
functionDef,
arrowFunctionDef,
textDef,
breakDef,
jsxDef,
importDef,
exportDef,
sourceDef,
fileDef
];
//#endregion
//#region src/visitor.ts
/**
* Child node fields per node kind, in traversal order (Babel's `VISITOR_KEYS`).
* Derived from each definition's `children`.
*/
const VISITOR_KEYS = Object.fromEntries(nodeDefs.flatMap((def) => def.children ? [[def.kind, def.children]] : []));
/**
* Maps a node kind to the matching visitor callback name. Derived from each
* definition's `visitorKey`.
*/
const VISITOR_KEY_BY_KIND = Object.fromEntries(nodeDefs.flatMap((def) => def.visitorKey ? [[def.kind, def.visitorKey]] : []));
/**
* Creates a small async concurrency limiter.
*
* At most `concurrency` tasks are in flight at once. Extra tasks are queued.
*
* @example
* ```ts
* const limit = createLimit(2)
* for (const task of [taskA, taskB, taskC]) {
* await limit(() => task())
* }
* // only 2 tasks run at the same time
* ```
*/
function createLimit(concurrency) {
let active = 0;
const queue = [];
function next() {
if (active < concurrency && queue.length > 0) {
active++;
queue.shift()();
}
}
return function limit(fn) {
return new Promise((resolve, reject) => {
queue.push(() => {
Promise.resolve(fn()).then(resolve, reject).finally(() => {
active--;
next();
});
});
next();
});
};
}
const visitorKeysByKind = VISITOR_KEYS;
/**
* Returns `true` when `value` is an AST node (an object carrying a `kind`).
*/
function isNode(value) {
return typeof value === "object" && value !== null && "kind" in value;
}
/**
* Returns the immediate traversable children of `node` based on {@link VISITOR_KEYS}.
*
* `Schema` children are only included when `recurse` is `true`. Shallow mode skips them.
*
* @example
* ```ts
* const children = getChildren(operationNode, true)
* // returns parameters, the request body, and responses
* ```
*/
function* getChildren(node, recurse) {
if (node.kind === "Schema" && !recurse) return;
const keys = visitorKeysByKind[node.kind];
if (!keys) return;
const record = node;
for (const key of keys) {
const value = record[key];
if (Array.isArray(value)) {
for (const item of value) if (isNode(item)) yield item;
} else if (isNode(value)) yield value;
}
}
/**
* Runs the visitor callback that matches `node.kind` with the traversal
* context. The result is a replacement node, a collected value, or `undefined`
* when no callback is registered for the kind.
*
* Shared by `walk`, `transform`, and `collectLazy` so node-kind dispatch lives
* in one place. `TResult` is the caller's expected return: the same node type
* for `transform`, the collected value type for `collectLazy`, ignored for `walk`.
*/
function applyVisitor(node, visitor, parent) {
const key = VISITOR_KEY_BY_KIND[node.kind];
if (!key) return void 0;
const fn = visitor[key];
return fn?.(node, { parent });
}
/**
* Async depth-first traversal for side effects. Visitor return values are
* ignored. Use `transform` when you want to rewrite nodes.
*
* Sibling nodes at each depth run concurrently up to `options.concurrency`
* (defaults to `WALK_CONCURRENCY`). Higher values overlap I/O-bound visitor
* work. Lower values reduce memory pressure.
*
* @example Log every operation
* ```ts
* await walk(root, {
* operation(node) {
* console.log(node.operationId)
* },
* })
* ```
*
* @example Only visit the root node
* ```ts
* await walk(root, { depth: 'shallow', input: () => {} })
* ```
*/
async function walk(node, options) {
return _walk(node, options, (options.depth ?? visitorDepths.deep) === visitorDepths.deep, createLimit(options.concurrency ?? 30), void 0);
}
async function _walk(node, visitor, recurse, limit, parent) {
await limit(() => applyVisitor(node, visitor, parent));
const children = Array.from(getChildren(node, recurse));
if (children.length === 0) return;
await Promise.all(children.map((child) => _walk(child, visitor, recurse, limit, node)));
}
function transform(node, options) {
const { depth, parent, ...visitor } = options;
const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep;
return transformChildren(applyVisitor(node, visitor, parent) ?? node, options, recurse);
}
/**
* Immutably rebuilds a node's children using {@link VISITOR_KEYS}, transforming
* each child node and leaving non-node values (e.g. `additionalProperties: true`) intact.
* `Schema` children are skipped in shallow mode.
*/
function transformChildren(node, options, recurse) {
if (node.kind === "Schema" && !recurse) return node;
const keys = visitorKeysByKind[node.kind];
if (!keys) return node;
const record = node;
const childOptions = {
...options,
parent: node
};
let updates;
for (const key of keys) {
if (!(key in record)) continue;
const value = record[key];
if (Array.isArray(value)) {
let changed = false;
const mapped = value.map((item) => {
if (!isNode(item)) return item;
const next = transform(item, childOptions);
if (next !== item) changed = true;
return next;
});
if (changed) (updates ??= {})[key] = mapped;
} else if (isNode(value)) {
const next = transform(value, childOptions);
if (next !== value) (updates ??= {})[key] = next;
}
}
return updates ? {
...node,
...updates
} : node;
}
/**
* Lazy depth-first collection pass. Yields every non-null value returned by
* the visitor callbacks. Use `collect` for the eager array form.
*
* @example Collect every operationId
* ```ts
* const ids: string[] = []
* for (const id of collectLazy<string>(root, {
* operation(node) {
* return node.operationId
* },
* })) {
* ids.push(id)
* }
* ```
*/
function* collectLazy(node, options) {
const { depth, parent, ...visitor } = options;
const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep;
const v = applyVisitor(node, visitor, parent);
if (v != null) yield v;
for (const child of getChildren(node, recurse)) yield* collectLazy(child, {
...options,
parent: node
});
}
/**
* Eager depth-first collection pass. Gathers every non-null value the visitor
* callbacks return into an array.
*
* @example Collect every operationId
* ```ts
* const ids = collect<string>(root, {
* operation(node) {
* return node.operationId
* },
* })
* ```
*/
function collect(node, options) {
return Array.from(collectLazy(node, options));
}
//#endregion
export { createJsx as $, indexedAccessTypeDef as A, sourceDef as B, createFunctionParameter as C, createTypeLiteral as D, createObjectBindingPattern as E, createImport as F, createContent as G, camelCase as H, createSource as I, constDef as J, arrowFunctionDef as K, exportDef as L, typeLiteralDef as M, createExport as N, functionParameterDef as O, createFile as P, createFunction as Q, fileDef as R, inputDef as S, createIndexedAccessType as T, pascalCase as U, extractStringsFromNodes as V, contentDef as W, createBreak as X, createArrowFunction as Y, createConst as Z, createOperation as _, nodeDefs as a, typeDef as at, requestBodyDef as b, createResponse as c, isHttpOperationNode as ct, propertyDef as d, schemaTypes as dt, createText as et, createParameter as f, outputDef as g, createOutput as h, walk as i, textDef as it, objectBindingPatternDef as j, functionParametersDef as k, responseDef as l, narrowSchema as lt, optionality as m, collectLazy as n, functionDef as nt, createSchema as o, defineNode as ot, parameterDef as p, breakDef as q, transform as r, jsxDef as rt, schemaDef as s, visitorKeys as st, collect as t, createType as tt, createProperty as u, INDENT as ut, operationDef as v, createFunctionParameters as w, createInput as x, createRequestBody as y, importDef as z };
//# sourceMappingURL=visitor-dcVC5TOW.js.map

Sorry, the diff of this file is too big to display

+2
-2
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const require_visitor = require("./visitor-CLLDwBvv.cjs");
const require_defineMacro = require("./defineMacro-Bh5E_Il6.cjs");
const require_visitor = require("./visitor-CQdSiClY.cjs");
const require_defineMacro = require("./defineMacro-5Dvct8k_.cjs");
//#region src/defineDialect.ts

@@ -5,0 +5,0 @@ /**

import { n as __name, t as __exportAll } from "./rolldown-runtime-CNktS9qV.js";
import { a as defineMacro, c as VisitorContext, d as walk, f as schemaTypes, i as composeMacros, l as collect, n as Macro, o as ParentOf, r as applyMacros, s as Visitor, t as Enforce, u as transform } from "./defineMacro-D9ekmTW5.js";
import { a as Dialect, i as createPrinter, n as PrinterFactoryOptions, o as SchemaDialect, r as PrinterPartial, s as defineDialect, t as Printer } from "./types-Df1jVmRy.js";
import { $ as exportDef, $t as textDef, A as IndexedAccessTypeNode, At as InferSchemaNode, B as functionParametersDef, Bt as TypeNode, C as ParameterNode, Ct as UrlSchemaNode, D as FunctionParamNode, Dt as UserPropertyNode, E as FunctionParamKind, Et as PropertyNode, F as createFunctionParameters, Ft as ConstNode, G as FileNode, Gt as createBreak, H as objectBindingPatternDef, Ht as breakDef, I as createIndexedAccessType, It as FunctionNode, J as UserFileNode, Jt as createJsx, K as ImportNode, Kt as createConst, L as createObjectBindingPattern, Lt as JSDocNode, M as TypeExpression, Mt as ArrowFunctionNode, N as TypeLiteralNode, Nt as BreakNode, O as FunctionParameterNode, Ot as createProperty, P as createFunctionParameter, Pt as CodeNode, Q as createSource, Qt as jsxDef, R as createTypeLiteral, Rt as JsxNode, S as ParameterLocation, St as UnionSchemaNode, T as parameterDef, Tt as schemaDef, U as typeLiteralDef, Ut as constDef, V as indexedAccessTypeDef, Vt as arrowFunctionDef, W as ExportNode, Wt as createArrowFunction, X as createFile, Xt as createType, Y as createExport, Yt as createText, Z as createImport, Zt as functionDef, _ as createResponse, _t as SchemaNode, a as InputMeta, an as NodeKind, at as createContent, b as createRequestBody, bt as StringSchemaNode, c as inputDef, ct as DatetimeSchemaNode, d as HttpOperationNode, dt as NumberSchemaNode, en as typeDef, et as fileDef, f as OperationNode, ft as ObjectSchemaNode, g as StatusCode, gt as ScalarSchemaType, h as ResponseNode, ht as ScalarSchemaNode, i as outputDef, in as BaseNode, it as contentDef, j as ObjectBindingPatternNode, jt as ParserOptions, k as FunctionParametersNode, kt as propertyDef, l as GenericOperationNode, lt as EnumSchemaNode, m as operationDef, mt as RefSchemaNode, n as OutputNode, nn as NodeDef, nt as sourceDef, o as InputNode, ot as ArraySchemaNode, p as createOperation, pt as PrimitiveSchemaType, q as SourceNode, qt as createFunction, r as createOutput, rn as defineNode, rt as ContentNode, s as createInput, st as DateSchemaNode, t as Node, tn as DistributiveOmit, tt as importDef, u as HttpMethod, ut as IntersectionSchemaNode, v as responseDef, vt as SchemaNodeByType, w as createParameter, wt as createSchema, x as requestBodyDef, xt as TimeSchemaNode, y as RequestBodyNode, yt as SchemaType, z as functionParameterDef, zt as TextNode } from "./index-q_ldM1YP.js";
import { n as OperationParamsResolver } from "./operationParams-Dme8H-sR.js";
import { a as defineMacro, c as VisitorContext, d as walk, f as schemaTypes, i as composeMacros, l as collect, n as Macro, o as ParentOf, r as applyMacros, s as Visitor, t as Enforce, u as transform } from "./defineMacro-BXpTwp0y.js";
import { a as Dialect, i as createPrinter, n as PrinterFactoryOptions, o as SchemaDialect, r as PrinterPartial, s as defineDialect, t as Printer } from "./types-BsP1SK9j.js";
import { $ as exportDef, $t as textDef, A as IndexedAccessTypeNode, At as InferSchemaNode, B as functionParametersDef, Bt as TypeNode, C as ParameterNode, Ct as UrlSchemaNode, D as FunctionParamNode, Dt as UserPropertyNode, E as FunctionParamKind, Et as PropertyNode, F as createFunctionParameters, Ft as ConstNode, G as FileNode, Gt as createBreak, H as objectBindingPatternDef, Ht as breakDef, I as createIndexedAccessType, It as FunctionNode, J as UserFileNode, Jt as createJsx, K as ImportNode, Kt as createConst, L as createObjectBindingPattern, Lt as JSDocNode, M as TypeExpression, Mt as ArrowFunctionNode, N as TypeLiteralNode, Nt as BreakNode, O as FunctionParameterNode, Ot as createProperty, P as createFunctionParameter, Pt as CodeNode, Q as createSource, Qt as jsxDef, R as createTypeLiteral, Rt as JsxNode, S as ParameterLocation, St as UnionSchemaNode, T as parameterDef, Tt as schemaDef, U as typeLiteralDef, Ut as constDef, V as indexedAccessTypeDef, Vt as arrowFunctionDef, W as ExportNode, Wt as createArrowFunction, X as createFile, Xt as createType, Y as createExport, Yt as createText, Z as createImport, Zt as functionDef, _ as createResponse, _t as SchemaNode, a as InputMeta, an as NodeKind, at as createContent, b as createRequestBody, bt as StringSchemaNode, c as inputDef, ct as DatetimeSchemaNode, d as HttpOperationNode, dt as NumberSchemaNode, en as typeDef, et as fileDef, f as OperationNode, ft as ObjectSchemaNode, g as StatusCode, gt as ScalarSchemaType, h as ResponseNode, ht as ScalarSchemaNode, i as outputDef, in as BaseNode, it as contentDef, j as ObjectBindingPatternNode, jt as ParserOptions, k as FunctionParametersNode, kt as propertyDef, l as GenericOperationNode, lt as EnumSchemaNode, m as operationDef, mt as RefSchemaNode, n as OutputNode, nn as NodeDef, nt as sourceDef, o as InputNode, ot as ArraySchemaNode, p as createOperation, pt as PrimitiveSchemaType, q as SourceNode, qt as createFunction, r as createOutput, rn as defineNode, rt as ContentNode, s as createInput, st as DateSchemaNode, t as Node, tn as DistributiveOmit, tt as importDef, u as HttpMethod, ut as IntersectionSchemaNode, v as responseDef, vt as SchemaNodeByType, w as createParameter, wt as createSchema, x as requestBodyDef, xt as TimeSchemaNode, y as RequestBodyNode, yt as SchemaType, z as functionParameterDef, zt as TextNode } from "./index-DJEyS5y6.js";
import { t as OperationParamsResolver } from "./operationParams-BaY12i2I.js";

@@ -62,3 +62,3 @@ //#region src/guards.d.ts

*/
declare const nodeDefs: (NodeDef<PropertyNode, UserPropertyNode> | NodeDef<ConstNode, Omit<ConstNode, "kind">> | NodeDef<TypeNode, Omit<TypeNode, "kind">> | NodeDef<FunctionNode, Omit<FunctionNode, "kind">> | NodeDef<ArrowFunctionNode, Omit<ArrowFunctionNode, "kind">> | NodeDef<TextNode, string> | NodeDef<BreakNode, void> | NodeDef<JsxNode, string> | NodeDef<SchemaNode, (Omit<ObjectSchemaNode, "kind" | "primitive" | "properties"> & {
declare const nodeDefs: (NodeDef<PropertyNode, UserPropertyNode> | NodeDef<SchemaNode, (Omit<ObjectSchemaNode, "kind" | "primitive" | "properties"> & {
properties?: Array<PropertyNode>;

@@ -119,3 +119,3 @@ primitive?: "object";

type: "ipv6";
}) | ScalarSchemaNode, "kind">> | NodeDef<InputNode<false>, Partial<Omit<InputNode<false>, "kind">>> | NodeDef<OutputNode, Partial<Omit<OutputNode, "kind">>> | NodeDef<RequestBodyNode, Omit<RequestBodyNode, "kind">> | NodeDef<OperationNode, {
}) | ScalarSchemaNode, "kind">> | NodeDef<ConstNode, Omit<ConstNode, "kind">> | NodeDef<TypeNode, Omit<TypeNode, "kind">> | NodeDef<FunctionNode, Omit<FunctionNode, "kind">> | NodeDef<ArrowFunctionNode, Omit<ArrowFunctionNode, "kind">> | NodeDef<TextNode, string> | NodeDef<BreakNode, void> | NodeDef<JsxNode, string> | NodeDef<InputNode<false>, Partial<Omit<InputNode<false>, "kind">>> | NodeDef<OutputNode, Partial<Omit<OutputNode, "kind">>> | NodeDef<RequestBodyNode, Omit<RequestBodyNode, "kind">> | NodeDef<OperationNode, {
[key: string]: unknown;

@@ -132,3 +132,3 @@ operationId: string;

}> | NodeDef<ParameterNode, Pick<ParameterNode, "name" | "schema" | "in"> & Partial<Omit<ParameterNode, "kind" | "name" | "schema" | "in">>> | NodeDef<ObjectBindingPatternNode, Pick<ObjectBindingPatternNode, "elements">> | NodeDef<TypeLiteralNode, Pick<TypeLiteralNode, "members">> | NodeDef<FunctionParameterNode, {
name: string;
name: string | ObjectBindingPatternNode;
type?: TypeExpression;

@@ -135,0 +135,0 @@ optional?: boolean;

import { t as __exportAll } from "./rolldown-runtime-CNktS9qV.js";
import { $ as createJsx, A as indexedAccessTypeDef, B as sourceDef, C as createFunctionParameter, D as createTypeLiteral, E as createObjectBindingPattern, F as createImport, G as createContent, I as createSource, J as constDef, K as arrowFunctionDef, L as exportDef, M as typeLiteralDef, N as createExport, O as functionParameterDef, P as createFile, Q as createFunction, R as fileDef, S as inputDef, T as createIndexedAccessType, W as contentDef, X as createBreak, Y as createArrowFunction, Z as createConst, _ as createOperation, a as nodeDefs, at as typeDef, b as requestBodyDef, c as createResponse, ct as isHttpOperationNode, d as propertyDef, dt as schemaTypes, et as createText, f as createParameter, g as outputDef, h as createOutput, i as walk, it as textDef, j as objectBindingPatternDef, k as functionParametersDef, l as responseDef, lt as narrowSchema, m as optionality, nt as functionDef, o as createSchema, ot as defineNode, p as parameterDef, q as breakDef, r as transform, rt as jsxDef, s as schemaDef, t as collect, tt as createType, u as createProperty, v as operationDef, w as createFunctionParameters, x as createInput, y as createRequestBody, z as importDef } from "./visitor-DG5ROqRx.js";
import { n as composeMacros, r as defineMacro, t as applyMacros } from "./defineMacro-CVrU3ajV.js";
import { $ as createJsx, A as indexedAccessTypeDef, B as sourceDef, C as createFunctionParameter, D as createTypeLiteral, E as createObjectBindingPattern, F as createImport, G as createContent, I as createSource, J as constDef, K as arrowFunctionDef, L as exportDef, M as typeLiteralDef, N as createExport, O as functionParameterDef, P as createFile, Q as createFunction, R as fileDef, S as inputDef, T as createIndexedAccessType, W as contentDef, X as createBreak, Y as createArrowFunction, Z as createConst, _ as createOperation, a as nodeDefs, at as typeDef, b as requestBodyDef, c as createResponse, ct as isHttpOperationNode, d as propertyDef, dt as schemaTypes, et as createText, f as createParameter, g as outputDef, h as createOutput, i as walk, it as textDef, j as objectBindingPatternDef, k as functionParametersDef, l as responseDef, lt as narrowSchema, m as optionality, nt as functionDef, o as createSchema, ot as defineNode, p as parameterDef, q as breakDef, r as transform, rt as jsxDef, s as schemaDef, t as collect, tt as createType, u as createProperty, v as operationDef, w as createFunctionParameters, x as createInput, y as createRequestBody, z as importDef } from "./visitor-dcVC5TOW.js";
import { n as composeMacros, r as defineMacro, t as applyMacros } from "./defineMacro-VfsvblGi.js";
//#region src/defineDialect.ts

@@ -5,0 +5,0 @@ /**

Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const require_visitor = require("./visitor-CLLDwBvv.cjs");
const require_defineMacro = require("./defineMacro-Bh5E_Il6.cjs");
const require_refs = require("./refs-8IwpesXW.cjs");
const require_visitor = require("./visitor-CQdSiClY.cjs");
const require_defineMacro = require("./defineMacro-5Dvct8k_.cjs");
const require_refs = require("./refs-DuP3_Leg.cjs");
//#region src/macros/macroDiscriminatorEnum.ts

@@ -6,0 +6,0 @@ /**

import { n as __name } from "./rolldown-runtime-CNktS9qV.js";
import { n as Macro } from "./defineMacro-D9ekmTW5.js";
import { n as Macro } from "./defineMacro-BXpTwp0y.js";

@@ -4,0 +4,0 @@ //#region src/macros/macroDiscriminatorEnum.d.ts

import "./rolldown-runtime-CNktS9qV.js";
import { lt as narrowSchema, o as createSchema, u as createProperty } from "./visitor-DG5ROqRx.js";
import { r as defineMacro } from "./defineMacro-CVrU3ajV.js";
import { n as enumPropName } from "./refs-D2qwT5ck.js";
import { lt as narrowSchema, o as createSchema, u as createProperty } from "./visitor-dcVC5TOW.js";
import { r as defineMacro } from "./defineMacro-VfsvblGi.js";
import { n as enumPropName } from "./refs-D18OeCgb.js";
//#region src/macros/macroDiscriminatorEnum.ts

@@ -6,0 +6,0 @@ /**

@@ -1,5 +0,5 @@

import { c as VisitorContext, n as Macro, o as ParentOf, s as Visitor, t as Enforce } from "./defineMacro-D9ekmTW5.js";
import { a as Dialect, n as PrinterFactoryOptions, o as SchemaDialect, r as PrinterPartial, t as Printer } from "./types-Df1jVmRy.js";
import { A as IndexedAccessTypeNode, At as InferSchemaNode, Bt as TypeNode, C as ParameterNode, Ct as UrlSchemaNode, D as FunctionParamNode, E as FunctionParamKind, Et as PropertyNode, Ft as ConstNode, G as FileNode, It as FunctionNode, J as UserFileNode, K as ImportNode, Lt as JSDocNode, M as TypeExpression, Mt as ArrowFunctionNode, N as TypeLiteralNode, Nt as BreakNode, O as FunctionParameterNode, Pt as CodeNode, Rt as JsxNode, S as ParameterLocation, St as UnionSchemaNode, W as ExportNode, _t as SchemaNode, a as InputMeta, an as NodeKind, bt as StringSchemaNode, ct as DatetimeSchemaNode, d as HttpOperationNode, dt as NumberSchemaNode, f as OperationNode, ft as ObjectSchemaNode, g as StatusCode, gt as ScalarSchemaType, h as ResponseNode, ht as ScalarSchemaNode, j as ObjectBindingPatternNode, jt as ParserOptions, k as FunctionParametersNode, l as GenericOperationNode, lt as EnumSchemaNode, mt as RefSchemaNode, n as OutputNode, nn as NodeDef, o as InputNode, ot as ArraySchemaNode, pt as PrimitiveSchemaType, q as SourceNode, rt as ContentNode, st as DateSchemaNode, t as Node, tn as DistributiveOmit, u as HttpMethod, ut as IntersectionSchemaNode, vt as SchemaNodeByType, xt as TimeSchemaNode, y as RequestBodyNode, yt as SchemaType, zt as TextNode } from "./index-q_ldM1YP.js";
import { n as OperationParamsResolver } from "./operationParams-Dme8H-sR.js";
import { c as VisitorContext, n as Macro, o as ParentOf, s as Visitor, t as Enforce } from "./defineMacro-BXpTwp0y.js";
import { a as Dialect, n as PrinterFactoryOptions, o as SchemaDialect, r as PrinterPartial, t as Printer } from "./types-BsP1SK9j.js";
import { A as IndexedAccessTypeNode, At as InferSchemaNode, Bt as TypeNode, C as ParameterNode, Ct as UrlSchemaNode, D as FunctionParamNode, E as FunctionParamKind, Et as PropertyNode, Ft as ConstNode, G as FileNode, It as FunctionNode, J as UserFileNode, K as ImportNode, Lt as JSDocNode, M as TypeExpression, Mt as ArrowFunctionNode, N as TypeLiteralNode, Nt as BreakNode, O as FunctionParameterNode, Pt as CodeNode, Rt as JsxNode, S as ParameterLocation, St as UnionSchemaNode, W as ExportNode, _t as SchemaNode, a as InputMeta, an as NodeKind, bt as StringSchemaNode, ct as DatetimeSchemaNode, d as HttpOperationNode, dt as NumberSchemaNode, f as OperationNode, ft as ObjectSchemaNode, g as StatusCode, gt as ScalarSchemaType, h as ResponseNode, ht as ScalarSchemaNode, j as ObjectBindingPatternNode, jt as ParserOptions, k as FunctionParametersNode, l as GenericOperationNode, lt as EnumSchemaNode, mt as RefSchemaNode, n as OutputNode, nn as NodeDef, o as InputNode, ot as ArraySchemaNode, pt as PrimitiveSchemaType, q as SourceNode, rt as ContentNode, st as DateSchemaNode, t as Node, tn as DistributiveOmit, u as HttpMethod, ut as IntersectionSchemaNode, vt as SchemaNodeByType, xt as TimeSchemaNode, y as RequestBodyNode, yt as SchemaType, zt as TextNode } from "./index-DJEyS5y6.js";
import { t as OperationParamsResolver } from "./operationParams-BaY12i2I.js";
export type { ArraySchemaNode, ArrowFunctionNode, BreakNode, CodeNode, ConstNode, ContentNode, DateSchemaNode, DatetimeSchemaNode, Dialect, DistributiveOmit, Enforce, EnumSchemaNode, ExportNode, FileNode, FunctionNode, FunctionParamKind, FunctionParamNode, FunctionParameterNode, FunctionParametersNode, GenericOperationNode, HttpMethod, HttpOperationNode, ImportNode, IndexedAccessTypeNode, InferSchemaNode, InputMeta, InputNode, IntersectionSchemaNode, JSDocNode, JsxNode, Macro, Node, NodeDef, NodeKind, NumberSchemaNode, ObjectBindingPatternNode, ObjectSchemaNode, OperationNode, OperationParamsResolver, OutputNode, ParameterLocation, ParameterNode, ParentOf, ParserOptions, PrimitiveSchemaType, Printer, PrinterFactoryOptions, PrinterPartial, PropertyNode, RefSchemaNode, RequestBodyNode, ResponseNode, ScalarSchemaNode, ScalarSchemaType, SchemaDialect, SchemaNode, SchemaNodeByType, SchemaType, SourceNode, StatusCode, StringSchemaNode, TextNode, TimeSchemaNode, TypeExpression, TypeLiteralNode, TypeNode, UnionSchemaNode, UrlSchemaNode, UserFileNode, Visitor, VisitorContext };
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const require_visitor = require("./visitor-CLLDwBvv.cjs");
const require_refs = require("./refs-8IwpesXW.cjs");
const require_visitor = require("./visitor-CQdSiClY.cjs");
const require_refs = require("./refs-DuP3_Leg.cjs");
//#region ../../internals/utils/src/promise.ts

@@ -775,7 +775,5 @@ /**

//#endregion
exports.buildGroupParam = buildGroupParam;
exports.buildJSDoc = buildJSDoc;
exports.buildList = buildList;
exports.buildObject = buildObject;
exports.buildTypeLiteral = buildTypeLiteral;
exports.caseParams = caseParams;

@@ -800,5 +798,2 @@ exports.childName = require_refs.childName;

exports.objectKey = objectKey;
exports.resolveGroupType = require_refs.resolveGroupType;
exports.resolveParamType = resolveParamType;
exports.resolveRefName = require_refs.resolveRefName;
exports.stringify = stringify;

@@ -805,0 +800,0 @@ exports.stringifyObject = stringifyObject;

import { n as __name } from "./rolldown-runtime-CNktS9qV.js";
import { C as ParameterNode, Et as PropertyNode, Pt as CodeNode, St as UnionSchemaNode, _t as SchemaNode, f as OperationNode, ft as ObjectSchemaNode, ot as ArraySchemaNode, ut as IntersectionSchemaNode } from "./index-q_ldM1YP.js";
import { a as buildTypeLiteral, c as resolveParamType, i as buildGroupParam, n as OperationParamsResolver, o as caseParams, r as ParamGroupType, s as createOperationParams, t as BuildGroupArgs } from "./operationParams-Dme8H-sR.js";
import { Et as PropertyNode, Pt as CodeNode, St as UnionSchemaNode, _t as SchemaNode, f as OperationNode, ft as ObjectSchemaNode, ot as ArraySchemaNode, ut as IntersectionSchemaNode } from "./index-DJEyS5y6.js";
import { n as caseParams, r as createOperationParams } from "./operationParams-BaY12i2I.js";

@@ -101,12 +101,2 @@ //#region ../../internals/utils/src/reserved.d.ts

/**
* Resolves the schema name of a ref node. Uses the last segment of `ref` when set, otherwise falls
* back to `name` then nested `schema.name`.
*
* Returns `null` for non-ref nodes or when no name resolves.
*
* @example
* `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Pet' }) // 'Pet'`
*/
declare function resolveRefName(node: SchemaNode | undefined): string | null;
/**
* Builds a PascalCase child schema name by joining a parent name and property name.

@@ -152,19 +142,2 @@ * Returns `null` when there is no parent to nest under.

declare function isStringType(node: SchemaNode): boolean;
/**
* Derives a {@link ParamGroupType} for a query or header group from the resolver.
*
* Returns `null` when there is no resolver, no params, or the group name equals the
* individual param name (so there is no real group to emit).
*/
declare function resolveGroupType({
node,
params,
group,
resolver
}: {
node: OperationNode;
params: Array<ParameterNode>;
group: 'query' | 'header';
resolver: OperationParamsResolver | undefined;
}): ParamGroupType | null;
//#endregion

@@ -382,3 +355,3 @@ //#region src/utils/schemaMerge.d.ts

//#endregion
export { type BuildGroupArgs, type MappedProperty, type MappedSchema, type ParamGroupType, type SchemaTransform, buildGroupParam, buildJSDoc, buildList, buildObject, buildTypeLiteral, caseParams, childName, collectUsedSchemaNames, containsCircularRef, createOperationParams, enumPropName, extractRefName, extractStringsFromNodes, findCircularSchemas, getNestedAccessor, isStringType, isValidVarName, jsStringEscape, lazyGetter, mapSchemaItems, mapSchemaMembers, mapSchemaProperties, mergeAdjacentObjectsLazy, objectKey, resolveGroupType, resolveParamType, resolveRefName, stringify, stringifyObject, syncSchemaRef, toRegExpString, trimQuotes };
export { buildJSDoc, buildList, buildObject, caseParams, childName, collectUsedSchemaNames, containsCircularRef, createOperationParams, enumPropName, extractRefName, extractStringsFromNodes, findCircularSchemas, getNestedAccessor, isStringType, isValidVarName, jsStringEscape, lazyGetter, mapSchemaItems, mapSchemaMembers, mapSchemaProperties, mergeAdjacentObjectsLazy, objectKey, stringify, stringifyObject, syncSchemaRef, toRegExpString, trimQuotes };
//# sourceMappingURL=utils.d.ts.map
import "./rolldown-runtime-CNktS9qV.js";
import { C as createFunctionParameter, D as createTypeLiteral, H as camelCase, T as createIndexedAccessType, V as extractStringsFromNodes, lt as narrowSchema, n as collectLazy, o as createSchema, t as collect, ut as INDENT, w as createFunctionParameters } from "./visitor-DG5ROqRx.js";
import { a as resolveGroupType, i as isStringType, n as enumPropName, o as resolveRefName, r as extractRefName, s as syncSchemaRef, t as childName } from "./refs-D2qwT5ck.js";
import { C as createFunctionParameter, D as createTypeLiteral, H as camelCase, T as createIndexedAccessType, V as extractStringsFromNodes, lt as narrowSchema, n as collectLazy, o as createSchema, t as collect, ut as INDENT, w as createFunctionParameters } from "./visitor-dcVC5TOW.js";
import { a as resolveGroupType, i as isStringType, n as enumPropName, o as resolveRefName, r as extractRefName, s as syncSchemaRef, t as childName } from "./refs-D18OeCgb.js";
//#region ../../internals/utils/src/promise.ts

@@ -775,4 +775,4 @@ /**

//#endregion
export { buildGroupParam, buildJSDoc, buildList, buildObject, buildTypeLiteral, caseParams, childName, collectUsedSchemaNames, containsCircularRef, createOperationParams, enumPropName, extractRefName, extractStringsFromNodes, findCircularSchemas, getNestedAccessor, isStringType, isValidVarName, jsStringEscape, lazyGetter, mapSchemaItems, mapSchemaMembers, mapSchemaProperties, mergeAdjacentObjectsLazy, objectKey, resolveGroupType, resolveParamType, resolveRefName, stringify, stringifyObject, syncSchemaRef, toRegExpString, trimQuotes };
export { buildJSDoc, buildList, buildObject, caseParams, childName, collectUsedSchemaNames, containsCircularRef, createOperationParams, enumPropName, extractRefName, extractStringsFromNodes, findCircularSchemas, getNestedAccessor, isStringType, isValidVarName, jsStringEscape, lazyGetter, mapSchemaItems, mapSchemaMembers, mapSchemaProperties, mergeAdjacentObjectsLazy, objectKey, stringify, stringifyObject, syncSchemaRef, toRegExpString, trimQuotes };
//# sourceMappingURL=utils.js.map
{
"name": "@kubb/ast",
"version": "5.0.0-beta.70",
"version": "5.0.0-beta.71",
"description": "Spec-agnostic AST layer for Kubb. Defines the node tree, visitor pattern, factory functions, and type guards used across all code generation plugins.",

@@ -5,0 +5,0 @@ "keywords": [

const require_visitor = require("./visitor-CLLDwBvv.cjs");
//#region src/defineMacro.ts
/**
* Sort weight for an `enforce` hint. `pre` sorts before unmarked items and `post` after, so a plain
* list keeps its authored order.
*/
function enforceWeight(enforce) {
if (enforce === "pre") return 0;
if (enforce === "post") return 2;
return 1;
}
/**
* Types a macro for inference and a single construction site, mirroring `definePlugin`.
* Adds no runtime behavior.
*
* @example
* ```ts
* const macroUntagged = defineMacro({
* name: 'untagged',
* operation(node) {
* return node.tags?.length ? undefined : { ...node, tags: ['untagged'] }
* },
* })
* ```
*/
function defineMacro(macro) {
return macro;
}
/**
* Runs every macro's callback for one node kind in order, chaining the result so each macro sees
* the previous macro's output. Returns `undefined` when nothing changed, so `transform` keeps the
* original reference (structural sharing).
*/
function chain({ macros, key, node, context }) {
let current = node;
for (const macro of macros) {
const callback = macro[key];
if (!callback) continue;
if (macro.when && !macro.when(current)) continue;
const next = callback(current, context);
if (next != null) current = next;
}
return current === node ? void 0 : current;
}
/**
* Folds an ordered list of macros into a single {@link Visitor} that `transform` (and the per-plugin
* transform layer in `@kubb/core`) can run. Macros are stable-sorted by `enforce`, then applied
* sequentially per node so later macros see earlier output. This differs from a plain visitor, which
* has no names, ordering, or composition.
*
* @example
* ```ts
* const visitor = composeMacros([macroSimplifyUnion, macroDiscriminatorEnum])
* const next = transform(root, visitor)
* ```
*/
function composeMacros(macros) {
const ordered = [...macros].sort((a, b) => enforceWeight(a.enforce) - enforceWeight(b.enforce));
const visitor = {};
for (const key of require_visitor.visitorKeys) {
if (!ordered.some((macro) => typeof macro[key] === "function")) continue;
const callback = (node, context) => chain({
macros: ordered,
key,
node,
context
});
visitor[key] = callback;
}
return visitor;
}
/**
* Runs a list of macros over a node tree and returns the rewritten tree. Keeps `transform`'s
* structural sharing, so an empty or no-op macro list returns the same reference. Pass
* `depth: 'shallow'` to rewrite the root node only.
*
* @example
* ```ts
* const next = applyMacros(root, [macroIntegerToString])
* ```
*
* @example Apply to the root node only
* ```ts
* const named = applyMacros(node, [macroEnumName({ parentName, propName, enumSuffix })], { depth: 'shallow' })
* ```
*/
function applyMacros(root, macros, options) {
if (macros.length === 0) return root;
return require_visitor.transform(root, {
...composeMacros(macros),
...options
});
}
//#endregion
Object.defineProperty(exports, "applyMacros", {
enumerable: true,
get: function() {
return applyMacros;
}
});
Object.defineProperty(exports, "composeMacros", {
enumerable: true,
get: function() {
return composeMacros;
}
});
Object.defineProperty(exports, "defineMacro", {
enumerable: true,
get: function() {
return defineMacro;
}
});
//# sourceMappingURL=defineMacro-Bh5E_Il6.cjs.map
{"version":3,"file":"defineMacro-Bh5E_Il6.cjs","names":["visitorKeys","transform"],"sources":["../src/defineMacro.ts"],"sourcesContent":["import type { VisitorDepth } from './constants.ts'\nimport type { VisitorKey } from './defineNode.ts'\nimport { visitorKeys } from './defineNode.ts'\nimport type { Node } from './nodes/index.ts'\nimport type { Visitor, VisitorContext } from './visitor.ts'\nimport { transform } from './visitor.ts'\n\n/**\n * Ordering hint shared by macros and plugins. `pre` runs before unmarked items, `post` after,\n * and `undefined` keeps declaration order.\n */\nexport type Enforce = 'pre' | 'post'\n\n/**\n * Sort weight for an `enforce` hint. `pre` sorts before unmarked items and `post` after, so a plain\n * list keeps its authored order.\n */\nfunction enforceWeight(enforce?: Enforce): number {\n if (enforce === 'pre') return 0\n if (enforce === 'post') return 2\n return 1\n}\n\n/**\n * A named, composable transform over the Kubb AST. It carries the same per-kind callbacks as a\n * {@link Visitor} (`schema`, `operation`, …), plus a `name`, an optional `enforce` order, and an\n * optional `when` gate. Macros run on the shared AST, so the same macro works across every adapter\n * and output target. Exports follow the `macro<Name>` convention, mirroring plugins (`pluginTs`).\n */\nexport type Macro = Visitor & {\n /**\n * Macro identifier used to tell macros apart, for example `'simplify-union'`.\n */\n name: string\n /**\n * Ordering hint. `pre` macros run before unmarked macros, `post` macros run after.\n * Ordering within a bucket follows list order.\n */\n enforce?: Enforce\n /**\n * Gate checked against the current node before any callback runs. When it returns `false`\n * the macro is skipped for that node.\n */\n when?: (node: Node) => boolean\n}\n\n/**\n * Types a macro for inference and a single construction site, mirroring `definePlugin`.\n * Adds no runtime behavior.\n *\n * @example\n * ```ts\n * const macroUntagged = defineMacro({\n * name: 'untagged',\n * operation(node) {\n * return node.tags?.length ? undefined : { ...node, tags: ['untagged'] }\n * },\n * })\n * ```\n */\nexport function defineMacro(macro: Macro): Macro {\n return macro\n}\n\ntype MacroCallback = (node: Node, context: VisitorContext) => Node | null | undefined\n\ntype ChainProps = {\n macros: ReadonlyArray<Macro>\n key: VisitorKey\n node: Node\n context: VisitorContext\n}\n\n/**\n * Runs every macro's callback for one node kind in order, chaining the result so each macro sees\n * the previous macro's output. Returns `undefined` when nothing changed, so `transform` keeps the\n * original reference (structural sharing).\n */\nfunction chain({ macros, key, node, context }: ChainProps): Node | undefined {\n let current = node\n\n for (const macro of macros) {\n const callback = macro[key] as MacroCallback | undefined\n if (!callback) continue\n if (macro.when && !macro.when(current)) continue\n\n const next = callback(current, context)\n if (next != null) current = next\n }\n\n return current === node ? undefined : current\n}\n\n/**\n * Folds an ordered list of macros into a single {@link Visitor} that `transform` (and the per-plugin\n * transform layer in `@kubb/core`) can run. Macros are stable-sorted by `enforce`, then applied\n * sequentially per node so later macros see earlier output. This differs from a plain visitor, which\n * has no names, ordering, or composition.\n *\n * @example\n * ```ts\n * const visitor = composeMacros([macroSimplifyUnion, macroDiscriminatorEnum])\n * const next = transform(root, visitor)\n * ```\n */\nexport function composeMacros(macros: ReadonlyArray<Macro>): Visitor {\n const ordered = [...macros].sort((a, b) => enforceWeight(a.enforce) - enforceWeight(b.enforce))\n\n const visitor: Visitor = {}\n for (const key of visitorKeys) {\n if (!ordered.some((macro) => typeof macro[key] === 'function')) continue\n\n const callback = (node: Node, context: VisitorContext) => chain({ macros: ordered, key, node, context })\n ;(visitor as Record<VisitorKey, MacroCallback>)[key] = callback\n }\n\n return visitor\n}\n\n/**\n * Runs a list of macros over a node tree and returns the rewritten tree. Keeps `transform`'s\n * structural sharing, so an empty or no-op macro list returns the same reference. Pass\n * `depth: 'shallow'` to rewrite the root node only.\n *\n * @example\n * ```ts\n * const next = applyMacros(root, [macroIntegerToString])\n * ```\n *\n * @example Apply to the root node only\n * ```ts\n * const named = applyMacros(node, [macroEnumName({ parentName, propName, enumSuffix })], { depth: 'shallow' })\n * ```\n */\nexport function applyMacros<TNode extends Node>(root: TNode, macros: ReadonlyArray<Macro>, options?: { depth?: VisitorDepth }): TNode {\n if (macros.length === 0) return root\n\n return transform(root, { ...composeMacros(macros), ...options }) as TNode\n}\n"],"mappings":";;;;;;AAiBA,SAAS,cAAc,SAA2B;CAChD,IAAI,YAAY,OAAO,OAAO;CAC9B,IAAI,YAAY,QAAQ,OAAO;CAC/B,OAAO;AACT;;;;;;;;;;;;;;;AAuCA,SAAgB,YAAY,OAAqB;CAC/C,OAAO;AACT;;;;;;AAgBA,SAAS,MAAM,EAAE,QAAQ,KAAK,MAAM,WAAyC;CAC3E,IAAI,UAAU;CAEd,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,WAAW,MAAM;EACvB,IAAI,CAAC,UAAU;EACf,IAAI,MAAM,QAAQ,CAAC,MAAM,KAAK,OAAO,GAAG;EAExC,MAAM,OAAO,SAAS,SAAS,OAAO;EACtC,IAAI,QAAQ,MAAM,UAAU;CAC9B;CAEA,OAAO,YAAY,OAAO,KAAA,IAAY;AACxC;;;;;;;;;;;;;AAcA,SAAgB,cAAc,QAAuC;CACnE,MAAM,UAAU,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,GAAG,MAAM,cAAc,EAAE,OAAO,IAAI,cAAc,EAAE,OAAO,CAAC;CAE9F,MAAM,UAAmB,CAAC;CAC1B,KAAK,MAAM,OAAOA,gBAAAA,aAAa;EAC7B,IAAI,CAAC,QAAQ,MAAM,UAAU,OAAO,MAAM,SAAS,UAAU,GAAG;EAEhE,MAAM,YAAY,MAAY,YAA4B,MAAM;GAAE,QAAQ;GAAS;GAAK;GAAM;EAAQ,CAAC;EACtG,QAA+C,OAAO;CACzD;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;AAiBA,SAAgB,YAAgC,MAAa,QAA8B,SAA2C;CACpI,IAAI,OAAO,WAAW,GAAG,OAAO;CAEhC,OAAOC,gBAAAA,UAAU,MAAM;EAAE,GAAG,cAAc,MAAM;EAAG,GAAG;CAAQ,CAAC;AACjE"}
import "./rolldown-runtime-CNktS9qV.js";
import { r as transform, st as visitorKeys } from "./visitor-DG5ROqRx.js";
//#region src/defineMacro.ts
/**
* Sort weight for an `enforce` hint. `pre` sorts before unmarked items and `post` after, so a plain
* list keeps its authored order.
*/
function enforceWeight(enforce) {
if (enforce === "pre") return 0;
if (enforce === "post") return 2;
return 1;
}
/**
* Types a macro for inference and a single construction site, mirroring `definePlugin`.
* Adds no runtime behavior.
*
* @example
* ```ts
* const macroUntagged = defineMacro({
* name: 'untagged',
* operation(node) {
* return node.tags?.length ? undefined : { ...node, tags: ['untagged'] }
* },
* })
* ```
*/
function defineMacro(macro) {
return macro;
}
/**
* Runs every macro's callback for one node kind in order, chaining the result so each macro sees
* the previous macro's output. Returns `undefined` when nothing changed, so `transform` keeps the
* original reference (structural sharing).
*/
function chain({ macros, key, node, context }) {
let current = node;
for (const macro of macros) {
const callback = macro[key];
if (!callback) continue;
if (macro.when && !macro.when(current)) continue;
const next = callback(current, context);
if (next != null) current = next;
}
return current === node ? void 0 : current;
}
/**
* Folds an ordered list of macros into a single {@link Visitor} that `transform` (and the per-plugin
* transform layer in `@kubb/core`) can run. Macros are stable-sorted by `enforce`, then applied
* sequentially per node so later macros see earlier output. This differs from a plain visitor, which
* has no names, ordering, or composition.
*
* @example
* ```ts
* const visitor = composeMacros([macroSimplifyUnion, macroDiscriminatorEnum])
* const next = transform(root, visitor)
* ```
*/
function composeMacros(macros) {
const ordered = [...macros].sort((a, b) => enforceWeight(a.enforce) - enforceWeight(b.enforce));
const visitor = {};
for (const key of visitorKeys) {
if (!ordered.some((macro) => typeof macro[key] === "function")) continue;
const callback = (node, context) => chain({
macros: ordered,
key,
node,
context
});
visitor[key] = callback;
}
return visitor;
}
/**
* Runs a list of macros over a node tree and returns the rewritten tree. Keeps `transform`'s
* structural sharing, so an empty or no-op macro list returns the same reference. Pass
* `depth: 'shallow'` to rewrite the root node only.
*
* @example
* ```ts
* const next = applyMacros(root, [macroIntegerToString])
* ```
*
* @example Apply to the root node only
* ```ts
* const named = applyMacros(node, [macroEnumName({ parentName, propName, enumSuffix })], { depth: 'shallow' })
* ```
*/
function applyMacros(root, macros, options) {
if (macros.length === 0) return root;
return transform(root, {
...composeMacros(macros),
...options
});
}
//#endregion
export { composeMacros as n, defineMacro as r, applyMacros as t };
//# sourceMappingURL=defineMacro-CVrU3ajV.js.map
{"version":3,"file":"defineMacro-CVrU3ajV.js","names":[],"sources":["../src/defineMacro.ts"],"sourcesContent":["import type { VisitorDepth } from './constants.ts'\nimport type { VisitorKey } from './defineNode.ts'\nimport { visitorKeys } from './defineNode.ts'\nimport type { Node } from './nodes/index.ts'\nimport type { Visitor, VisitorContext } from './visitor.ts'\nimport { transform } from './visitor.ts'\n\n/**\n * Ordering hint shared by macros and plugins. `pre` runs before unmarked items, `post` after,\n * and `undefined` keeps declaration order.\n */\nexport type Enforce = 'pre' | 'post'\n\n/**\n * Sort weight for an `enforce` hint. `pre` sorts before unmarked items and `post` after, so a plain\n * list keeps its authored order.\n */\nfunction enforceWeight(enforce?: Enforce): number {\n if (enforce === 'pre') return 0\n if (enforce === 'post') return 2\n return 1\n}\n\n/**\n * A named, composable transform over the Kubb AST. It carries the same per-kind callbacks as a\n * {@link Visitor} (`schema`, `operation`, …), plus a `name`, an optional `enforce` order, and an\n * optional `when` gate. Macros run on the shared AST, so the same macro works across every adapter\n * and output target. Exports follow the `macro<Name>` convention, mirroring plugins (`pluginTs`).\n */\nexport type Macro = Visitor & {\n /**\n * Macro identifier used to tell macros apart, for example `'simplify-union'`.\n */\n name: string\n /**\n * Ordering hint. `pre` macros run before unmarked macros, `post` macros run after.\n * Ordering within a bucket follows list order.\n */\n enforce?: Enforce\n /**\n * Gate checked against the current node before any callback runs. When it returns `false`\n * the macro is skipped for that node.\n */\n when?: (node: Node) => boolean\n}\n\n/**\n * Types a macro for inference and a single construction site, mirroring `definePlugin`.\n * Adds no runtime behavior.\n *\n * @example\n * ```ts\n * const macroUntagged = defineMacro({\n * name: 'untagged',\n * operation(node) {\n * return node.tags?.length ? undefined : { ...node, tags: ['untagged'] }\n * },\n * })\n * ```\n */\nexport function defineMacro(macro: Macro): Macro {\n return macro\n}\n\ntype MacroCallback = (node: Node, context: VisitorContext) => Node | null | undefined\n\ntype ChainProps = {\n macros: ReadonlyArray<Macro>\n key: VisitorKey\n node: Node\n context: VisitorContext\n}\n\n/**\n * Runs every macro's callback for one node kind in order, chaining the result so each macro sees\n * the previous macro's output. Returns `undefined` when nothing changed, so `transform` keeps the\n * original reference (structural sharing).\n */\nfunction chain({ macros, key, node, context }: ChainProps): Node | undefined {\n let current = node\n\n for (const macro of macros) {\n const callback = macro[key] as MacroCallback | undefined\n if (!callback) continue\n if (macro.when && !macro.when(current)) continue\n\n const next = callback(current, context)\n if (next != null) current = next\n }\n\n return current === node ? undefined : current\n}\n\n/**\n * Folds an ordered list of macros into a single {@link Visitor} that `transform` (and the per-plugin\n * transform layer in `@kubb/core`) can run. Macros are stable-sorted by `enforce`, then applied\n * sequentially per node so later macros see earlier output. This differs from a plain visitor, which\n * has no names, ordering, or composition.\n *\n * @example\n * ```ts\n * const visitor = composeMacros([macroSimplifyUnion, macroDiscriminatorEnum])\n * const next = transform(root, visitor)\n * ```\n */\nexport function composeMacros(macros: ReadonlyArray<Macro>): Visitor {\n const ordered = [...macros].sort((a, b) => enforceWeight(a.enforce) - enforceWeight(b.enforce))\n\n const visitor: Visitor = {}\n for (const key of visitorKeys) {\n if (!ordered.some((macro) => typeof macro[key] === 'function')) continue\n\n const callback = (node: Node, context: VisitorContext) => chain({ macros: ordered, key, node, context })\n ;(visitor as Record<VisitorKey, MacroCallback>)[key] = callback\n }\n\n return visitor\n}\n\n/**\n * Runs a list of macros over a node tree and returns the rewritten tree. Keeps `transform`'s\n * structural sharing, so an empty or no-op macro list returns the same reference. Pass\n * `depth: 'shallow'` to rewrite the root node only.\n *\n * @example\n * ```ts\n * const next = applyMacros(root, [macroIntegerToString])\n * ```\n *\n * @example Apply to the root node only\n * ```ts\n * const named = applyMacros(node, [macroEnumName({ parentName, propName, enumSuffix })], { depth: 'shallow' })\n * ```\n */\nexport function applyMacros<TNode extends Node>(root: TNode, macros: ReadonlyArray<Macro>, options?: { depth?: VisitorDepth }): TNode {\n if (macros.length === 0) return root\n\n return transform(root, { ...composeMacros(macros), ...options }) as TNode\n}\n"],"mappings":";;;;;;;AAiBA,SAAS,cAAc,SAA2B;CAChD,IAAI,YAAY,OAAO,OAAO;CAC9B,IAAI,YAAY,QAAQ,OAAO;CAC/B,OAAO;AACT;;;;;;;;;;;;;;;AAuCA,SAAgB,YAAY,OAAqB;CAC/C,OAAO;AACT;;;;;;AAgBA,SAAS,MAAM,EAAE,QAAQ,KAAK,MAAM,WAAyC;CAC3E,IAAI,UAAU;CAEd,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,WAAW,MAAM;EACvB,IAAI,CAAC,UAAU;EACf,IAAI,MAAM,QAAQ,CAAC,MAAM,KAAK,OAAO,GAAG;EAExC,MAAM,OAAO,SAAS,SAAS,OAAO;EACtC,IAAI,QAAQ,MAAM,UAAU;CAC9B;CAEA,OAAO,YAAY,OAAO,KAAA,IAAY;AACxC;;;;;;;;;;;;;AAcA,SAAgB,cAAc,QAAuC;CACnE,MAAM,UAAU,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,GAAG,MAAM,cAAc,EAAE,OAAO,IAAI,cAAc,EAAE,OAAO,CAAC;CAE9F,MAAM,UAAmB,CAAC;CAC1B,KAAK,MAAM,OAAO,aAAa;EAC7B,IAAI,CAAC,QAAQ,MAAM,UAAU,OAAO,MAAM,SAAS,UAAU,GAAG;EAEhE,MAAM,YAAY,MAAY,YAA4B,MAAM;GAAE,QAAQ;GAAS;GAAK;GAAM;EAAQ,CAAC;EACtG,QAA+C,OAAO;CACzD;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;AAiBA,SAAgB,YAAgC,MAAa,QAA8B,SAA2C;CACpI,IAAI,OAAO,WAAW,GAAG,OAAO;CAEhC,OAAO,UAAU,MAAM;EAAE,GAAG,cAAc,MAAM;EAAG,GAAG;CAAQ,CAAC;AACjE"}
import { n as __name } from "./rolldown-runtime-CNktS9qV.js";
import { C as ParameterNode, Et as PropertyNode, _t as SchemaNode, f as OperationNode, h as ResponseNode, n as OutputNode, o as InputNode, rt as ContentNode, t as Node, y as RequestBodyNode } from "./index-q_ldM1YP.js";
//#region src/constants.d.ts
/**
* Traversal depth for AST visitor utilities.
*
* - `'shallow'` visits only the immediate node, skipping children.
* - `'deep'` recursively visits all descendant nodes.
*/
type VisitorDepth = 'shallow' | 'deep';
/**
* Schema type discriminators used by all AST schema nodes.
*
* Each value is a stable discriminator across the AST (for example `schema.type === schemaTypes.object`).
*/
declare const schemaTypes: {
/**
* Text value.
*/
readonly string: "string";
/**
* Floating-point number (`float`, `double`).
*/
readonly number: "number";
/**
* Whole number (`int32`). Use `bigint` for `int64`.
*/
readonly integer: "integer";
/**
* 64-bit integer (`int64`). Only used when `integerType` is set to `'bigint'`.
*/
readonly bigint: "bigint";
/**
* Boolean value.
*/
readonly boolean: "boolean";
/**
* Explicit null value.
*/
readonly null: "null";
/**
* Any value (no type restriction).
*/
readonly any: "any";
/**
* Unknown value (must be narrowed before usage).
*/
readonly unknown: "unknown";
/**
* No return value (`void`).
*/
readonly void: "void";
/**
* Object with named properties.
*/
readonly object: "object";
/**
* Sequential list of items.
*/
readonly array: "array";
/**
* Fixed-length list with position-specific items.
*/
readonly tuple: "tuple";
/**
* "One of" multiple schema members.
*/
readonly union: "union";
/**
* "All of" multiple schema members.
*/
readonly intersection: "intersection";
/**
* Enum schema.
*/
readonly enum: "enum";
/**
* Reference to another schema.
*/
readonly ref: "ref";
/**
* Calendar date (for example `2026-03-24`).
*/
readonly date: "date";
/**
* Date-time value (for example `2026-03-24T09:00:00Z`).
*/
readonly datetime: "datetime";
/**
* Time-only value (for example `09:00:00`).
*/
readonly time: "time";
/**
* UUID value.
*/
readonly uuid: "uuid";
/**
* Email address value.
*/
readonly email: "email";
/**
* URL value.
*/
readonly url: "url";
/**
* IPv4 address value.
*/
readonly ipv4: "ipv4";
/**
* IPv6 address value.
*/
readonly ipv6: "ipv6";
/**
* Binary/blob value.
*/
readonly blob: "blob";
/**
* Impossible value (`never`).
*/
readonly never: "never";
};
//#endregion
//#region src/visitor.d.ts
/**
* Ordered mapping of `[NodeType, ParentType]` pairs.
*
* `ParentOf` uses this map to find parent types.
*/
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]];
/**
* Resolves the parent node type for a given AST node type.
*
* Visitor context relies on this so `ctx.parent` is typed for each callback.
*
* @example
* ```ts
* type InputParent = ParentOf<InputNode>
* // undefined
* ```
*
* @example
* ```ts
* type PropertyParent = ParentOf<PropertyNode>
* // SchemaNode
* ```
*
* @example
* ```ts
* type SchemaParent = ParentOf<SchemaNode>
* // InputNode | ContentNode | SchemaNode | PropertyNode | ParameterNode
* ```
*/
type ParentOf<T extends Node, TEntries extends ReadonlyArray<[Node, unknown]> = ParentNodeMap> = TEntries extends [infer TEntry extends [Node, unknown], ...infer TRest extends ReadonlyArray<[Node, unknown]>] ? T extends TEntry[0] ? TEntry[1] : ParentOf<T, TRest> : Node;
/**
* Traversal context passed as the second argument to every visitor callback.
* `parent` is typed from the current node type.
*
* @example
* ```ts
* const visitor: Visitor = {
* schema(node, { parent }) {
* // parent type is narrowed by node kind
* },
* }
* ```
*/
type VisitorContext<T extends Node = Node> = {
/**
* Parent node of the currently visited node.
* For `InputNode`, this is `undefined`.
*/
parent?: ParentOf<T>;
};
/**
* Synchronous visitor consumed by `transform`. Each optional callback runs
* for the matching node type. Return a new node to replace it, or `undefined`
* to leave it untouched.
*
* Plugins typically expose `transformer` so users can supply a `Visitor` that
* rewrites the AST before printing.
*
* @example Prefix every operationId
* ```ts
* const visitor: Visitor = {
* operation(node) {
* return { ...node, operationId: `api_${node.operationId}` }
* },
* }
* ```
*
* @example Strip schema descriptions
* ```ts
* const visitor: Visitor = {
* schema(node) {
* return { ...node, description: undefined }
* },
* }
* ```
*/
type Visitor = {
input?(node: InputNode, context: VisitorContext<InputNode>): undefined | null | InputNode;
output?(node: OutputNode, context: VisitorContext<OutputNode>): undefined | null | OutputNode;
operation?(node: OperationNode, context: VisitorContext<OperationNode>): undefined | null | OperationNode;
schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): undefined | null | SchemaNode;
property?(node: PropertyNode, context: VisitorContext<PropertyNode>): undefined | null | PropertyNode;
parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): undefined | null | ParameterNode;
response?(node: ResponseNode, context: VisitorContext<ResponseNode>): undefined | null | ResponseNode;
};
/**
* A visitor callback result that may be sync or async.
*/
type MaybePromise<T> = T | Promise<T>;
/**
* Async visitor for `walk`. Synchronous `Visitor` objects are compatible.
*
* @example
* ```ts
* const visitor: AsyncVisitor = {
* async operation(node) {
* await Promise.resolve(node.operationId)
* },
* }
* ```
*/
type AsyncVisitor = {
input?(node: InputNode, context: VisitorContext<InputNode>): MaybePromise<undefined | null | InputNode>;
output?(node: OutputNode, context: VisitorContext<OutputNode>): MaybePromise<undefined | null | OutputNode>;
operation?(node: OperationNode, context: VisitorContext<OperationNode>): MaybePromise<undefined | null | OperationNode>;
schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): MaybePromise<undefined | null | SchemaNode>;
property?(node: PropertyNode, context: VisitorContext<PropertyNode>): MaybePromise<undefined | null | PropertyNode>;
parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): MaybePromise<undefined | null | ParameterNode>;
response?(node: ResponseNode, context: VisitorContext<ResponseNode>): MaybePromise<undefined | null | ResponseNode>;
};
/**
* Visitor used by `collect`.
*
* @example
* ```ts
* const visitor: CollectVisitor<string> = {
* operation(node) {
* return node.operationId
* },
* }
* ```
*/
type CollectVisitor<T> = {
input?(node: InputNode, context: VisitorContext<InputNode>): T | null | undefined;
output?(node: OutputNode, context: VisitorContext<OutputNode>): T | null | undefined;
operation?(node: OperationNode, context: VisitorContext<OperationNode>): T | null | undefined;
schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): T | null | undefined;
property?(node: PropertyNode, context: VisitorContext<PropertyNode>): T | null | undefined;
parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): T | null | undefined;
response?(node: ResponseNode, context: VisitorContext<ResponseNode>): T | null | undefined;
};
/**
* Options for `transform`.
*
* @example
* ```ts
* const options: TransformOptions = { depth: 'deep', schema: (node) => node }
* ```
*
* @example
* ```ts
* // Only transform the current node, not nested children
* const options: TransformOptions = { depth: 'shallow', schema: (node) => node }
* ```
*/
type TransformOptions = Visitor & {
/**
* Traversal depth.
* @default 'deep'
*/
depth?: VisitorDepth;
/**
* Internal parent override used during recursion.
*/
parent?: Node;
};
/**
* Options for `walk`.
*
* @example
* ```ts
* const options: WalkOptions = { depth: 'deep', concurrency: 10, root: () => {} }
* ```
*/
type WalkOptions = AsyncVisitor & {
/**
* Traversal depth.
* @default 'deep'
*/
depth?: VisitorDepth;
/**
* Maximum number of sibling nodes visited concurrently.
* @default 30
*/
concurrency?: number;
};
/**
* Options for `collect`.
*
* @example
* ```ts
* const options: CollectOptions<string> = { depth: 'shallow', schema: () => undefined }
* ```
*/
type CollectOptions<T> = CollectVisitor<T> & {
/**
* Traversal depth.
* @default 'deep'
*/
depth?: VisitorDepth;
/**
* Internal parent override used during recursion.
*/
parent?: Node;
};
/**
* Async depth-first traversal for side effects. Visitor return values are
* ignored. Use `transform` when you want to rewrite nodes.
*
* Sibling nodes at each depth run concurrently up to `options.concurrency`
* (defaults to `WALK_CONCURRENCY`). Higher values overlap I/O-bound visitor
* work. Lower values reduce memory pressure.
*
* @example Log every operation
* ```ts
* await walk(root, {
* operation(node) {
* console.log(node.operationId)
* },
* })
* ```
*
* @example Only visit the root node
* ```ts
* await walk(root, { depth: 'shallow', input: () => {} })
* ```
*/
declare function walk(node: Node, options: WalkOptions): Promise<void>;
/**
* Synchronous depth-first transform. Each visitor callback can return a
* replacement node. Returning `undefined` keeps the original.
*
* The original tree is never mutated, a new tree is returned. Pass
* `depth: 'shallow'` to skip recursion into children.
*
* @example Prefix every operationId
* ```ts
* const next = transform(root, {
* operation(node) {
* return { ...node, operationId: `prefixed_${node.operationId}` }
* },
* })
* ```
*
* @example Replace only the root node
* ```ts
* const next = transform(root, {
* depth: 'shallow',
* input: (node) => ({ ...node, meta: { ...node.meta, title: 'Rewritten' } }),
* })
* ```
*/
declare function transform(node: InputNode, options: TransformOptions): InputNode;
declare function transform(node: OutputNode, options: TransformOptions): OutputNode;
declare function transform(node: OperationNode, options: TransformOptions): OperationNode;
declare function transform(node: SchemaNode, options: TransformOptions): SchemaNode;
declare function transform(node: PropertyNode, options: TransformOptions): PropertyNode;
declare function transform(node: ParameterNode, options: TransformOptions): ParameterNode;
declare function transform(node: ResponseNode, options: TransformOptions): ResponseNode;
declare function transform(node: Node, options: TransformOptions): Node;
/**
* Eager depth-first collection pass. Gathers every non-null value the visitor
* callbacks return into an array.
*
* @example Collect every operationId
* ```ts
* const ids = collect<string>(root, {
* operation(node) {
* return node.operationId
* },
* })
* ```
*/
declare function collect<T>(node: Node, options: CollectOptions<T>): Array<T>;
//#endregion
//#region src/defineMacro.d.ts
/**
* Ordering hint shared by macros and plugins. `pre` runs before unmarked items, `post` after,
* and `undefined` keeps declaration order.
*/
type Enforce = 'pre' | 'post';
/**
* A named, composable transform over the Kubb AST. It carries the same per-kind callbacks as a
* {@link Visitor} (`schema`, `operation`, …), plus a `name`, an optional `enforce` order, and an
* optional `when` gate. Macros run on the shared AST, so the same macro works across every adapter
* and output target. Exports follow the `macro<Name>` convention, mirroring plugins (`pluginTs`).
*/
type Macro = Visitor & {
/**
* Macro identifier used to tell macros apart, for example `'simplify-union'`.
*/
name: string;
/**
* Ordering hint. `pre` macros run before unmarked macros, `post` macros run after.
* Ordering within a bucket follows list order.
*/
enforce?: Enforce;
/**
* Gate checked against the current node before any callback runs. When it returns `false`
* the macro is skipped for that node.
*/
when?: (node: Node) => boolean;
};
/**
* Types a macro for inference and a single construction site, mirroring `definePlugin`.
* Adds no runtime behavior.
*
* @example
* ```ts
* const macroUntagged = defineMacro({
* name: 'untagged',
* operation(node) {
* return node.tags?.length ? undefined : { ...node, tags: ['untagged'] }
* },
* })
* ```
*/
declare function defineMacro(macro: Macro): Macro;
/**
* Folds an ordered list of macros into a single {@link Visitor} that `transform` (and the per-plugin
* transform layer in `@kubb/core`) can run. Macros are stable-sorted by `enforce`, then applied
* sequentially per node so later macros see earlier output. This differs from a plain visitor, which
* has no names, ordering, or composition.
*
* @example
* ```ts
* const visitor = composeMacros([macroSimplifyUnion, macroDiscriminatorEnum])
* const next = transform(root, visitor)
* ```
*/
declare function composeMacros(macros: ReadonlyArray<Macro>): Visitor;
/**
* Runs a list of macros over a node tree and returns the rewritten tree. Keeps `transform`'s
* structural sharing, so an empty or no-op macro list returns the same reference. Pass
* `depth: 'shallow'` to rewrite the root node only.
*
* @example
* ```ts
* const next = applyMacros(root, [macroIntegerToString])
* ```
*
* @example Apply to the root node only
* ```ts
* const named = applyMacros(node, [macroEnumName({ parentName, propName, enumSuffix })], { depth: 'shallow' })
* ```
*/
declare function applyMacros<TNode extends Node>(root: TNode, macros: ReadonlyArray<Macro>, options?: {
depth?: VisitorDepth;
}): TNode;
//#endregion
export { defineMacro as a, VisitorContext as c, walk as d, schemaTypes as f, composeMacros as i, collect as l, Macro as n, ParentOf as o, applyMacros as r, Visitor as s, Enforce as t, transform as u };
//# sourceMappingURL=defineMacro-D9ekmTW5.d.ts.map

Sorry, the diff of this file is too big to display

import { n as __name } from "./rolldown-runtime-CNktS9qV.js";
import { C as ParameterNode, M as TypeExpression, N as TypeLiteralNode, O as FunctionParameterNode, f as OperationNode, k as FunctionParametersNode } from "./index-q_ldM1YP.js";
//#region src/utils/operationParams.d.ts
/**
* Applies casing rules to parameter names and returns a new array without mutating the input.
*
* Run it before handing parameters to schema builders so output property keys get the right casing
* while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the
* original array is returned unchanged.
*/
declare function caseParams(params: Array<ParameterNode>, casing: 'camelcase' | undefined): Array<ParameterNode>;
/**
* Named type for a group of parameters (query or header) emitted as a single typed parameter.
*/
type ParamGroupType = {
/**
* Type expression for the group, a plain group-name reference.
*/
type: TypeExpression;
/**
* Whether the parameter group is optional.
*/
optional: boolean;
};
/**
* Resolver interface for {@link createOperationParams}.
*
* `ResolverTs` from `@kubb/plugin-ts` satisfies this interface and can be passed directly.
*/
type OperationParamsResolver = {
/**
* Resolves the type name for an individual parameter.
*
* @example Individual path parameter name
* `resolver.resolveParamName(node, param) // → 'DeletePetPathPetId'`
*/
resolveParamName(node: OperationNode, param: ParameterNode): string;
/**
* Resolves the request body type name.
*
* @example Request body type name
* `resolver.resolveDataName(node) // → 'CreatePetData'`
*/
resolveDataName(node: OperationNode): string;
/**
* Resolves the grouped path parameters type name.
* When the return value equals `resolveParamName`, no indexed access is emitted.
*
* @example Grouped path params type name
* `resolver.resolvePathParamsName(node, param) // → 'DeletePetPathParams'`
*/
resolvePathParamsName(node: OperationNode, param: ParameterNode): string;
/**
* Resolves the grouped query parameters type name.
* When the return value equals `resolveParamName`, an inline struct type is emitted instead.
*
* @example Grouped query params type name
* `resolver.resolveQueryParamsName(node, param) // → 'FindPetsByStatusQueryParams'`
*/
resolveQueryParamsName(node: OperationNode, param: ParameterNode): string;
/**
* Resolves the grouped header parameters type name.
* When the return value equals `resolveParamName`, an inline struct type is emitted instead.
*
* @example Grouped header params type name
* `resolver.resolveHeaderParamsName(node, param) // → 'DeletePetHeaderParams'`
*/
resolveHeaderParamsName(node: OperationNode, param: ParameterNode): string;
};
/**
* Options for {@link createOperationParams}.
*/
type CreateOperationParamsOptions = {
/**
* How all operation parameters are grouped in the function signature.
* - `'object'` wraps all params into a single destructured object `{ petId, data, params }`
* - `'inline'` emits each param category as a separate top-level parameter
*/
paramsType: 'object' | 'inline';
/**
* How path parameters are emitted when `paramsType` is `'inline'`.
* - `'object'` groups them as `{ petId, storeId }: PathParams`
* - `'inline'` spreads them as individual parameters `petId: string, storeId: string`
* - `'inlineSpread'` emits a single rest parameter `...pathParams: PathParams`
*/
pathParamsType: 'object' | 'inline' | 'inlineSpread';
/**
* Converts parameter names to camelCase before output.
*/
paramsCasing?: 'camelcase';
/**
* Resolver for parameter and request body type names.
* Pass `ResolverTs` from `@kubb/plugin-ts` directly.
* When omitted, falls back to the schema primitive or `'unknown'`.
*/
resolver?: OperationParamsResolver;
/**
* Default value for the path parameters binding when `pathParamsType` is `'object'`.
* Falls back to `'{}'` when all path params are optional.
*/
pathParamsDefault?: string;
/**
* Extra parameters appended after the standard operation parameters.
*
* @example Plugin-specific trailing parameter
* ```ts
* extraParams: [createFunctionParameter({ name: 'options', type: 'Partial<RequestOptions>', default: '{}' })]
* ```
*/
extraParams?: Array<FunctionParameterNode>;
/**
* Override the default parameter names used for body, query, header, and rest-path groups.
*
* Useful when targeting languages or frameworks with different naming conventions.
*
* @default { data: 'data', params: 'params', headers: 'headers', path: 'pathParams' }
*/
paramNames?: {
/**
* Name for the request body parameter.
* @default 'data'
*/
data?: string;
/**
* Name for the query parameters group parameter.
* @default 'params'
*/
params?: string;
/**
* Name for the header parameters group parameter.
* @default 'headers'
*/
headers?: string;
/**
* Name for the rest path-parameters parameter when `pathParamsType` is `'inlineSpread'`.
* @default 'pathParams'
*/
path?: string;
};
/**
* Transforms every resolved type name before it lands in a parameter node, for framework-level
* type wrappers.
*
* @example Vue Query, wrap every parameter type with `MaybeRefOrGetter`
* `typeWrapper: (t) => \`MaybeRefOrGetter<${t}>\``
*/
typeWrapper?: (type: string) => string;
};
/**
* Resolves the {@link TypeExpression} for an individual parameter.
*
* Without a resolver, it falls back to the schema primitive (a plain type-name string). When the
* parameter belongs to a named group, it emits an {@link IndexedAccessTypeNode} like
* `GroupParams['petId']`, otherwise the resolved individual name.
*/
declare function resolveParamType({
node,
param,
resolver
}: {
node: OperationNode;
param: ParameterNode;
resolver: OperationParamsResolver | undefined;
}): TypeExpression;
/**
* Converts an `OperationNode` into function parameters for code generation.
*
* Centralizes parameter grouping logic for all plugins. `paramsType` chooses between one
* destructured object parameter (`object`) and separate top-level parameters (`inline`), while
* `pathParamsType` controls how path params render in inline mode. Provide a `resolver` for type
* name resolution and `extraParams` for plugin-specific trailing parameters such as an `options` object.
*/
declare function createOperationParams(node: OperationNode, options: CreateOperationParamsOptions): FunctionParametersNode;
/**
* Shared arguments for building a query or header parameter group.
*/
type BuildGroupArgs = {
name: string;
node: OperationNode;
params: Array<ParameterNode>;
groupType: ParamGroupType | null;
resolver: OperationParamsResolver | undefined;
wrapType: (type: string) => string;
};
/**
* Builds a single {@link FunctionParameterNode} for a query or header group.
* Returns an empty array when there are no params to emit.
*
* A pre-resolved `groupType` emits `name: GroupType`. Otherwise it builds an inline
* {@link TypeLiteralNode} from the individual params.
*/
declare function buildGroupParam(args: BuildGroupArgs): Array<FunctionParameterNode>;
/**
* Builds a {@link TypeLiteralNode} for an inline anonymous type grouping named fields.
*
* Used when query or header parameters have no dedicated group type name.
* Each language printer renders this appropriately (TypeScript: `{ petId: string; name?: string }`).
*/
declare function buildTypeLiteral({
node,
params,
resolver
}: {
node: OperationNode;
params: Array<ParameterNode>;
resolver: OperationParamsResolver | undefined;
}): TypeLiteralNode;
//#endregion
export { buildTypeLiteral as a, resolveParamType as c, buildGroupParam as i, OperationParamsResolver as n, caseParams as o, ParamGroupType as r, createOperationParams as s, BuildGroupArgs as t };
//# sourceMappingURL=operationParams-Dme8H-sR.d.ts.map
const require_visitor = require("./visitor-CLLDwBvv.cjs");
//#region src/utils/refs.ts
const plainStringTypes = new Set([
"string",
"uuid",
"email",
"url",
"datetime"
]);
/**
* Returns the last path segment of a reference string.
*
* @example
* `extractRefName('#/components/schemas/Pet') // 'Pet'`
*/
function extractRefName(ref) {
return ref.split("/").at(-1) ?? ref;
}
/**
* Resolves the schema name of a ref node. Uses the last segment of `ref` when set, otherwise falls
* back to `name` then nested `schema.name`.
*
* Returns `null` for non-ref nodes or when no name resolves.
*
* @example
* `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Pet' }) // 'Pet'`
*/
function resolveRefName(node) {
if (!node || node.type !== "ref") return null;
if (node.ref) return extractRefName(node.ref) ?? node.name ?? node.schema?.name ?? null;
return node.name ?? node.schema?.name ?? null;
}
/**
* Builds a PascalCase child schema name by joining a parent name and property name.
* Returns `null` when there is no parent to nest under.
*
* @example Nested under a parent
* `childName('Order', 'shipping_address') // 'OrderShippingAddress'`
*
* @example No parent
* `childName(undefined, 'params') // null`
*/
function childName(parentName, propName) {
return parentName ? require_visitor.pascalCase([parentName, propName].join(" ")) : null;
}
/**
* Builds a PascalCase enum name from the parent name, property name, and a suffix, skipping any
* empty parts.
*
* @example
* `enumPropName('Order', 'status', 'enum') // 'OrderStatusEnum'`
*/
function enumPropName(parentName, propName, enumSuffix) {
return require_visitor.pascalCase([
parentName,
propName,
enumSuffix
].filter(Boolean).join(" "));
}
/**
* Merges a ref node with its resolved schema, giving usage-site fields precedence.
*
* Every field set on the ref node except `kind`, `type`, `name`, `ref`, and `schema` overrides the
* same field in the resolved `node.schema` (for example `description`, `nullable`, `readOnly`,
* `deprecated`). Fields left `undefined` on the ref do not shadow the resolved schema. Non-ref
* nodes and refs without a resolved `schema` are returned unchanged.
*
* @example
* ```ts
* const ref = createSchema({ type: 'ref', ref: '#/components/schemas/Pet', description: 'A cute pet' })
* const merged = syncSchemaRef(ref) // merges with resolved Pet schema
* ```
*/
function syncSchemaRef(node) {
const ref = require_visitor.narrowSchema(node, "ref");
if (!ref) return node;
if (!ref.schema) return node;
const { kind: _kind, type: _type, name: _name, ref: _ref, schema: _schema, ...overrides } = ref;
const definedOverrides = Object.fromEntries(Object.entries(overrides).filter(([, v]) => v !== void 0));
return require_visitor.createSchema({
...ref.schema,
...definedOverrides
});
}
/**
* Type guard that returns `true` when a schema emits as a plain `string` type.
*
* Covers `string`, `uuid`, `email`, `url`, and `datetime` types. For `date` and `time`
* types, returns `true` only when `representation` is `'string'` rather than `'date'`.
*/
function isStringType(node) {
if (plainStringTypes.has(node.type)) return true;
const temporal = require_visitor.narrowSchema(node, "date") ?? require_visitor.narrowSchema(node, "time");
if (temporal) return temporal.representation !== "date";
return false;
}
/**
* Derives a {@link ParamGroupType} for a query or header group from the resolver.
*
* Returns `null` when there is no resolver, no params, or the group name equals the
* individual param name (so there is no real group to emit).
*/
function resolveGroupType({ node, params, group, resolver }) {
if (!resolver || !params.length) return null;
const firstParam = params[0];
const groupName = (group === "query" ? resolver.resolveQueryParamsName : resolver.resolveHeaderParamsName).call(resolver, node, firstParam);
if (groupName === resolver.resolveParamName(node, firstParam)) return null;
return {
type: groupName,
optional: params.every((p) => !p.required)
};
}
//#endregion
Object.defineProperty(exports, "childName", {
enumerable: true,
get: function() {
return childName;
}
});
Object.defineProperty(exports, "enumPropName", {
enumerable: true,
get: function() {
return enumPropName;
}
});
Object.defineProperty(exports, "extractRefName", {
enumerable: true,
get: function() {
return extractRefName;
}
});
Object.defineProperty(exports, "isStringType", {
enumerable: true,
get: function() {
return isStringType;
}
});
Object.defineProperty(exports, "resolveGroupType", {
enumerable: true,
get: function() {
return resolveGroupType;
}
});
Object.defineProperty(exports, "resolveRefName", {
enumerable: true,
get: function() {
return resolveRefName;
}
});
Object.defineProperty(exports, "syncSchemaRef", {
enumerable: true,
get: function() {
return syncSchemaRef;
}
});
//# sourceMappingURL=refs-8IwpesXW.cjs.map
{"version":3,"file":"refs-8IwpesXW.cjs","names":["pascalCase","narrowSchema","createSchema"],"sources":["../src/utils/refs.ts"],"sourcesContent":["import { pascalCase } from '@internals/utils'\nimport { narrowSchema } from '../guards.ts'\nimport type { OperationNode, ParameterNode, SchemaNode } from '../nodes/index.ts'\nimport { createSchema, type SchemaType } from '../nodes/schema.ts'\nimport type { OperationParamsResolver, ParamGroupType } from './operationParams.ts'\n\nconst plainStringTypes = new Set<SchemaType>(['string', 'uuid', 'email', 'url', 'datetime'] as const)\n\n/**\n * Returns the last path segment of a reference string.\n *\n * @example\n * `extractRefName('#/components/schemas/Pet') // 'Pet'`\n */\nexport function extractRefName(ref: string): string {\n return ref.split('/').at(-1) ?? ref\n}\n\n/**\n * Resolves the schema name of a ref node. Uses the last segment of `ref` when set, otherwise falls\n * back to `name` then nested `schema.name`.\n *\n * Returns `null` for non-ref nodes or when no name resolves.\n *\n * @example\n * `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Pet' }) // 'Pet'`\n */\nexport function resolveRefName(node: SchemaNode | undefined): string | null {\n if (!node || node.type !== 'ref') return null\n if (node.ref) return extractRefName(node.ref) ?? node.name ?? node.schema?.name ?? null\n\n return node.name ?? node.schema?.name ?? null\n}\n\n/**\n * Builds a PascalCase child schema name by joining a parent name and property name.\n * Returns `null` when there is no parent to nest under.\n *\n * @example Nested under a parent\n * `childName('Order', 'shipping_address') // 'OrderShippingAddress'`\n *\n * @example No parent\n * `childName(undefined, 'params') // null`\n */\nexport function childName(parentName: string | null | undefined, propName: string): string | null {\n return parentName ? pascalCase([parentName, propName].join(' ')) : null\n}\n\n/**\n * Builds a PascalCase enum name from the parent name, property name, and a suffix, skipping any\n * empty parts.\n *\n * @example\n * `enumPropName('Order', 'status', 'enum') // 'OrderStatusEnum'`\n */\nexport function enumPropName(parentName: string | null | undefined, propName: string, enumSuffix: string): string {\n return pascalCase([parentName, propName, enumSuffix].filter(Boolean).join(' '))\n}\n\n/**\n * Merges a ref node with its resolved schema, giving usage-site fields precedence.\n *\n * Every field set on the ref node except `kind`, `type`, `name`, `ref`, and `schema` overrides the\n * same field in the resolved `node.schema` (for example `description`, `nullable`, `readOnly`,\n * `deprecated`). Fields left `undefined` on the ref do not shadow the resolved schema. Non-ref\n * nodes and refs without a resolved `schema` are returned unchanged.\n *\n * @example\n * ```ts\n * const ref = createSchema({ type: 'ref', ref: '#/components/schemas/Pet', description: 'A cute pet' })\n * const merged = syncSchemaRef(ref) // merges with resolved Pet schema\n * ```\n */\nexport function syncSchemaRef(node: SchemaNode): SchemaNode {\n const ref = narrowSchema(node, 'ref')\n\n if (!ref) return node\n if (!ref.schema) return node\n\n const { kind: _kind, type: _type, name: _name, ref: _ref, schema: _schema, ...overrides } = ref\n\n // Filter out undefined override values so they don't shadow the resolved schema's fields.\n const definedOverrides = Object.fromEntries(Object.entries(overrides).filter(([, v]) => v !== undefined))\n\n return createSchema({ ...ref.schema, ...definedOverrides })\n}\n\n/**\n * Type guard that returns `true` when a schema emits as a plain `string` type.\n *\n * Covers `string`, `uuid`, `email`, `url`, and `datetime` types. For `date` and `time`\n * types, returns `true` only when `representation` is `'string'` rather than `'date'`.\n */\nexport function isStringType(node: SchemaNode): boolean {\n if (plainStringTypes.has(node.type)) {\n return true\n }\n\n const temporal = narrowSchema(node, 'date') ?? narrowSchema(node, 'time')\n if (temporal) {\n return temporal.representation !== 'date'\n }\n\n return false\n}\n\n/**\n * Derives a {@link ParamGroupType} for a query or header group from the resolver.\n *\n * Returns `null` when there is no resolver, no params, or the group name equals the\n * individual param name (so there is no real group to emit).\n */\nexport function resolveGroupType({\n node,\n params,\n group,\n resolver,\n}: {\n node: OperationNode\n params: Array<ParameterNode>\n group: 'query' | 'header'\n resolver: OperationParamsResolver | undefined\n}): ParamGroupType | null {\n if (!resolver || !params.length) {\n return null\n }\n const firstParam = params[0]!\n const groupMethod = group === 'query' ? resolver.resolveQueryParamsName : resolver.resolveHeaderParamsName\n const groupName = groupMethod.call(resolver, node, firstParam)\n if (groupName === resolver.resolveParamName(node, firstParam)) {\n return null\n }\n return { type: groupName, optional: params.every((p) => !p.required) }\n}\n"],"mappings":";;AAMA,MAAM,mBAAmB,IAAI,IAAgB;CAAC;CAAU;CAAQ;CAAS;CAAO;AAAU,CAAU;;;;;;;AAQpG,SAAgB,eAAe,KAAqB;CAClD,OAAO,IAAI,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK;AAClC;;;;;;;;;;AAWA,SAAgB,eAAe,MAA6C;CAC1E,IAAI,CAAC,QAAQ,KAAK,SAAS,OAAO,OAAO;CACzC,IAAI,KAAK,KAAK,OAAO,eAAe,KAAK,GAAG,KAAK,KAAK,QAAQ,KAAK,QAAQ,QAAQ;CAEnF,OAAO,KAAK,QAAQ,KAAK,QAAQ,QAAQ;AAC3C;;;;;;;;;;;AAYA,SAAgB,UAAU,YAAuC,UAAiC;CAChG,OAAO,aAAaA,gBAAAA,WAAW,CAAC,YAAY,QAAQ,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI;AACrE;;;;;;;;AASA,SAAgB,aAAa,YAAuC,UAAkB,YAA4B;CAChH,OAAOA,gBAAAA,WAAW;EAAC;EAAY;EAAU;CAAU,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC;AAChF;;;;;;;;;;;;;;;AAgBA,SAAgB,cAAc,MAA8B;CAC1D,MAAM,MAAMC,gBAAAA,aAAa,MAAM,KAAK;CAEpC,IAAI,CAAC,KAAK,OAAO;CACjB,IAAI,CAAC,IAAI,QAAQ,OAAO;CAExB,MAAM,EAAE,MAAM,OAAO,MAAM,OAAO,MAAM,OAAO,KAAK,MAAM,QAAQ,SAAS,GAAG,cAAc;CAG5F,MAAM,mBAAmB,OAAO,YAAY,OAAO,QAAQ,SAAS,CAAC,CAAC,QAAQ,GAAG,OAAO,MAAM,KAAA,CAAS,CAAC;CAExG,OAAOC,gBAAAA,aAAa;EAAE,GAAG,IAAI;EAAQ,GAAG;CAAiB,CAAC;AAC5D;;;;;;;AAQA,SAAgB,aAAa,MAA2B;CACtD,IAAI,iBAAiB,IAAI,KAAK,IAAI,GAChC,OAAO;CAGT,MAAM,WAAWD,gBAAAA,aAAa,MAAM,MAAM,KAAKA,gBAAAA,aAAa,MAAM,MAAM;CACxE,IAAI,UACF,OAAO,SAAS,mBAAmB;CAGrC,OAAO;AACT;;;;;;;AAQA,SAAgB,iBAAiB,EAC/B,MACA,QACA,OACA,YAMwB;CACxB,IAAI,CAAC,YAAY,CAAC,OAAO,QACvB,OAAO;CAET,MAAM,aAAa,OAAO;CAE1B,MAAM,aADc,UAAU,UAAU,SAAS,yBAAyB,SAAS,wBAAA,CACrD,KAAK,UAAU,MAAM,UAAU;CAC7D,IAAI,cAAc,SAAS,iBAAiB,MAAM,UAAU,GAC1D,OAAO;CAET,OAAO;EAAE,MAAM;EAAW,UAAU,OAAO,OAAO,MAAM,CAAC,EAAE,QAAQ;CAAE;AACvE"}
import "./rolldown-runtime-CNktS9qV.js";
import { U as pascalCase, lt as narrowSchema, o as createSchema } from "./visitor-DG5ROqRx.js";
//#region src/utils/refs.ts
const plainStringTypes = new Set([
"string",
"uuid",
"email",
"url",
"datetime"
]);
/**
* Returns the last path segment of a reference string.
*
* @example
* `extractRefName('#/components/schemas/Pet') // 'Pet'`
*/
function extractRefName(ref) {
return ref.split("/").at(-1) ?? ref;
}
/**
* Resolves the schema name of a ref node. Uses the last segment of `ref` when set, otherwise falls
* back to `name` then nested `schema.name`.
*
* Returns `null` for non-ref nodes or when no name resolves.
*
* @example
* `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Pet' }) // 'Pet'`
*/
function resolveRefName(node) {
if (!node || node.type !== "ref") return null;
if (node.ref) return extractRefName(node.ref) ?? node.name ?? node.schema?.name ?? null;
return node.name ?? node.schema?.name ?? null;
}
/**
* Builds a PascalCase child schema name by joining a parent name and property name.
* Returns `null` when there is no parent to nest under.
*
* @example Nested under a parent
* `childName('Order', 'shipping_address') // 'OrderShippingAddress'`
*
* @example No parent
* `childName(undefined, 'params') // null`
*/
function childName(parentName, propName) {
return parentName ? pascalCase([parentName, propName].join(" ")) : null;
}
/**
* Builds a PascalCase enum name from the parent name, property name, and a suffix, skipping any
* empty parts.
*
* @example
* `enumPropName('Order', 'status', 'enum') // 'OrderStatusEnum'`
*/
function enumPropName(parentName, propName, enumSuffix) {
return pascalCase([
parentName,
propName,
enumSuffix
].filter(Boolean).join(" "));
}
/**
* Merges a ref node with its resolved schema, giving usage-site fields precedence.
*
* Every field set on the ref node except `kind`, `type`, `name`, `ref`, and `schema` overrides the
* same field in the resolved `node.schema` (for example `description`, `nullable`, `readOnly`,
* `deprecated`). Fields left `undefined` on the ref do not shadow the resolved schema. Non-ref
* nodes and refs without a resolved `schema` are returned unchanged.
*
* @example
* ```ts
* const ref = createSchema({ type: 'ref', ref: '#/components/schemas/Pet', description: 'A cute pet' })
* const merged = syncSchemaRef(ref) // merges with resolved Pet schema
* ```
*/
function syncSchemaRef(node) {
const ref = narrowSchema(node, "ref");
if (!ref) return node;
if (!ref.schema) return node;
const { kind: _kind, type: _type, name: _name, ref: _ref, schema: _schema, ...overrides } = ref;
const definedOverrides = Object.fromEntries(Object.entries(overrides).filter(([, v]) => v !== void 0));
return createSchema({
...ref.schema,
...definedOverrides
});
}
/**
* Type guard that returns `true` when a schema emits as a plain `string` type.
*
* Covers `string`, `uuid`, `email`, `url`, and `datetime` types. For `date` and `time`
* types, returns `true` only when `representation` is `'string'` rather than `'date'`.
*/
function isStringType(node) {
if (plainStringTypes.has(node.type)) return true;
const temporal = narrowSchema(node, "date") ?? narrowSchema(node, "time");
if (temporal) return temporal.representation !== "date";
return false;
}
/**
* Derives a {@link ParamGroupType} for a query or header group from the resolver.
*
* Returns `null` when there is no resolver, no params, or the group name equals the
* individual param name (so there is no real group to emit).
*/
function resolveGroupType({ node, params, group, resolver }) {
if (!resolver || !params.length) return null;
const firstParam = params[0];
const groupName = (group === "query" ? resolver.resolveQueryParamsName : resolver.resolveHeaderParamsName).call(resolver, node, firstParam);
if (groupName === resolver.resolveParamName(node, firstParam)) return null;
return {
type: groupName,
optional: params.every((p) => !p.required)
};
}
//#endregion
export { resolveGroupType as a, isStringType as i, enumPropName as n, resolveRefName as o, extractRefName as r, syncSchemaRef as s, childName as t };
//# sourceMappingURL=refs-D2qwT5ck.js.map
{"version":3,"file":"refs-D2qwT5ck.js","names":[],"sources":["../src/utils/refs.ts"],"sourcesContent":["import { pascalCase } from '@internals/utils'\nimport { narrowSchema } from '../guards.ts'\nimport type { OperationNode, ParameterNode, SchemaNode } from '../nodes/index.ts'\nimport { createSchema, type SchemaType } from '../nodes/schema.ts'\nimport type { OperationParamsResolver, ParamGroupType } from './operationParams.ts'\n\nconst plainStringTypes = new Set<SchemaType>(['string', 'uuid', 'email', 'url', 'datetime'] as const)\n\n/**\n * Returns the last path segment of a reference string.\n *\n * @example\n * `extractRefName('#/components/schemas/Pet') // 'Pet'`\n */\nexport function extractRefName(ref: string): string {\n return ref.split('/').at(-1) ?? ref\n}\n\n/**\n * Resolves the schema name of a ref node. Uses the last segment of `ref` when set, otherwise falls\n * back to `name` then nested `schema.name`.\n *\n * Returns `null` for non-ref nodes or when no name resolves.\n *\n * @example\n * `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Pet' }) // 'Pet'`\n */\nexport function resolveRefName(node: SchemaNode | undefined): string | null {\n if (!node || node.type !== 'ref') return null\n if (node.ref) return extractRefName(node.ref) ?? node.name ?? node.schema?.name ?? null\n\n return node.name ?? node.schema?.name ?? null\n}\n\n/**\n * Builds a PascalCase child schema name by joining a parent name and property name.\n * Returns `null` when there is no parent to nest under.\n *\n * @example Nested under a parent\n * `childName('Order', 'shipping_address') // 'OrderShippingAddress'`\n *\n * @example No parent\n * `childName(undefined, 'params') // null`\n */\nexport function childName(parentName: string | null | undefined, propName: string): string | null {\n return parentName ? pascalCase([parentName, propName].join(' ')) : null\n}\n\n/**\n * Builds a PascalCase enum name from the parent name, property name, and a suffix, skipping any\n * empty parts.\n *\n * @example\n * `enumPropName('Order', 'status', 'enum') // 'OrderStatusEnum'`\n */\nexport function enumPropName(parentName: string | null | undefined, propName: string, enumSuffix: string): string {\n return pascalCase([parentName, propName, enumSuffix].filter(Boolean).join(' '))\n}\n\n/**\n * Merges a ref node with its resolved schema, giving usage-site fields precedence.\n *\n * Every field set on the ref node except `kind`, `type`, `name`, `ref`, and `schema` overrides the\n * same field in the resolved `node.schema` (for example `description`, `nullable`, `readOnly`,\n * `deprecated`). Fields left `undefined` on the ref do not shadow the resolved schema. Non-ref\n * nodes and refs without a resolved `schema` are returned unchanged.\n *\n * @example\n * ```ts\n * const ref = createSchema({ type: 'ref', ref: '#/components/schemas/Pet', description: 'A cute pet' })\n * const merged = syncSchemaRef(ref) // merges with resolved Pet schema\n * ```\n */\nexport function syncSchemaRef(node: SchemaNode): SchemaNode {\n const ref = narrowSchema(node, 'ref')\n\n if (!ref) return node\n if (!ref.schema) return node\n\n const { kind: _kind, type: _type, name: _name, ref: _ref, schema: _schema, ...overrides } = ref\n\n // Filter out undefined override values so they don't shadow the resolved schema's fields.\n const definedOverrides = Object.fromEntries(Object.entries(overrides).filter(([, v]) => v !== undefined))\n\n return createSchema({ ...ref.schema, ...definedOverrides })\n}\n\n/**\n * Type guard that returns `true` when a schema emits as a plain `string` type.\n *\n * Covers `string`, `uuid`, `email`, `url`, and `datetime` types. For `date` and `time`\n * types, returns `true` only when `representation` is `'string'` rather than `'date'`.\n */\nexport function isStringType(node: SchemaNode): boolean {\n if (plainStringTypes.has(node.type)) {\n return true\n }\n\n const temporal = narrowSchema(node, 'date') ?? narrowSchema(node, 'time')\n if (temporal) {\n return temporal.representation !== 'date'\n }\n\n return false\n}\n\n/**\n * Derives a {@link ParamGroupType} for a query or header group from the resolver.\n *\n * Returns `null` when there is no resolver, no params, or the group name equals the\n * individual param name (so there is no real group to emit).\n */\nexport function resolveGroupType({\n node,\n params,\n group,\n resolver,\n}: {\n node: OperationNode\n params: Array<ParameterNode>\n group: 'query' | 'header'\n resolver: OperationParamsResolver | undefined\n}): ParamGroupType | null {\n if (!resolver || !params.length) {\n return null\n }\n const firstParam = params[0]!\n const groupMethod = group === 'query' ? resolver.resolveQueryParamsName : resolver.resolveHeaderParamsName\n const groupName = groupMethod.call(resolver, node, firstParam)\n if (groupName === resolver.resolveParamName(node, firstParam)) {\n return null\n }\n return { type: groupName, optional: params.every((p) => !p.required) }\n}\n"],"mappings":";;;AAMA,MAAM,mBAAmB,IAAI,IAAgB;CAAC;CAAU;CAAQ;CAAS;CAAO;AAAU,CAAU;;;;;;;AAQpG,SAAgB,eAAe,KAAqB;CAClD,OAAO,IAAI,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK;AAClC;;;;;;;;;;AAWA,SAAgB,eAAe,MAA6C;CAC1E,IAAI,CAAC,QAAQ,KAAK,SAAS,OAAO,OAAO;CACzC,IAAI,KAAK,KAAK,OAAO,eAAe,KAAK,GAAG,KAAK,KAAK,QAAQ,KAAK,QAAQ,QAAQ;CAEnF,OAAO,KAAK,QAAQ,KAAK,QAAQ,QAAQ;AAC3C;;;;;;;;;;;AAYA,SAAgB,UAAU,YAAuC,UAAiC;CAChG,OAAO,aAAa,WAAW,CAAC,YAAY,QAAQ,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI;AACrE;;;;;;;;AASA,SAAgB,aAAa,YAAuC,UAAkB,YAA4B;CAChH,OAAO,WAAW;EAAC;EAAY;EAAU;CAAU,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC;AAChF;;;;;;;;;;;;;;;AAgBA,SAAgB,cAAc,MAA8B;CAC1D,MAAM,MAAM,aAAa,MAAM,KAAK;CAEpC,IAAI,CAAC,KAAK,OAAO;CACjB,IAAI,CAAC,IAAI,QAAQ,OAAO;CAExB,MAAM,EAAE,MAAM,OAAO,MAAM,OAAO,MAAM,OAAO,KAAK,MAAM,QAAQ,SAAS,GAAG,cAAc;CAG5F,MAAM,mBAAmB,OAAO,YAAY,OAAO,QAAQ,SAAS,CAAC,CAAC,QAAQ,GAAG,OAAO,MAAM,KAAA,CAAS,CAAC;CAExG,OAAO,aAAa;EAAE,GAAG,IAAI;EAAQ,GAAG;CAAiB,CAAC;AAC5D;;;;;;;AAQA,SAAgB,aAAa,MAA2B;CACtD,IAAI,iBAAiB,IAAI,KAAK,IAAI,GAChC,OAAO;CAGT,MAAM,WAAW,aAAa,MAAM,MAAM,KAAK,aAAa,MAAM,MAAM;CACxE,IAAI,UACF,OAAO,SAAS,mBAAmB;CAGrC,OAAO;AACT;;;;;;;AAQA,SAAgB,iBAAiB,EAC/B,MACA,QACA,OACA,YAMwB;CACxB,IAAI,CAAC,YAAY,CAAC,OAAO,QACvB,OAAO;CAET,MAAM,aAAa,OAAO;CAE1B,MAAM,aADc,UAAU,UAAU,SAAS,yBAAyB,SAAS,wBAAA,CACrD,KAAK,UAAU,MAAM,UAAU;CAC7D,IAAI,cAAc,SAAS,iBAAiB,MAAM,UAAU,GAC1D,OAAO;CAET,OAAO;EAAE,MAAM;EAAW,UAAU,OAAO,OAAO,MAAM,CAAC,EAAE,QAAQ;CAAE;AACvE"}
import { n as __name } from "./rolldown-runtime-CNktS9qV.js";
import { _t as SchemaNode, vt as SchemaNodeByType, yt as SchemaType } from "./index-q_ldM1YP.js";
//#region src/defineDialect.d.ts
/**
* The spec-specific questions a schema parser answers while turning a source document into Kubb
* AST nodes. The rest of the pipeline is generic JSON Schema, so this is the one seam where
* OpenAPI, AsyncAPI, and plain JSON Schema differ.
*/
type SchemaDialect<TSchema = unknown, TRef = TSchema, TDiscriminated = TSchema, TDocument = unknown> = {
/**
* Whether the schema is nullable.
*/
isNullable(schema?: TSchema): boolean;
/**
* Whether the value is a `$ref` pointer.
*/
isReference(value?: unknown): value is TRef;
/**
* Whether the schema carries a discriminator for polymorphism.
*/
isDiscriminator(value?: unknown): value is TDiscriminated;
/**
* Whether the schema is binary data, converted to a `blob` node.
*/
isBinary(schema: TSchema): boolean;
/**
* Resolves a local `$ref` against the document, or nullish when it cannot.
*/
resolveRef<TResolved>(document: TDocument, ref: string): TResolved | null | undefined;
};
/**
* A spec adapter's dialect. `name` identifies it in logs and diagnostics, and `schema` holds the
* spec-specific schema questions the parser answers.
*/
type Dialect<TSchema = unknown, TRef = TSchema, TDiscriminated = TSchema, TDocument = unknown> = {
/**
* Identifies the dialect in logs and diagnostics.
*/
name: string;
/**
* The spec-specific schema behavior. See {@link SchemaDialect}.
*/
schema: SchemaDialect<TSchema, TRef, TDiscriminated, TDocument>;
};
/**
* Types a {@link Dialect} for an adapter. Adds no runtime behavior and only pins the
* dialect's type for inference.
*
* @example
* ```ts
* export const oasDialect = defineDialect({
* name: 'oas',
* schema: {
* isNullable,
* isReference,
* isDiscriminator,
* isBinary: (schema) => schema.type === 'string' && schema.contentMediaType === 'application/octet-stream',
* resolveRef,
* },
* })
* ```
*/
declare function defineDialect<TSchema, TRef, TDiscriminated, TDocument>(dialect: Dialect<TSchema, TRef, TDiscriminated, TDocument>): Dialect<TSchema, TRef, TDiscriminated, TDocument>;
//#endregion
//#region src/createPrinter.d.ts
/**
* Runtime context passed as `this` to printer handlers.
*
* `this.transform` dispatches to node-level handlers from `nodes`.
*
* @example
* ```ts
* const context: PrinterHandlerContext<string, {}> = {
* options: {},
* transform: () => 'value',
* }
* ```
*/
type PrinterHandlerContext<TOutput, TOptions extends object> = {
/**
* Recursively transform a nested `SchemaNode` to `TOutput` using the node-level handlers.
* Use `this.transform` inside `nodes` handlers and inside the `print` override.
*/
transform: (node: SchemaNode) => TOutput | null;
/**
* Options for this printer instance.
*/
options: TOptions;
};
/**
* Handler for one schema node type.
*
* Use a regular function (not an arrow function) if you need `this`.
*
* @example
* ```ts
* const handler: PrinterHandler<string, {}, 'string'> = function () {
* return 'string'
* }
* ```
*/
type PrinterHandler<TOutput, TOptions extends object, T extends SchemaType = SchemaType> = (this: PrinterHandlerContext<TOutput, TOptions>, node: SchemaNodeByType[T]) => TOutput | null;
/**
* Partial map of per-node-type handler overrides for a printer.
*
* Each key is a `SchemaType` string (e.g. `'date'`, `'string'`).
* Supply only the handlers you want to replace. The printer's built-in
* defaults fill in the rest.
*
* @example
* ```ts
* pluginZod({
* printer: {
* nodes: {
* date(): string {
* return 'z.string().date()'
* },
* } satisfies PrinterPartial<string, PrinterZodOptions>,
* },
* })
* ```
*/
type PrinterPartial<TOutput, TOptions extends object> = Partial<{ [K in SchemaType]: PrinterHandler<TOutput, TOptions, K> }>;
/**
* Generic shape used by `definePrinter`.
*
* - `TName` unique string identifier (e.g. `'zod'`, `'ts'`)
* - `TOptions` options passed to and stored on the printer instance
* - `TOutput` the type emitted by node handlers
* - `TPrintOutput` type returned by public `print` (defaults to `TOutput`)
*
* @example
* ```ts
* type MyPrinter = PrinterFactoryOptions<'my', { strict: boolean }, string>
* ```
*/
type PrinterFactoryOptions<TName extends string = string, TOptions extends object = object, TOutput = unknown, TPrintOutput = TOutput> = {
name: TName;
options: TOptions;
output: TOutput;
printOutput: TPrintOutput;
};
/**
* Printer instance returned by a printer factory.
*
* @example
* ```ts
* const printer = definePrinter((options: {}) => ({ name: 'x', options, nodes: {} }))({})
* ```
*/
type Printer<T extends PrinterFactoryOptions = PrinterFactoryOptions> = {
/**
* Unique identifier supplied at creation time.
*/
name: T['name'];
/**
* Options for this printer instance.
*/
options: T['options'];
/**
* Node-level dispatcher, converts a `SchemaNode` directly to `TOutput` using the `nodes` handlers.
* Always dispatches through the `nodes` map. Never calls the `print` override.
* Reach for it when you need the raw output (e.g. `ts.TypeNode`) without declaration wrapping.
*/
transform: (node: SchemaNode) => T['output'] | null;
/**
* Public printer. If the builder provides a root-level `print`, this calls that
* higher-level function (which may produce full declarations).
* Otherwise, falls back to the node-level dispatcher.
*/
print: (node: SchemaNode) => T['printOutput'] | null;
};
/**
* Builder function passed to `definePrinter`.
*
* It receives resolved options and returns:
* - `name`
* - `options`
* - `nodes` handlers
* - optional top-level `print` override
*
* @example
* ```ts
* const build = (options: {}) => ({ name: 'x' as const, options, nodes: {} })
* ```
*/
type PrinterBuilder<T extends PrinterFactoryOptions> = (options: T['options']) => {
name: T['name'];
/**
* Options to store on the printer.
*/
options: T['options'];
nodes: Partial<{ [K in SchemaType]: PrinterHandler<T['output'], T['options'], K> }>;
/**
* Optional root-level print override. When provided, becomes the public `printer.print`.
* Use `this.transform(node)` inside this function to dispatch to the node-level handlers (`nodes`),
* not the override itself, so recursion is safe.
*/
print?: (this: PrinterHandlerContext<T['output'], T['options']>, node: SchemaNode) => T['printOutput'] | null;
};
/**
* Creates a schema printer: a function that takes a `SchemaNode` and emits
* code in your target language. Each plugin that produces code from schemas
* (TypeScript types, Zod schemas, Faker factories) ships a printer built
* with this helper.
*
* The builder receives resolved options and returns:
*
* - `name` unique identifier for the printer.
* - `options` stored on the returned printer instance.
* - `nodes` map of `SchemaType` → handler. Handlers return the rendered
* output (a string, a TypeScript AST node, ...) for that schema type.
* - `print` (optional), top-level override exposed as `printer.print`.
* Use `this.transform(node)` inside it to dispatch to `nodes` recursively.
*
* Without a `print` override, `printer.print` falls back to `printer.transform`
* (the node-level dispatcher).
*
* @example Tiny Zod printer
* ```ts
* import { createPrinter, type PrinterFactoryOptions } from '@kubb/ast'
*
* type PrinterZod = PrinterFactoryOptions<'zod', { strict?: boolean }, string>
*
* export const zodPrinter = createPrinter<PrinterZod>((options) => ({
* name: 'zod',
* options: { strict: options.strict ?? true },
* nodes: {
* string: () => 'z.string()',
* object(node) {
* const props = node.properties
* .map((p) => `${p.name}: ${this.transform(p.schema)}`)
* .join(', ')
* return `z.object({ ${props} })`
* },
* },
* }))
* ```
*/
declare function createPrinter<T extends PrinterFactoryOptions = PrinterFactoryOptions>(build: PrinterBuilder<T>): (options?: T['options']) => Printer<T>;
//#endregion
export { Dialect as a, createPrinter as i, PrinterFactoryOptions as n, SchemaDialect as o, PrinterPartial as r, defineDialect as s, Printer as t };
//# sourceMappingURL=types-Df1jVmRy.d.ts.map
//#region \0rolldown/runtime.js
var __create = Object.create;
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", {
value,
configurable: true
});
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __exportAll = (all, no_symbols) => {
let target = {};
for (var name in all) __defProp(target, name, {
get: all[name],
enumerable: true
});
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
return target;
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
key = keys[i];
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: ((k) => from[k]).bind(null, key),
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
value: mod,
enumerable: true
}) : target, mod));
//#endregion
let node_crypto = require("node:crypto");
let node_path = require("node:path");
node_path = __toESM(node_path, 1);
//#region src/constants.ts
const visitorDepths = {
shallow: "shallow",
deep: "deep"
};
/**
* Schema type discriminators used by all AST schema nodes.
*
* Each value is a stable discriminator across the AST (for example `schema.type === schemaTypes.object`).
*/
const schemaTypes = {
/**
* Text value.
*/
string: "string",
/**
* Floating-point number (`float`, `double`).
*/
number: "number",
/**
* Whole number (`int32`). Use `bigint` for `int64`.
*/
integer: "integer",
/**
* 64-bit integer (`int64`). Only used when `integerType` is set to `'bigint'`.
*/
bigint: "bigint",
/**
* Boolean value.
*/
boolean: "boolean",
/**
* Explicit null value.
*/
null: "null",
/**
* Any value (no type restriction).
*/
any: "any",
/**
* Unknown value (must be narrowed before usage).
*/
unknown: "unknown",
/**
* No return value (`void`).
*/
void: "void",
/**
* Object with named properties.
*/
object: "object",
/**
* Sequential list of items.
*/
array: "array",
/**
* Fixed-length list with position-specific items.
*/
tuple: "tuple",
/**
* "One of" multiple schema members.
*/
union: "union",
/**
* "All of" multiple schema members.
*/
intersection: "intersection",
/**
* Enum schema.
*/
enum: "enum",
/**
* Reference to another schema.
*/
ref: "ref",
/**
* Calendar date (for example `2026-03-24`).
*/
date: "date",
/**
* Date-time value (for example `2026-03-24T09:00:00Z`).
*/
datetime: "datetime",
/**
* Time-only value (for example `09:00:00`).
*/
time: "time",
/**
* UUID value.
*/
uuid: "uuid",
/**
* Email address value.
*/
email: "email",
/**
* URL value.
*/
url: "url",
/**
* IPv4 address value.
*/
ipv4: "ipv4",
/**
* IPv6 address value.
*/
ipv6: "ipv6",
/**
* Binary/blob value.
*/
blob: "blob",
/**
* Impossible value (`never`).
*/
never: "never"
};
/**
* One indentation level, derived from {@link INDENT_SIZE}.
*/
const INDENT = Array.from({ length: 2 }, () => " ").join("");
//#endregion
//#region src/guards.ts
/**
* Narrows a `SchemaNode` to the variant that matches `type`.
*
* @example
* ```ts
* const schema = createSchema({ type: 'string' })
* const stringNode = narrowSchema(schema, 'string') // StringSchemaNode | null
* ```
*/
function narrowSchema(node, type) {
return node?.type === type ? node : null;
}
/**
* Narrows an `OperationNode` to an `HttpOperationNode` so `method` and `path` are present.
*
* @example
* ```ts
* if (isHttpOperationNode(node)) {
* console.log(node.method, node.path)
* }
* ```
*/
function isHttpOperationNode(node) {
return node.protocol === "http" || node.method !== void 0 && node.path !== void 0;
}
//#endregion
//#region src/defineNode.ts
/**
* Visitor callback names, one per traversable node kind, in traversal order.
* Kept in sync with the keys of `Visitor` in `visitor.ts`.
*/
const visitorKeys = [
"input",
"output",
"operation",
"schema",
"property",
"parameter",
"response"
];
/**
* Builds a type guard that matches nodes of the given `kind`.
*/
function isKind(kind) {
return (node) => node?.kind === kind;
}
/**
* Defines a node once and derives its `create` builder, `is` guard, and traversal
* metadata. `create` merges `defaults`, the `build` hook (or the raw input), and the
* `kind`, so node construction lives in one place without scattered `as` casts.
*
* @example Simple node
* ```ts
* const importDef = defineNode<ImportNode>({ kind: 'Import' })
* const createImport = importDef.create
* ```
*
* @example Node with a build hook
* ```ts
* const propertyDef = defineNode<PropertyNode, UserPropertyNode>({
* kind: 'Property',
* build: (props) => ({ ...props, required: props.required ?? false }),
* children: ['schema'],
* visitorKey: 'property',
* })
* ```
*/
function defineNode(config) {
const { kind, defaults, build, children, visitorKey } = config;
function create(input) {
const base = build ? build(input) : input;
return {
...defaults,
...base,
kind
};
}
return {
kind,
create,
is: isKind(kind),
children,
visitorKey
};
}
//#endregion
//#region src/nodes/code.ts
/**
* Definition for the {@link ConstNode}.
*/
const constDef = defineNode({ kind: "Const" });
/**
* Definition for the {@link TypeNode}.
*/
const typeDef = defineNode({ kind: "Type" });
/**
* Definition for the {@link FunctionNode}.
*/
const functionDef = defineNode({ kind: "Function" });
/**
* Definition for the {@link ArrowFunctionNode}.
*/
const arrowFunctionDef = defineNode({ kind: "ArrowFunction" });
/**
* Definition for the {@link TextNode}.
*/
const textDef = defineNode({
kind: "Text",
build: (value) => ({ value })
});
/**
* Definition for the {@link BreakNode}.
*/
const breakDef = defineNode({
kind: "Break",
build: () => ({})
});
/**
* Definition for the {@link JsxNode}.
*/
const jsxDef = defineNode({
kind: "Jsx",
build: (value) => ({ value })
});
/**
* Creates a `ConstNode` representing a TypeScript `const` declaration.
*
* @example Exported constant with type and `as const`
* ```ts
* createConst({ name: 'pets', export: true, type: 'Pet[]', asConst: true })
* // export const pets: Pet[] = ... as const
* ```
*/
const createConst = constDef.create;
/**
* Creates a `TypeNode` representing a TypeScript `type` alias declaration.
*
* @example
* ```ts
* createType({ name: 'Pet', export: true })
* // export type Pet = ...
* ```
*/
const createType = typeDef.create;
/**
* Creates a `FunctionNode` representing a TypeScript `function` declaration.
*
* @example
* ```ts
* createFunction({ name: 'fetchPet', export: true, async: true, returnType: 'Pet' })
* // export async function fetchPet(): Promise<Pet> { ... }
* ```
*/
const createFunction = functionDef.create;
/**
* Creates an `ArrowFunctionNode` representing a TypeScript arrow function.
*
* @example
* ```ts
* createArrowFunction({ name: 'double', export: true, params: 'n: number', singleLine: true })
* // export const double = (n: number) => ...
* ```
*/
const createArrowFunction = arrowFunctionDef.create;
/**
* Creates a {@link TextNode} representing a raw string fragment in the source output.
*
* @example
* ```ts
* createText('return fetch(id)')
* // { kind: 'Text', value: 'return fetch(id)' }
* ```
*/
const createText = textDef.create;
/**
* Creates a {@link BreakNode} representing a line break in the source output.
*
* @example
* ```ts
* createBreak()
* // { kind: 'Break' }
* ```
*/
function createBreak() {
return breakDef.create();
}
/**
* Creates a {@link JsxNode} representing a raw JSX fragment in the source output.
*
* @example
* ```ts
* createJsx('<>\n <a href={href}>Open</a>\n</>')
* // { kind: 'Jsx', value: '<>\n <a href={href}>Open</a>\n</>' }
* ```
*/
const createJsx = jsxDef.create;
//#endregion
//#region src/nodes/content.ts
/**
* Definition for the {@link ContentNode}.
*/
const contentDef = defineNode({
kind: "Content",
children: ["schema"]
});
/**
* Creates a `ContentNode` for a single request-body or response content type.
*/
const createContent = contentDef.create;
//#endregion
//#region ../../internals/utils/src/casing.ts
/**
* Shared implementation for camelCase and PascalCase conversion.
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
* and capitalizes each word according to `pascal`.
*
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
*/
function toCamelOrPascal(text, pascal) {
return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
if (word.length > 1 && word === word.toUpperCase()) return word;
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
}).join("").replace(/[^a-zA-Z0-9]/g, "");
}
/**
* Converts `text` to camelCase.
*
* @example Word boundaries
* `camelCase('hello-world') // 'helloWorld'`
*
* @example With a prefix
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
*/
function camelCase(text, { prefix = "", suffix = "" } = {}) {
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
}
/**
* Converts `text` to PascalCase.
*
* @example Word boundaries
* `pascalCase('hello-world') // 'HelloWorld'`
*
* @example With a suffix
* `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`
*/
function pascalCase(text, { prefix = "", suffix = "" } = {}) {
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
}
//#endregion
//#region ../../internals/utils/src/fs.ts
/**
* Strips the file extension from a path or file name.
* Only removes the last `.ext` segment when the dot is not part of a directory name.
*
* @example
* trimExtName('petStore.ts') // 'petStore'
* trimExtName('/src/models/pet.ts') // '/src/models/pet'
* trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet'
* trimExtName('noExtension') // 'noExtension'
*/
function trimExtName(text) {
const dotIndex = text.lastIndexOf(".");
if (dotIndex > 0 && !text.includes("/", dotIndex)) return text.slice(0, dotIndex);
return text;
}
//#endregion
//#region src/utils/extractStringsFromNodes.ts
/**
* Extracts all string content from a `CodeNode` tree recursively.
*
* Collects text node values, identifier references in string fields (`params`, `generics`, `returnType`, `type`),
* and nested node content. Used to build the full source string for import filtering.
*/
function extractStringsFromNodes(nodes) {
if (!nodes?.length) return "";
return nodes.map((node) => {
if (typeof node === "string") return node;
if (node.kind === "Text") return node.value;
if (node.kind === "Break") return "";
if (node.kind === "Jsx") return node.value;
const parts = [];
if ("params" in node && node.params) parts.push(node.params);
if ("generics" in node && node.generics) parts.push(Array.isArray(node.generics) ? node.generics.join(", ") : node.generics);
if ("returnType" in node && node.returnType) parts.push(node.returnType);
if ("type" in node && typeof node.type === "string") parts.push(node.type);
const nested = extractStringsFromNodes(node.nodes);
if (nested) parts.push(nested);
return parts.join("\n");
}).filter(Boolean).join("\n");
}
//#endregion
//#region src/utils/fileMerge.ts
function sourceKey(source) {
return `${source.name ?? extractStringsFromNodes(source.nodes)}:${source.isExportable ?? false}:${source.isTypeOnly ?? false}`;
}
function pathTypeKey(path, isTypeOnly) {
return `${path}:${isTypeOnly ?? false}`;
}
function exportKey(path, name, isTypeOnly, asAlias) {
return `${path}:${name ?? ""}:${isTypeOnly ?? false}:${asAlias ?? ""}`;
}
function importKey(path, name, isTypeOnly) {
return `${path}:${name ?? ""}:${isTypeOnly ?? false}`;
}
/**
* Computes a multi-level sort key for exports and imports:
* non-array names first (wildcards/namespace aliases). Type-only before value. Alphabetical path. Unnamed before named.
*/
function sortKey(node) {
const isArray = Array.isArray(node.name) ? "1" : "0";
const typeOnly = node.isTypeOnly ? "0" : "1";
const hasName = node.name != null ? "1" : "0";
const name = Array.isArray(node.name) ? node.name.toSorted().join("\0") : node.name ?? "";
return `${isArray}:${typeOnly}:${node.path}:${hasName}:${name}`;
}
/**
* Deduplicates `SourceNode` objects by `name + isExportable + isTypeOnly`, keeping the first of each
* key. Unnamed sources fall back to their extracted node strings as the name part of the key. Returns
* the deduplicated array in original order.
*/
function combineSources(sources) {
const seen = /* @__PURE__ */ new Map();
for (const source of sources) {
const key = sourceKey(source);
if (!seen.has(key)) seen.set(key, source);
}
return [...seen.values()];
}
/**
* Merges `incoming` names into `existing`, preserving order and dropping duplicates.
*
* Shared by `combineExports` and `combineImports` for the same-path name-merge case.
*/
function mergeNameArrays(existing, incoming) {
const merged = new Set(existing);
for (const name of incoming) merged.add(name);
return [...merged];
}
/**
* Deduplicates and merges `ExportNode` objects by path and type.
*
* Named exports with the same path and `isTypeOnly` flag have their names merged into a single export.
* Non-array exports are deduplicated by exact identity. Returns a sorted, deduplicated array.
*/
function combineExports(exports) {
const result = [];
const namedByPath = /* @__PURE__ */ new Map();
const seen = /* @__PURE__ */ new Set();
const keyed = exports.map((node) => ({
node,
key: sortKey(node)
}));
keyed.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
for (const { node: curr } of keyed) {
const { name, path, isTypeOnly, asAlias } = curr;
if (Array.isArray(name)) {
if (!name.length) continue;
const key = pathTypeKey(path, isTypeOnly);
const existing = namedByPath.get(key);
if (existing && Array.isArray(existing.name)) existing.name = mergeNameArrays(existing.name, name);
else {
const newItem = {
...curr,
name: [...new Set(name)]
};
result.push(newItem);
namedByPath.set(key, newItem);
}
} else {
const key = exportKey(path, name, isTypeOnly, asAlias);
if (!seen.has(key)) {
result.push(curr);
seen.add(key);
}
}
}
return result;
}
/**
* Deduplicates and merges `ImportNode` objects, filtering out unused imports.
*
* Retains imports that are referenced in `source` or re-exported. Imports with the same path and
* `isTypeOnly` flag have their names merged. Returns a sorted, deduplicated, filtered array.
*/
function combineImports(imports, exports, source) {
const exportedNames = new Set(exports.flatMap((e) => Array.isArray(e.name) ? e.name : e.name ? [e.name] : []));
const isUsed = (importName) => !source || source.includes(importName) || exportedNames.has(importName);
const importNameMemo = /* @__PURE__ */ new Map();
const canonicalizeName = (n) => {
if (typeof n === "string") return n;
const key = `${n.propertyName}:${n.name ?? ""}`;
if (!importNameMemo.has(key)) importNameMemo.set(key, n);
return importNameMemo.get(key);
};
const pathsWithUsedNamedImport = /* @__PURE__ */ new Set();
for (const node of imports) {
if (!Array.isArray(node.name)) continue;
if (node.name.some((item) => typeof item === "string" ? isUsed(item) : isUsed(item.name ?? item.propertyName))) pathsWithUsedNamedImport.add(node.path);
}
const result = [];
const namedByPath = /* @__PURE__ */ new Map();
const seen = /* @__PURE__ */ new Set();
const keyed = imports.map((node) => ({
node,
key: sortKey(node)
}));
keyed.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
for (const { node: curr } of keyed) {
if (curr.path === curr.root) continue;
const { path, isTypeOnly } = curr;
let { name } = curr;
if (Array.isArray(name)) {
name = [...new Set(name.map(canonicalizeName))].filter((item) => typeof item === "string" ? isUsed(item) : isUsed(item.name ?? item.propertyName));
if (!name.length) continue;
const key = pathTypeKey(path, isTypeOnly);
const existing = namedByPath.get(key);
if (existing && Array.isArray(existing.name)) existing.name = mergeNameArrays(existing.name, name);
else {
const newItem = {
...curr,
name
};
result.push(newItem);
namedByPath.set(key, newItem);
}
} else {
if (name && !isUsed(name) && !pathsWithUsedNamedImport.has(path)) continue;
const key = importKey(path, name, isTypeOnly);
if (!seen.has(key)) {
result.push(curr);
seen.add(key);
}
}
}
return result;
}
//#endregion
//#region src/nodes/file.ts
/**
* Definition for the {@link ImportNode}.
*/
const importDef = defineNode({ kind: "Import" });
/**
* Definition for the {@link ExportNode}.
*/
const exportDef = defineNode({ kind: "Export" });
/**
* Definition for the {@link SourceNode}.
*/
const sourceDef = defineNode({ kind: "Source" });
/**
* Definition for the {@link FileNode}. The fully resolved builder lives in
* `createFile`, so this definition only supplies the guard.
*/
const fileDef = defineNode({ kind: "File" });
/**
* Creates an `ImportNode` representing a language-agnostic import/dependency declaration.
*
* @example Named import
* ```ts
* createImport({ name: ['useState'], path: 'react' })
* // import { useState } from 'react'
* ```
*/
const createImport = importDef.create;
/**
* Creates an `ExportNode` representing a language-agnostic export/public API declaration.
*
* @example Named export
* ```ts
* createExport({ name: ['Pet'], path: './Pet' })
* // export { Pet } from './Pet'
* ```
*/
const createExport = exportDef.create;
/**
* Creates a `SourceNode` representing a fragment of source code within a file.
*
* @example
* ```ts
* createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')], isExportable: true })
* ```
*/
const createSource = sourceDef.create;
/**
* Creates a fully resolved `FileNode` from a file input descriptor.
*
* Computes:
* - `id` SHA256 hash of the file path
* - `name` `baseName` without extension
* - `extname` extension extracted from `baseName`
*
* Deduplicates:
* - `sources` via `combineSources`
* - `exports` via `combineExports`
* - `imports` via `combineImports` (also filters unused imports)
*
* @throws {Error} when `baseName` has no extension.
*
* @example
* ```ts
* const file = createFile({
* baseName: 'petStore.ts',
* path: 'src/models/petStore.ts',
* sources: [createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')] })],
* imports: [createImport({ name: ['z'], path: 'zod' })],
* exports: [createExport({ name: ['Pet'], path: './petStore' })],
* })
* // file.id = SHA256 hash of 'src/models/petStore.ts'
* // file.name = 'petStore'
* // file.extname = '.ts'
* ```
*
* @example Copy a real file into the output verbatim
* ```ts
* const file = createFile({
* baseName: 'client.ts',
* path: 'src/gen/client.ts',
* copy: '/abs/path/to/templates/client.ts',
* })
* ```
*/
function createFile(input) {
const extname = node_path.default.extname(input.baseName) || (input.baseName.startsWith(".") ? input.baseName : "");
if (!extname) throw new Error(`No extname found for ${input.baseName}`);
const source = (input.sources ?? []).flatMap((item) => item.nodes ?? []).map((node) => extractStringsFromNodes([node])).filter(Boolean).join("\n\n");
const resolvedExports = input.exports?.length ? combineExports(input.exports) : [];
const combinedImports = input.imports?.length ? combineImports(input.imports, resolvedExports, source || void 0) : [];
const localNames = new Set((input.sources ?? []).map((item) => item.name).filter((name) => Boolean(name)));
const nameOf = (item) => typeof item === "string" ? item : item.name ?? item.propertyName;
const resolvedImports = combinedImports.filter((imp) => imp.path !== input.path).flatMap((imp) => {
if (!Array.isArray(imp.name)) return typeof imp.name === "string" && localNames.has(imp.name) ? [] : [imp];
const kept = imp.name.filter((item) => !localNames.has(nameOf(item)));
if (!kept.length) return [];
return [kept.length === imp.name.length ? imp : {
...imp,
name: kept
}];
});
const resolvedSources = input.sources?.length ? combineSources(input.sources) : [];
return {
kind: "File",
...input,
id: (0, node_crypto.hash)("sha256", input.path, "hex"),
name: trimExtName(input.baseName),
extname,
imports: resolvedImports,
exports: resolvedExports,
sources: resolvedSources,
meta: input.meta ?? {}
};
}
//#endregion
//#region src/nodes/function.ts
/**
* Definition for the {@link TypeLiteralNode}.
*/
const typeLiteralDef = defineNode({ kind: "TypeLiteral" });
/**
* Definition for the {@link IndexedAccessTypeNode}.
*/
const indexedAccessTypeDef = defineNode({ kind: "IndexedAccessType" });
/**
* Definition for the {@link ObjectBindingPatternNode}.
*/
const objectBindingPatternDef = defineNode({ kind: "ObjectBindingPattern" });
/**
* Definition for the {@link FunctionParameterNode}. `optional` defaults to `false`.
* Passing `properties` builds a destructured group: an {@link ObjectBindingPatternNode} name
* paired with a {@link TypeLiteralNode} type.
*/
const functionParameterDef = defineNode({
kind: "FunctionParameter",
build: (input) => {
if ("properties" in input) return {
name: createObjectBindingPattern({ elements: input.properties.map((p) => ({ name: p.name })) }),
type: createTypeLiteral({ members: input.properties.map((p) => ({
name: p.name,
type: p.type,
optional: p.optional ?? false
})) }),
optional: input.optional ?? false,
...input.default !== void 0 ? { default: input.default } : {}
};
return {
optional: false,
...input
};
}
});
/**
* Definition for the {@link FunctionParametersNode}.
*/
const functionParametersDef = defineNode({
kind: "FunctionParameters",
defaults: { params: [] }
});
/**
* Creates a {@link TypeLiteralNode} representing an inline anonymous object type.
*
* @example
* ```ts
* createTypeLiteral({ members: [{ name: 'petId', type: 'string', optional: false }] })
* // { petId: string }
* ```
*/
const createTypeLiteral = typeLiteralDef.create;
/**
* Creates an {@link IndexedAccessTypeNode} representing a single field accessed from a named type.
*
* @example
* ```ts
* createIndexedAccessType({ target: 'DeletePetPathParams', key: 'petId' })
* // DeletePetPathParams['petId']
* ```
*/
const createIndexedAccessType = indexedAccessTypeDef.create;
/**
* Creates an {@link ObjectBindingPatternNode} for a destructured parameter binding.
*
* @example
* ```ts
* createObjectBindingPattern({ elements: [{ name: 'id' }, { name: 'name' }] })
* // { id, name }
* ```
*/
const createObjectBindingPattern = objectBindingPatternDef.create;
/**
* Creates a `FunctionParameterNode`. `optional` defaults to `false`.
*
* @example Optional param
* ```ts
* createFunctionParameter({ name: 'params', type: 'QueryParams', optional: true })
* // → params?: QueryParams
* ```
*
* @example Destructured group
* ```ts
* createFunctionParameter({ properties: [{ name: 'id', type: 'string' }, { name: 'name', type: 'string', optional: true }], default: '{}' })
* // → { id, name }: { id: string; name?: string } = {}
* ```
*/
const createFunctionParameter = functionParameterDef.create;
/**
* Creates a `FunctionParametersNode` from an ordered list of parameters.
*
* @example
* ```ts
* const empty = createFunctionParameters()
* // { kind: 'FunctionParameters', params: [] }
* ```
*/
function createFunctionParameters(props = {}) {
return functionParametersDef.create(props);
}
//#endregion
//#region src/nodes/input.ts
/**
* Definition for the {@link InputNode}.
*/
const inputDef = defineNode({
kind: "Input",
defaults: {
schemas: [],
operations: [],
meta: {
circularNames: [],
enumNames: []
}
},
children: ["schemas", "operations"],
visitorKey: "input"
});
/**
* Creates an `InputNode`. Pass `stream: true` for the streaming variant whose `schemas` and
* `operations` are `AsyncIterable` sources. Otherwise it builds the eager variant with array
* `schemas`/`operations`. Both variants get the defaulted `meta`.
*
* @example Eager
* ```ts
* const input = createInput()
* // { kind: 'Input', schemas: [], operations: [] }
* ```
*
* @example Streaming
* ```ts
* const node = createInput({ stream: true, schemas: schemasIterable, operations: operationsIterable, meta: { title: 'My API' } })
* ```
*/
function createInput(options = {}) {
const { stream, ...overrides } = options;
if (stream) return {
kind: "Input",
meta: {
circularNames: [],
enumNames: []
},
...overrides
};
return inputDef.create(overrides);
}
//#endregion
//#region src/nodes/requestBody.ts
/**
* Definition for the {@link RequestBodyNode}. Content entries are built upfront with
* {@link createContent}, mirroring how `parameters` and `responses` take prebuilt nodes.
*/
const requestBodyDef = defineNode({
kind: "RequestBody",
children: ["content"]
});
/**
* Creates a `RequestBodyNode`.
*/
const createRequestBody = requestBodyDef.create;
//#endregion
//#region src/nodes/operation.ts
/**
* Definition for the {@link OperationNode}. HTTP operations (those carrying both
* `method` and `path`) are tagged with `protocol: 'http'`, and the request body is
* normalized into a `RequestBodyNode`.
*/
const operationDef = defineNode({
kind: "Operation",
build: (props) => {
const { requestBody, ...rest } = props;
const isHttp = rest.method !== void 0 && rest.path !== void 0;
return {
tags: [],
parameters: [],
responses: [],
...rest,
...isHttp ? { protocol: "http" } : {},
requestBody: requestBody ? createRequestBody(requestBody) : void 0
};
},
children: [
"parameters",
"requestBody",
"responses"
],
visitorKey: "operation"
});
function createOperation(props) {
return operationDef.create(props);
}
//#endregion
//#region src/nodes/output.ts
/**
* Definition for the {@link OutputNode}.
*/
const outputDef = defineNode({
kind: "Output",
defaults: { files: [] },
visitorKey: "output"
});
/**
* Creates an `OutputNode` with a stable default for `files`.
*
* @example
* ```ts
* const output = createOutput()
* // { kind: 'Output', files: [] }
* ```
*/
function createOutput(overrides = {}) {
return outputDef.create(overrides);
}
//#endregion
//#region src/optionality.ts
/**
* Generic JSON Schema optionality: a non-required field is optional, and a
* non-required nullable field is nullish.
*/
function optionality(schema, required) {
const nullable = schema.nullable ?? false;
return {
...schema,
optional: !required && !nullable ? true : void 0,
nullish: !required && nullable ? true : void 0
};
}
//#endregion
//#region src/nodes/parameter.ts
/**
* Definition for the {@link ParameterNode}. `required` defaults to `false`, and the schema's
* `optional`/`nullish` flags are derived from it through {@link optionality}.
*/
const parameterDef = defineNode({
kind: "Parameter",
build: (props) => {
const required = props.required ?? false;
return {
...props,
required,
schema: optionality(props.schema, required)
};
},
children: ["schema"],
visitorKey: "parameter"
});
/**
* Creates a `ParameterNode`.
*
* @example
* ```ts
* const param = createParameter({
* name: 'petId',
* in: 'path',
* required: true,
* schema: createSchema({ type: 'string' }),
* })
* ```
*/
const createParameter = parameterDef.create;
//#endregion
//#region src/nodes/property.ts
/**
* Definition for the {@link PropertyNode}. `required` defaults to `false`, and the schema's
* `optional`/`nullish` flags are derived from it through {@link optionality}.
*/
const propertyDef = defineNode({
kind: "Property",
build: (props) => {
const required = props.required ?? false;
return {
...props,
required,
schema: optionality(props.schema, required)
};
},
children: ["schema"],
visitorKey: "property"
});
/**
* Creates a `PropertyNode`.
*
* @example
* ```ts
* const property = createProperty({
* name: 'status',
* required: true,
* schema: createSchema({ type: 'string', nullable: true }),
* })
* // required=true, no optional/nullish
* ```
*/
const createProperty = propertyDef.create;
//#endregion
//#region src/nodes/response.ts
/**
* Definition for the {@link ResponseNode}. A single legacy `schema` (with optional
* `mediaType`/`keysToOmit`) is normalized into one `content` entry.
*/
const responseDef = defineNode({
kind: "Response",
build: (props) => {
const { schema, mediaType, keysToOmit, content, ...rest } = props;
const entries = content ?? (schema ? [createContent({
contentType: mediaType ?? "application/json",
schema,
keysToOmit: keysToOmit ?? null
})] : void 0);
return {
...rest,
content: entries
};
},
children: ["content"],
visitorKey: "response"
});
/**
* Creates a `ResponseNode`.
*
* @example
* ```ts
* const response = createResponse({
* statusCode: '200',
* content: [createContent({ contentType: 'application/json', schema: createSchema({ type: 'object', properties: [] }) })],
* })
* ```
*/
const createResponse = responseDef.create;
//#endregion
//#region src/nodes/schema.ts
/**
* Maps schema `type` to its underlying `primitive`.
* Primitive types map to themselves and special string formats map to `'string'`.
* Any type not listed here (such as `ref`, `enum`, `union`, `intersection`, `tuple`, `ipv4`, `ipv6`, `blob`) has no `primitive`.
*/
const TYPE_TO_PRIMITIVE = {
string: "string",
number: "number",
integer: "integer",
bigint: "bigint",
boolean: "boolean",
null: "null",
any: "any",
unknown: "unknown",
void: "void",
never: "never",
object: "object",
array: "array",
date: "date",
uuid: "string",
email: "string",
url: "string",
datetime: "string",
time: "string"
};
/**
* Definition for the {@link SchemaNode}. Object schemas default `properties` to an
* empty array, and `primitive` is inferred from `type` when not explicitly provided.
*/
const schemaDef = defineNode({
kind: "Schema",
build: (props) => {
if (props.type === "object") return {
properties: [],
primitive: "object",
...props
};
return {
primitive: TYPE_TO_PRIMITIVE[props.type],
...props
};
},
children: [
"properties",
"items",
"members",
"additionalProperties"
],
visitorKey: "schema"
});
function createSchema(props) {
return schemaDef.create(props);
}
//#endregion
//#region src/registry.ts
/**
* Every node definition. Adding a node means adding its `defineNode` to one
* `nodes/*.ts` file and listing it here. The visitor tables in `visitor.ts` derive from it.
*/
const nodeDefs = [
inputDef,
outputDef,
operationDef,
requestBodyDef,
contentDef,
responseDef,
schemaDef,
propertyDef,
parameterDef,
functionParameterDef,
functionParametersDef,
typeLiteralDef,
indexedAccessTypeDef,
objectBindingPatternDef,
constDef,
typeDef,
functionDef,
arrowFunctionDef,
textDef,
breakDef,
jsxDef,
importDef,
exportDef,
sourceDef,
fileDef
];
//#endregion
//#region src/visitor.ts
/**
* Child node fields per node kind, in traversal order (Babel's `VISITOR_KEYS`).
* Derived from each definition's `children`.
*/
const VISITOR_KEYS = Object.fromEntries(nodeDefs.flatMap((def) => def.children ? [[def.kind, def.children]] : []));
/**
* Maps a node kind to the matching visitor callback name. Derived from each
* definition's `visitorKey`.
*/
const VISITOR_KEY_BY_KIND = Object.fromEntries(nodeDefs.flatMap((def) => def.visitorKey ? [[def.kind, def.visitorKey]] : []));
/**
* Creates a small async concurrency limiter.
*
* At most `concurrency` tasks are in flight at once. Extra tasks are queued.
*
* @example
* ```ts
* const limit = createLimit(2)
* for (const task of [taskA, taskB, taskC]) {
* await limit(() => task())
* }
* // only 2 tasks run at the same time
* ```
*/
function createLimit(concurrency) {
let active = 0;
const queue = [];
function next() {
if (active < concurrency && queue.length > 0) {
active++;
queue.shift()();
}
}
return function limit(fn) {
return new Promise((resolve, reject) => {
queue.push(() => {
Promise.resolve(fn()).then(resolve, reject).finally(() => {
active--;
next();
});
});
next();
});
};
}
const visitorKeysByKind = VISITOR_KEYS;
/**
* Returns `true` when `value` is an AST node (an object carrying a `kind`).
*/
function isNode(value) {
return typeof value === "object" && value !== null && "kind" in value;
}
/**
* Returns the immediate traversable children of `node` based on {@link VISITOR_KEYS}.
*
* `Schema` children are only included when `recurse` is `true`. Shallow mode skips them.
*
* @example
* ```ts
* const children = getChildren(operationNode, true)
* // returns parameters, the request body, and responses
* ```
*/
function* getChildren(node, recurse) {
if (node.kind === "Schema" && !recurse) return;
const keys = visitorKeysByKind[node.kind];
if (!keys) return;
const record = node;
for (const key of keys) {
const value = record[key];
if (Array.isArray(value)) {
for (const item of value) if (isNode(item)) yield item;
} else if (isNode(value)) yield value;
}
}
/**
* Runs the visitor callback that matches `node.kind` with the traversal
* context. The result is a replacement node, a collected value, or `undefined`
* when no callback is registered for the kind.
*
* Shared by `walk`, `transform`, and `collectLazy` so node-kind dispatch lives
* in one place. `TResult` is the caller's expected return: the same node type
* for `transform`, the collected value type for `collectLazy`, ignored for `walk`.
*/
function applyVisitor(node, visitor, parent) {
const key = VISITOR_KEY_BY_KIND[node.kind];
if (!key) return void 0;
const fn = visitor[key];
return fn?.(node, { parent });
}
/**
* Async depth-first traversal for side effects. Visitor return values are
* ignored. Use `transform` when you want to rewrite nodes.
*
* Sibling nodes at each depth run concurrently up to `options.concurrency`
* (defaults to `WALK_CONCURRENCY`). Higher values overlap I/O-bound visitor
* work. Lower values reduce memory pressure.
*
* @example Log every operation
* ```ts
* await walk(root, {
* operation(node) {
* console.log(node.operationId)
* },
* })
* ```
*
* @example Only visit the root node
* ```ts
* await walk(root, { depth: 'shallow', input: () => {} })
* ```
*/
async function walk(node, options) {
return _walk(node, options, (options.depth ?? visitorDepths.deep) === visitorDepths.deep, createLimit(options.concurrency ?? 30), void 0);
}
async function _walk(node, visitor, recurse, limit, parent) {
await limit(() => applyVisitor(node, visitor, parent));
const children = Array.from(getChildren(node, recurse));
if (children.length === 0) return;
await Promise.all(children.map((child) => _walk(child, visitor, recurse, limit, node)));
}
function transform(node, options) {
const { depth, parent, ...visitor } = options;
const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep;
return transformChildren(applyVisitor(node, visitor, parent) ?? node, options, recurse);
}
/**
* Immutably rebuilds a node's children using {@link VISITOR_KEYS}, transforming
* each child node and leaving non-node values (e.g. `additionalProperties: true`) intact.
* `Schema` children are skipped in shallow mode.
*/
function transformChildren(node, options, recurse) {
if (node.kind === "Schema" && !recurse) return node;
const keys = visitorKeysByKind[node.kind];
if (!keys) return node;
const record = node;
const childOptions = {
...options,
parent: node
};
let updates;
for (const key of keys) {
if (!(key in record)) continue;
const value = record[key];
if (Array.isArray(value)) {
let changed = false;
const mapped = value.map((item) => {
if (!isNode(item)) return item;
const next = transform(item, childOptions);
if (next !== item) changed = true;
return next;
});
if (changed) (updates ??= {})[key] = mapped;
} else if (isNode(value)) {
const next = transform(value, childOptions);
if (next !== value) (updates ??= {})[key] = next;
}
}
return updates ? {
...node,
...updates
} : node;
}
/**
* Lazy depth-first collection pass. Yields every non-null value returned by
* the visitor callbacks. Use `collect` for the eager array form.
*
* @example Collect every operationId
* ```ts
* const ids: string[] = []
* for (const id of collectLazy<string>(root, {
* operation(node) {
* return node.operationId
* },
* })) {
* ids.push(id)
* }
* ```
*/
function* collectLazy(node, options) {
const { depth, parent, ...visitor } = options;
const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep;
const v = applyVisitor(node, visitor, parent);
if (v != null) yield v;
for (const child of getChildren(node, recurse)) yield* collectLazy(child, {
...options,
parent: node
});
}
/**
* Eager depth-first collection pass. Gathers every non-null value the visitor
* callbacks return into an array.
*
* @example Collect every operationId
* ```ts
* const ids = collect<string>(root, {
* operation(node) {
* return node.operationId
* },
* })
* ```
*/
function collect(node, options) {
return Array.from(collectLazy(node, options));
}
//#endregion
Object.defineProperty(exports, "INDENT", {
enumerable: true,
get: function() {
return INDENT;
}
});
Object.defineProperty(exports, "__exportAll", {
enumerable: true,
get: function() {
return __exportAll;
}
});
Object.defineProperty(exports, "__name", {
enumerable: true,
get: function() {
return __name;
}
});
Object.defineProperty(exports, "arrowFunctionDef", {
enumerable: true,
get: function() {
return arrowFunctionDef;
}
});
Object.defineProperty(exports, "breakDef", {
enumerable: true,
get: function() {
return breakDef;
}
});
Object.defineProperty(exports, "camelCase", {
enumerable: true,
get: function() {
return camelCase;
}
});
Object.defineProperty(exports, "collect", {
enumerable: true,
get: function() {
return collect;
}
});
Object.defineProperty(exports, "collectLazy", {
enumerable: true,
get: function() {
return collectLazy;
}
});
Object.defineProperty(exports, "constDef", {
enumerable: true,
get: function() {
return constDef;
}
});
Object.defineProperty(exports, "contentDef", {
enumerable: true,
get: function() {
return contentDef;
}
});
Object.defineProperty(exports, "createArrowFunction", {
enumerable: true,
get: function() {
return createArrowFunction;
}
});
Object.defineProperty(exports, "createBreak", {
enumerable: true,
get: function() {
return createBreak;
}
});
Object.defineProperty(exports, "createConst", {
enumerable: true,
get: function() {
return createConst;
}
});
Object.defineProperty(exports, "createContent", {
enumerable: true,
get: function() {
return createContent;
}
});
Object.defineProperty(exports, "createExport", {
enumerable: true,
get: function() {
return createExport;
}
});
Object.defineProperty(exports, "createFile", {
enumerable: true,
get: function() {
return createFile;
}
});
Object.defineProperty(exports, "createFunction", {
enumerable: true,
get: function() {
return createFunction;
}
});
Object.defineProperty(exports, "createFunctionParameter", {
enumerable: true,
get: function() {
return createFunctionParameter;
}
});
Object.defineProperty(exports, "createFunctionParameters", {
enumerable: true,
get: function() {
return createFunctionParameters;
}
});
Object.defineProperty(exports, "createImport", {
enumerable: true,
get: function() {
return createImport;
}
});
Object.defineProperty(exports, "createIndexedAccessType", {
enumerable: true,
get: function() {
return createIndexedAccessType;
}
});
Object.defineProperty(exports, "createInput", {
enumerable: true,
get: function() {
return createInput;
}
});
Object.defineProperty(exports, "createJsx", {
enumerable: true,
get: function() {
return createJsx;
}
});
Object.defineProperty(exports, "createObjectBindingPattern", {
enumerable: true,
get: function() {
return createObjectBindingPattern;
}
});
Object.defineProperty(exports, "createOperation", {
enumerable: true,
get: function() {
return createOperation;
}
});
Object.defineProperty(exports, "createOutput", {
enumerable: true,
get: function() {
return createOutput;
}
});
Object.defineProperty(exports, "createParameter", {
enumerable: true,
get: function() {
return createParameter;
}
});
Object.defineProperty(exports, "createProperty", {
enumerable: true,
get: function() {
return createProperty;
}
});
Object.defineProperty(exports, "createRequestBody", {
enumerable: true,
get: function() {
return createRequestBody;
}
});
Object.defineProperty(exports, "createResponse", {
enumerable: true,
get: function() {
return createResponse;
}
});
Object.defineProperty(exports, "createSchema", {
enumerable: true,
get: function() {
return createSchema;
}
});
Object.defineProperty(exports, "createSource", {
enumerable: true,
get: function() {
return createSource;
}
});
Object.defineProperty(exports, "createText", {
enumerable: true,
get: function() {
return createText;
}
});
Object.defineProperty(exports, "createType", {
enumerable: true,
get: function() {
return createType;
}
});
Object.defineProperty(exports, "createTypeLiteral", {
enumerable: true,
get: function() {
return createTypeLiteral;
}
});
Object.defineProperty(exports, "defineNode", {
enumerable: true,
get: function() {
return defineNode;
}
});
Object.defineProperty(exports, "exportDef", {
enumerable: true,
get: function() {
return exportDef;
}
});
Object.defineProperty(exports, "extractStringsFromNodes", {
enumerable: true,
get: function() {
return extractStringsFromNodes;
}
});
Object.defineProperty(exports, "fileDef", {
enumerable: true,
get: function() {
return fileDef;
}
});
Object.defineProperty(exports, "functionDef", {
enumerable: true,
get: function() {
return functionDef;
}
});
Object.defineProperty(exports, "functionParameterDef", {
enumerable: true,
get: function() {
return functionParameterDef;
}
});
Object.defineProperty(exports, "functionParametersDef", {
enumerable: true,
get: function() {
return functionParametersDef;
}
});
Object.defineProperty(exports, "importDef", {
enumerable: true,
get: function() {
return importDef;
}
});
Object.defineProperty(exports, "indexedAccessTypeDef", {
enumerable: true,
get: function() {
return indexedAccessTypeDef;
}
});
Object.defineProperty(exports, "inputDef", {
enumerable: true,
get: function() {
return inputDef;
}
});
Object.defineProperty(exports, "isHttpOperationNode", {
enumerable: true,
get: function() {
return isHttpOperationNode;
}
});
Object.defineProperty(exports, "jsxDef", {
enumerable: true,
get: function() {
return jsxDef;
}
});
Object.defineProperty(exports, "narrowSchema", {
enumerable: true,
get: function() {
return narrowSchema;
}
});
Object.defineProperty(exports, "nodeDefs", {
enumerable: true,
get: function() {
return nodeDefs;
}
});
Object.defineProperty(exports, "objectBindingPatternDef", {
enumerable: true,
get: function() {
return objectBindingPatternDef;
}
});
Object.defineProperty(exports, "operationDef", {
enumerable: true,
get: function() {
return operationDef;
}
});
Object.defineProperty(exports, "optionality", {
enumerable: true,
get: function() {
return optionality;
}
});
Object.defineProperty(exports, "outputDef", {
enumerable: true,
get: function() {
return outputDef;
}
});
Object.defineProperty(exports, "parameterDef", {
enumerable: true,
get: function() {
return parameterDef;
}
});
Object.defineProperty(exports, "pascalCase", {
enumerable: true,
get: function() {
return pascalCase;
}
});
Object.defineProperty(exports, "propertyDef", {
enumerable: true,
get: function() {
return propertyDef;
}
});
Object.defineProperty(exports, "requestBodyDef", {
enumerable: true,
get: function() {
return requestBodyDef;
}
});
Object.defineProperty(exports, "responseDef", {
enumerable: true,
get: function() {
return responseDef;
}
});
Object.defineProperty(exports, "schemaDef", {
enumerable: true,
get: function() {
return schemaDef;
}
});
Object.defineProperty(exports, "schemaTypes", {
enumerable: true,
get: function() {
return schemaTypes;
}
});
Object.defineProperty(exports, "sourceDef", {
enumerable: true,
get: function() {
return sourceDef;
}
});
Object.defineProperty(exports, "textDef", {
enumerable: true,
get: function() {
return textDef;
}
});
Object.defineProperty(exports, "transform", {
enumerable: true,
get: function() {
return transform;
}
});
Object.defineProperty(exports, "typeDef", {
enumerable: true,
get: function() {
return typeDef;
}
});
Object.defineProperty(exports, "typeLiteralDef", {
enumerable: true,
get: function() {
return typeLiteralDef;
}
});
Object.defineProperty(exports, "visitorKeys", {
enumerable: true,
get: function() {
return visitorKeys;
}
});
Object.defineProperty(exports, "walk", {
enumerable: true,
get: function() {
return walk;
}
});
//# sourceMappingURL=visitor-CLLDwBvv.cjs.map

Sorry, the diff of this file is too big to display

import "./rolldown-runtime-CNktS9qV.js";
import { hash } from "node:crypto";
import path from "node:path";
//#region src/constants.ts
const visitorDepths = {
shallow: "shallow",
deep: "deep"
};
/**
* Schema type discriminators used by all AST schema nodes.
*
* Each value is a stable discriminator across the AST (for example `schema.type === schemaTypes.object`).
*/
const schemaTypes = {
/**
* Text value.
*/
string: "string",
/**
* Floating-point number (`float`, `double`).
*/
number: "number",
/**
* Whole number (`int32`). Use `bigint` for `int64`.
*/
integer: "integer",
/**
* 64-bit integer (`int64`). Only used when `integerType` is set to `'bigint'`.
*/
bigint: "bigint",
/**
* Boolean value.
*/
boolean: "boolean",
/**
* Explicit null value.
*/
null: "null",
/**
* Any value (no type restriction).
*/
any: "any",
/**
* Unknown value (must be narrowed before usage).
*/
unknown: "unknown",
/**
* No return value (`void`).
*/
void: "void",
/**
* Object with named properties.
*/
object: "object",
/**
* Sequential list of items.
*/
array: "array",
/**
* Fixed-length list with position-specific items.
*/
tuple: "tuple",
/**
* "One of" multiple schema members.
*/
union: "union",
/**
* "All of" multiple schema members.
*/
intersection: "intersection",
/**
* Enum schema.
*/
enum: "enum",
/**
* Reference to another schema.
*/
ref: "ref",
/**
* Calendar date (for example `2026-03-24`).
*/
date: "date",
/**
* Date-time value (for example `2026-03-24T09:00:00Z`).
*/
datetime: "datetime",
/**
* Time-only value (for example `09:00:00`).
*/
time: "time",
/**
* UUID value.
*/
uuid: "uuid",
/**
* Email address value.
*/
email: "email",
/**
* URL value.
*/
url: "url",
/**
* IPv4 address value.
*/
ipv4: "ipv4",
/**
* IPv6 address value.
*/
ipv6: "ipv6",
/**
* Binary/blob value.
*/
blob: "blob",
/**
* Impossible value (`never`).
*/
never: "never"
};
/**
* One indentation level, derived from {@link INDENT_SIZE}.
*/
const INDENT = Array.from({ length: 2 }, () => " ").join("");
//#endregion
//#region src/guards.ts
/**
* Narrows a `SchemaNode` to the variant that matches `type`.
*
* @example
* ```ts
* const schema = createSchema({ type: 'string' })
* const stringNode = narrowSchema(schema, 'string') // StringSchemaNode | null
* ```
*/
function narrowSchema(node, type) {
return node?.type === type ? node : null;
}
/**
* Narrows an `OperationNode` to an `HttpOperationNode` so `method` and `path` are present.
*
* @example
* ```ts
* if (isHttpOperationNode(node)) {
* console.log(node.method, node.path)
* }
* ```
*/
function isHttpOperationNode(node) {
return node.protocol === "http" || node.method !== void 0 && node.path !== void 0;
}
//#endregion
//#region src/defineNode.ts
/**
* Visitor callback names, one per traversable node kind, in traversal order.
* Kept in sync with the keys of `Visitor` in `visitor.ts`.
*/
const visitorKeys = [
"input",
"output",
"operation",
"schema",
"property",
"parameter",
"response"
];
/**
* Builds a type guard that matches nodes of the given `kind`.
*/
function isKind(kind) {
return (node) => node?.kind === kind;
}
/**
* Defines a node once and derives its `create` builder, `is` guard, and traversal
* metadata. `create` merges `defaults`, the `build` hook (or the raw input), and the
* `kind`, so node construction lives in one place without scattered `as` casts.
*
* @example Simple node
* ```ts
* const importDef = defineNode<ImportNode>({ kind: 'Import' })
* const createImport = importDef.create
* ```
*
* @example Node with a build hook
* ```ts
* const propertyDef = defineNode<PropertyNode, UserPropertyNode>({
* kind: 'Property',
* build: (props) => ({ ...props, required: props.required ?? false }),
* children: ['schema'],
* visitorKey: 'property',
* })
* ```
*/
function defineNode(config) {
const { kind, defaults, build, children, visitorKey } = config;
function create(input) {
const base = build ? build(input) : input;
return {
...defaults,
...base,
kind
};
}
return {
kind,
create,
is: isKind(kind),
children,
visitorKey
};
}
//#endregion
//#region src/nodes/code.ts
/**
* Definition for the {@link ConstNode}.
*/
const constDef = defineNode({ kind: "Const" });
/**
* Definition for the {@link TypeNode}.
*/
const typeDef = defineNode({ kind: "Type" });
/**
* Definition for the {@link FunctionNode}.
*/
const functionDef = defineNode({ kind: "Function" });
/**
* Definition for the {@link ArrowFunctionNode}.
*/
const arrowFunctionDef = defineNode({ kind: "ArrowFunction" });
/**
* Definition for the {@link TextNode}.
*/
const textDef = defineNode({
kind: "Text",
build: (value) => ({ value })
});
/**
* Definition for the {@link BreakNode}.
*/
const breakDef = defineNode({
kind: "Break",
build: () => ({})
});
/**
* Definition for the {@link JsxNode}.
*/
const jsxDef = defineNode({
kind: "Jsx",
build: (value) => ({ value })
});
/**
* Creates a `ConstNode` representing a TypeScript `const` declaration.
*
* @example Exported constant with type and `as const`
* ```ts
* createConst({ name: 'pets', export: true, type: 'Pet[]', asConst: true })
* // export const pets: Pet[] = ... as const
* ```
*/
const createConst = constDef.create;
/**
* Creates a `TypeNode` representing a TypeScript `type` alias declaration.
*
* @example
* ```ts
* createType({ name: 'Pet', export: true })
* // export type Pet = ...
* ```
*/
const createType = typeDef.create;
/**
* Creates a `FunctionNode` representing a TypeScript `function` declaration.
*
* @example
* ```ts
* createFunction({ name: 'fetchPet', export: true, async: true, returnType: 'Pet' })
* // export async function fetchPet(): Promise<Pet> { ... }
* ```
*/
const createFunction = functionDef.create;
/**
* Creates an `ArrowFunctionNode` representing a TypeScript arrow function.
*
* @example
* ```ts
* createArrowFunction({ name: 'double', export: true, params: 'n: number', singleLine: true })
* // export const double = (n: number) => ...
* ```
*/
const createArrowFunction = arrowFunctionDef.create;
/**
* Creates a {@link TextNode} representing a raw string fragment in the source output.
*
* @example
* ```ts
* createText('return fetch(id)')
* // { kind: 'Text', value: 'return fetch(id)' }
* ```
*/
const createText = textDef.create;
/**
* Creates a {@link BreakNode} representing a line break in the source output.
*
* @example
* ```ts
* createBreak()
* // { kind: 'Break' }
* ```
*/
function createBreak() {
return breakDef.create();
}
/**
* Creates a {@link JsxNode} representing a raw JSX fragment in the source output.
*
* @example
* ```ts
* createJsx('<>\n <a href={href}>Open</a>\n</>')
* // { kind: 'Jsx', value: '<>\n <a href={href}>Open</a>\n</>' }
* ```
*/
const createJsx = jsxDef.create;
//#endregion
//#region src/nodes/content.ts
/**
* Definition for the {@link ContentNode}.
*/
const contentDef = defineNode({
kind: "Content",
children: ["schema"]
});
/**
* Creates a `ContentNode` for a single request-body or response content type.
*/
const createContent = contentDef.create;
//#endregion
//#region ../../internals/utils/src/casing.ts
/**
* Shared implementation for camelCase and PascalCase conversion.
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
* and capitalizes each word according to `pascal`.
*
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
*/
function toCamelOrPascal(text, pascal) {
return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
if (word.length > 1 && word === word.toUpperCase()) return word;
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
}).join("").replace(/[^a-zA-Z0-9]/g, "");
}
/**
* Converts `text` to camelCase.
*
* @example Word boundaries
* `camelCase('hello-world') // 'helloWorld'`
*
* @example With a prefix
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
*/
function camelCase(text, { prefix = "", suffix = "" } = {}) {
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
}
/**
* Converts `text` to PascalCase.
*
* @example Word boundaries
* `pascalCase('hello-world') // 'HelloWorld'`
*
* @example With a suffix
* `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`
*/
function pascalCase(text, { prefix = "", suffix = "" } = {}) {
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
}
//#endregion
//#region ../../internals/utils/src/fs.ts
/**
* Strips the file extension from a path or file name.
* Only removes the last `.ext` segment when the dot is not part of a directory name.
*
* @example
* trimExtName('petStore.ts') // 'petStore'
* trimExtName('/src/models/pet.ts') // '/src/models/pet'
* trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet'
* trimExtName('noExtension') // 'noExtension'
*/
function trimExtName(text) {
const dotIndex = text.lastIndexOf(".");
if (dotIndex > 0 && !text.includes("/", dotIndex)) return text.slice(0, dotIndex);
return text;
}
//#endregion
//#region src/utils/extractStringsFromNodes.ts
/**
* Extracts all string content from a `CodeNode` tree recursively.
*
* Collects text node values, identifier references in string fields (`params`, `generics`, `returnType`, `type`),
* and nested node content. Used to build the full source string for import filtering.
*/
function extractStringsFromNodes(nodes) {
if (!nodes?.length) return "";
return nodes.map((node) => {
if (typeof node === "string") return node;
if (node.kind === "Text") return node.value;
if (node.kind === "Break") return "";
if (node.kind === "Jsx") return node.value;
const parts = [];
if ("params" in node && node.params) parts.push(node.params);
if ("generics" in node && node.generics) parts.push(Array.isArray(node.generics) ? node.generics.join(", ") : node.generics);
if ("returnType" in node && node.returnType) parts.push(node.returnType);
if ("type" in node && typeof node.type === "string") parts.push(node.type);
const nested = extractStringsFromNodes(node.nodes);
if (nested) parts.push(nested);
return parts.join("\n");
}).filter(Boolean).join("\n");
}
//#endregion
//#region src/utils/fileMerge.ts
function sourceKey(source) {
return `${source.name ?? extractStringsFromNodes(source.nodes)}:${source.isExportable ?? false}:${source.isTypeOnly ?? false}`;
}
function pathTypeKey(path, isTypeOnly) {
return `${path}:${isTypeOnly ?? false}`;
}
function exportKey(path, name, isTypeOnly, asAlias) {
return `${path}:${name ?? ""}:${isTypeOnly ?? false}:${asAlias ?? ""}`;
}
function importKey(path, name, isTypeOnly) {
return `${path}:${name ?? ""}:${isTypeOnly ?? false}`;
}
/**
* Computes a multi-level sort key for exports and imports:
* non-array names first (wildcards/namespace aliases). Type-only before value. Alphabetical path. Unnamed before named.
*/
function sortKey(node) {
const isArray = Array.isArray(node.name) ? "1" : "0";
const typeOnly = node.isTypeOnly ? "0" : "1";
const hasName = node.name != null ? "1" : "0";
const name = Array.isArray(node.name) ? node.name.toSorted().join("\0") : node.name ?? "";
return `${isArray}:${typeOnly}:${node.path}:${hasName}:${name}`;
}
/**
* Deduplicates `SourceNode` objects by `name + isExportable + isTypeOnly`, keeping the first of each
* key. Unnamed sources fall back to their extracted node strings as the name part of the key. Returns
* the deduplicated array in original order.
*/
function combineSources(sources) {
const seen = /* @__PURE__ */ new Map();
for (const source of sources) {
const key = sourceKey(source);
if (!seen.has(key)) seen.set(key, source);
}
return [...seen.values()];
}
/**
* Merges `incoming` names into `existing`, preserving order and dropping duplicates.
*
* Shared by `combineExports` and `combineImports` for the same-path name-merge case.
*/
function mergeNameArrays(existing, incoming) {
const merged = new Set(existing);
for (const name of incoming) merged.add(name);
return [...merged];
}
/**
* Deduplicates and merges `ExportNode` objects by path and type.
*
* Named exports with the same path and `isTypeOnly` flag have their names merged into a single export.
* Non-array exports are deduplicated by exact identity. Returns a sorted, deduplicated array.
*/
function combineExports(exports) {
const result = [];
const namedByPath = /* @__PURE__ */ new Map();
const seen = /* @__PURE__ */ new Set();
const keyed = exports.map((node) => ({
node,
key: sortKey(node)
}));
keyed.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
for (const { node: curr } of keyed) {
const { name, path, isTypeOnly, asAlias } = curr;
if (Array.isArray(name)) {
if (!name.length) continue;
const key = pathTypeKey(path, isTypeOnly);
const existing = namedByPath.get(key);
if (existing && Array.isArray(existing.name)) existing.name = mergeNameArrays(existing.name, name);
else {
const newItem = {
...curr,
name: [...new Set(name)]
};
result.push(newItem);
namedByPath.set(key, newItem);
}
} else {
const key = exportKey(path, name, isTypeOnly, asAlias);
if (!seen.has(key)) {
result.push(curr);
seen.add(key);
}
}
}
return result;
}
/**
* Deduplicates and merges `ImportNode` objects, filtering out unused imports.
*
* Retains imports that are referenced in `source` or re-exported. Imports with the same path and
* `isTypeOnly` flag have their names merged. Returns a sorted, deduplicated, filtered array.
*/
function combineImports(imports, exports, source) {
const exportedNames = new Set(exports.flatMap((e) => Array.isArray(e.name) ? e.name : e.name ? [e.name] : []));
const isUsed = (importName) => !source || source.includes(importName) || exportedNames.has(importName);
const importNameMemo = /* @__PURE__ */ new Map();
const canonicalizeName = (n) => {
if (typeof n === "string") return n;
const key = `${n.propertyName}:${n.name ?? ""}`;
if (!importNameMemo.has(key)) importNameMemo.set(key, n);
return importNameMemo.get(key);
};
const pathsWithUsedNamedImport = /* @__PURE__ */ new Set();
for (const node of imports) {
if (!Array.isArray(node.name)) continue;
if (node.name.some((item) => typeof item === "string" ? isUsed(item) : isUsed(item.name ?? item.propertyName))) pathsWithUsedNamedImport.add(node.path);
}
const result = [];
const namedByPath = /* @__PURE__ */ new Map();
const seen = /* @__PURE__ */ new Set();
const keyed = imports.map((node) => ({
node,
key: sortKey(node)
}));
keyed.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
for (const { node: curr } of keyed) {
if (curr.path === curr.root) continue;
const { path, isTypeOnly } = curr;
let { name } = curr;
if (Array.isArray(name)) {
name = [...new Set(name.map(canonicalizeName))].filter((item) => typeof item === "string" ? isUsed(item) : isUsed(item.name ?? item.propertyName));
if (!name.length) continue;
const key = pathTypeKey(path, isTypeOnly);
const existing = namedByPath.get(key);
if (existing && Array.isArray(existing.name)) existing.name = mergeNameArrays(existing.name, name);
else {
const newItem = {
...curr,
name
};
result.push(newItem);
namedByPath.set(key, newItem);
}
} else {
if (name && !isUsed(name) && !pathsWithUsedNamedImport.has(path)) continue;
const key = importKey(path, name, isTypeOnly);
if (!seen.has(key)) {
result.push(curr);
seen.add(key);
}
}
}
return result;
}
//#endregion
//#region src/nodes/file.ts
/**
* Definition for the {@link ImportNode}.
*/
const importDef = defineNode({ kind: "Import" });
/**
* Definition for the {@link ExportNode}.
*/
const exportDef = defineNode({ kind: "Export" });
/**
* Definition for the {@link SourceNode}.
*/
const sourceDef = defineNode({ kind: "Source" });
/**
* Definition for the {@link FileNode}. The fully resolved builder lives in
* `createFile`, so this definition only supplies the guard.
*/
const fileDef = defineNode({ kind: "File" });
/**
* Creates an `ImportNode` representing a language-agnostic import/dependency declaration.
*
* @example Named import
* ```ts
* createImport({ name: ['useState'], path: 'react' })
* // import { useState } from 'react'
* ```
*/
const createImport = importDef.create;
/**
* Creates an `ExportNode` representing a language-agnostic export/public API declaration.
*
* @example Named export
* ```ts
* createExport({ name: ['Pet'], path: './Pet' })
* // export { Pet } from './Pet'
* ```
*/
const createExport = exportDef.create;
/**
* Creates a `SourceNode` representing a fragment of source code within a file.
*
* @example
* ```ts
* createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')], isExportable: true })
* ```
*/
const createSource = sourceDef.create;
/**
* Creates a fully resolved `FileNode` from a file input descriptor.
*
* Computes:
* - `id` SHA256 hash of the file path
* - `name` `baseName` without extension
* - `extname` extension extracted from `baseName`
*
* Deduplicates:
* - `sources` via `combineSources`
* - `exports` via `combineExports`
* - `imports` via `combineImports` (also filters unused imports)
*
* @throws {Error} when `baseName` has no extension.
*
* @example
* ```ts
* const file = createFile({
* baseName: 'petStore.ts',
* path: 'src/models/petStore.ts',
* sources: [createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')] })],
* imports: [createImport({ name: ['z'], path: 'zod' })],
* exports: [createExport({ name: ['Pet'], path: './petStore' })],
* })
* // file.id = SHA256 hash of 'src/models/petStore.ts'
* // file.name = 'petStore'
* // file.extname = '.ts'
* ```
*
* @example Copy a real file into the output verbatim
* ```ts
* const file = createFile({
* baseName: 'client.ts',
* path: 'src/gen/client.ts',
* copy: '/abs/path/to/templates/client.ts',
* })
* ```
*/
function createFile(input) {
const extname = path.extname(input.baseName) || (input.baseName.startsWith(".") ? input.baseName : "");
if (!extname) throw new Error(`No extname found for ${input.baseName}`);
const source = (input.sources ?? []).flatMap((item) => item.nodes ?? []).map((node) => extractStringsFromNodes([node])).filter(Boolean).join("\n\n");
const resolvedExports = input.exports?.length ? combineExports(input.exports) : [];
const combinedImports = input.imports?.length ? combineImports(input.imports, resolvedExports, source || void 0) : [];
const localNames = new Set((input.sources ?? []).map((item) => item.name).filter((name) => Boolean(name)));
const nameOf = (item) => typeof item === "string" ? item : item.name ?? item.propertyName;
const resolvedImports = combinedImports.filter((imp) => imp.path !== input.path).flatMap((imp) => {
if (!Array.isArray(imp.name)) return typeof imp.name === "string" && localNames.has(imp.name) ? [] : [imp];
const kept = imp.name.filter((item) => !localNames.has(nameOf(item)));
if (!kept.length) return [];
return [kept.length === imp.name.length ? imp : {
...imp,
name: kept
}];
});
const resolvedSources = input.sources?.length ? combineSources(input.sources) : [];
return {
kind: "File",
...input,
id: hash("sha256", input.path, "hex"),
name: trimExtName(input.baseName),
extname,
imports: resolvedImports,
exports: resolvedExports,
sources: resolvedSources,
meta: input.meta ?? {}
};
}
//#endregion
//#region src/nodes/function.ts
/**
* Definition for the {@link TypeLiteralNode}.
*/
const typeLiteralDef = defineNode({ kind: "TypeLiteral" });
/**
* Definition for the {@link IndexedAccessTypeNode}.
*/
const indexedAccessTypeDef = defineNode({ kind: "IndexedAccessType" });
/**
* Definition for the {@link ObjectBindingPatternNode}.
*/
const objectBindingPatternDef = defineNode({ kind: "ObjectBindingPattern" });
/**
* Definition for the {@link FunctionParameterNode}. `optional` defaults to `false`.
* Passing `properties` builds a destructured group: an {@link ObjectBindingPatternNode} name
* paired with a {@link TypeLiteralNode} type.
*/
const functionParameterDef = defineNode({
kind: "FunctionParameter",
build: (input) => {
if ("properties" in input) return {
name: createObjectBindingPattern({ elements: input.properties.map((p) => ({ name: p.name })) }),
type: createTypeLiteral({ members: input.properties.map((p) => ({
name: p.name,
type: p.type,
optional: p.optional ?? false
})) }),
optional: input.optional ?? false,
...input.default !== void 0 ? { default: input.default } : {}
};
return {
optional: false,
...input
};
}
});
/**
* Definition for the {@link FunctionParametersNode}.
*/
const functionParametersDef = defineNode({
kind: "FunctionParameters",
defaults: { params: [] }
});
/**
* Creates a {@link TypeLiteralNode} representing an inline anonymous object type.
*
* @example
* ```ts
* createTypeLiteral({ members: [{ name: 'petId', type: 'string', optional: false }] })
* // { petId: string }
* ```
*/
const createTypeLiteral = typeLiteralDef.create;
/**
* Creates an {@link IndexedAccessTypeNode} representing a single field accessed from a named type.
*
* @example
* ```ts
* createIndexedAccessType({ target: 'DeletePetPathParams', key: 'petId' })
* // DeletePetPathParams['petId']
* ```
*/
const createIndexedAccessType = indexedAccessTypeDef.create;
/**
* Creates an {@link ObjectBindingPatternNode} for a destructured parameter binding.
*
* @example
* ```ts
* createObjectBindingPattern({ elements: [{ name: 'id' }, { name: 'name' }] })
* // { id, name }
* ```
*/
const createObjectBindingPattern = objectBindingPatternDef.create;
/**
* Creates a `FunctionParameterNode`. `optional` defaults to `false`.
*
* @example Optional param
* ```ts
* createFunctionParameter({ name: 'params', type: 'QueryParams', optional: true })
* // → params?: QueryParams
* ```
*
* @example Destructured group
* ```ts
* createFunctionParameter({ properties: [{ name: 'id', type: 'string' }, { name: 'name', type: 'string', optional: true }], default: '{}' })
* // → { id, name }: { id: string; name?: string } = {}
* ```
*/
const createFunctionParameter = functionParameterDef.create;
/**
* Creates a `FunctionParametersNode` from an ordered list of parameters.
*
* @example
* ```ts
* const empty = createFunctionParameters()
* // { kind: 'FunctionParameters', params: [] }
* ```
*/
function createFunctionParameters(props = {}) {
return functionParametersDef.create(props);
}
//#endregion
//#region src/nodes/input.ts
/**
* Definition for the {@link InputNode}.
*/
const inputDef = defineNode({
kind: "Input",
defaults: {
schemas: [],
operations: [],
meta: {
circularNames: [],
enumNames: []
}
},
children: ["schemas", "operations"],
visitorKey: "input"
});
/**
* Creates an `InputNode`. Pass `stream: true` for the streaming variant whose `schemas` and
* `operations` are `AsyncIterable` sources. Otherwise it builds the eager variant with array
* `schemas`/`operations`. Both variants get the defaulted `meta`.
*
* @example Eager
* ```ts
* const input = createInput()
* // { kind: 'Input', schemas: [], operations: [] }
* ```
*
* @example Streaming
* ```ts
* const node = createInput({ stream: true, schemas: schemasIterable, operations: operationsIterable, meta: { title: 'My API' } })
* ```
*/
function createInput(options = {}) {
const { stream, ...overrides } = options;
if (stream) return {
kind: "Input",
meta: {
circularNames: [],
enumNames: []
},
...overrides
};
return inputDef.create(overrides);
}
//#endregion
//#region src/nodes/requestBody.ts
/**
* Definition for the {@link RequestBodyNode}. Content entries are built upfront with
* {@link createContent}, mirroring how `parameters` and `responses` take prebuilt nodes.
*/
const requestBodyDef = defineNode({
kind: "RequestBody",
children: ["content"]
});
/**
* Creates a `RequestBodyNode`.
*/
const createRequestBody = requestBodyDef.create;
//#endregion
//#region src/nodes/operation.ts
/**
* Definition for the {@link OperationNode}. HTTP operations (those carrying both
* `method` and `path`) are tagged with `protocol: 'http'`, and the request body is
* normalized into a `RequestBodyNode`.
*/
const operationDef = defineNode({
kind: "Operation",
build: (props) => {
const { requestBody, ...rest } = props;
const isHttp = rest.method !== void 0 && rest.path !== void 0;
return {
tags: [],
parameters: [],
responses: [],
...rest,
...isHttp ? { protocol: "http" } : {},
requestBody: requestBody ? createRequestBody(requestBody) : void 0
};
},
children: [
"parameters",
"requestBody",
"responses"
],
visitorKey: "operation"
});
function createOperation(props) {
return operationDef.create(props);
}
//#endregion
//#region src/nodes/output.ts
/**
* Definition for the {@link OutputNode}.
*/
const outputDef = defineNode({
kind: "Output",
defaults: { files: [] },
visitorKey: "output"
});
/**
* Creates an `OutputNode` with a stable default for `files`.
*
* @example
* ```ts
* const output = createOutput()
* // { kind: 'Output', files: [] }
* ```
*/
function createOutput(overrides = {}) {
return outputDef.create(overrides);
}
//#endregion
//#region src/optionality.ts
/**
* Generic JSON Schema optionality: a non-required field is optional, and a
* non-required nullable field is nullish.
*/
function optionality(schema, required) {
const nullable = schema.nullable ?? false;
return {
...schema,
optional: !required && !nullable ? true : void 0,
nullish: !required && nullable ? true : void 0
};
}
//#endregion
//#region src/nodes/parameter.ts
/**
* Definition for the {@link ParameterNode}. `required` defaults to `false`, and the schema's
* `optional`/`nullish` flags are derived from it through {@link optionality}.
*/
const parameterDef = defineNode({
kind: "Parameter",
build: (props) => {
const required = props.required ?? false;
return {
...props,
required,
schema: optionality(props.schema, required)
};
},
children: ["schema"],
visitorKey: "parameter"
});
/**
* Creates a `ParameterNode`.
*
* @example
* ```ts
* const param = createParameter({
* name: 'petId',
* in: 'path',
* required: true,
* schema: createSchema({ type: 'string' }),
* })
* ```
*/
const createParameter = parameterDef.create;
//#endregion
//#region src/nodes/property.ts
/**
* Definition for the {@link PropertyNode}. `required` defaults to `false`, and the schema's
* `optional`/`nullish` flags are derived from it through {@link optionality}.
*/
const propertyDef = defineNode({
kind: "Property",
build: (props) => {
const required = props.required ?? false;
return {
...props,
required,
schema: optionality(props.schema, required)
};
},
children: ["schema"],
visitorKey: "property"
});
/**
* Creates a `PropertyNode`.
*
* @example
* ```ts
* const property = createProperty({
* name: 'status',
* required: true,
* schema: createSchema({ type: 'string', nullable: true }),
* })
* // required=true, no optional/nullish
* ```
*/
const createProperty = propertyDef.create;
//#endregion
//#region src/nodes/response.ts
/**
* Definition for the {@link ResponseNode}. A single legacy `schema` (with optional
* `mediaType`/`keysToOmit`) is normalized into one `content` entry.
*/
const responseDef = defineNode({
kind: "Response",
build: (props) => {
const { schema, mediaType, keysToOmit, content, ...rest } = props;
const entries = content ?? (schema ? [createContent({
contentType: mediaType ?? "application/json",
schema,
keysToOmit: keysToOmit ?? null
})] : void 0);
return {
...rest,
content: entries
};
},
children: ["content"],
visitorKey: "response"
});
/**
* Creates a `ResponseNode`.
*
* @example
* ```ts
* const response = createResponse({
* statusCode: '200',
* content: [createContent({ contentType: 'application/json', schema: createSchema({ type: 'object', properties: [] }) })],
* })
* ```
*/
const createResponse = responseDef.create;
//#endregion
//#region src/nodes/schema.ts
/**
* Maps schema `type` to its underlying `primitive`.
* Primitive types map to themselves and special string formats map to `'string'`.
* Any type not listed here (such as `ref`, `enum`, `union`, `intersection`, `tuple`, `ipv4`, `ipv6`, `blob`) has no `primitive`.
*/
const TYPE_TO_PRIMITIVE = {
string: "string",
number: "number",
integer: "integer",
bigint: "bigint",
boolean: "boolean",
null: "null",
any: "any",
unknown: "unknown",
void: "void",
never: "never",
object: "object",
array: "array",
date: "date",
uuid: "string",
email: "string",
url: "string",
datetime: "string",
time: "string"
};
/**
* Definition for the {@link SchemaNode}. Object schemas default `properties` to an
* empty array, and `primitive` is inferred from `type` when not explicitly provided.
*/
const schemaDef = defineNode({
kind: "Schema",
build: (props) => {
if (props.type === "object") return {
properties: [],
primitive: "object",
...props
};
return {
primitive: TYPE_TO_PRIMITIVE[props.type],
...props
};
},
children: [
"properties",
"items",
"members",
"additionalProperties"
],
visitorKey: "schema"
});
function createSchema(props) {
return schemaDef.create(props);
}
//#endregion
//#region src/registry.ts
/**
* Every node definition. Adding a node means adding its `defineNode` to one
* `nodes/*.ts` file and listing it here. The visitor tables in `visitor.ts` derive from it.
*/
const nodeDefs = [
inputDef,
outputDef,
operationDef,
requestBodyDef,
contentDef,
responseDef,
schemaDef,
propertyDef,
parameterDef,
functionParameterDef,
functionParametersDef,
typeLiteralDef,
indexedAccessTypeDef,
objectBindingPatternDef,
constDef,
typeDef,
functionDef,
arrowFunctionDef,
textDef,
breakDef,
jsxDef,
importDef,
exportDef,
sourceDef,
fileDef
];
//#endregion
//#region src/visitor.ts
/**
* Child node fields per node kind, in traversal order (Babel's `VISITOR_KEYS`).
* Derived from each definition's `children`.
*/
const VISITOR_KEYS = Object.fromEntries(nodeDefs.flatMap((def) => def.children ? [[def.kind, def.children]] : []));
/**
* Maps a node kind to the matching visitor callback name. Derived from each
* definition's `visitorKey`.
*/
const VISITOR_KEY_BY_KIND = Object.fromEntries(nodeDefs.flatMap((def) => def.visitorKey ? [[def.kind, def.visitorKey]] : []));
/**
* Creates a small async concurrency limiter.
*
* At most `concurrency` tasks are in flight at once. Extra tasks are queued.
*
* @example
* ```ts
* const limit = createLimit(2)
* for (const task of [taskA, taskB, taskC]) {
* await limit(() => task())
* }
* // only 2 tasks run at the same time
* ```
*/
function createLimit(concurrency) {
let active = 0;
const queue = [];
function next() {
if (active < concurrency && queue.length > 0) {
active++;
queue.shift()();
}
}
return function limit(fn) {
return new Promise((resolve, reject) => {
queue.push(() => {
Promise.resolve(fn()).then(resolve, reject).finally(() => {
active--;
next();
});
});
next();
});
};
}
const visitorKeysByKind = VISITOR_KEYS;
/**
* Returns `true` when `value` is an AST node (an object carrying a `kind`).
*/
function isNode(value) {
return typeof value === "object" && value !== null && "kind" in value;
}
/**
* Returns the immediate traversable children of `node` based on {@link VISITOR_KEYS}.
*
* `Schema` children are only included when `recurse` is `true`. Shallow mode skips them.
*
* @example
* ```ts
* const children = getChildren(operationNode, true)
* // returns parameters, the request body, and responses
* ```
*/
function* getChildren(node, recurse) {
if (node.kind === "Schema" && !recurse) return;
const keys = visitorKeysByKind[node.kind];
if (!keys) return;
const record = node;
for (const key of keys) {
const value = record[key];
if (Array.isArray(value)) {
for (const item of value) if (isNode(item)) yield item;
} else if (isNode(value)) yield value;
}
}
/**
* Runs the visitor callback that matches `node.kind` with the traversal
* context. The result is a replacement node, a collected value, or `undefined`
* when no callback is registered for the kind.
*
* Shared by `walk`, `transform`, and `collectLazy` so node-kind dispatch lives
* in one place. `TResult` is the caller's expected return: the same node type
* for `transform`, the collected value type for `collectLazy`, ignored for `walk`.
*/
function applyVisitor(node, visitor, parent) {
const key = VISITOR_KEY_BY_KIND[node.kind];
if (!key) return void 0;
const fn = visitor[key];
return fn?.(node, { parent });
}
/**
* Async depth-first traversal for side effects. Visitor return values are
* ignored. Use `transform` when you want to rewrite nodes.
*
* Sibling nodes at each depth run concurrently up to `options.concurrency`
* (defaults to `WALK_CONCURRENCY`). Higher values overlap I/O-bound visitor
* work. Lower values reduce memory pressure.
*
* @example Log every operation
* ```ts
* await walk(root, {
* operation(node) {
* console.log(node.operationId)
* },
* })
* ```
*
* @example Only visit the root node
* ```ts
* await walk(root, { depth: 'shallow', input: () => {} })
* ```
*/
async function walk(node, options) {
return _walk(node, options, (options.depth ?? visitorDepths.deep) === visitorDepths.deep, createLimit(options.concurrency ?? 30), void 0);
}
async function _walk(node, visitor, recurse, limit, parent) {
await limit(() => applyVisitor(node, visitor, parent));
const children = Array.from(getChildren(node, recurse));
if (children.length === 0) return;
await Promise.all(children.map((child) => _walk(child, visitor, recurse, limit, node)));
}
function transform(node, options) {
const { depth, parent, ...visitor } = options;
const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep;
return transformChildren(applyVisitor(node, visitor, parent) ?? node, options, recurse);
}
/**
* Immutably rebuilds a node's children using {@link VISITOR_KEYS}, transforming
* each child node and leaving non-node values (e.g. `additionalProperties: true`) intact.
* `Schema` children are skipped in shallow mode.
*/
function transformChildren(node, options, recurse) {
if (node.kind === "Schema" && !recurse) return node;
const keys = visitorKeysByKind[node.kind];
if (!keys) return node;
const record = node;
const childOptions = {
...options,
parent: node
};
let updates;
for (const key of keys) {
if (!(key in record)) continue;
const value = record[key];
if (Array.isArray(value)) {
let changed = false;
const mapped = value.map((item) => {
if (!isNode(item)) return item;
const next = transform(item, childOptions);
if (next !== item) changed = true;
return next;
});
if (changed) (updates ??= {})[key] = mapped;
} else if (isNode(value)) {
const next = transform(value, childOptions);
if (next !== value) (updates ??= {})[key] = next;
}
}
return updates ? {
...node,
...updates
} : node;
}
/**
* Lazy depth-first collection pass. Yields every non-null value returned by
* the visitor callbacks. Use `collect` for the eager array form.
*
* @example Collect every operationId
* ```ts
* const ids: string[] = []
* for (const id of collectLazy<string>(root, {
* operation(node) {
* return node.operationId
* },
* })) {
* ids.push(id)
* }
* ```
*/
function* collectLazy(node, options) {
const { depth, parent, ...visitor } = options;
const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep;
const v = applyVisitor(node, visitor, parent);
if (v != null) yield v;
for (const child of getChildren(node, recurse)) yield* collectLazy(child, {
...options,
parent: node
});
}
/**
* Eager depth-first collection pass. Gathers every non-null value the visitor
* callbacks return into an array.
*
* @example Collect every operationId
* ```ts
* const ids = collect<string>(root, {
* operation(node) {
* return node.operationId
* },
* })
* ```
*/
function collect(node, options) {
return Array.from(collectLazy(node, options));
}
//#endregion
export { createJsx as $, indexedAccessTypeDef as A, sourceDef as B, createFunctionParameter as C, createTypeLiteral as D, createObjectBindingPattern as E, createImport as F, createContent as G, camelCase as H, createSource as I, constDef as J, arrowFunctionDef as K, exportDef as L, typeLiteralDef as M, createExport as N, functionParameterDef as O, createFile as P, createFunction as Q, fileDef as R, inputDef as S, createIndexedAccessType as T, pascalCase as U, extractStringsFromNodes as V, contentDef as W, createBreak as X, createArrowFunction as Y, createConst as Z, createOperation as _, nodeDefs as a, typeDef as at, requestBodyDef as b, createResponse as c, isHttpOperationNode as ct, propertyDef as d, schemaTypes as dt, createText as et, createParameter as f, outputDef as g, createOutput as h, walk as i, textDef as it, objectBindingPatternDef as j, functionParametersDef as k, responseDef as l, narrowSchema as lt, optionality as m, collectLazy as n, functionDef as nt, createSchema as o, defineNode as ot, parameterDef as p, breakDef as q, transform as r, jsxDef as rt, schemaDef as s, visitorKeys as st, collect as t, createType as tt, createProperty as u, INDENT as ut, operationDef as v, createFunctionParameters as w, createInput as x, createRequestBody as y, importDef as z };
//# sourceMappingURL=visitor-DG5ROqRx.js.map

Sorry, the diff of this file is too big to display