🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@kubb/parser-ts

Package Overview
Dependencies
Maintainers
1
Versions
511
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@kubb/parser-ts - npm Package Compare versions

Comparing version
5.0.0-beta.75
to
5.0.0-beta.76
+8
dist/rolldown-runtime-C0LytTxp.js
//#region \0rolldown/runtime.js
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", {
value,
configurable: true
});
//#endregion
export { __name as t };
<div align="center">
<a href="https://kubb.dev" target="_blank" rel="noopener noreferrer">
<img src="https://kubb.dev/og.png" alt="Kubb banner">
</a>
[![npm version][npm-version-src]][npm-version-href]
[![npm downloads][npm-downloads-src]][npm-downloads-href]
[![Stars][stars-src]][stars-href]
[![License][license-src]][license-href]
[![Node][node-src]][node-href]
<h4>
<a href="https://kubb.dev" target="_blank">Documentation</a>
<span> · </span>
<a href="https://github.com/kubb-labs/kubb/issues/" target="_blank">Report Bug</a>
<span> · </span>
<a href="https://github.com/kubb-labs/kubb/issues/" target="_blank">Request Feature</a>
</h4>
</div>
<br />
# @kubb/parser-ts
### TypeScript source file parser for Kubb
Converts AST nodes and raw TypeScript code into formatted source strings using the TypeScript compiler API. Handles both `.ts` and `.tsx` output.
## Installation
```bash
bun add @kubb/parser-ts
# or
pnpm add @kubb/parser-ts
# or
npm install @kubb/parser-ts
```
## Usage
```typescript
import { defineConfig } from 'kubb'
import { parserTs, parserTsx } from '@kubb/parser-ts'
export default defineConfig({
input: { path: './petstore.yaml' },
output: { path: './src/gen' },
parsers: [parserTs, parserTsx],
})
```
To render compiler AST nodes to source text from inside a plugin, call `print` on the parser instance:
```typescript
import { parserTs } from '@kubb/parser-ts'
import ts from 'typescript'
const source = parserTs.print(
ts.factory.createVariableStatement(
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
ts.factory.createVariableDeclarationList(
[ts.factory.createVariableDeclaration('hello', undefined, undefined, ts.factory.createStringLiteral('world'))],
ts.NodeFlags.Const,
),
),
)
// → export const hello = 'world'
```
## API
### `parserTs`
Parser instance for `.ts` and `.js` files. Pass to `defineConfig({ parsers: [...] })` to emit TypeScript source files.
- `parserTs.parse(file, options?)` — serialize a `FileNode` to TypeScript source.
- `parserTs.print(...nodes)` — convert TypeScript compiler `Node` instances to a formatted source string.
### `parserTsx`
Parser instance for `.tsx` and `.jsx` files. Same API as `parserTs` with JSX support.
## Supporting Kubb
Kubb is an open source project, and its development is funded entirely by sponsors. If you would like to become a sponsor, please consider:
- [Become a Sponsor on GitHub](https://github.com/sponsors/stijnvanhulle)
- [See sponsorship tiers and our sponsors](https://kubb.dev/sponsors)
<p align="center">
<a href="https://github.com/sponsors/stijnvanhulle">
<img src="https://raw.githubusercontent.com/stijnvanhulle/sponsors/main/sponsors.svg" alt="My sponsors" />
</a>
</p>
## License
[MIT](https://github.com/kubb-labs/kubb/blob/main/licenses/LICENSE-MIT)
<!-- Badges -->
[npm-version-src]: https://shieldcn.dev/npm/v/@kubb/parser-ts.svg?variant=secondary&size=xs&theme=zinc&mode=dark
[npm-version-href]: https://npmx.dev/package/@kubb/parser-ts
[npm-downloads-src]: https://shieldcn.dev/npm/dm/@kubb/parser-ts.svg?variant=secondary&size=xs&theme=zinc&mode=dark
[npm-downloads-href]: https://npmx.dev/package/@kubb/parser-ts
[stars-src]: https://shieldcn.dev/github/stars/kubb-labs/kubb.svg?variant=secondary&size=xs&theme=zinc&mode=dark
[stars-href]: https://github.com/kubb-labs/kubb
[license-src]: https://shieldcn.dev/npm/license/@kubb/parser-ts.svg?variant=secondary&size=xs&theme=zinc
[license-href]: https://github.com/kubb-labs/kubb/blob/main/LICENSE
[node-src]: https://shieldcn.dev/npm/node/@kubb/parser-ts.svg?variant=secondary&size=xs&theme=zinc&mode=dark
[node-href]: https://npmx.dev/package/@kubb/parser-ts
+245
-133

@@ -24,11 +24,30 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });

//#endregion
let _kubb_core = require("@kubb/core");
let node_path = require("node:path");
let _kubb_core = require("@kubb/core");
let typescript = require("typescript");
typescript = __toESM(typescript, 1);
//#region src/constants.ts
//#region ../../internals/utils/src/fs.ts
/**
* Matches the trailing `.<ext>` segment of a path (keeps segments like `foo.bar.ts`
* intact by only trimming the last run of non-`/`/`.` characters).
* 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;
}
/**
* Indentation unit prepended once per nesting level when pretty-printing.
*/
const INDENT = " ".repeat(2);
/**
* Matches only the final `.<ext>` of a path, so a name like `foo.bar.ts` keeps
* `foo.bar` and loses just `.ts`.
*/
const FILE_EXTENSION_PATTERN = /\.[^/.]+$/;

@@ -40,3 +59,3 @@ /**

/**
* Matches `*\/` in free-form text so JSDoc bodies can neutralise premature
* Matches `*\/` in free-form text so JSDoc bodies can neutralize premature
* comment terminators (`*\/` → `* /`).

@@ -46,17 +65,20 @@ */

/**
* Matches carriage returns for normalising CRLF/CR line endings to LF.
* Matches carriage returns for normalizing CRLF/CR line endings to LF.
*/
const CARRIAGE_RETURN_PATTERN = /\r/g;
/**
* Matches CRLF sequences used when normalising TypeScript printer output.
* Matches CRLF sequences used when normalizing TypeScript printer output.
*/
const CRLF_PATTERN = /\r\n/g;
/**
* Matches an identifier that starts with a digit — JavaScript disallows this
* so the printer prefixes such names with `_`.
* Matches an identifier that starts with a digit. JavaScript disallows this,
* so the printer replaces the leading digit with `_`.
*/
const LEADING_DIGIT_PATTERN = /^\d/;
//#endregion
//#region src/parserTs.ts
//#region src/utils.ts
const { factory } = typescript.default;
/**
* Normalizes a file-system path to POSIX separators and strips any leading `../` segment.
*/
function slash(path) {

@@ -74,9 +96,2 @@ return (0, node_path.normalize)(path).replaceAll(WINDOWS_PATH_SEPARATOR, "/").replace("../", "");

/**
* Strips the trailing file extension (for example `.ts`) from a path.
* Preserves intermediate dots like `foo.bar.ts` → `foo.bar`.
*/
function trimExtName(text) {
return text.replace(FILE_EXTENSION_PATTERN, "");
}
/**
* Rewrites an import/export path so its extension matches the caller-supplied

@@ -92,55 +107,100 @@ * `options.extname`. When the source path has no extension the original is kept,

/**
* Validates TypeScript AST nodes before printing.
* Throws an error if any node has SyntaxKind.Unknown which would cause the
* TypeScript printer to crash.
* Serializes a `nodes` array into source text. Each entry is rendered via {@link printCodeNode}
* and joined with a single newline. A `Break` node (`<br/>`) inserts one blank line between
* statements. Consecutive breaks, and breaks at the very start or end, are folded into the
* separator, so a double `<br/>` never emits more than one blank line.
*/
function validateNodes(...nodes) {
function printNodes(nodes) {
if (!nodes || nodes.length === 0) return "";
let result = "";
let hasContent = false;
let pendingBreak = false;
for (const node of nodes) {
if (!node) throw new Error("Attempted to print undefined or null TypeScript node");
if (node.kind === typescript.default.SyntaxKind.Unknown) throw new Error(`Invalid TypeScript AST node detected with SyntaxKind.Unknown. This typically indicates a schema pattern that could not be properly converted to TypeScript. Node: ${JSON.stringify(node, null, 2)}`);
if (node.kind === "Break") {
if (hasContent) pendingBreak = true;
continue;
}
const text = printCodeNode(node);
if (!text) continue;
if (hasContent) result += pendingBreak ? "\n\n" : "\n";
result += text;
hasContent = true;
pendingBreak = false;
}
return result;
}
/**
* Converts TypeScript/TSX AST nodes to a string using the TypeScript printer.
* Indents every non-empty line of `text` by one indent unit. Pass a number to repeat
* {@link INDENT_CHAR} that many times, or a string to use as the indent verbatim.
*/
function print(...elements) {
const sourceFile = typescript.default.createSourceFile("print.tsx", "", typescript.default.ScriptTarget.ES2022, true, typescript.default.ScriptKind.TSX);
return typescript.default.createPrinter({
omitTrailingSemicolon: true,
newLine: typescript.default.NewLineKind.LineFeed,
removeComments: false,
noEmitHelpers: true
}).printList(typescript.default.ListFormat.MultiLine, factory.createNodeArray(elements.filter(Boolean)), sourceFile).replace(CRLF_PATTERN, "\n");
function indentLines(text, indent = INDENT) {
if (!text) return "";
const pad = typeof indent === "string" ? indent : " ".repeat(indent);
return text.split("\n").map((line) => line.trim() ? `${pad}${line}` : "").join("\n");
}
/**
* Like `print` but validates nodes first to surface issues early.
* Removes the common leading whitespace shared by every non-blank line and trims
* surrounding blank lines, so multi-line content authored inside an indented template
* literal lines up at a column-zero baseline. Leading whitespace is counted by
* character, so N tabs and N spaces are treated as the same depth.
*
* @example
* ```ts
* dedent('\n foo\n bar\n ')
* // 'foo\n bar'
* ```
*/
function safePrint(...elements) {
validateNodes(...elements);
return print(...elements);
function dedent(text) {
if (!text) return "";
const lines = text.split("\n");
const isBlank = (line) => line.trim() === "";
const start = lines.findIndex((line) => !isBlank(line));
if (start === -1) return "";
const end = lines.findLastIndex((line) => !isBlank(line));
const trimmed = lines.slice(start, end + 1);
const indents = trimmed.filter((line) => !isBlank(line)).map((line) => line.match(/^\s*/)?.[0].length ?? 0);
const min = indents.length ? Math.min(...indents) : 0;
return trimmed.map((line) => isBlank(line) ? "" : line.slice(min)).join("\n");
}
function createImport({ name, path, root, isTypeOnly = false, isNameSpace = false }) {
const resolvePath = root ? getRelativePath(root, path) : path;
if (!Array.isArray(name)) {
if (isNameSpace) return factory.createImportDeclaration(void 0, factory.createImportClause(isTypeOnly, void 0, factory.createNamespaceImport(factory.createIdentifier(name))), factory.createStringLiteral(resolvePath), void 0);
return factory.createImportDeclaration(void 0, factory.createImportClause(isTypeOnly, factory.createIdentifier(name), void 0), factory.createStringLiteral(resolvePath), void 0);
}
const specifiers = name.map((item) => {
if (typeof item === "object") {
const { propertyName, name: alias } = item;
return factory.createImportSpecifier(false, alias ? factory.createIdentifier(propertyName) : void 0, factory.createIdentifier(alias ?? propertyName));
}
return factory.createImportSpecifier(false, void 0, factory.createIdentifier(item));
});
return factory.createImportDeclaration(void 0, factory.createImportClause(isTypeOnly, void 0, factory.createNamedImports(specifiers)), factory.createStringLiteral(resolvePath), void 0);
/**
* Renders the generic clause (`<T, U>`) shared by function and arrow-function nodes.
* Accepts either a raw string (rendered verbatim) or an array of type-parameter names.
*/
function formatGenerics(generics) {
if (!generics) return "";
return `<${Array.isArray(generics) ? generics.join(", ") : generics}>`;
}
function createExport({ path, asAlias, isTypeOnly = false, name }) {
if (name && !Array.isArray(name) && !asAlias) console.warn(`When using name as string, asAlias should be true: ${name}`);
if (!Array.isArray(name)) {
const parsedName = name && LEADING_DIGIT_PATTERN.test(name) ? `_${name.slice(1)}` : name;
return factory.createExportDeclaration(void 0, isTypeOnly, asAlias && parsedName ? factory.createNamespaceExport(factory.createIdentifier(parsedName)) : void 0, factory.createStringLiteral(path), void 0);
}
return factory.createExportDeclaration(void 0, isTypeOnly, factory.createNamedExports(name.map((propertyName) => factory.createExportSpecifier(false, void 0, typeof propertyName === "string" ? factory.createIdentifier(propertyName) : propertyName))), factory.createStringLiteral(path), void 0);
/**
* Renders the return-type suffix (`: T` or `: Promise<T>` when `isAsync` is true).
* Returns an empty string when no return type is provided.
*/
function formatReturnType(returnType, isAsync) {
if (!returnType) return "";
return isAsync ? `: Promise<${returnType}>` : `: ${returnType}`;
}
/**
* Module-scoped TypeScript printer instance. A printer does not mutate the source file, so one
* instance is reused across every `print()` call instead of constructing a new printer each time.
*/
const TS_PRINTER = typescript.default.createPrinter({
omitTrailingSemicolon: true,
newLine: typescript.default.NewLineKind.LineFeed,
removeComments: false,
noEmitHelpers: true
});
/**
* Module-scoped source file used as the print target. `printList` only reads the source
* file's compiler options / language version. It never mutates it.
*/
const PRINT_SOURCE_FILE = typescript.default.createSourceFile("print.tsx", "", typescript.default.ScriptTarget.ES2022, true, typescript.default.ScriptKind.TSX);
TS_PRINTER.printList(typescript.default.ListFormat.MultiLine, factory.createNodeArray([]), PRINT_SOURCE_FILE);
/**
* Converts TypeScript/TSX AST nodes to a string using the TypeScript printer.
*/
function print(...elements) {
const filtered = elements.filter(Boolean);
if (filtered.length === 0) return "";
return TS_PRINTER.printList(typescript.default.ListFormat.MultiLine, factory.createNodeArray(filtered), PRINT_SOURCE_FILE).replace(CRLF_PATTERN, "\n");
}
/**
* Converts a {@link JSDocNode} to a JSDoc comment block string.

@@ -169,37 +229,2 @@ *

/**
* Serializes the body / value content from a `nodes` array.
*
* Each element is either a raw string or a structured {@link CodeNode}
* (recursively converted via {@link printCodeNode}).
* Elements are joined with `\n`.
*/
function printNodes(nodes) {
if (!nodes || nodes.length === 0) return "";
return nodes.map(printCodeNode).join("\n");
}
/**
* Indents every non-empty line of `text` by `spaces` spaces.
*/
function indentLines(text, spaces = 2) {
if (!text) return "";
const pad = " ".repeat(spaces);
return text.split("\n").map((line) => line.trim() ? `${pad}${line}` : "").join("\n");
}
/**
* Renders the generic clause (`<T, U>`) shared by function and arrow-function nodes.
* Accepts either a raw string (rendered verbatim) or an array of type-parameter names.
*/
function formatGenerics(generics) {
if (!generics) return "";
return `<${Array.isArray(generics) ? generics.join(", ") : generics}>`;
}
/**
* Renders the return-type suffix (`: T` or `: Promise<T>` when `isAsync` is true).
* Returns an empty string when no return type is provided.
*/
function formatReturnType(returnType, isAsync) {
if (!returnType) return "";
return isAsync ? `: Promise<${returnType}>` : `: ${returnType}`;
}
/**
* Converts a {@link ConstNode} to a TypeScript `const` declaration string.

@@ -211,3 +236,3 @@ *

* ```ts
* printConst(createConst({ name: 'pet', export: true, nodes: ['{}'] }))
* printConst(factory.createConst({ name: 'pet', export: true, nodes: ['{}'] }))
* // 'export const pet = {}'

@@ -218,3 +243,3 @@ * ```

* ```ts
* printConst(createConst({ name: 'pets', export: true, type: 'Pet[]', asConst: true, nodes: ['[]'] }))
* printConst(factory.createConst({ name: 'pets', export: true, type: 'Pet[]', asConst: true, nodes: ['[]'] }))
* // 'export const pets: Pet[] = [] as const'

@@ -244,3 +269,3 @@ * ```

* ```ts
* printType(createType({ name: 'Pet', export: true, nodes: ['{ id: number }'] }))
* printType(factory.createType({ name: 'Pet', export: true, nodes: ['{ id: number }'] }))
* // 'export type Pet = { id: number }'

@@ -268,3 +293,3 @@ * ```

* ```ts
* printFunction(createFunction({ name: 'getPet', export: true, params: 'id: string', returnType: 'Pet', nodes: ['return fetch(id)'] }))
* printFunction(factory.createFunction({ name: 'getPet', export: true, params: 'id: string', returnType: 'Pet', nodes: ['return fetch(id)'] }))
* // 'export function getPet(id: string): Pet {\n return fetch(id)\n}'

@@ -275,3 +300,3 @@ * ```

* ```ts
* printFunction(createFunction({ name: 'fetchPet', export: true, async: true, generics: ['T'], params: 'id: string', returnType: 'T' }))
* printFunction(factory.createFunction({ name: 'fetchPet', export: true, async: true, generics: ['T'], params: 'id: string', returnType: 'T' }))
* // 'export async function fetchPet<T>(id: string): Promise<T> {\n}'

@@ -306,3 +331,3 @@ * ```

* ```ts
* printArrowFunction(createArrowFunction({ name: 'getPet', export: true, params: 'id: string', nodes: ['return fetch(id)'] }))
* printArrowFunction(factory.createArrowFunction({ name: 'getPet', export: true, params: 'id: string', nodes: ['return fetch(id)'] }))
* // 'export const getPet = (id: string) => {\n return fetch(id)\n}'

@@ -313,3 +338,3 @@ * ```

* ```ts
* printArrowFunction(createArrowFunction({ name: 'double', params: 'n: number', singleLine: true, nodes: ['n * 2'] }))
* printArrowFunction(factory.createArrowFunction({ name: 'double', params: 'n: number', singleLine: true, nodes: ['n * 2'] }))
* // 'const double = (n: number) => n * 2'

@@ -343,3 +368,3 @@ * ```

* ```ts
* printCodeNode(createConst({ name: 'x', nodes: ['1'] }))
* printCodeNode(factory.createConst({ name: 'x', nodes: ['1'] }))
* // 'const x = 1'

@@ -349,11 +374,10 @@ * ```

function printCodeNode(node) {
switch (node.kind) {
case "Break": return "";
case "Text": return node.value;
case "Jsx": return node.value;
case "Const": return printConst(node);
case "Type": return printType(node);
case "Function": return printFunction(node);
case "ArrowFunction": return printArrowFunction(node);
}
if (node.kind === "Break") return "";
if (node.kind === "Text") return dedent(node.value);
if (node.kind === "Jsx") return dedent(node.value);
if (node.kind === "Const") return printConst(node);
if (node.kind === "Type") return printType(node);
if (node.kind === "Function") return printFunction(node);
if (node.kind === "ArrowFunction") return printArrowFunction(node);
return "";
}

@@ -366,22 +390,98 @@ /**

*
* Top-level declarations are separated by a blank line so the source reads
* cleanly without an external formatter.
*
* @example From nodes
* ```ts
* printSource({ kind: 'Source', nodes: [createConst({ name: 'x', nodes: [createText('1')] }), createText('x.toString()')] })
* // 'const x = 1\nx.toString()'
* printSource({ kind: 'Source', nodes: [factory.createConst({ name: 'x', nodes: [factory.createText('1')] }), factory.createText('x.toString()')] })
* // 'const x = 1\n\nx.toString()'
* ```
*/
function printSource(node) {
if (node.nodes && node.nodes.length > 0) return node.nodes.map(printCodeNode).join("\n");
return "";
const nodes = node.nodes;
if (!nodes || nodes.length === 0) return "";
return nodes.map((child) => printCodeNode(child)).filter(Boolean).join("\n\n");
}
/**
* Parser that converts `.ts` and `.js` files to strings using the TypeScript
* compiler. Handles import/export statement generation from file metadata.
* Wraps a module specifier in single quotes, escaping any embedded backslash or quote so the emitted
* statement stays valid even for unusual paths.
*/
function quoteModulePath(path) {
return `'${path.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
}
/**
* Renders an import declaration string in the repo style (single quotes, no semicolons), covering
* default, namespace (`* as`), and named imports with `{ a as b }` aliases, each optionally
* `type`-only. `path` is used verbatim, so resolve it first.
*
* @default Used automatically when no `parsers` option is set in `defineConfig`.
* @example
* ```ts
* printImport({ name: ['z'], path: './zod.ts' })
* // "import { z } from './zod.ts'"
* ```
*/
function printImport({ name, path, isTypeOnly = false, isNameSpace = false }) {
const typePrefix = isTypeOnly ? "type " : "";
const from = quoteModulePath(path);
if (!Array.isArray(name)) {
if (isNameSpace) return `import ${typePrefix}* as ${name} from ${from}`;
return `import ${typePrefix}${name} from ${from}`;
}
return `import ${typePrefix}{ ${name.map((item) => {
if (typeof item === "object") return item.name ? `${item.propertyName} as ${item.name}` : item.propertyName;
return item;
}).join(", ")} } from ${from}`;
}
/**
* Renders an export declaration string in the repo style (single quotes, no semicolons), covering
* named re-exports, namespace alias (`* as name`), and wildcard, each optionally `type`-only.
* `path` is used verbatim, so resolve it first.
*
* @example
* ```ts
* printExport({ name: ['Pet', 'Order'], path: './models.ts' })
* // "export { Pet, Order } from './models.ts'"
* ```
*/
function printExport({ path, name, isTypeOnly = false, asAlias = false }) {
const typePrefix = isTypeOnly ? "type " : "";
const from = quoteModulePath(path);
if (Array.isArray(name)) return `export ${typePrefix}{ ${name.map((item) => typeof item === "string" ? item : item.text).join(", ")} } from ${from}`;
if (asAlias && name) return `export ${typePrefix}* as ${LEADING_DIGIT_PATTERN.test(name) ? `_${name.slice(1)}` : name} from ${from}`;
if (name) console.warn(`When using name as string, asAlias should be true: ${name}`);
return `export ${typePrefix}* from ${from}`;
}
//#endregion
//#region src/parserTs.ts
/**
* Default Kubb parser for `.ts` and `.js` files. Takes the universal AST
* produced by an adapter and prints it as TypeScript source using the official
* TypeScript compiler. Imports and exports are rewritten based on each file's
* metadata.
*
* Used automatically when no `parsers` option is set on `defineConfig`. Use
* `parserTsx` instead for React projects that emit JSX.
*
* @example
* ```ts
* import { defineConfig } from 'kubb'
* import { adapterOas } from '@kubb/adapter-oas'
* import { parserTs } from '@kubb/parser-ts'
*
* export default defineConfig({
* input: { path: './petStore.yaml' },
* output: { path: './src/gen' },
* adapter: adapterOas(),
* parsers: [parserTs],
* plugins: [],
* })
* ```
*/
const parserTs = (0, _kubb_core.defineParser)({
name: "typescript",
extNames: [".ts", ".js"],
async parse(file, options = { extname: ".ts" }) {
print(...nodes) {
return print(...nodes);
},
parse(file, options = { extname: ".ts" }) {
const sourceParts = [];

@@ -393,6 +493,6 @@ for (const item of file.sources) {

const source = sourceParts.join("\n\n");
const importNodes = [];
const importLines = [];
for (const item of file.imports) {
const importPath = item.root ? getRelativePath(item.root, item.path) : item.path;
importNodes.push(createImport({
importLines.push(printImport({
name: item.name,

@@ -404,4 +504,4 @@ path: resolveOutputPath(importPath, options, Boolean(item.root)),

}
const exportNodes = [];
for (const item of file.exports) exportNodes.push(createExport({
const exportLines = [];
for (const item of file.exports) exportLines.push(printExport({
name: item.name,

@@ -412,5 +512,6 @@ path: resolveOutputPath(item.path, options, true),

}));
const importExportBlock = [...importLines, ...exportLines].join("\n");
return [
file.banner,
print(...importNodes, ...exportNodes),
importExportBlock,
source,

@@ -424,9 +525,22 @@ file.footer

/**
* Parser that converts `.tsx` and `.jsx` files to strings.
* Delegates to `typescriptParser` since the TypeScript compiler natively
* supports JSX/TSX syntax via `ScriptKind.TSX`.
* Kubb parser for `.tsx` and `.jsx` files. Delegates to `parserTs` because the
* TypeScript compiler handles JSX natively via `ScriptKind.TSX`.
*
* Add this parser to the `parsers` option in `defineConfig` when generating `.tsx`/`.jsx` files.
* Add to the `parsers` array on `defineConfig` when generating components for
* React (or any framework that emits JSX).
*
* @default extname '.tsx'
* @example
* ```ts
* import { defineConfig } from 'kubb'
* import { adapterOas } from '@kubb/adapter-oas'
* import { parserTsx } from '@kubb/parser-ts'
*
* export default defineConfig({
* input: { path: './petStore.yaml' },
* output: { path: './src/gen' },
* adapter: adapterOas(),
* parsers: [parserTsx],
* plugins: [],
* })
* ```
*/

@@ -436,3 +550,6 @@ const parserTsx = (0, _kubb_core.defineParser)({

extNames: [".tsx", ".jsx"],
async parse(file, options = { extname: ".tsx" }) {
print(...nodes) {
return print(...nodes);
},
parse(file, options = { extname: ".tsx" }) {
return parserTs.parse(file, options);

@@ -442,10 +559,5 @@ }

//#endregion
exports.createExport = createExport;
exports.createImport = createImport;
exports.parserTs = parserTs;
exports.parserTsx = parserTsx;
exports.print = print;
exports.safePrint = safePrint;
exports.validateNodes = validateNodes;
//# sourceMappingURL=index.cjs.map

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

{"version":3,"file":"index.cjs","names":["ts"],"sources":["../src/constants.ts","../src/parserTs.ts","../src/parserTsx.ts"],"sourcesContent":["/**\n * Number of spaces used to indent a nested block when pretty-printing.\n */\nexport const INDENT_SIZE = 2 as const\n\n/**\n * Matches the trailing `.<ext>` segment of a path (keeps segments like `foo.bar.ts`\n * intact by only trimming the last run of non-`/`/`.` characters).\n */\nexport const FILE_EXTENSION_PATTERN = /\\.[^/.]+$/\n\n/**\n * Matches Windows-style backslash path separators.\n */\nexport const WINDOWS_PATH_SEPARATOR = /\\\\/g\n\n/**\n * Matches `*\\/` in free-form text so JSDoc bodies can neutralise premature\n * comment terminators (`*\\/` → `* /`).\n */\nexport const JSDOC_TERMINATOR_PATTERN = /\\*\\//g\n\n/**\n * Matches carriage returns for normalising CRLF/CR line endings to LF.\n */\nexport const CARRIAGE_RETURN_PATTERN = /\\r/g\n\n/**\n * Matches CRLF sequences used when normalising TypeScript printer output.\n */\nexport const CRLF_PATTERN = /\\r\\n/g\n\n/**\n * Matches an identifier that starts with a digit — JavaScript disallows this\n * so the printer prefixes such names with `_`.\n */\nexport const LEADING_DIGIT_PATTERN = /^\\d/\n\n/**\n * Relative path prefix used to detect traversal segments (`../`).\n */\nexport const PARENT_DIRECTORY_PREFIX = '../' as const\n\n/**\n * Relative path prefix used when resolving imports within the output root.\n */\nexport const CURRENT_DIRECTORY_PREFIX = './' as const\n","import { normalize, relative } from 'node:path'\nimport type { ArrowFunctionNode, CodeNode, ConstNode, FileNode, FunctionNode, JSDocNode, JsxNode, SourceNode, TextNode, TypeNode } from '@kubb/ast'\nimport type { Parser } from '@kubb/core'\nimport { defineParser } from '@kubb/core'\nimport ts from 'typescript'\nimport {\n CARRIAGE_RETURN_PATTERN,\n CRLF_PATTERN,\n CURRENT_DIRECTORY_PREFIX,\n FILE_EXTENSION_PATTERN,\n INDENT_SIZE,\n JSDOC_TERMINATOR_PATTERN,\n LEADING_DIGIT_PATTERN,\n PARENT_DIRECTORY_PREFIX,\n WINDOWS_PATH_SEPARATOR,\n} from './constants.ts'\n\nconst { factory } = ts\n\nfunction slash(path: string): string {\n return normalize(path).replaceAll(WINDOWS_PATH_SEPARATOR, '/').replace(PARENT_DIRECTORY_PREFIX, '')\n}\n\n/**\n * Resolves `filePath` relative to `rootDir` and returns a POSIX-style path\n * prefixed with `./` when the target sits inside the root, or `../` when it escapes it.\n */\nfunction getRelativePath(rootDir: string, filePath: string): string {\n const rel = relative(rootDir, filePath)\n const slashed = slash(rel)\n return slashed.startsWith(PARENT_DIRECTORY_PREFIX) ? slashed : `${CURRENT_DIRECTORY_PREFIX}${slashed}`\n}\n\n/**\n * Strips the trailing file extension (for example `.ts`) from a path.\n * Preserves intermediate dots like `foo.bar.ts` → `foo.bar`.\n */\nfunction trimExtName(text: string): string {\n return text.replace(FILE_EXTENSION_PATTERN, '')\n}\n\n/**\n * Rewrites an import/export path so its extension matches the caller-supplied\n * `options.extname`. When the source path has no extension the original is kept,\n * so virtual/module-only paths flow through unchanged.\n */\nfunction resolveOutputPath(path: string, options: { extname?: string } | undefined, rootAware: boolean): string {\n const hasExtname = FILE_EXTENSION_PATTERN.test(path)\n if (options?.extname && hasExtname) {\n return `${trimExtName(path)}${options.extname}`\n }\n return rootAware ? trimExtName(path) : path\n}\n\n/**\n * Validates TypeScript AST nodes before printing.\n * Throws an error if any node has SyntaxKind.Unknown which would cause the\n * TypeScript printer to crash.\n */\nexport function validateNodes(...nodes: ts.Node[]): void {\n for (const node of nodes) {\n if (!node) {\n throw new Error('Attempted to print undefined or null TypeScript node')\n }\n if (node.kind === ts.SyntaxKind.Unknown) {\n throw new Error(\n 'Invalid TypeScript AST node detected with SyntaxKind.Unknown. ' +\n 'This typically indicates a schema pattern that could not be properly converted to TypeScript. ' +\n `Node: ${JSON.stringify(node, null, 2)}`,\n )\n }\n }\n}\n\n/**\n * Converts TypeScript/TSX AST nodes to a string using the TypeScript printer.\n */\nexport function print(...elements: Array<ts.Node>): string {\n const sourceFile = ts.createSourceFile('print.tsx', '', ts.ScriptTarget.ES2022, true, ts.ScriptKind.TSX)\n\n const printer = ts.createPrinter({\n omitTrailingSemicolon: true,\n newLine: ts.NewLineKind.LineFeed,\n removeComments: false,\n noEmitHelpers: true,\n })\n\n const output = printer.printList(ts.ListFormat.MultiLine, factory.createNodeArray(elements.filter(Boolean)), sourceFile)\n\n return output.replace(CRLF_PATTERN, '\\n')\n}\n\n/**\n * Like `print` but validates nodes first to surface issues early.\n */\nexport function safePrint(...elements: Array<ts.Node>): string {\n validateNodes(...elements)\n return print(...elements)\n}\n\nexport function createImport({\n name,\n path,\n root,\n isTypeOnly = false,\n isNameSpace = false,\n}: {\n name: string | Array<string | { propertyName: string; name?: string }>\n path: string\n root?: string\n /** @default false */\n isTypeOnly?: boolean\n /** @default false */\n isNameSpace?: boolean\n}): ts.ImportDeclaration {\n const resolvePath = root ? getRelativePath(root, path) : path\n\n if (!Array.isArray(name)) {\n if (isNameSpace) {\n return factory.createImportDeclaration(\n undefined,\n factory.createImportClause(isTypeOnly, undefined, factory.createNamespaceImport(factory.createIdentifier(name))),\n factory.createStringLiteral(resolvePath),\n undefined,\n )\n }\n\n return factory.createImportDeclaration(\n undefined,\n factory.createImportClause(isTypeOnly, factory.createIdentifier(name), undefined),\n factory.createStringLiteral(resolvePath),\n undefined,\n )\n }\n\n const specifiers = name.map((item) => {\n if (typeof item === 'object') {\n const { propertyName, name: alias } = item\n return factory.createImportSpecifier(false, alias ? factory.createIdentifier(propertyName) : undefined, factory.createIdentifier(alias ?? propertyName))\n }\n return factory.createImportSpecifier(false, undefined, factory.createIdentifier(item))\n })\n\n return factory.createImportDeclaration(\n undefined,\n factory.createImportClause(isTypeOnly, undefined, factory.createNamedImports(specifiers)),\n factory.createStringLiteral(resolvePath),\n undefined,\n )\n}\n\nexport function createExport({\n path,\n asAlias,\n isTypeOnly = false,\n name,\n}: {\n path: string\n /** @default false */\n asAlias?: boolean\n /** @default false */\n isTypeOnly?: boolean\n name?: string | Array<ts.Identifier | string>\n}): ts.ExportDeclaration {\n if (name && !Array.isArray(name) && !asAlias) {\n console.warn(`When using name as string, asAlias should be true: ${name}`)\n }\n\n if (!Array.isArray(name)) {\n const parsedName = name && LEADING_DIGIT_PATTERN.test(name) ? `_${name.slice(1)}` : name\n\n return factory.createExportDeclaration(\n undefined,\n isTypeOnly,\n asAlias && parsedName ? factory.createNamespaceExport(factory.createIdentifier(parsedName)) : undefined,\n factory.createStringLiteral(path),\n undefined,\n )\n }\n\n return factory.createExportDeclaration(\n undefined,\n isTypeOnly,\n factory.createNamedExports(\n name.map((propertyName) =>\n factory.createExportSpecifier(false, undefined, typeof propertyName === 'string' ? factory.createIdentifier(propertyName) : propertyName),\n ),\n ),\n factory.createStringLiteral(path),\n undefined,\n )\n}\n\n/**\n * Converts a {@link JSDocNode} to a JSDoc comment block string.\n *\n * @example\n * ```ts\n * printJSDoc({ comments: ['@description A pet', '@deprecated'] })\n * // /**\n * // * @description A pet\n * // * @deprecated\n * // *\\/\n * ```\n */\nexport function printJSDoc(jsDoc: JSDocNode): string {\n const comments = (jsDoc.comments ?? []).filter((c) => c != null)\n if (comments.length === 0) return ''\n\n const lines = comments\n .flatMap((c) => c.split(/\\r?\\n/))\n .map((l) => l.replace(JSDOC_TERMINATOR_PATTERN, '* /').replace(CARRIAGE_RETURN_PATTERN, ''))\n .filter((l) => l.trim().length > 0)\n\n if (lines.length === 0) return ''\n\n return ['/**', ...lines.map((l) => ` * ${l}`), ' */'].join('\\n')\n}\n\n/**\n * Serializes the body / value content from a `nodes` array.\n *\n * Each element is either a raw string or a structured {@link CodeNode}\n * (recursively converted via {@link printCodeNode}).\n * Elements are joined with `\\n`.\n */\nfunction printNodes(nodes: Array<CodeNode> | undefined): string {\n if (!nodes || nodes.length === 0) return ''\n return nodes.map(printCodeNode).join('\\n')\n}\n\n/**\n * Indents every non-empty line of `text` by `spaces` spaces.\n */\nfunction indentLines(text: string, spaces: number = INDENT_SIZE): string {\n if (!text) return ''\n const pad = ' '.repeat(spaces)\n return text\n .split('\\n')\n .map((line) => (line.trim() ? `${pad}${line}` : ''))\n .join('\\n')\n}\n\n/**\n * Renders the generic clause (`<T, U>`) shared by function and arrow-function nodes.\n * Accepts either a raw string (rendered verbatim) or an array of type-parameter names.\n */\nfunction formatGenerics(generics: FunctionNode['generics'] | ArrowFunctionNode['generics']): string {\n if (!generics) return ''\n return `<${Array.isArray(generics) ? generics.join(', ') : generics}>`\n}\n\n/**\n * Renders the return-type suffix (`: T` or `: Promise<T>` when `isAsync` is true).\n * Returns an empty string when no return type is provided.\n */\nfunction formatReturnType(returnType: string | undefined, isAsync: boolean | undefined): string {\n if (!returnType) return ''\n return isAsync ? `: Promise<${returnType}>` : `: ${returnType}`\n}\n\n/**\n * Converts a {@link ConstNode} to a TypeScript `const` declaration string.\n *\n * Mirrors the `Const` component from `@kubb/renderer-jsx`.\n *\n * @example\n * ```ts\n * printConst(createConst({ name: 'pet', export: true, nodes: ['{}'] }))\n * // 'export const pet = {}'\n * ```\n *\n * @example With type and `as const`\n * ```ts\n * printConst(createConst({ name: 'pets', export: true, type: 'Pet[]', asConst: true, nodes: ['[]'] }))\n * // 'export const pets: Pet[] = [] as const'\n * ```\n */\nexport function printConst(node: ConstNode): string {\n const { name, export: canExport, type, JSDoc, asConst, nodes } = node\n\n const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''\n const body = printNodes(nodes)\n\n const parts: string[] = []\n if (canExport) parts.push('export ')\n parts.push('const ')\n parts.push(name)\n if (type) {\n parts.push(`: ${type}`)\n }\n parts.push(' = ')\n parts.push(body)\n if (asConst) parts.push(' as const')\n\n const declaration = parts.join('')\n return [jsDocStr, declaration].filter(Boolean).join('\\n')\n}\n\n/**\n * Converts a {@link TypeNode} to a TypeScript `type` alias declaration string.\n *\n * Mirrors the `Type` component from `@kubb/renderer-jsx`.\n *\n * @example\n * ```ts\n * printType(createType({ name: 'Pet', export: true, nodes: ['{ id: number }'] }))\n * // 'export type Pet = { id: number }'\n * ```\n */\nexport function printType(node: TypeNode): string {\n const { name, export: canExport, JSDoc, nodes } = node\n\n const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''\n const body = printNodes(nodes)\n\n const parts: string[] = []\n if (canExport) parts.push('export ')\n parts.push('type ')\n parts.push(name)\n parts.push(' = ')\n parts.push(body)\n\n const declaration = parts.join('')\n return [jsDocStr, declaration].filter(Boolean).join('\\n')\n}\n\n/**\n * Converts a {@link FunctionNode} to a TypeScript `function` declaration string.\n *\n * Mirrors the `Function` component from `@kubb/renderer-jsx`.\n *\n * @example\n * ```ts\n * printFunction(createFunction({ name: 'getPet', export: true, params: 'id: string', returnType: 'Pet', nodes: ['return fetch(id)'] }))\n * // 'export function getPet(id: string): Pet {\\n return fetch(id)\\n}'\n * ```\n *\n * @example Async with generics\n * ```ts\n * printFunction(createFunction({ name: 'fetchPet', export: true, async: true, generics: ['T'], params: 'id: string', returnType: 'T' }))\n * // 'export async function fetchPet<T>(id: string): Promise<T> {\\n}'\n * ```\n */\nexport function printFunction(node: FunctionNode): string {\n const { name, default: isDefault, export: canExport, async: isAsync, generics, params, returnType, JSDoc, nodes } = node\n\n const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''\n const body = printNodes(nodes)\n const indented = body ? indentLines(body) : ''\n\n const parts: string[] = []\n if (canExport) parts.push('export ')\n if (isDefault) parts.push('default ')\n if (isAsync) parts.push('async ')\n parts.push('function ')\n parts.push(name)\n parts.push(formatGenerics(generics))\n parts.push(`(${params ?? ''})`)\n parts.push(formatReturnType(returnType, isAsync))\n parts.push(' {')\n if (indented) {\n parts.push(`\\n${indented}\\n`)\n }\n parts.push('}')\n\n const declaration = parts.join('')\n return [jsDocStr, declaration].filter(Boolean).join('\\n')\n}\n\n/**\n * Converts an {@link ArrowFunctionNode} to a TypeScript arrow function declaration string.\n *\n * Mirrors the `Function.Arrow` component from `@kubb/renderer-jsx`.\n *\n * @example Multi-line arrow function\n * ```ts\n * printArrowFunction(createArrowFunction({ name: 'getPet', export: true, params: 'id: string', nodes: ['return fetch(id)'] }))\n * // 'export const getPet = (id: string) => {\\n return fetch(id)\\n}'\n * ```\n *\n * @example Single-line arrow function\n * ```ts\n * printArrowFunction(createArrowFunction({ name: 'double', params: 'n: number', singleLine: true, nodes: ['n * 2'] }))\n * // 'const double = (n: number) => n * 2'\n * ```\n */\nexport function printArrowFunction(node: ArrowFunctionNode): string {\n const { name, default: isDefault, export: canExport, async: isAsync, generics, params, returnType, JSDoc, nodes, singleLine } = node\n\n const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''\n const body = printNodes(nodes)\n const arrowBody = singleLine ? ` => ${body}` : body ? ` => {\\n${indentLines(body)}\\n}` : ' => {}'\n\n const parts: string[] = []\n if (canExport) parts.push('export ')\n if (isDefault) parts.push('default ')\n parts.push('const ')\n parts.push(name)\n parts.push(' = ')\n if (isAsync) parts.push('async ')\n parts.push(formatGenerics(generics))\n parts.push(`(${params ?? ''})`)\n parts.push(formatReturnType(returnType, isAsync))\n parts.push(arrowBody)\n\n const declaration = parts.join('')\n return [jsDocStr, declaration].filter(Boolean).join('\\n')\n}\n\n/**\n * Converts a {@link CodeNode} to its TypeScript string representation.\n *\n * Dispatches to the appropriate printer based on the node's `kind`.\n *\n * @example\n * ```ts\n * printCodeNode(createConst({ name: 'x', nodes: ['1'] }))\n * // 'const x = 1'\n * ```\n */\nexport function printCodeNode(node: CodeNode): string {\n switch (node.kind) {\n case 'Break':\n return ''\n case 'Text':\n return (node as TextNode).value\n case 'Jsx':\n return (node as JsxNode).value\n case 'Const':\n return printConst(node)\n case 'Type':\n return printType(node)\n case 'Function':\n return printFunction(node)\n case 'ArrowFunction':\n return printArrowFunction(node)\n }\n}\n\n/**\n * Converts a {@link SourceNode} to its TypeScript string representation.\n *\n * Iterates `nodes` in DOM order, rendering each {@link CodeNode} via\n * {@link printCodeNode}.\n *\n * @example From nodes\n * ```ts\n * printSource({ kind: 'Source', nodes: [createConst({ name: 'x', nodes: [createText('1')] }), createText('x.toString()')] })\n * // 'const x = 1\\nx.toString()'\n * ```\n */\nexport function printSource(node: SourceNode): string {\n if (node.nodes && node.nodes.length > 0) {\n return node.nodes.map(printCodeNode).join('\\n')\n }\n return ''\n}\n\n/**\n * Parser that converts `.ts` and `.js` files to strings using the TypeScript\n * compiler. Handles import/export statement generation from file metadata.\n *\n * @default Used automatically when no `parsers` option is set in `defineConfig`.\n */\nexport const parserTs: Parser = defineParser({\n name: 'typescript',\n extNames: ['.ts', '.js'],\n async parse(file, options = { extname: '.ts' }) {\n const sourceParts: Array<string> = []\n for (const item of file.sources) {\n const sourceStr = printSource(item as SourceNode)\n if (sourceStr) {\n sourceParts.push(sourceStr.trimEnd())\n }\n }\n const source = sourceParts.join('\\n\\n')\n\n const importNodes: Array<ts.ImportDeclaration> = []\n for (const item of (file as FileNode).imports) {\n const importPath = item.root ? getRelativePath(item.root, item.path) : item.path\n importNodes.push(\n createImport({\n name: item.name as string | Array<string | { propertyName: string; name?: string }>,\n path: resolveOutputPath(importPath, options, Boolean(item.root)),\n isTypeOnly: item.isTypeOnly,\n isNameSpace: item.isNameSpace,\n }),\n )\n }\n\n const exportNodes: Array<ts.ExportDeclaration> = []\n for (const item of (file as FileNode).exports) {\n exportNodes.push(\n createExport({\n name: item.name as string | Array<ts.Identifier | string> | undefined,\n path: resolveOutputPath(item.path, options, true),\n isTypeOnly: item.isTypeOnly,\n asAlias: item.asAlias,\n }),\n )\n }\n\n const parts = [file.banner, print(...importNodes, ...exportNodes), source, file.footer]\n .filter((segment): segment is string => Boolean(segment))\n .map((s) => s.trimEnd())\n return parts.join('\\n\\n')\n },\n})\n","import type { Parser } from '@kubb/core'\nimport { defineParser } from '@kubb/core'\nimport { parserTs } from './parserTs.ts'\n\n/**\n * Parser that converts `.tsx` and `.jsx` files to strings.\n * Delegates to `typescriptParser` since the TypeScript compiler natively\n * supports JSX/TSX syntax via `ScriptKind.TSX`.\n *\n * Add this parser to the `parsers` option in `defineConfig` when generating `.tsx`/`.jsx` files.\n *\n * @default extname '.tsx'\n */\nexport const parserTsx: Parser = defineParser({\n name: 'tsx',\n extNames: ['.tsx', '.jsx'],\n async parse(file, options = { extname: '.tsx' }) {\n return parserTs.parse(file, options)\n },\n})\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AASA,MAAa,yBAAyB;;;;AAKtC,MAAa,yBAAyB;;;;;AAMtC,MAAa,2BAA2B;;;;AAKxC,MAAa,0BAA0B;;;;AAKvC,MAAa,eAAe;;;;;AAM5B,MAAa,wBAAwB;;;ACnBrC,MAAM,EAAE,YAAYA,WAAAA;AAEpB,SAAS,MAAM,MAAsB;AACnC,SAAA,GAAA,UAAA,WAAiB,KAAK,CAAC,WAAW,wBAAwB,IAAI,CAAC,QAAA,OAAiC,GAAG;;;;;;AAOrG,SAAS,gBAAgB,SAAiB,UAA0B;CAElE,MAAM,UAAU,OAAA,GAAA,UAAA,UADK,SAAS,SACL,CAAC;AAC1B,QAAO,QAAQ,WAAA,MAAmC,GAAG,UAAU,KAA8B;;;;;;AAO/F,SAAS,YAAY,MAAsB;AACzC,QAAO,KAAK,QAAQ,wBAAwB,GAAG;;;;;;;AAQjD,SAAS,kBAAkB,MAAc,SAA2C,WAA4B;CAC9G,MAAM,aAAa,uBAAuB,KAAK,KAAK;AACpD,KAAI,SAAS,WAAW,WACtB,QAAO,GAAG,YAAY,KAAK,GAAG,QAAQ;AAExC,QAAO,YAAY,YAAY,KAAK,GAAG;;;;;;;AAQzC,SAAgB,cAAc,GAAG,OAAwB;AACvD,MAAK,MAAM,QAAQ,OAAO;AACxB,MAAI,CAAC,KACH,OAAM,IAAI,MAAM,uDAAuD;AAEzE,MAAI,KAAK,SAASA,WAAAA,QAAG,WAAW,QAC9B,OAAM,IAAI,MACR,qKAEW,KAAK,UAAU,MAAM,MAAM,EAAE,GACzC;;;;;;AAQP,SAAgB,MAAM,GAAG,UAAkC;CACzD,MAAM,aAAaA,WAAAA,QAAG,iBAAiB,aAAa,IAAIA,WAAAA,QAAG,aAAa,QAAQ,MAAMA,WAAAA,QAAG,WAAW,IAAI;AAWxG,QATgBA,WAAAA,QAAG,cAAc;EAC/B,uBAAuB;EACvB,SAASA,WAAAA,QAAG,YAAY;EACxB,gBAAgB;EAChB,eAAe;EAChB,CAEqB,CAAC,UAAUA,WAAAA,QAAG,WAAW,WAAW,QAAQ,gBAAgB,SAAS,OAAO,QAAQ,CAAC,EAAE,WAEhG,CAAC,QAAQ,cAAc,KAAK;;;;;AAM3C,SAAgB,UAAU,GAAG,UAAkC;AAC7D,eAAc,GAAG,SAAS;AAC1B,QAAO,MAAM,GAAG,SAAS;;AAG3B,SAAgB,aAAa,EAC3B,MACA,MACA,MACA,aAAa,OACb,cAAc,SASS;CACvB,MAAM,cAAc,OAAO,gBAAgB,MAAM,KAAK,GAAG;AAEzD,KAAI,CAAC,MAAM,QAAQ,KAAK,EAAE;AACxB,MAAI,YACF,QAAO,QAAQ,wBACb,KAAA,GACA,QAAQ,mBAAmB,YAAY,KAAA,GAAW,QAAQ,sBAAsB,QAAQ,iBAAiB,KAAK,CAAC,CAAC,EAChH,QAAQ,oBAAoB,YAAY,EACxC,KAAA,EACD;AAGH,SAAO,QAAQ,wBACb,KAAA,GACA,QAAQ,mBAAmB,YAAY,QAAQ,iBAAiB,KAAK,EAAE,KAAA,EAAU,EACjF,QAAQ,oBAAoB,YAAY,EACxC,KAAA,EACD;;CAGH,MAAM,aAAa,KAAK,KAAK,SAAS;AACpC,MAAI,OAAO,SAAS,UAAU;GAC5B,MAAM,EAAE,cAAc,MAAM,UAAU;AACtC,UAAO,QAAQ,sBAAsB,OAAO,QAAQ,QAAQ,iBAAiB,aAAa,GAAG,KAAA,GAAW,QAAQ,iBAAiB,SAAS,aAAa,CAAC;;AAE1J,SAAO,QAAQ,sBAAsB,OAAO,KAAA,GAAW,QAAQ,iBAAiB,KAAK,CAAC;GACtF;AAEF,QAAO,QAAQ,wBACb,KAAA,GACA,QAAQ,mBAAmB,YAAY,KAAA,GAAW,QAAQ,mBAAmB,WAAW,CAAC,EACzF,QAAQ,oBAAoB,YAAY,EACxC,KAAA,EACD;;AAGH,SAAgB,aAAa,EAC3B,MACA,SACA,aAAa,OACb,QAQuB;AACvB,KAAI,QAAQ,CAAC,MAAM,QAAQ,KAAK,IAAI,CAAC,QACnC,SAAQ,KAAK,sDAAsD,OAAO;AAG5E,KAAI,CAAC,MAAM,QAAQ,KAAK,EAAE;EACxB,MAAM,aAAa,QAAQ,sBAAsB,KAAK,KAAK,GAAG,IAAI,KAAK,MAAM,EAAE,KAAK;AAEpF,SAAO,QAAQ,wBACb,KAAA,GACA,YACA,WAAW,aAAa,QAAQ,sBAAsB,QAAQ,iBAAiB,WAAW,CAAC,GAAG,KAAA,GAC9F,QAAQ,oBAAoB,KAAK,EACjC,KAAA,EACD;;AAGH,QAAO,QAAQ,wBACb,KAAA,GACA,YACA,QAAQ,mBACN,KAAK,KAAK,iBACR,QAAQ,sBAAsB,OAAO,KAAA,GAAW,OAAO,iBAAiB,WAAW,QAAQ,iBAAiB,aAAa,GAAG,aAAa,CAC1I,CACF,EACD,QAAQ,oBAAoB,KAAK,EACjC,KAAA,EACD;;;;;;;;;;;;;;AAeH,SAAgB,WAAW,OAA0B;CACnD,MAAM,YAAY,MAAM,YAAY,EAAE,EAAE,QAAQ,MAAM,KAAK,KAAK;AAChE,KAAI,SAAS,WAAW,EAAG,QAAO;CAElC,MAAM,QAAQ,SACX,SAAS,MAAM,EAAE,MAAM,QAAQ,CAAC,CAChC,KAAK,MAAM,EAAE,QAAQ,0BAA0B,MAAM,CAAC,QAAQ,yBAAyB,GAAG,CAAC,CAC3F,QAAQ,MAAM,EAAE,MAAM,CAAC,SAAS,EAAE;AAErC,KAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,QAAO;EAAC;EAAO,GAAG,MAAM,KAAK,MAAM,MAAM,IAAI;EAAE;EAAM,CAAC,KAAK,KAAK;;;;;;;;;AAUlE,SAAS,WAAW,OAA4C;AAC9D,KAAI,CAAC,SAAS,MAAM,WAAW,EAAG,QAAO;AACzC,QAAO,MAAM,IAAI,cAAc,CAAC,KAAK,KAAK;;;;;AAM5C,SAAS,YAAY,MAAc,SAAA,GAAsC;AACvE,KAAI,CAAC,KAAM,QAAO;CAClB,MAAM,MAAM,IAAI,OAAO,OAAO;AAC9B,QAAO,KACJ,MAAM,KAAK,CACX,KAAK,SAAU,KAAK,MAAM,GAAG,GAAG,MAAM,SAAS,GAAI,CACnD,KAAK,KAAK;;;;;;AAOf,SAAS,eAAe,UAA4E;AAClG,KAAI,CAAC,SAAU,QAAO;AACtB,QAAO,IAAI,MAAM,QAAQ,SAAS,GAAG,SAAS,KAAK,KAAK,GAAG,SAAS;;;;;;AAOtE,SAAS,iBAAiB,YAAgC,SAAsC;AAC9F,KAAI,CAAC,WAAY,QAAO;AACxB,QAAO,UAAU,aAAa,WAAW,KAAK,KAAK;;;;;;;;;;;;;;;;;;;AAoBrD,SAAgB,WAAW,MAAyB;CAClD,MAAM,EAAE,MAAM,QAAQ,WAAW,MAAM,OAAO,SAAS,UAAU;CAEjE,MAAM,WAAW,QAAQ,WAAW,MAAM,GAAG;CAC7C,MAAM,OAAO,WAAW,MAAM;CAE9B,MAAM,QAAkB,EAAE;AAC1B,KAAI,UAAW,OAAM,KAAK,UAAU;AACpC,OAAM,KAAK,SAAS;AACpB,OAAM,KAAK,KAAK;AAChB,KAAI,KACF,OAAM,KAAK,KAAK,OAAO;AAEzB,OAAM,KAAK,MAAM;AACjB,OAAM,KAAK,KAAK;AAChB,KAAI,QAAS,OAAM,KAAK,YAAY;AAGpC,QAAO,CAAC,UADY,MAAM,KAAK,GACF,CAAC,CAAC,OAAO,QAAQ,CAAC,KAAK,KAAK;;;;;;;;;;;;;AAc3D,SAAgB,UAAU,MAAwB;CAChD,MAAM,EAAE,MAAM,QAAQ,WAAW,OAAO,UAAU;CAElD,MAAM,WAAW,QAAQ,WAAW,MAAM,GAAG;CAC7C,MAAM,OAAO,WAAW,MAAM;CAE9B,MAAM,QAAkB,EAAE;AAC1B,KAAI,UAAW,OAAM,KAAK,UAAU;AACpC,OAAM,KAAK,QAAQ;AACnB,OAAM,KAAK,KAAK;AAChB,OAAM,KAAK,MAAM;AACjB,OAAM,KAAK,KAAK;AAGhB,QAAO,CAAC,UADY,MAAM,KAAK,GACF,CAAC,CAAC,OAAO,QAAQ,CAAC,KAAK,KAAK;;;;;;;;;;;;;;;;;;;AAoB3D,SAAgB,cAAc,MAA4B;CACxD,MAAM,EAAE,MAAM,SAAS,WAAW,QAAQ,WAAW,OAAO,SAAS,UAAU,QAAQ,YAAY,OAAO,UAAU;CAEpH,MAAM,WAAW,QAAQ,WAAW,MAAM,GAAG;CAC7C,MAAM,OAAO,WAAW,MAAM;CAC9B,MAAM,WAAW,OAAO,YAAY,KAAK,GAAG;CAE5C,MAAM,QAAkB,EAAE;AAC1B,KAAI,UAAW,OAAM,KAAK,UAAU;AACpC,KAAI,UAAW,OAAM,KAAK,WAAW;AACrC,KAAI,QAAS,OAAM,KAAK,SAAS;AACjC,OAAM,KAAK,YAAY;AACvB,OAAM,KAAK,KAAK;AAChB,OAAM,KAAK,eAAe,SAAS,CAAC;AACpC,OAAM,KAAK,IAAI,UAAU,GAAG,GAAG;AAC/B,OAAM,KAAK,iBAAiB,YAAY,QAAQ,CAAC;AACjD,OAAM,KAAK,KAAK;AAChB,KAAI,SACF,OAAM,KAAK,KAAK,SAAS,IAAI;AAE/B,OAAM,KAAK,IAAI;AAGf,QAAO,CAAC,UADY,MAAM,KAAK,GACF,CAAC,CAAC,OAAO,QAAQ,CAAC,KAAK,KAAK;;;;;;;;;;;;;;;;;;;AAoB3D,SAAgB,mBAAmB,MAAiC;CAClE,MAAM,EAAE,MAAM,SAAS,WAAW,QAAQ,WAAW,OAAO,SAAS,UAAU,QAAQ,YAAY,OAAO,OAAO,eAAe;CAEhI,MAAM,WAAW,QAAQ,WAAW,MAAM,GAAG;CAC7C,MAAM,OAAO,WAAW,MAAM;CAC9B,MAAM,YAAY,aAAa,OAAO,SAAS,OAAO,UAAU,YAAY,KAAK,CAAC,OAAO;CAEzF,MAAM,QAAkB,EAAE;AAC1B,KAAI,UAAW,OAAM,KAAK,UAAU;AACpC,KAAI,UAAW,OAAM,KAAK,WAAW;AACrC,OAAM,KAAK,SAAS;AACpB,OAAM,KAAK,KAAK;AAChB,OAAM,KAAK,MAAM;AACjB,KAAI,QAAS,OAAM,KAAK,SAAS;AACjC,OAAM,KAAK,eAAe,SAAS,CAAC;AACpC,OAAM,KAAK,IAAI,UAAU,GAAG,GAAG;AAC/B,OAAM,KAAK,iBAAiB,YAAY,QAAQ,CAAC;AACjD,OAAM,KAAK,UAAU;AAGrB,QAAO,CAAC,UADY,MAAM,KAAK,GACF,CAAC,CAAC,OAAO,QAAQ,CAAC,KAAK,KAAK;;;;;;;;;;;;;AAc3D,SAAgB,cAAc,MAAwB;AACpD,SAAQ,KAAK,MAAb;EACE,KAAK,QACH,QAAO;EACT,KAAK,OACH,QAAQ,KAAkB;EAC5B,KAAK,MACH,QAAQ,KAAiB;EAC3B,KAAK,QACH,QAAO,WAAW,KAAK;EACzB,KAAK,OACH,QAAO,UAAU,KAAK;EACxB,KAAK,WACH,QAAO,cAAc,KAAK;EAC5B,KAAK,gBACH,QAAO,mBAAmB,KAAK;;;;;;;;;;;;;;;AAgBrC,SAAgB,YAAY,MAA0B;AACpD,KAAI,KAAK,SAAS,KAAK,MAAM,SAAS,EACpC,QAAO,KAAK,MAAM,IAAI,cAAc,CAAC,KAAK,KAAK;AAEjD,QAAO;;;;;;;;AAST,MAAa,YAAA,GAAA,WAAA,cAAgC;CAC3C,MAAM;CACN,UAAU,CAAC,OAAO,MAAM;CACxB,MAAM,MAAM,MAAM,UAAU,EAAE,SAAS,OAAO,EAAE;EAC9C,MAAM,cAA6B,EAAE;AACrC,OAAK,MAAM,QAAQ,KAAK,SAAS;GAC/B,MAAM,YAAY,YAAY,KAAmB;AACjD,OAAI,UACF,aAAY,KAAK,UAAU,SAAS,CAAC;;EAGzC,MAAM,SAAS,YAAY,KAAK,OAAO;EAEvC,MAAM,cAA2C,EAAE;AACnD,OAAK,MAAM,QAAS,KAAkB,SAAS;GAC7C,MAAM,aAAa,KAAK,OAAO,gBAAgB,KAAK,MAAM,KAAK,KAAK,GAAG,KAAK;AAC5E,eAAY,KACV,aAAa;IACX,MAAM,KAAK;IACX,MAAM,kBAAkB,YAAY,SAAS,QAAQ,KAAK,KAAK,CAAC;IAChE,YAAY,KAAK;IACjB,aAAa,KAAK;IACnB,CAAC,CACH;;EAGH,MAAM,cAA2C,EAAE;AACnD,OAAK,MAAM,QAAS,KAAkB,QACpC,aAAY,KACV,aAAa;GACX,MAAM,KAAK;GACX,MAAM,kBAAkB,KAAK,MAAM,SAAS,KAAK;GACjD,YAAY,KAAK;GACjB,SAAS,KAAK;GACf,CAAC,CACH;AAMH,SAHc;GAAC,KAAK;GAAQ,MAAM,GAAG,aAAa,GAAG,YAAY;GAAE;GAAQ,KAAK;GAAO,CACpF,QAAQ,YAA+B,QAAQ,QAAQ,CAAC,CACxD,KAAK,MAAM,EAAE,SAAS,CACb,CAAC,KAAK,OAAO;;CAE5B,CAAC;;;;;;;;;;;;AC/eF,MAAa,aAAA,GAAA,WAAA,cAAiC;CAC5C,MAAM;CACN,UAAU,CAAC,QAAQ,OAAO;CAC1B,MAAM,MAAM,MAAM,UAAU,EAAE,SAAS,QAAQ,EAAE;AAC/C,SAAO,SAAS,MAAM,MAAM,QAAQ;;CAEvC,CAAC"}
{"version":3,"file":"index.cjs","names":["ts"],"sources":["../../../internals/utils/src/fs.ts","../src/constants.ts","../src/utils.ts","../src/parserTs.ts","../src/parserTsx.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { access, mkdir, readFile, rm, writeFile } from 'node:fs/promises'\nimport { dirname, join, posix, resolve } from 'node:path'\nimport { camelCase } from './casing.ts'\nimport { runtime } from './runtime.ts'\n\n/**\n * Walks up the directory tree from `cwd` (defaults to `process.cwd()`) and\n * returns the absolute path of the nearest `package.json`, or `null` when none\n * is found before reaching the filesystem root.\n *\n * @example\n * ```ts\n * const pkgPath = findPackageJSON('/home/user/project/src') // '/home/user/project/package.json'\n * ```\n */\nexport function findPackageJSON(cwd?: string): string | null {\n let dir = cwd ? resolve(cwd) : process.cwd()\n while (true) {\n const pkgPath = join(dir, 'package.json')\n if (existsSync(pkgPath)) return pkgPath\n const parent = dirname(dir)\n if (parent === dir) return null\n dir = parent\n }\n}\n\n/**\n * Converts all backslashes to forward slashes.\n * Extended-length Windows paths (`\\\\?\\...`) are left unchanged.\n */\nfunction toSlash(p: string): string {\n if (p.startsWith('\\\\\\\\?\\\\')) return p\n\n return p.replaceAll('\\\\', '/')\n}\n\n/**\n * Returns the relative path from `rootDir` to `filePath`, always using forward slashes\n * and prefixed with `./` when not already traversing upward.\n *\n * @example\n * ```ts\n * getRelativePath('/src/components', '/src/components/Button.tsx') // './Button.tsx'\n * getRelativePath('/src/components', '/src/utils/helpers.ts') // '../utils/helpers.ts'\n * ```\n */\nexport function getRelativePath(rootDir?: string | null, filePath?: string | null): string {\n if (!rootDir || !filePath) {\n throw new Error(`Root and file should be filled in when retrieving the relativePath, ${rootDir || ''} ${filePath || ''}`)\n }\n\n const relativePath = posix.relative(toSlash(rootDir), toSlash(filePath))\n\n return relativePath.startsWith('../') ? relativePath : `./${relativePath}`\n}\n\n/**\n * Resolves to `true` when the file or directory at `path` exists.\n * Uses `Bun.file().exists()` when running under Bun, `fs.access` otherwise.\n *\n * @example\n * ```ts\n * if (await exists('./kubb.config.ts')) {\n * const content = await read('./kubb.config.ts')\n * }\n * ```\n */\nexport async function exists(path: string): Promise<boolean> {\n if (runtime.isBun) {\n return Bun.file(path).exists()\n }\n return access(path).then(\n () => true,\n () => false,\n )\n}\n\n/**\n * Reads the file at `path` as a UTF-8 string.\n * Uses `Bun.file().text()` when running under Bun, `fs.readFile` otherwise.\n *\n * @example\n * ```ts\n * const source = await read('./src/Pet.ts')\n * ```\n */\nexport async function read(path: string): Promise<string> {\n if (runtime.isBun) {\n return Bun.file(path).text()\n }\n return readFile(path, { encoding: 'utf8' })\n}\n\ntype WriteOptions = {\n /**\n * When `true`, re-reads the file immediately after writing and throws if the\n * content does not match — useful for catching write failures on unreliable file systems.\n */\n sanity?: boolean\n}\n\n/**\n * Writes `data` to `path`, trimming leading/trailing whitespace before saving.\n * Skips the write when the trimmed content is empty or identical to what is already on disk.\n * Creates any missing parent directories automatically.\n * When `sanity` is `true`, re-reads the file after writing and throws if the content does not match.\n *\n * @example\n * ```ts\n * await write('./src/Pet.ts', source) // writes and returns trimmed content\n * await write('./src/Pet.ts', source) // null — file unchanged\n * await write('./src/Pet.ts', ' ') // null — empty content skipped\n * ```\n */\nexport async function write(path: string, data: string, options: WriteOptions = {}): Promise<string | null> {\n const trimmed = data.trim()\n if (trimmed === '') return null\n\n const resolved = resolve(path)\n\n if (runtime.isBun) {\n const file = Bun.file(resolved)\n const oldContent = (await file.exists()) ? await file.text() : null\n if (oldContent === trimmed) return null\n await Bun.write(resolved, trimmed)\n return trimmed\n }\n\n try {\n const oldContent = await readFile(resolved, { encoding: 'utf-8' })\n if (oldContent === trimmed) return null\n } catch {\n /* file doesn't exist yet */\n }\n\n await mkdir(dirname(resolved), { recursive: true })\n await writeFile(resolved, trimmed, { encoding: 'utf-8' })\n\n if (options.sanity) {\n const savedData = await readFile(resolved, { encoding: 'utf-8' })\n if (savedData !== trimmed) {\n throw new Error(`Sanity check failed for ${path}\\n\\nData[${data.length}]:\\n${data}\\n\\nSaved[${savedData.length}]:\\n${savedData}\\n`)\n }\n return savedData\n }\n\n return trimmed\n}\n\n/**\n * Recursively removes `path`. Silently succeeds when `path` does not exist.\n *\n * @example\n * ```ts\n * await clean('./dist')\n * ```\n */\nexport async function clean(path: string): Promise<void> {\n return rm(path, { recursive: true, force: true })\n}\n\n/**\n * Converts a filesystem path to use POSIX (`/`) separators.\n *\n * Most of the codebase compares and composes paths as strings (prefix matching, joining for\n * import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated\n * paths, but on Windows it returns `\\`-separated paths, which breaks every such comparison.\n *\n * Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the\n * code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is\n * exercisable from POSIX CI.\n *\n * @example\n * toPosixPath('C:\\\\repo\\\\src\\\\pet.ts') // 'C:/repo/src/pet.ts'\n */\nexport function toPosixPath(filePath: string): string {\n return filePath.replaceAll('\\\\', '/')\n}\n\n/**\n * Strips the file extension from a path or file name.\n * Only removes the last `.ext` segment when the dot is not part of a directory name.\n *\n * @example\n * trimExtName('petStore.ts') // 'petStore'\n * trimExtName('/src/models/pet.ts') // '/src/models/pet'\n * trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet'\n * trimExtName('noExtension') // 'noExtension'\n */\nexport function trimExtName(text: string): string {\n const dotIndex = text.lastIndexOf('.')\n if (dotIndex > 0 && !text.includes('/', dotIndex)) {\n return text.slice(0, dotIndex)\n }\n return text\n}\n\n/**\n * Builds a nested file path from a dotted name. Splits on dots that precede a letter\n * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases\n * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.\n *\n * Empty segments are dropped before joining. They arise when the name starts with a dot\n * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to\n * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an\n * absolute path, letting generated files escape the configured output directory.\n *\n * @example Nested path from a dotted name\n * `toFilePath('pet.petId') // 'pet/petId'`\n *\n * @example PascalCase the final segment\n * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`\n *\n * @example Suffix applied to the final segment only\n * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`\n */\nexport function toFilePath(name: string, caseLast: (part: string) => string = camelCase): string {\n const parts = name.split(/\\.(?=[a-zA-Z])/)\n return parts\n .map((part, i) => (i === parts.length - 1 ? caseLast(part) : camelCase(part)))\n .filter(Boolean)\n .join('/')\n}\n","/**\n * Character used for a single indent step. Set to `'\\t'` to emit tab-indented output.\n */\nexport const INDENT_CHAR = ' '\n\n/**\n * Number of {@link INDENT_CHAR} repeats that make up one nesting level.\n */\nconst INDENT_SIZE = 2 as const\n\n/**\n * Indentation unit prepended once per nesting level when pretty-printing.\n */\nexport const INDENT = INDENT_CHAR.repeat(INDENT_SIZE)\n\n/**\n * Matches only the final `.<ext>` of a path, so a name like `foo.bar.ts` keeps\n * `foo.bar` and loses just `.ts`.\n */\nexport const FILE_EXTENSION_PATTERN = /\\.[^/.]+$/\n\n/**\n * Matches Windows-style backslash path separators.\n */\nexport const WINDOWS_PATH_SEPARATOR = /\\\\/g\n\n/**\n * Matches `*\\/` in free-form text so JSDoc bodies can neutralize premature\n * comment terminators (`*\\/` → `* /`).\n */\nexport const JSDOC_TERMINATOR_PATTERN = /\\*\\//g\n\n/**\n * Matches carriage returns for normalizing CRLF/CR line endings to LF.\n */\nexport const CARRIAGE_RETURN_PATTERN = /\\r/g\n\n/**\n * Matches CRLF sequences used when normalizing TypeScript printer output.\n */\nexport const CRLF_PATTERN = /\\r\\n/g\n\n/**\n * Matches an identifier that starts with a digit. JavaScript disallows this,\n * so the printer replaces the leading digit with `_`.\n */\nexport const LEADING_DIGIT_PATTERN = /^\\d/\n\n/**\n * Relative path prefix used to detect traversal segments (`../`).\n */\nexport const PARENT_DIRECTORY_PREFIX = '../' as const\n\n/**\n * Relative path prefix used when resolving imports within the output root.\n */\nexport const CURRENT_DIRECTORY_PREFIX = './' as const\n","import { normalize, relative } from 'node:path'\nimport { trimExtName } from '@internals/utils'\nimport type { ArrowFunctionNode, CodeNode, ConstNode, FunctionNode, JSDocNode, JsxNode, SourceNode, TextNode, TypeNode } from '@kubb/ast'\nimport ts from 'typescript'\nimport {\n CARRIAGE_RETURN_PATTERN,\n CRLF_PATTERN,\n CURRENT_DIRECTORY_PREFIX,\n FILE_EXTENSION_PATTERN,\n INDENT,\n INDENT_CHAR,\n JSDOC_TERMINATOR_PATTERN,\n LEADING_DIGIT_PATTERN,\n PARENT_DIRECTORY_PREFIX,\n WINDOWS_PATH_SEPARATOR,\n} from './constants.ts'\n\nconst { factory } = ts\n\n/**\n * Normalizes a file-system path to POSIX separators and strips any leading `../` segment.\n */\nexport function slash(path: string): string {\n return normalize(path).replaceAll(WINDOWS_PATH_SEPARATOR, '/').replace(PARENT_DIRECTORY_PREFIX, '')\n}\n\n/**\n * Resolves `filePath` relative to `rootDir` and returns a POSIX-style path\n * prefixed with `./` when the target sits inside the root, or `../` when it escapes it.\n */\nexport function getRelativePath(rootDir: string, filePath: string): string {\n const rel = relative(rootDir, filePath)\n const slashed = slash(rel)\n return slashed.startsWith(PARENT_DIRECTORY_PREFIX) ? slashed : `${CURRENT_DIRECTORY_PREFIX}${slashed}`\n}\n\n/**\n * Rewrites an import/export path so its extension matches the caller-supplied\n * `options.extname`. When the source path has no extension the original is kept,\n * so virtual/module-only paths flow through unchanged.\n */\nexport function resolveOutputPath(path: string, options: { extname?: string } | undefined, rootAware: boolean): string {\n const hasExtname = FILE_EXTENSION_PATTERN.test(path)\n if (options?.extname && hasExtname) {\n return `${trimExtName(path)}${options.extname}`\n }\n return rootAware ? trimExtName(path) : path\n}\n\n/**\n * Serializes a `nodes` array into source text. Each entry is rendered via {@link printCodeNode}\n * and joined with a single newline. A `Break` node (`<br/>`) inserts one blank line between\n * statements. Consecutive breaks, and breaks at the very start or end, are folded into the\n * separator, so a double `<br/>` never emits more than one blank line.\n */\nexport function printNodes(nodes: Array<CodeNode> | undefined): string {\n if (!nodes || nodes.length === 0) return ''\n\n let result = ''\n let hasContent = false\n let pendingBreak = false\n\n for (const node of nodes) {\n if (node.kind === 'Break') {\n if (hasContent) pendingBreak = true\n continue\n }\n\n const text = printCodeNode(node)\n if (!text) continue\n\n if (hasContent) result += pendingBreak ? '\\n\\n' : '\\n'\n result += text\n hasContent = true\n pendingBreak = false\n }\n\n return result\n}\n\n/**\n * Indents every non-empty line of `text` by one indent unit. Pass a number to repeat\n * {@link INDENT_CHAR} that many times, or a string to use as the indent verbatim.\n */\nexport function indentLines(text: string, indent: number | string = INDENT): string {\n if (!text) return ''\n const pad = typeof indent === 'string' ? indent : INDENT_CHAR.repeat(indent)\n return text\n .split('\\n')\n .map((line) => (line.trim() ? `${pad}${line}` : ''))\n .join('\\n')\n}\n\n/**\n * Removes the common leading whitespace shared by every non-blank line and trims\n * surrounding blank lines, so multi-line content authored inside an indented template\n * literal lines up at a column-zero baseline. Leading whitespace is counted by\n * character, so N tabs and N spaces are treated as the same depth.\n *\n * @example\n * ```ts\n * dedent('\\n foo\\n bar\\n ')\n * // 'foo\\n bar'\n * ```\n */\nexport function dedent(text: string): string {\n if (!text) return ''\n\n const lines = text.split('\\n')\n const isBlank = (line: string) => line.trim() === ''\n\n const start = lines.findIndex((line) => !isBlank(line))\n if (start === -1) return ''\n const end = lines.findLastIndex((line) => !isBlank(line))\n\n const trimmed = lines.slice(start, end + 1)\n const indents = trimmed.filter((line) => !isBlank(line)).map((line) => line.match(/^\\s*/)?.[0].length ?? 0)\n const min = indents.length ? Math.min(...indents) : 0\n\n return trimmed.map((line) => (isBlank(line) ? '' : line.slice(min))).join('\\n')\n}\n\n/**\n * Renders the generic clause (`<T, U>`) shared by function and arrow-function nodes.\n * Accepts either a raw string (rendered verbatim) or an array of type-parameter names.\n */\nexport function formatGenerics(generics: FunctionNode['generics'] | ArrowFunctionNode['generics']): string {\n if (!generics) return ''\n return `<${Array.isArray(generics) ? generics.join(', ') : generics}>`\n}\n\n/**\n * Renders the return-type suffix (`: T` or `: Promise<T>` when `isAsync` is true).\n * Returns an empty string when no return type is provided.\n */\nexport function formatReturnType(returnType: string | null | undefined, isAsync: boolean | null | undefined): string {\n if (!returnType) return ''\n return isAsync ? `: Promise<${returnType}>` : `: ${returnType}`\n}\n\n/**\n * Module-scoped TypeScript printer instance. A printer does not mutate the source file, so one\n * instance is reused across every `print()` call instead of constructing a new printer each time.\n */\nconst TS_PRINTER = ts.createPrinter({\n omitTrailingSemicolon: true,\n newLine: ts.NewLineKind.LineFeed,\n removeComments: false,\n noEmitHelpers: true,\n})\n\n/**\n * Module-scoped source file used as the print target. `printList` only reads the source\n * file's compiler options / language version. It never mutates it.\n */\nconst PRINT_SOURCE_FILE = ts.createSourceFile('print.tsx', '', ts.ScriptTarget.ES2022, true, ts.ScriptKind.TSX)\n\n// Pre-warm the printer at module load. The first `printList` call lazily initializes\n// the printer's internal string-builder and identifier tables. Doing it once at import\n// time keeps that cost off the critical path for short-lived CLI builds.\nTS_PRINTER.printList(ts.ListFormat.MultiLine, factory.createNodeArray([]), PRINT_SOURCE_FILE)\n\n/**\n * Converts TypeScript/TSX AST nodes to a string using the TypeScript printer.\n */\nexport function print(...elements: Array<ts.Node>): string {\n const filtered = elements.filter(Boolean)\n if (filtered.length === 0) return ''\n\n const output = TS_PRINTER.printList(ts.ListFormat.MultiLine, factory.createNodeArray(filtered), PRINT_SOURCE_FILE)\n\n return output.replace(CRLF_PATTERN, '\\n')\n}\n\n/**\n * Converts a {@link JSDocNode} to a JSDoc comment block string.\n *\n * @example\n * ```ts\n * printJSDoc({ comments: ['@description A pet', '@deprecated'] })\n * // /**\n * // * @description A pet\n * // * @deprecated\n * // *\\/\n * ```\n */\nexport function printJSDoc(jsDoc: JSDocNode): string {\n const comments = (jsDoc.comments ?? []).filter((c) => c != null)\n if (comments.length === 0) return ''\n\n const lines = comments\n .flatMap((c) => c.split(/\\r?\\n/))\n .map((l) => l.replace(JSDOC_TERMINATOR_PATTERN, '* /').replace(CARRIAGE_RETURN_PATTERN, ''))\n .filter((l) => l.trim().length > 0)\n\n if (lines.length === 0) return ''\n\n return ['/**', ...lines.map((l) => ` * ${l}`), ' */'].join('\\n')\n}\n\n/**\n * Converts a {@link ConstNode} to a TypeScript `const` declaration string.\n *\n * Mirrors the `Const` component from `@kubb/renderer-jsx`.\n *\n * @example\n * ```ts\n * printConst(factory.createConst({ name: 'pet', export: true, nodes: ['{}'] }))\n * // 'export const pet = {}'\n * ```\n *\n * @example With type and `as const`\n * ```ts\n * printConst(factory.createConst({ name: 'pets', export: true, type: 'Pet[]', asConst: true, nodes: ['[]'] }))\n * // 'export const pets: Pet[] = [] as const'\n * ```\n */\nexport function printConst(node: ConstNode): string {\n const { name, export: canExport, type, JSDoc, asConst, nodes } = node\n\n const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''\n const body = printNodes(nodes)\n\n const parts: Array<string> = []\n if (canExport) parts.push('export ')\n parts.push('const ')\n parts.push(name)\n if (type) {\n parts.push(`: ${type}`)\n }\n parts.push(' = ')\n parts.push(body)\n if (asConst) parts.push(' as const')\n\n const declaration = parts.join('')\n return [jsDocStr, declaration].filter(Boolean).join('\\n')\n}\n\n/**\n * Converts a {@link TypeNode} to a TypeScript `type` alias declaration string.\n *\n * Mirrors the `Type` component from `@kubb/renderer-jsx`.\n *\n * @example\n * ```ts\n * printType(factory.createType({ name: 'Pet', export: true, nodes: ['{ id: number }'] }))\n * // 'export type Pet = { id: number }'\n * ```\n */\nexport function printType(node: TypeNode): string {\n const { name, export: canExport, JSDoc, nodes } = node\n\n const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''\n const body = printNodes(nodes)\n\n const parts: Array<string> = []\n if (canExport) parts.push('export ')\n parts.push('type ')\n parts.push(name)\n parts.push(' = ')\n parts.push(body)\n\n const declaration = parts.join('')\n return [jsDocStr, declaration].filter(Boolean).join('\\n')\n}\n\n/**\n * Converts a {@link FunctionNode} to a TypeScript `function` declaration string.\n *\n * Mirrors the `Function` component from `@kubb/renderer-jsx`.\n *\n * @example\n * ```ts\n * printFunction(factory.createFunction({ name: 'getPet', export: true, params: 'id: string', returnType: 'Pet', nodes: ['return fetch(id)'] }))\n * // 'export function getPet(id: string): Pet {\\n return fetch(id)\\n}'\n * ```\n *\n * @example Async with generics\n * ```ts\n * printFunction(factory.createFunction({ name: 'fetchPet', export: true, async: true, generics: ['T'], params: 'id: string', returnType: 'T' }))\n * // 'export async function fetchPet<T>(id: string): Promise<T> {\\n}'\n * ```\n */\nexport function printFunction(node: FunctionNode): string {\n const { name, default: isDefault, export: canExport, async: isAsync, generics, params, returnType, JSDoc, nodes } = node\n\n const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''\n const body = printNodes(nodes)\n const indented = body ? indentLines(body) : ''\n\n const parts: Array<string> = []\n if (canExport) parts.push('export ')\n if (isDefault) parts.push('default ')\n if (isAsync) parts.push('async ')\n parts.push('function ')\n parts.push(name)\n parts.push(formatGenerics(generics))\n parts.push(`(${params ?? ''})`)\n parts.push(formatReturnType(returnType, isAsync))\n parts.push(' {')\n if (indented) {\n parts.push(`\\n${indented}\\n`)\n }\n parts.push('}')\n\n const declaration = parts.join('')\n return [jsDocStr, declaration].filter(Boolean).join('\\n')\n}\n\n/**\n * Converts an {@link ArrowFunctionNode} to a TypeScript arrow function declaration string.\n *\n * Mirrors the `Function.Arrow` component from `@kubb/renderer-jsx`.\n *\n * @example Multi-line arrow function\n * ```ts\n * printArrowFunction(factory.createArrowFunction({ name: 'getPet', export: true, params: 'id: string', nodes: ['return fetch(id)'] }))\n * // 'export const getPet = (id: string) => {\\n return fetch(id)\\n}'\n * ```\n *\n * @example Single-line arrow function\n * ```ts\n * printArrowFunction(factory.createArrowFunction({ name: 'double', params: 'n: number', singleLine: true, nodes: ['n * 2'] }))\n * // 'const double = (n: number) => n * 2'\n * ```\n */\nexport function printArrowFunction(node: ArrowFunctionNode): string {\n const { name, default: isDefault, export: canExport, async: isAsync, generics, params, returnType, JSDoc, nodes, singleLine } = node\n\n const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''\n const body = printNodes(nodes)\n const arrowBody = singleLine ? ` => ${body}` : body ? ` => {\\n${indentLines(body)}\\n}` : ' => {}'\n\n const parts: Array<string> = []\n if (canExport) parts.push('export ')\n if (isDefault) parts.push('default ')\n parts.push('const ')\n parts.push(name)\n parts.push(' = ')\n if (isAsync) parts.push('async ')\n parts.push(formatGenerics(generics))\n parts.push(`(${params ?? ''})`)\n parts.push(formatReturnType(returnType, isAsync))\n parts.push(arrowBody)\n\n const declaration = parts.join('')\n return [jsDocStr, declaration].filter(Boolean).join('\\n')\n}\n\n/**\n * Converts a {@link CodeNode} to its TypeScript string representation.\n *\n * Dispatches to the appropriate printer based on the node's `kind`.\n *\n * @example\n * ```ts\n * printCodeNode(factory.createConst({ name: 'x', nodes: ['1'] }))\n * // 'const x = 1'\n * ```\n */\nexport function printCodeNode(node: CodeNode): string {\n if (node.kind === 'Break') return ''\n if (node.kind === 'Text') return dedent((node as TextNode).value)\n if (node.kind === 'Jsx') return dedent((node as JsxNode).value)\n if (node.kind === 'Const') return printConst(node)\n if (node.kind === 'Type') return printType(node)\n if (node.kind === 'Function') return printFunction(node)\n if (node.kind === 'ArrowFunction') return printArrowFunction(node)\n return ''\n}\n\n/**\n * Converts a {@link SourceNode} to its TypeScript string representation.\n *\n * Iterates `nodes` in DOM order, rendering each {@link CodeNode} via\n * {@link printCodeNode}.\n *\n * Top-level declarations are separated by a blank line so the source reads\n * cleanly without an external formatter.\n *\n * @example From nodes\n * ```ts\n * printSource({ kind: 'Source', nodes: [factory.createConst({ name: 'x', nodes: [factory.createText('1')] }), factory.createText('x.toString()')] })\n * // 'const x = 1\\n\\nx.toString()'\n * ```\n */\nexport function printSource(node: SourceNode): string {\n const nodes = node.nodes\n\n if (!nodes || nodes.length === 0) return ''\n\n return nodes\n .map((child) => printCodeNode(child as CodeNode))\n .filter(Boolean)\n .join('\\n\\n')\n}\n\n/**\n * Wraps a module specifier in single quotes, escaping any embedded backslash or quote so the emitted\n * statement stays valid even for unusual paths.\n */\nfunction quoteModulePath(path: string): string {\n return `'${path.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\")}'`\n}\n\n/**\n * Renders an import declaration string in the repo style (single quotes, no semicolons), covering\n * default, namespace (`* as`), and named imports with `{ a as b }` aliases, each optionally\n * `type`-only. `path` is used verbatim, so resolve it first.\n *\n * @example\n * ```ts\n * printImport({ name: ['z'], path: './zod.ts' })\n * // \"import { z } from './zod.ts'\"\n * ```\n */\nexport function printImport({\n name,\n path,\n isTypeOnly = false,\n isNameSpace = false,\n}: {\n name: string | Array<string | { propertyName: string; name?: string }>\n path: string\n isTypeOnly?: boolean | null\n isNameSpace?: boolean | null\n}): string {\n const typePrefix = isTypeOnly ? 'type ' : ''\n const from = quoteModulePath(path)\n\n if (!Array.isArray(name)) {\n if (isNameSpace) return `import ${typePrefix}* as ${name} from ${from}`\n return `import ${typePrefix}${name} from ${from}`\n }\n\n const specifiers = name.map((item) => {\n if (typeof item === 'object') {\n return item.name ? `${item.propertyName} as ${item.name}` : item.propertyName\n }\n return item\n })\n\n return `import ${typePrefix}{ ${specifiers.join(', ')} } from ${from}`\n}\n\n/**\n * Renders an export declaration string in the repo style (single quotes, no semicolons), covering\n * named re-exports, namespace alias (`* as name`), and wildcard, each optionally `type`-only.\n * `path` is used verbatim, so resolve it first.\n *\n * @example\n * ```ts\n * printExport({ name: ['Pet', 'Order'], path: './models.ts' })\n * // \"export { Pet, Order } from './models.ts'\"\n * ```\n */\nexport function printExport({\n path,\n name,\n isTypeOnly = false,\n asAlias = false,\n}: {\n path: string\n name?: string | Array<ts.Identifier | string> | null\n isTypeOnly?: boolean | null\n asAlias?: boolean | null\n}): string {\n const typePrefix = isTypeOnly ? 'type ' : ''\n const from = quoteModulePath(path)\n\n if (Array.isArray(name)) {\n const specifiers = name.map((item) => (typeof item === 'string' ? item : item.text))\n return `export ${typePrefix}{ ${specifiers.join(', ')} } from ${from}`\n }\n\n if (asAlias && name) {\n const parsedName = LEADING_DIGIT_PATTERN.test(name) ? `_${name.slice(1)}` : name\n return `export ${typePrefix}* as ${parsedName} from ${from}`\n }\n\n if (name) {\n console.warn(`When using name as string, asAlias should be true: ${name}`)\n }\n\n return `export ${typePrefix}* from ${from}`\n}\n","import type { FileNode, SourceNode } from '@kubb/ast'\nimport { defineParser } from '@kubb/core'\nimport type * as ts from 'typescript'\nimport { getRelativePath, print, printExport, printImport, printSource, resolveOutputPath } from './utils.ts'\n\n/**\n * Default Kubb parser for `.ts` and `.js` files. Takes the universal AST\n * produced by an adapter and prints it as TypeScript source using the official\n * TypeScript compiler. Imports and exports are rewritten based on each file's\n * metadata.\n *\n * Used automatically when no `parsers` option is set on `defineConfig`. Use\n * `parserTsx` instead for React projects that emit JSX.\n *\n * @example\n * ```ts\n * import { defineConfig } from 'kubb'\n * import { adapterOas } from '@kubb/adapter-oas'\n * import { parserTs } from '@kubb/parser-ts'\n *\n * export default defineConfig({\n * input: { path: './petStore.yaml' },\n * output: { path: './src/gen' },\n * adapter: adapterOas(),\n * parsers: [parserTs],\n * plugins: [],\n * })\n * ```\n */\nexport const parserTs = defineParser({\n name: 'typescript',\n extNames: ['.ts', '.js'],\n print(...nodes: Array<ts.Node>) {\n return print(...nodes)\n },\n parse(file, options = { extname: '.ts' }) {\n const sourceParts: Array<string> = []\n for (const item of file.sources) {\n const sourceStr = printSource(item as SourceNode)\n if (sourceStr) {\n sourceParts.push(sourceStr.trimEnd())\n }\n }\n const source = sourceParts.join('\\n\\n')\n\n const importLines: Array<string> = []\n for (const item of (file as FileNode).imports) {\n const importPath = item.root ? getRelativePath(item.root, item.path) : item.path\n importLines.push(\n printImport({\n name: item.name as string | Array<string | { propertyName: string; name?: string }>,\n path: resolveOutputPath(importPath, options, Boolean(item.root)),\n isTypeOnly: item.isTypeOnly,\n isNameSpace: item.isNameSpace,\n }),\n )\n }\n\n const exportLines: Array<string> = []\n for (const item of (file as FileNode).exports) {\n exportLines.push(\n printExport({\n name: item.name as string | Array<ts.Identifier | string> | null | undefined,\n path: resolveOutputPath(item.path, options, true),\n isTypeOnly: item.isTypeOnly,\n asAlias: item.asAlias,\n }),\n )\n }\n\n const importExportBlock = [...importLines, ...exportLines].join('\\n')\n\n const parts = [file.banner, importExportBlock, source, file.footer].filter((segment): segment is string => Boolean(segment)).map((s) => s.trimEnd())\n\n return parts.join('\\n\\n')\n },\n})\n","import { defineParser } from '@kubb/core'\nimport type * as ts from 'typescript'\nimport { parserTs } from './parserTs.ts'\nimport { print } from './utils.ts'\n\n/**\n * Kubb parser for `.tsx` and `.jsx` files. Delegates to `parserTs` because the\n * TypeScript compiler handles JSX natively via `ScriptKind.TSX`.\n *\n * Add to the `parsers` array on `defineConfig` when generating components for\n * React (or any framework that emits JSX).\n *\n * @example\n * ```ts\n * import { defineConfig } from 'kubb'\n * import { adapterOas } from '@kubb/adapter-oas'\n * import { parserTsx } from '@kubb/parser-ts'\n *\n * export default defineConfig({\n * input: { path: './petStore.yaml' },\n * output: { path: './src/gen' },\n * adapter: adapterOas(),\n * parsers: [parserTsx],\n * plugins: [],\n * })\n * ```\n */\nexport const parserTsx = defineParser({\n name: 'tsx',\n extNames: ['.tsx', '.jsx'],\n print(...nodes: Array<ts.Node>) {\n return print(...nodes)\n },\n parse(file, options = { extname: '.tsx' }) {\n return parserTs.parse(file, options)\n },\n})\n"],"mappings":"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"}

@@ -1,67 +0,72 @@

import { t as __name } from "./chunk--u3MIqq1.js";
import { Parser } from "@kubb/core";
import ts from "typescript";
import { t as __name } from "./rolldown-runtime-C0LytTxp.js";
import * as ts$1 from "typescript";
import { FileNode } from "@kubb/ast";
//#region src/parserTs.d.ts
/**
* Validates TypeScript AST nodes before printing.
* Throws an error if any node has SyntaxKind.Unknown which would cause the
* TypeScript printer to crash.
*/
declare function validateNodes(...nodes: ts.Node[]): void;
/**
* Converts TypeScript/TSX AST nodes to a string using the TypeScript printer.
*/
declare function print(...elements: Array<ts.Node>): string;
/**
* Like `print` but validates nodes first to surface issues early.
*/
declare function safePrint(...elements: Array<ts.Node>): string;
declare function createImport({
name,
path,
root,
isTypeOnly,
isNameSpace
}: {
name: string | Array<string | {
propertyName: string;
name?: string;
}>;
path: string;
root?: string; /** @default false */
isTypeOnly?: boolean; /** @default false */
isNameSpace?: boolean;
}): ts.ImportDeclaration;
declare function createExport({
path,
asAlias,
isTypeOnly,
name
}: {
path: string; /** @default false */
asAlias?: boolean; /** @default false */
isTypeOnly?: boolean;
name?: string | Array<ts.Identifier | string>;
}): ts.ExportDeclaration;
/**
* Parser that converts `.ts` and `.js` files to strings using the TypeScript
* compiler. Handles import/export statement generation from file metadata.
* Default Kubb parser for `.ts` and `.js` files. Takes the universal AST
* produced by an adapter and prints it as TypeScript source using the official
* TypeScript compiler. Imports and exports are rewritten based on each file's
* metadata.
*
* @default Used automatically when no `parsers` option is set in `defineConfig`.
* Used automatically when no `parsers` option is set on `defineConfig`. Use
* `parserTsx` instead for React projects that emit JSX.
*
* @example
* ```ts
* import { defineConfig } from 'kubb'
* import { adapterOas } from '@kubb/adapter-oas'
* import { parserTs } from '@kubb/parser-ts'
*
* export default defineConfig({
* input: { path: './petStore.yaml' },
* output: { path: './src/gen' },
* adapter: adapterOas(),
* parsers: [parserTs],
* plugins: [],
* })
* ```
*/
declare const parserTs: Parser;
declare const parserTs: {
name: string;
extNames: (".ts" | ".js")[];
print(...nodes: Array<ts$1.Node>): string;
parse(file: FileNode<object>, options?: {
extname?: FileNode["extname"];
} | undefined): string;
};
//#endregion
//#region src/parserTsx.d.ts
/**
* Parser that converts `.tsx` and `.jsx` files to strings.
* Delegates to `typescriptParser` since the TypeScript compiler natively
* supports JSX/TSX syntax via `ScriptKind.TSX`.
* Kubb parser for `.tsx` and `.jsx` files. Delegates to `parserTs` because the
* TypeScript compiler handles JSX natively via `ScriptKind.TSX`.
*
* Add this parser to the `parsers` option in `defineConfig` when generating `.tsx`/`.jsx` files.
* Add to the `parsers` array on `defineConfig` when generating components for
* React (or any framework that emits JSX).
*
* @default extname '.tsx'
* @example
* ```ts
* import { defineConfig } from 'kubb'
* import { adapterOas } from '@kubb/adapter-oas'
* import { parserTsx } from '@kubb/parser-ts'
*
* export default defineConfig({
* input: { path: './petStore.yaml' },
* output: { path: './src/gen' },
* adapter: adapterOas(),
* parsers: [parserTsx],
* plugins: [],
* })
* ```
*/
declare const parserTsx: Parser;
declare const parserTsx: {
name: string;
extNames: (".tsx" | ".jsx")[];
print(...nodes: Array<ts$1.Node>): string;
parse(file: import("@kubb/ast").FileNode<object>, options?: {
extname?: import("@kubb/ast").FileNode["extname"];
} | undefined): string;
};
//#endregion
export { createExport, createImport, parserTs, parserTsx, print, safePrint, validateNodes };
export { parserTs, parserTsx };
//# sourceMappingURL=index.d.ts.map

@@ -1,10 +0,29 @@

import "./chunk--u3MIqq1.js";
import "./rolldown-runtime-C0LytTxp.js";
import { defineParser } from "@kubb/core";
import { normalize, relative } from "node:path";
import { defineParser } from "@kubb/core";
import ts from "typescript";
//#region src/constants.ts
//#region ../../internals/utils/src/fs.ts
/**
* Matches the trailing `.<ext>` segment of a path (keeps segments like `foo.bar.ts`
* intact by only trimming the last run of non-`/`/`.` characters).
* 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;
}
/**
* Indentation unit prepended once per nesting level when pretty-printing.
*/
const INDENT = " ".repeat(2);
/**
* Matches only the final `.<ext>` of a path, so a name like `foo.bar.ts` keeps
* `foo.bar` and loses just `.ts`.
*/
const FILE_EXTENSION_PATTERN = /\.[^/.]+$/;

@@ -16,3 +35,3 @@ /**

/**
* Matches `*\/` in free-form text so JSDoc bodies can neutralise premature
* Matches `*\/` in free-form text so JSDoc bodies can neutralize premature
* comment terminators (`*\/` → `* /`).

@@ -22,17 +41,20 @@ */

/**
* Matches carriage returns for normalising CRLF/CR line endings to LF.
* Matches carriage returns for normalizing CRLF/CR line endings to LF.
*/
const CARRIAGE_RETURN_PATTERN = /\r/g;
/**
* Matches CRLF sequences used when normalising TypeScript printer output.
* Matches CRLF sequences used when normalizing TypeScript printer output.
*/
const CRLF_PATTERN = /\r\n/g;
/**
* Matches an identifier that starts with a digit — JavaScript disallows this
* so the printer prefixes such names with `_`.
* Matches an identifier that starts with a digit. JavaScript disallows this,
* so the printer replaces the leading digit with `_`.
*/
const LEADING_DIGIT_PATTERN = /^\d/;
//#endregion
//#region src/parserTs.ts
//#region src/utils.ts
const { factory } = ts;
/**
* Normalizes a file-system path to POSIX separators and strips any leading `../` segment.
*/
function slash(path) {

@@ -50,9 +72,2 @@ return normalize(path).replaceAll(WINDOWS_PATH_SEPARATOR, "/").replace("../", "");

/**
* Strips the trailing file extension (for example `.ts`) from a path.
* Preserves intermediate dots like `foo.bar.ts` → `foo.bar`.
*/
function trimExtName(text) {
return text.replace(FILE_EXTENSION_PATTERN, "");
}
/**
* Rewrites an import/export path so its extension matches the caller-supplied

@@ -68,55 +83,100 @@ * `options.extname`. When the source path has no extension the original is kept,

/**
* Validates TypeScript AST nodes before printing.
* Throws an error if any node has SyntaxKind.Unknown which would cause the
* TypeScript printer to crash.
* Serializes a `nodes` array into source text. Each entry is rendered via {@link printCodeNode}
* and joined with a single newline. A `Break` node (`<br/>`) inserts one blank line between
* statements. Consecutive breaks, and breaks at the very start or end, are folded into the
* separator, so a double `<br/>` never emits more than one blank line.
*/
function validateNodes(...nodes) {
function printNodes(nodes) {
if (!nodes || nodes.length === 0) return "";
let result = "";
let hasContent = false;
let pendingBreak = false;
for (const node of nodes) {
if (!node) throw new Error("Attempted to print undefined or null TypeScript node");
if (node.kind === ts.SyntaxKind.Unknown) throw new Error(`Invalid TypeScript AST node detected with SyntaxKind.Unknown. This typically indicates a schema pattern that could not be properly converted to TypeScript. Node: ${JSON.stringify(node, null, 2)}`);
if (node.kind === "Break") {
if (hasContent) pendingBreak = true;
continue;
}
const text = printCodeNode(node);
if (!text) continue;
if (hasContent) result += pendingBreak ? "\n\n" : "\n";
result += text;
hasContent = true;
pendingBreak = false;
}
return result;
}
/**
* Converts TypeScript/TSX AST nodes to a string using the TypeScript printer.
* Indents every non-empty line of `text` by one indent unit. Pass a number to repeat
* {@link INDENT_CHAR} that many times, or a string to use as the indent verbatim.
*/
function print(...elements) {
const sourceFile = ts.createSourceFile("print.tsx", "", ts.ScriptTarget.ES2022, true, ts.ScriptKind.TSX);
return ts.createPrinter({
omitTrailingSemicolon: true,
newLine: ts.NewLineKind.LineFeed,
removeComments: false,
noEmitHelpers: true
}).printList(ts.ListFormat.MultiLine, factory.createNodeArray(elements.filter(Boolean)), sourceFile).replace(CRLF_PATTERN, "\n");
function indentLines(text, indent = INDENT) {
if (!text) return "";
const pad = typeof indent === "string" ? indent : " ".repeat(indent);
return text.split("\n").map((line) => line.trim() ? `${pad}${line}` : "").join("\n");
}
/**
* Like `print` but validates nodes first to surface issues early.
* Removes the common leading whitespace shared by every non-blank line and trims
* surrounding blank lines, so multi-line content authored inside an indented template
* literal lines up at a column-zero baseline. Leading whitespace is counted by
* character, so N tabs and N spaces are treated as the same depth.
*
* @example
* ```ts
* dedent('\n foo\n bar\n ')
* // 'foo\n bar'
* ```
*/
function safePrint(...elements) {
validateNodes(...elements);
return print(...elements);
function dedent(text) {
if (!text) return "";
const lines = text.split("\n");
const isBlank = (line) => line.trim() === "";
const start = lines.findIndex((line) => !isBlank(line));
if (start === -1) return "";
const end = lines.findLastIndex((line) => !isBlank(line));
const trimmed = lines.slice(start, end + 1);
const indents = trimmed.filter((line) => !isBlank(line)).map((line) => line.match(/^\s*/)?.[0].length ?? 0);
const min = indents.length ? Math.min(...indents) : 0;
return trimmed.map((line) => isBlank(line) ? "" : line.slice(min)).join("\n");
}
function createImport({ name, path, root, isTypeOnly = false, isNameSpace = false }) {
const resolvePath = root ? getRelativePath(root, path) : path;
if (!Array.isArray(name)) {
if (isNameSpace) return factory.createImportDeclaration(void 0, factory.createImportClause(isTypeOnly, void 0, factory.createNamespaceImport(factory.createIdentifier(name))), factory.createStringLiteral(resolvePath), void 0);
return factory.createImportDeclaration(void 0, factory.createImportClause(isTypeOnly, factory.createIdentifier(name), void 0), factory.createStringLiteral(resolvePath), void 0);
}
const specifiers = name.map((item) => {
if (typeof item === "object") {
const { propertyName, name: alias } = item;
return factory.createImportSpecifier(false, alias ? factory.createIdentifier(propertyName) : void 0, factory.createIdentifier(alias ?? propertyName));
}
return factory.createImportSpecifier(false, void 0, factory.createIdentifier(item));
});
return factory.createImportDeclaration(void 0, factory.createImportClause(isTypeOnly, void 0, factory.createNamedImports(specifiers)), factory.createStringLiteral(resolvePath), void 0);
/**
* Renders the generic clause (`<T, U>`) shared by function and arrow-function nodes.
* Accepts either a raw string (rendered verbatim) or an array of type-parameter names.
*/
function formatGenerics(generics) {
if (!generics) return "";
return `<${Array.isArray(generics) ? generics.join(", ") : generics}>`;
}
function createExport({ path, asAlias, isTypeOnly = false, name }) {
if (name && !Array.isArray(name) && !asAlias) console.warn(`When using name as string, asAlias should be true: ${name}`);
if (!Array.isArray(name)) {
const parsedName = name && LEADING_DIGIT_PATTERN.test(name) ? `_${name.slice(1)}` : name;
return factory.createExportDeclaration(void 0, isTypeOnly, asAlias && parsedName ? factory.createNamespaceExport(factory.createIdentifier(parsedName)) : void 0, factory.createStringLiteral(path), void 0);
}
return factory.createExportDeclaration(void 0, isTypeOnly, factory.createNamedExports(name.map((propertyName) => factory.createExportSpecifier(false, void 0, typeof propertyName === "string" ? factory.createIdentifier(propertyName) : propertyName))), factory.createStringLiteral(path), void 0);
/**
* Renders the return-type suffix (`: T` or `: Promise<T>` when `isAsync` is true).
* Returns an empty string when no return type is provided.
*/
function formatReturnType(returnType, isAsync) {
if (!returnType) return "";
return isAsync ? `: Promise<${returnType}>` : `: ${returnType}`;
}
/**
* Module-scoped TypeScript printer instance. A printer does not mutate the source file, so one
* instance is reused across every `print()` call instead of constructing a new printer each time.
*/
const TS_PRINTER = ts.createPrinter({
omitTrailingSemicolon: true,
newLine: ts.NewLineKind.LineFeed,
removeComments: false,
noEmitHelpers: true
});
/**
* Module-scoped source file used as the print target. `printList` only reads the source
* file's compiler options / language version. It never mutates it.
*/
const PRINT_SOURCE_FILE = ts.createSourceFile("print.tsx", "", ts.ScriptTarget.ES2022, true, ts.ScriptKind.TSX);
TS_PRINTER.printList(ts.ListFormat.MultiLine, factory.createNodeArray([]), PRINT_SOURCE_FILE);
/**
* Converts TypeScript/TSX AST nodes to a string using the TypeScript printer.
*/
function print(...elements) {
const filtered = elements.filter(Boolean);
if (filtered.length === 0) return "";
return TS_PRINTER.printList(ts.ListFormat.MultiLine, factory.createNodeArray(filtered), PRINT_SOURCE_FILE).replace(CRLF_PATTERN, "\n");
}
/**
* Converts a {@link JSDocNode} to a JSDoc comment block string.

@@ -145,37 +205,2 @@ *

/**
* Serializes the body / value content from a `nodes` array.
*
* Each element is either a raw string or a structured {@link CodeNode}
* (recursively converted via {@link printCodeNode}).
* Elements are joined with `\n`.
*/
function printNodes(nodes) {
if (!nodes || nodes.length === 0) return "";
return nodes.map(printCodeNode).join("\n");
}
/**
* Indents every non-empty line of `text` by `spaces` spaces.
*/
function indentLines(text, spaces = 2) {
if (!text) return "";
const pad = " ".repeat(spaces);
return text.split("\n").map((line) => line.trim() ? `${pad}${line}` : "").join("\n");
}
/**
* Renders the generic clause (`<T, U>`) shared by function and arrow-function nodes.
* Accepts either a raw string (rendered verbatim) or an array of type-parameter names.
*/
function formatGenerics(generics) {
if (!generics) return "";
return `<${Array.isArray(generics) ? generics.join(", ") : generics}>`;
}
/**
* Renders the return-type suffix (`: T` or `: Promise<T>` when `isAsync` is true).
* Returns an empty string when no return type is provided.
*/
function formatReturnType(returnType, isAsync) {
if (!returnType) return "";
return isAsync ? `: Promise<${returnType}>` : `: ${returnType}`;
}
/**
* Converts a {@link ConstNode} to a TypeScript `const` declaration string.

@@ -187,3 +212,3 @@ *

* ```ts
* printConst(createConst({ name: 'pet', export: true, nodes: ['{}'] }))
* printConst(factory.createConst({ name: 'pet', export: true, nodes: ['{}'] }))
* // 'export const pet = {}'

@@ -194,3 +219,3 @@ * ```

* ```ts
* printConst(createConst({ name: 'pets', export: true, type: 'Pet[]', asConst: true, nodes: ['[]'] }))
* printConst(factory.createConst({ name: 'pets', export: true, type: 'Pet[]', asConst: true, nodes: ['[]'] }))
* // 'export const pets: Pet[] = [] as const'

@@ -220,3 +245,3 @@ * ```

* ```ts
* printType(createType({ name: 'Pet', export: true, nodes: ['{ id: number }'] }))
* printType(factory.createType({ name: 'Pet', export: true, nodes: ['{ id: number }'] }))
* // 'export type Pet = { id: number }'

@@ -244,3 +269,3 @@ * ```

* ```ts
* printFunction(createFunction({ name: 'getPet', export: true, params: 'id: string', returnType: 'Pet', nodes: ['return fetch(id)'] }))
* printFunction(factory.createFunction({ name: 'getPet', export: true, params: 'id: string', returnType: 'Pet', nodes: ['return fetch(id)'] }))
* // 'export function getPet(id: string): Pet {\n return fetch(id)\n}'

@@ -251,3 +276,3 @@ * ```

* ```ts
* printFunction(createFunction({ name: 'fetchPet', export: true, async: true, generics: ['T'], params: 'id: string', returnType: 'T' }))
* printFunction(factory.createFunction({ name: 'fetchPet', export: true, async: true, generics: ['T'], params: 'id: string', returnType: 'T' }))
* // 'export async function fetchPet<T>(id: string): Promise<T> {\n}'

@@ -282,3 +307,3 @@ * ```

* ```ts
* printArrowFunction(createArrowFunction({ name: 'getPet', export: true, params: 'id: string', nodes: ['return fetch(id)'] }))
* printArrowFunction(factory.createArrowFunction({ name: 'getPet', export: true, params: 'id: string', nodes: ['return fetch(id)'] }))
* // 'export const getPet = (id: string) => {\n return fetch(id)\n}'

@@ -289,3 +314,3 @@ * ```

* ```ts
* printArrowFunction(createArrowFunction({ name: 'double', params: 'n: number', singleLine: true, nodes: ['n * 2'] }))
* printArrowFunction(factory.createArrowFunction({ name: 'double', params: 'n: number', singleLine: true, nodes: ['n * 2'] }))
* // 'const double = (n: number) => n * 2'

@@ -319,3 +344,3 @@ * ```

* ```ts
* printCodeNode(createConst({ name: 'x', nodes: ['1'] }))
* printCodeNode(factory.createConst({ name: 'x', nodes: ['1'] }))
* // 'const x = 1'

@@ -325,11 +350,10 @@ * ```

function printCodeNode(node) {
switch (node.kind) {
case "Break": return "";
case "Text": return node.value;
case "Jsx": return node.value;
case "Const": return printConst(node);
case "Type": return printType(node);
case "Function": return printFunction(node);
case "ArrowFunction": return printArrowFunction(node);
}
if (node.kind === "Break") return "";
if (node.kind === "Text") return dedent(node.value);
if (node.kind === "Jsx") return dedent(node.value);
if (node.kind === "Const") return printConst(node);
if (node.kind === "Type") return printType(node);
if (node.kind === "Function") return printFunction(node);
if (node.kind === "ArrowFunction") return printArrowFunction(node);
return "";
}

@@ -342,22 +366,98 @@ /**

*
* Top-level declarations are separated by a blank line so the source reads
* cleanly without an external formatter.
*
* @example From nodes
* ```ts
* printSource({ kind: 'Source', nodes: [createConst({ name: 'x', nodes: [createText('1')] }), createText('x.toString()')] })
* // 'const x = 1\nx.toString()'
* printSource({ kind: 'Source', nodes: [factory.createConst({ name: 'x', nodes: [factory.createText('1')] }), factory.createText('x.toString()')] })
* // 'const x = 1\n\nx.toString()'
* ```
*/
function printSource(node) {
if (node.nodes && node.nodes.length > 0) return node.nodes.map(printCodeNode).join("\n");
return "";
const nodes = node.nodes;
if (!nodes || nodes.length === 0) return "";
return nodes.map((child) => printCodeNode(child)).filter(Boolean).join("\n\n");
}
/**
* Parser that converts `.ts` and `.js` files to strings using the TypeScript
* compiler. Handles import/export statement generation from file metadata.
* Wraps a module specifier in single quotes, escaping any embedded backslash or quote so the emitted
* statement stays valid even for unusual paths.
*/
function quoteModulePath(path) {
return `'${path.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
}
/**
* Renders an import declaration string in the repo style (single quotes, no semicolons), covering
* default, namespace (`* as`), and named imports with `{ a as b }` aliases, each optionally
* `type`-only. `path` is used verbatim, so resolve it first.
*
* @default Used automatically when no `parsers` option is set in `defineConfig`.
* @example
* ```ts
* printImport({ name: ['z'], path: './zod.ts' })
* // "import { z } from './zod.ts'"
* ```
*/
function printImport({ name, path, isTypeOnly = false, isNameSpace = false }) {
const typePrefix = isTypeOnly ? "type " : "";
const from = quoteModulePath(path);
if (!Array.isArray(name)) {
if (isNameSpace) return `import ${typePrefix}* as ${name} from ${from}`;
return `import ${typePrefix}${name} from ${from}`;
}
return `import ${typePrefix}{ ${name.map((item) => {
if (typeof item === "object") return item.name ? `${item.propertyName} as ${item.name}` : item.propertyName;
return item;
}).join(", ")} } from ${from}`;
}
/**
* Renders an export declaration string in the repo style (single quotes, no semicolons), covering
* named re-exports, namespace alias (`* as name`), and wildcard, each optionally `type`-only.
* `path` is used verbatim, so resolve it first.
*
* @example
* ```ts
* printExport({ name: ['Pet', 'Order'], path: './models.ts' })
* // "export { Pet, Order } from './models.ts'"
* ```
*/
function printExport({ path, name, isTypeOnly = false, asAlias = false }) {
const typePrefix = isTypeOnly ? "type " : "";
const from = quoteModulePath(path);
if (Array.isArray(name)) return `export ${typePrefix}{ ${name.map((item) => typeof item === "string" ? item : item.text).join(", ")} } from ${from}`;
if (asAlias && name) return `export ${typePrefix}* as ${LEADING_DIGIT_PATTERN.test(name) ? `_${name.slice(1)}` : name} from ${from}`;
if (name) console.warn(`When using name as string, asAlias should be true: ${name}`);
return `export ${typePrefix}* from ${from}`;
}
//#endregion
//#region src/parserTs.ts
/**
* Default Kubb parser for `.ts` and `.js` files. Takes the universal AST
* produced by an adapter and prints it as TypeScript source using the official
* TypeScript compiler. Imports and exports are rewritten based on each file's
* metadata.
*
* Used automatically when no `parsers` option is set on `defineConfig`. Use
* `parserTsx` instead for React projects that emit JSX.
*
* @example
* ```ts
* import { defineConfig } from 'kubb'
* import { adapterOas } from '@kubb/adapter-oas'
* import { parserTs } from '@kubb/parser-ts'
*
* export default defineConfig({
* input: { path: './petStore.yaml' },
* output: { path: './src/gen' },
* adapter: adapterOas(),
* parsers: [parserTs],
* plugins: [],
* })
* ```
*/
const parserTs = defineParser({
name: "typescript",
extNames: [".ts", ".js"],
async parse(file, options = { extname: ".ts" }) {
print(...nodes) {
return print(...nodes);
},
parse(file, options = { extname: ".ts" }) {
const sourceParts = [];

@@ -369,6 +469,6 @@ for (const item of file.sources) {

const source = sourceParts.join("\n\n");
const importNodes = [];
const importLines = [];
for (const item of file.imports) {
const importPath = item.root ? getRelativePath(item.root, item.path) : item.path;
importNodes.push(createImport({
importLines.push(printImport({
name: item.name,

@@ -380,4 +480,4 @@ path: resolveOutputPath(importPath, options, Boolean(item.root)),

}
const exportNodes = [];
for (const item of file.exports) exportNodes.push(createExport({
const exportLines = [];
for (const item of file.exports) exportLines.push(printExport({
name: item.name,

@@ -388,5 +488,6 @@ path: resolveOutputPath(item.path, options, true),

}));
const importExportBlock = [...importLines, ...exportLines].join("\n");
return [
file.banner,
print(...importNodes, ...exportNodes),
importExportBlock,
source,

@@ -400,9 +501,22 @@ file.footer

/**
* Parser that converts `.tsx` and `.jsx` files to strings.
* Delegates to `typescriptParser` since the TypeScript compiler natively
* supports JSX/TSX syntax via `ScriptKind.TSX`.
* Kubb parser for `.tsx` and `.jsx` files. Delegates to `parserTs` because the
* TypeScript compiler handles JSX natively via `ScriptKind.TSX`.
*
* Add this parser to the `parsers` option in `defineConfig` when generating `.tsx`/`.jsx` files.
* Add to the `parsers` array on `defineConfig` when generating components for
* React (or any framework that emits JSX).
*
* @default extname '.tsx'
* @example
* ```ts
* import { defineConfig } from 'kubb'
* import { adapterOas } from '@kubb/adapter-oas'
* import { parserTsx } from '@kubb/parser-ts'
*
* export default defineConfig({
* input: { path: './petStore.yaml' },
* output: { path: './src/gen' },
* adapter: adapterOas(),
* parsers: [parserTsx],
* plugins: [],
* })
* ```
*/

@@ -412,3 +526,6 @@ const parserTsx = defineParser({

extNames: [".tsx", ".jsx"],
async parse(file, options = { extname: ".tsx" }) {
print(...nodes) {
return print(...nodes);
},
parse(file, options = { extname: ".tsx" }) {
return parserTs.parse(file, options);

@@ -418,4 +535,4 @@ }

//#endregion
export { createExport, createImport, parserTs, parserTsx, print, safePrint, validateNodes };
export { parserTs, parserTsx };
//# sourceMappingURL=index.js.map

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

{"version":3,"file":"index.js","names":[],"sources":["../src/constants.ts","../src/parserTs.ts","../src/parserTsx.ts"],"sourcesContent":["/**\n * Number of spaces used to indent a nested block when pretty-printing.\n */\nexport const INDENT_SIZE = 2 as const\n\n/**\n * Matches the trailing `.<ext>` segment of a path (keeps segments like `foo.bar.ts`\n * intact by only trimming the last run of non-`/`/`.` characters).\n */\nexport const FILE_EXTENSION_PATTERN = /\\.[^/.]+$/\n\n/**\n * Matches Windows-style backslash path separators.\n */\nexport const WINDOWS_PATH_SEPARATOR = /\\\\/g\n\n/**\n * Matches `*\\/` in free-form text so JSDoc bodies can neutralise premature\n * comment terminators (`*\\/` → `* /`).\n */\nexport const JSDOC_TERMINATOR_PATTERN = /\\*\\//g\n\n/**\n * Matches carriage returns for normalising CRLF/CR line endings to LF.\n */\nexport const CARRIAGE_RETURN_PATTERN = /\\r/g\n\n/**\n * Matches CRLF sequences used when normalising TypeScript printer output.\n */\nexport const CRLF_PATTERN = /\\r\\n/g\n\n/**\n * Matches an identifier that starts with a digit — JavaScript disallows this\n * so the printer prefixes such names with `_`.\n */\nexport const LEADING_DIGIT_PATTERN = /^\\d/\n\n/**\n * Relative path prefix used to detect traversal segments (`../`).\n */\nexport const PARENT_DIRECTORY_PREFIX = '../' as const\n\n/**\n * Relative path prefix used when resolving imports within the output root.\n */\nexport const CURRENT_DIRECTORY_PREFIX = './' as const\n","import { normalize, relative } from 'node:path'\nimport type { ArrowFunctionNode, CodeNode, ConstNode, FileNode, FunctionNode, JSDocNode, JsxNode, SourceNode, TextNode, TypeNode } from '@kubb/ast'\nimport type { Parser } from '@kubb/core'\nimport { defineParser } from '@kubb/core'\nimport ts from 'typescript'\nimport {\n CARRIAGE_RETURN_PATTERN,\n CRLF_PATTERN,\n CURRENT_DIRECTORY_PREFIX,\n FILE_EXTENSION_PATTERN,\n INDENT_SIZE,\n JSDOC_TERMINATOR_PATTERN,\n LEADING_DIGIT_PATTERN,\n PARENT_DIRECTORY_PREFIX,\n WINDOWS_PATH_SEPARATOR,\n} from './constants.ts'\n\nconst { factory } = ts\n\nfunction slash(path: string): string {\n return normalize(path).replaceAll(WINDOWS_PATH_SEPARATOR, '/').replace(PARENT_DIRECTORY_PREFIX, '')\n}\n\n/**\n * Resolves `filePath` relative to `rootDir` and returns a POSIX-style path\n * prefixed with `./` when the target sits inside the root, or `../` when it escapes it.\n */\nfunction getRelativePath(rootDir: string, filePath: string): string {\n const rel = relative(rootDir, filePath)\n const slashed = slash(rel)\n return slashed.startsWith(PARENT_DIRECTORY_PREFIX) ? slashed : `${CURRENT_DIRECTORY_PREFIX}${slashed}`\n}\n\n/**\n * Strips the trailing file extension (for example `.ts`) from a path.\n * Preserves intermediate dots like `foo.bar.ts` → `foo.bar`.\n */\nfunction trimExtName(text: string): string {\n return text.replace(FILE_EXTENSION_PATTERN, '')\n}\n\n/**\n * Rewrites an import/export path so its extension matches the caller-supplied\n * `options.extname`. When the source path has no extension the original is kept,\n * so virtual/module-only paths flow through unchanged.\n */\nfunction resolveOutputPath(path: string, options: { extname?: string } | undefined, rootAware: boolean): string {\n const hasExtname = FILE_EXTENSION_PATTERN.test(path)\n if (options?.extname && hasExtname) {\n return `${trimExtName(path)}${options.extname}`\n }\n return rootAware ? trimExtName(path) : path\n}\n\n/**\n * Validates TypeScript AST nodes before printing.\n * Throws an error if any node has SyntaxKind.Unknown which would cause the\n * TypeScript printer to crash.\n */\nexport function validateNodes(...nodes: ts.Node[]): void {\n for (const node of nodes) {\n if (!node) {\n throw new Error('Attempted to print undefined or null TypeScript node')\n }\n if (node.kind === ts.SyntaxKind.Unknown) {\n throw new Error(\n 'Invalid TypeScript AST node detected with SyntaxKind.Unknown. ' +\n 'This typically indicates a schema pattern that could not be properly converted to TypeScript. ' +\n `Node: ${JSON.stringify(node, null, 2)}`,\n )\n }\n }\n}\n\n/**\n * Converts TypeScript/TSX AST nodes to a string using the TypeScript printer.\n */\nexport function print(...elements: Array<ts.Node>): string {\n const sourceFile = ts.createSourceFile('print.tsx', '', ts.ScriptTarget.ES2022, true, ts.ScriptKind.TSX)\n\n const printer = ts.createPrinter({\n omitTrailingSemicolon: true,\n newLine: ts.NewLineKind.LineFeed,\n removeComments: false,\n noEmitHelpers: true,\n })\n\n const output = printer.printList(ts.ListFormat.MultiLine, factory.createNodeArray(elements.filter(Boolean)), sourceFile)\n\n return output.replace(CRLF_PATTERN, '\\n')\n}\n\n/**\n * Like `print` but validates nodes first to surface issues early.\n */\nexport function safePrint(...elements: Array<ts.Node>): string {\n validateNodes(...elements)\n return print(...elements)\n}\n\nexport function createImport({\n name,\n path,\n root,\n isTypeOnly = false,\n isNameSpace = false,\n}: {\n name: string | Array<string | { propertyName: string; name?: string }>\n path: string\n root?: string\n /** @default false */\n isTypeOnly?: boolean\n /** @default false */\n isNameSpace?: boolean\n}): ts.ImportDeclaration {\n const resolvePath = root ? getRelativePath(root, path) : path\n\n if (!Array.isArray(name)) {\n if (isNameSpace) {\n return factory.createImportDeclaration(\n undefined,\n factory.createImportClause(isTypeOnly, undefined, factory.createNamespaceImport(factory.createIdentifier(name))),\n factory.createStringLiteral(resolvePath),\n undefined,\n )\n }\n\n return factory.createImportDeclaration(\n undefined,\n factory.createImportClause(isTypeOnly, factory.createIdentifier(name), undefined),\n factory.createStringLiteral(resolvePath),\n undefined,\n )\n }\n\n const specifiers = name.map((item) => {\n if (typeof item === 'object') {\n const { propertyName, name: alias } = item\n return factory.createImportSpecifier(false, alias ? factory.createIdentifier(propertyName) : undefined, factory.createIdentifier(alias ?? propertyName))\n }\n return factory.createImportSpecifier(false, undefined, factory.createIdentifier(item))\n })\n\n return factory.createImportDeclaration(\n undefined,\n factory.createImportClause(isTypeOnly, undefined, factory.createNamedImports(specifiers)),\n factory.createStringLiteral(resolvePath),\n undefined,\n )\n}\n\nexport function createExport({\n path,\n asAlias,\n isTypeOnly = false,\n name,\n}: {\n path: string\n /** @default false */\n asAlias?: boolean\n /** @default false */\n isTypeOnly?: boolean\n name?: string | Array<ts.Identifier | string>\n}): ts.ExportDeclaration {\n if (name && !Array.isArray(name) && !asAlias) {\n console.warn(`When using name as string, asAlias should be true: ${name}`)\n }\n\n if (!Array.isArray(name)) {\n const parsedName = name && LEADING_DIGIT_PATTERN.test(name) ? `_${name.slice(1)}` : name\n\n return factory.createExportDeclaration(\n undefined,\n isTypeOnly,\n asAlias && parsedName ? factory.createNamespaceExport(factory.createIdentifier(parsedName)) : undefined,\n factory.createStringLiteral(path),\n undefined,\n )\n }\n\n return factory.createExportDeclaration(\n undefined,\n isTypeOnly,\n factory.createNamedExports(\n name.map((propertyName) =>\n factory.createExportSpecifier(false, undefined, typeof propertyName === 'string' ? factory.createIdentifier(propertyName) : propertyName),\n ),\n ),\n factory.createStringLiteral(path),\n undefined,\n )\n}\n\n/**\n * Converts a {@link JSDocNode} to a JSDoc comment block string.\n *\n * @example\n * ```ts\n * printJSDoc({ comments: ['@description A pet', '@deprecated'] })\n * // /**\n * // * @description A pet\n * // * @deprecated\n * // *\\/\n * ```\n */\nexport function printJSDoc(jsDoc: JSDocNode): string {\n const comments = (jsDoc.comments ?? []).filter((c) => c != null)\n if (comments.length === 0) return ''\n\n const lines = comments\n .flatMap((c) => c.split(/\\r?\\n/))\n .map((l) => l.replace(JSDOC_TERMINATOR_PATTERN, '* /').replace(CARRIAGE_RETURN_PATTERN, ''))\n .filter((l) => l.trim().length > 0)\n\n if (lines.length === 0) return ''\n\n return ['/**', ...lines.map((l) => ` * ${l}`), ' */'].join('\\n')\n}\n\n/**\n * Serializes the body / value content from a `nodes` array.\n *\n * Each element is either a raw string or a structured {@link CodeNode}\n * (recursively converted via {@link printCodeNode}).\n * Elements are joined with `\\n`.\n */\nfunction printNodes(nodes: Array<CodeNode> | undefined): string {\n if (!nodes || nodes.length === 0) return ''\n return nodes.map(printCodeNode).join('\\n')\n}\n\n/**\n * Indents every non-empty line of `text` by `spaces` spaces.\n */\nfunction indentLines(text: string, spaces: number = INDENT_SIZE): string {\n if (!text) return ''\n const pad = ' '.repeat(spaces)\n return text\n .split('\\n')\n .map((line) => (line.trim() ? `${pad}${line}` : ''))\n .join('\\n')\n}\n\n/**\n * Renders the generic clause (`<T, U>`) shared by function and arrow-function nodes.\n * Accepts either a raw string (rendered verbatim) or an array of type-parameter names.\n */\nfunction formatGenerics(generics: FunctionNode['generics'] | ArrowFunctionNode['generics']): string {\n if (!generics) return ''\n return `<${Array.isArray(generics) ? generics.join(', ') : generics}>`\n}\n\n/**\n * Renders the return-type suffix (`: T` or `: Promise<T>` when `isAsync` is true).\n * Returns an empty string when no return type is provided.\n */\nfunction formatReturnType(returnType: string | undefined, isAsync: boolean | undefined): string {\n if (!returnType) return ''\n return isAsync ? `: Promise<${returnType}>` : `: ${returnType}`\n}\n\n/**\n * Converts a {@link ConstNode} to a TypeScript `const` declaration string.\n *\n * Mirrors the `Const` component from `@kubb/renderer-jsx`.\n *\n * @example\n * ```ts\n * printConst(createConst({ name: 'pet', export: true, nodes: ['{}'] }))\n * // 'export const pet = {}'\n * ```\n *\n * @example With type and `as const`\n * ```ts\n * printConst(createConst({ name: 'pets', export: true, type: 'Pet[]', asConst: true, nodes: ['[]'] }))\n * // 'export const pets: Pet[] = [] as const'\n * ```\n */\nexport function printConst(node: ConstNode): string {\n const { name, export: canExport, type, JSDoc, asConst, nodes } = node\n\n const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''\n const body = printNodes(nodes)\n\n const parts: string[] = []\n if (canExport) parts.push('export ')\n parts.push('const ')\n parts.push(name)\n if (type) {\n parts.push(`: ${type}`)\n }\n parts.push(' = ')\n parts.push(body)\n if (asConst) parts.push(' as const')\n\n const declaration = parts.join('')\n return [jsDocStr, declaration].filter(Boolean).join('\\n')\n}\n\n/**\n * Converts a {@link TypeNode} to a TypeScript `type` alias declaration string.\n *\n * Mirrors the `Type` component from `@kubb/renderer-jsx`.\n *\n * @example\n * ```ts\n * printType(createType({ name: 'Pet', export: true, nodes: ['{ id: number }'] }))\n * // 'export type Pet = { id: number }'\n * ```\n */\nexport function printType(node: TypeNode): string {\n const { name, export: canExport, JSDoc, nodes } = node\n\n const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''\n const body = printNodes(nodes)\n\n const parts: string[] = []\n if (canExport) parts.push('export ')\n parts.push('type ')\n parts.push(name)\n parts.push(' = ')\n parts.push(body)\n\n const declaration = parts.join('')\n return [jsDocStr, declaration].filter(Boolean).join('\\n')\n}\n\n/**\n * Converts a {@link FunctionNode} to a TypeScript `function` declaration string.\n *\n * Mirrors the `Function` component from `@kubb/renderer-jsx`.\n *\n * @example\n * ```ts\n * printFunction(createFunction({ name: 'getPet', export: true, params: 'id: string', returnType: 'Pet', nodes: ['return fetch(id)'] }))\n * // 'export function getPet(id: string): Pet {\\n return fetch(id)\\n}'\n * ```\n *\n * @example Async with generics\n * ```ts\n * printFunction(createFunction({ name: 'fetchPet', export: true, async: true, generics: ['T'], params: 'id: string', returnType: 'T' }))\n * // 'export async function fetchPet<T>(id: string): Promise<T> {\\n}'\n * ```\n */\nexport function printFunction(node: FunctionNode): string {\n const { name, default: isDefault, export: canExport, async: isAsync, generics, params, returnType, JSDoc, nodes } = node\n\n const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''\n const body = printNodes(nodes)\n const indented = body ? indentLines(body) : ''\n\n const parts: string[] = []\n if (canExport) parts.push('export ')\n if (isDefault) parts.push('default ')\n if (isAsync) parts.push('async ')\n parts.push('function ')\n parts.push(name)\n parts.push(formatGenerics(generics))\n parts.push(`(${params ?? ''})`)\n parts.push(formatReturnType(returnType, isAsync))\n parts.push(' {')\n if (indented) {\n parts.push(`\\n${indented}\\n`)\n }\n parts.push('}')\n\n const declaration = parts.join('')\n return [jsDocStr, declaration].filter(Boolean).join('\\n')\n}\n\n/**\n * Converts an {@link ArrowFunctionNode} to a TypeScript arrow function declaration string.\n *\n * Mirrors the `Function.Arrow` component from `@kubb/renderer-jsx`.\n *\n * @example Multi-line arrow function\n * ```ts\n * printArrowFunction(createArrowFunction({ name: 'getPet', export: true, params: 'id: string', nodes: ['return fetch(id)'] }))\n * // 'export const getPet = (id: string) => {\\n return fetch(id)\\n}'\n * ```\n *\n * @example Single-line arrow function\n * ```ts\n * printArrowFunction(createArrowFunction({ name: 'double', params: 'n: number', singleLine: true, nodes: ['n * 2'] }))\n * // 'const double = (n: number) => n * 2'\n * ```\n */\nexport function printArrowFunction(node: ArrowFunctionNode): string {\n const { name, default: isDefault, export: canExport, async: isAsync, generics, params, returnType, JSDoc, nodes, singleLine } = node\n\n const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''\n const body = printNodes(nodes)\n const arrowBody = singleLine ? ` => ${body}` : body ? ` => {\\n${indentLines(body)}\\n}` : ' => {}'\n\n const parts: string[] = []\n if (canExport) parts.push('export ')\n if (isDefault) parts.push('default ')\n parts.push('const ')\n parts.push(name)\n parts.push(' = ')\n if (isAsync) parts.push('async ')\n parts.push(formatGenerics(generics))\n parts.push(`(${params ?? ''})`)\n parts.push(formatReturnType(returnType, isAsync))\n parts.push(arrowBody)\n\n const declaration = parts.join('')\n return [jsDocStr, declaration].filter(Boolean).join('\\n')\n}\n\n/**\n * Converts a {@link CodeNode} to its TypeScript string representation.\n *\n * Dispatches to the appropriate printer based on the node's `kind`.\n *\n * @example\n * ```ts\n * printCodeNode(createConst({ name: 'x', nodes: ['1'] }))\n * // 'const x = 1'\n * ```\n */\nexport function printCodeNode(node: CodeNode): string {\n switch (node.kind) {\n case 'Break':\n return ''\n case 'Text':\n return (node as TextNode).value\n case 'Jsx':\n return (node as JsxNode).value\n case 'Const':\n return printConst(node)\n case 'Type':\n return printType(node)\n case 'Function':\n return printFunction(node)\n case 'ArrowFunction':\n return printArrowFunction(node)\n }\n}\n\n/**\n * Converts a {@link SourceNode} to its TypeScript string representation.\n *\n * Iterates `nodes` in DOM order, rendering each {@link CodeNode} via\n * {@link printCodeNode}.\n *\n * @example From nodes\n * ```ts\n * printSource({ kind: 'Source', nodes: [createConst({ name: 'x', nodes: [createText('1')] }), createText('x.toString()')] })\n * // 'const x = 1\\nx.toString()'\n * ```\n */\nexport function printSource(node: SourceNode): string {\n if (node.nodes && node.nodes.length > 0) {\n return node.nodes.map(printCodeNode).join('\\n')\n }\n return ''\n}\n\n/**\n * Parser that converts `.ts` and `.js` files to strings using the TypeScript\n * compiler. Handles import/export statement generation from file metadata.\n *\n * @default Used automatically when no `parsers` option is set in `defineConfig`.\n */\nexport const parserTs: Parser = defineParser({\n name: 'typescript',\n extNames: ['.ts', '.js'],\n async parse(file, options = { extname: '.ts' }) {\n const sourceParts: Array<string> = []\n for (const item of file.sources) {\n const sourceStr = printSource(item as SourceNode)\n if (sourceStr) {\n sourceParts.push(sourceStr.trimEnd())\n }\n }\n const source = sourceParts.join('\\n\\n')\n\n const importNodes: Array<ts.ImportDeclaration> = []\n for (const item of (file as FileNode).imports) {\n const importPath = item.root ? getRelativePath(item.root, item.path) : item.path\n importNodes.push(\n createImport({\n name: item.name as string | Array<string | { propertyName: string; name?: string }>,\n path: resolveOutputPath(importPath, options, Boolean(item.root)),\n isTypeOnly: item.isTypeOnly,\n isNameSpace: item.isNameSpace,\n }),\n )\n }\n\n const exportNodes: Array<ts.ExportDeclaration> = []\n for (const item of (file as FileNode).exports) {\n exportNodes.push(\n createExport({\n name: item.name as string | Array<ts.Identifier | string> | undefined,\n path: resolveOutputPath(item.path, options, true),\n isTypeOnly: item.isTypeOnly,\n asAlias: item.asAlias,\n }),\n )\n }\n\n const parts = [file.banner, print(...importNodes, ...exportNodes), source, file.footer]\n .filter((segment): segment is string => Boolean(segment))\n .map((s) => s.trimEnd())\n return parts.join('\\n\\n')\n },\n})\n","import type { Parser } from '@kubb/core'\nimport { defineParser } from '@kubb/core'\nimport { parserTs } from './parserTs.ts'\n\n/**\n * Parser that converts `.tsx` and `.jsx` files to strings.\n * Delegates to `typescriptParser` since the TypeScript compiler natively\n * supports JSX/TSX syntax via `ScriptKind.TSX`.\n *\n * Add this parser to the `parsers` option in `defineConfig` when generating `.tsx`/`.jsx` files.\n *\n * @default extname '.tsx'\n */\nexport const parserTsx: Parser = defineParser({\n name: 'tsx',\n extNames: ['.tsx', '.jsx'],\n async parse(file, options = { extname: '.tsx' }) {\n return parserTs.parse(file, options)\n },\n})\n"],"mappings":"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"}
{"version":3,"file":"index.js","names":[],"sources":["../../../internals/utils/src/fs.ts","../src/constants.ts","../src/utils.ts","../src/parserTs.ts","../src/parserTsx.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { access, mkdir, readFile, rm, writeFile } from 'node:fs/promises'\nimport { dirname, join, posix, resolve } from 'node:path'\nimport { camelCase } from './casing.ts'\nimport { runtime } from './runtime.ts'\n\n/**\n * Walks up the directory tree from `cwd` (defaults to `process.cwd()`) and\n * returns the absolute path of the nearest `package.json`, or `null` when none\n * is found before reaching the filesystem root.\n *\n * @example\n * ```ts\n * const pkgPath = findPackageJSON('/home/user/project/src') // '/home/user/project/package.json'\n * ```\n */\nexport function findPackageJSON(cwd?: string): string | null {\n let dir = cwd ? resolve(cwd) : process.cwd()\n while (true) {\n const pkgPath = join(dir, 'package.json')\n if (existsSync(pkgPath)) return pkgPath\n const parent = dirname(dir)\n if (parent === dir) return null\n dir = parent\n }\n}\n\n/**\n * Converts all backslashes to forward slashes.\n * Extended-length Windows paths (`\\\\?\\...`) are left unchanged.\n */\nfunction toSlash(p: string): string {\n if (p.startsWith('\\\\\\\\?\\\\')) return p\n\n return p.replaceAll('\\\\', '/')\n}\n\n/**\n * Returns the relative path from `rootDir` to `filePath`, always using forward slashes\n * and prefixed with `./` when not already traversing upward.\n *\n * @example\n * ```ts\n * getRelativePath('/src/components', '/src/components/Button.tsx') // './Button.tsx'\n * getRelativePath('/src/components', '/src/utils/helpers.ts') // '../utils/helpers.ts'\n * ```\n */\nexport function getRelativePath(rootDir?: string | null, filePath?: string | null): string {\n if (!rootDir || !filePath) {\n throw new Error(`Root and file should be filled in when retrieving the relativePath, ${rootDir || ''} ${filePath || ''}`)\n }\n\n const relativePath = posix.relative(toSlash(rootDir), toSlash(filePath))\n\n return relativePath.startsWith('../') ? relativePath : `./${relativePath}`\n}\n\n/**\n * Resolves to `true` when the file or directory at `path` exists.\n * Uses `Bun.file().exists()` when running under Bun, `fs.access` otherwise.\n *\n * @example\n * ```ts\n * if (await exists('./kubb.config.ts')) {\n * const content = await read('./kubb.config.ts')\n * }\n * ```\n */\nexport async function exists(path: string): Promise<boolean> {\n if (runtime.isBun) {\n return Bun.file(path).exists()\n }\n return access(path).then(\n () => true,\n () => false,\n )\n}\n\n/**\n * Reads the file at `path` as a UTF-8 string.\n * Uses `Bun.file().text()` when running under Bun, `fs.readFile` otherwise.\n *\n * @example\n * ```ts\n * const source = await read('./src/Pet.ts')\n * ```\n */\nexport async function read(path: string): Promise<string> {\n if (runtime.isBun) {\n return Bun.file(path).text()\n }\n return readFile(path, { encoding: 'utf8' })\n}\n\ntype WriteOptions = {\n /**\n * When `true`, re-reads the file immediately after writing and throws if the\n * content does not match — useful for catching write failures on unreliable file systems.\n */\n sanity?: boolean\n}\n\n/**\n * Writes `data` to `path`, trimming leading/trailing whitespace before saving.\n * Skips the write when the trimmed content is empty or identical to what is already on disk.\n * Creates any missing parent directories automatically.\n * When `sanity` is `true`, re-reads the file after writing and throws if the content does not match.\n *\n * @example\n * ```ts\n * await write('./src/Pet.ts', source) // writes and returns trimmed content\n * await write('./src/Pet.ts', source) // null — file unchanged\n * await write('./src/Pet.ts', ' ') // null — empty content skipped\n * ```\n */\nexport async function write(path: string, data: string, options: WriteOptions = {}): Promise<string | null> {\n const trimmed = data.trim()\n if (trimmed === '') return null\n\n const resolved = resolve(path)\n\n if (runtime.isBun) {\n const file = Bun.file(resolved)\n const oldContent = (await file.exists()) ? await file.text() : null\n if (oldContent === trimmed) return null\n await Bun.write(resolved, trimmed)\n return trimmed\n }\n\n try {\n const oldContent = await readFile(resolved, { encoding: 'utf-8' })\n if (oldContent === trimmed) return null\n } catch {\n /* file doesn't exist yet */\n }\n\n await mkdir(dirname(resolved), { recursive: true })\n await writeFile(resolved, trimmed, { encoding: 'utf-8' })\n\n if (options.sanity) {\n const savedData = await readFile(resolved, { encoding: 'utf-8' })\n if (savedData !== trimmed) {\n throw new Error(`Sanity check failed for ${path}\\n\\nData[${data.length}]:\\n${data}\\n\\nSaved[${savedData.length}]:\\n${savedData}\\n`)\n }\n return savedData\n }\n\n return trimmed\n}\n\n/**\n * Recursively removes `path`. Silently succeeds when `path` does not exist.\n *\n * @example\n * ```ts\n * await clean('./dist')\n * ```\n */\nexport async function clean(path: string): Promise<void> {\n return rm(path, { recursive: true, force: true })\n}\n\n/**\n * Converts a filesystem path to use POSIX (`/`) separators.\n *\n * Most of the codebase compares and composes paths as strings (prefix matching, joining for\n * import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated\n * paths, but on Windows it returns `\\`-separated paths, which breaks every such comparison.\n *\n * Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the\n * code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is\n * exercisable from POSIX CI.\n *\n * @example\n * toPosixPath('C:\\\\repo\\\\src\\\\pet.ts') // 'C:/repo/src/pet.ts'\n */\nexport function toPosixPath(filePath: string): string {\n return filePath.replaceAll('\\\\', '/')\n}\n\n/**\n * Strips the file extension from a path or file name.\n * Only removes the last `.ext` segment when the dot is not part of a directory name.\n *\n * @example\n * trimExtName('petStore.ts') // 'petStore'\n * trimExtName('/src/models/pet.ts') // '/src/models/pet'\n * trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet'\n * trimExtName('noExtension') // 'noExtension'\n */\nexport function trimExtName(text: string): string {\n const dotIndex = text.lastIndexOf('.')\n if (dotIndex > 0 && !text.includes('/', dotIndex)) {\n return text.slice(0, dotIndex)\n }\n return text\n}\n\n/**\n * Builds a nested file path from a dotted name. Splits on dots that precede a letter\n * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases\n * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.\n *\n * Empty segments are dropped before joining. They arise when the name starts with a dot\n * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to\n * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an\n * absolute path, letting generated files escape the configured output directory.\n *\n * @example Nested path from a dotted name\n * `toFilePath('pet.petId') // 'pet/petId'`\n *\n * @example PascalCase the final segment\n * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`\n *\n * @example Suffix applied to the final segment only\n * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`\n */\nexport function toFilePath(name: string, caseLast: (part: string) => string = camelCase): string {\n const parts = name.split(/\\.(?=[a-zA-Z])/)\n return parts\n .map((part, i) => (i === parts.length - 1 ? caseLast(part) : camelCase(part)))\n .filter(Boolean)\n .join('/')\n}\n","/**\n * Character used for a single indent step. Set to `'\\t'` to emit tab-indented output.\n */\nexport const INDENT_CHAR = ' '\n\n/**\n * Number of {@link INDENT_CHAR} repeats that make up one nesting level.\n */\nconst INDENT_SIZE = 2 as const\n\n/**\n * Indentation unit prepended once per nesting level when pretty-printing.\n */\nexport const INDENT = INDENT_CHAR.repeat(INDENT_SIZE)\n\n/**\n * Matches only the final `.<ext>` of a path, so a name like `foo.bar.ts` keeps\n * `foo.bar` and loses just `.ts`.\n */\nexport const FILE_EXTENSION_PATTERN = /\\.[^/.]+$/\n\n/**\n * Matches Windows-style backslash path separators.\n */\nexport const WINDOWS_PATH_SEPARATOR = /\\\\/g\n\n/**\n * Matches `*\\/` in free-form text so JSDoc bodies can neutralize premature\n * comment terminators (`*\\/` → `* /`).\n */\nexport const JSDOC_TERMINATOR_PATTERN = /\\*\\//g\n\n/**\n * Matches carriage returns for normalizing CRLF/CR line endings to LF.\n */\nexport const CARRIAGE_RETURN_PATTERN = /\\r/g\n\n/**\n * Matches CRLF sequences used when normalizing TypeScript printer output.\n */\nexport const CRLF_PATTERN = /\\r\\n/g\n\n/**\n * Matches an identifier that starts with a digit. JavaScript disallows this,\n * so the printer replaces the leading digit with `_`.\n */\nexport const LEADING_DIGIT_PATTERN = /^\\d/\n\n/**\n * Relative path prefix used to detect traversal segments (`../`).\n */\nexport const PARENT_DIRECTORY_PREFIX = '../' as const\n\n/**\n * Relative path prefix used when resolving imports within the output root.\n */\nexport const CURRENT_DIRECTORY_PREFIX = './' as const\n","import { normalize, relative } from 'node:path'\nimport { trimExtName } from '@internals/utils'\nimport type { ArrowFunctionNode, CodeNode, ConstNode, FunctionNode, JSDocNode, JsxNode, SourceNode, TextNode, TypeNode } from '@kubb/ast'\nimport ts from 'typescript'\nimport {\n CARRIAGE_RETURN_PATTERN,\n CRLF_PATTERN,\n CURRENT_DIRECTORY_PREFIX,\n FILE_EXTENSION_PATTERN,\n INDENT,\n INDENT_CHAR,\n JSDOC_TERMINATOR_PATTERN,\n LEADING_DIGIT_PATTERN,\n PARENT_DIRECTORY_PREFIX,\n WINDOWS_PATH_SEPARATOR,\n} from './constants.ts'\n\nconst { factory } = ts\n\n/**\n * Normalizes a file-system path to POSIX separators and strips any leading `../` segment.\n */\nexport function slash(path: string): string {\n return normalize(path).replaceAll(WINDOWS_PATH_SEPARATOR, '/').replace(PARENT_DIRECTORY_PREFIX, '')\n}\n\n/**\n * Resolves `filePath` relative to `rootDir` and returns a POSIX-style path\n * prefixed with `./` when the target sits inside the root, or `../` when it escapes it.\n */\nexport function getRelativePath(rootDir: string, filePath: string): string {\n const rel = relative(rootDir, filePath)\n const slashed = slash(rel)\n return slashed.startsWith(PARENT_DIRECTORY_PREFIX) ? slashed : `${CURRENT_DIRECTORY_PREFIX}${slashed}`\n}\n\n/**\n * Rewrites an import/export path so its extension matches the caller-supplied\n * `options.extname`. When the source path has no extension the original is kept,\n * so virtual/module-only paths flow through unchanged.\n */\nexport function resolveOutputPath(path: string, options: { extname?: string } | undefined, rootAware: boolean): string {\n const hasExtname = FILE_EXTENSION_PATTERN.test(path)\n if (options?.extname && hasExtname) {\n return `${trimExtName(path)}${options.extname}`\n }\n return rootAware ? trimExtName(path) : path\n}\n\n/**\n * Serializes a `nodes` array into source text. Each entry is rendered via {@link printCodeNode}\n * and joined with a single newline. A `Break` node (`<br/>`) inserts one blank line between\n * statements. Consecutive breaks, and breaks at the very start or end, are folded into the\n * separator, so a double `<br/>` never emits more than one blank line.\n */\nexport function printNodes(nodes: Array<CodeNode> | undefined): string {\n if (!nodes || nodes.length === 0) return ''\n\n let result = ''\n let hasContent = false\n let pendingBreak = false\n\n for (const node of nodes) {\n if (node.kind === 'Break') {\n if (hasContent) pendingBreak = true\n continue\n }\n\n const text = printCodeNode(node)\n if (!text) continue\n\n if (hasContent) result += pendingBreak ? '\\n\\n' : '\\n'\n result += text\n hasContent = true\n pendingBreak = false\n }\n\n return result\n}\n\n/**\n * Indents every non-empty line of `text` by one indent unit. Pass a number to repeat\n * {@link INDENT_CHAR} that many times, or a string to use as the indent verbatim.\n */\nexport function indentLines(text: string, indent: number | string = INDENT): string {\n if (!text) return ''\n const pad = typeof indent === 'string' ? indent : INDENT_CHAR.repeat(indent)\n return text\n .split('\\n')\n .map((line) => (line.trim() ? `${pad}${line}` : ''))\n .join('\\n')\n}\n\n/**\n * Removes the common leading whitespace shared by every non-blank line and trims\n * surrounding blank lines, so multi-line content authored inside an indented template\n * literal lines up at a column-zero baseline. Leading whitespace is counted by\n * character, so N tabs and N spaces are treated as the same depth.\n *\n * @example\n * ```ts\n * dedent('\\n foo\\n bar\\n ')\n * // 'foo\\n bar'\n * ```\n */\nexport function dedent(text: string): string {\n if (!text) return ''\n\n const lines = text.split('\\n')\n const isBlank = (line: string) => line.trim() === ''\n\n const start = lines.findIndex((line) => !isBlank(line))\n if (start === -1) return ''\n const end = lines.findLastIndex((line) => !isBlank(line))\n\n const trimmed = lines.slice(start, end + 1)\n const indents = trimmed.filter((line) => !isBlank(line)).map((line) => line.match(/^\\s*/)?.[0].length ?? 0)\n const min = indents.length ? Math.min(...indents) : 0\n\n return trimmed.map((line) => (isBlank(line) ? '' : line.slice(min))).join('\\n')\n}\n\n/**\n * Renders the generic clause (`<T, U>`) shared by function and arrow-function nodes.\n * Accepts either a raw string (rendered verbatim) or an array of type-parameter names.\n */\nexport function formatGenerics(generics: FunctionNode['generics'] | ArrowFunctionNode['generics']): string {\n if (!generics) return ''\n return `<${Array.isArray(generics) ? generics.join(', ') : generics}>`\n}\n\n/**\n * Renders the return-type suffix (`: T` or `: Promise<T>` when `isAsync` is true).\n * Returns an empty string when no return type is provided.\n */\nexport function formatReturnType(returnType: string | null | undefined, isAsync: boolean | null | undefined): string {\n if (!returnType) return ''\n return isAsync ? `: Promise<${returnType}>` : `: ${returnType}`\n}\n\n/**\n * Module-scoped TypeScript printer instance. A printer does not mutate the source file, so one\n * instance is reused across every `print()` call instead of constructing a new printer each time.\n */\nconst TS_PRINTER = ts.createPrinter({\n omitTrailingSemicolon: true,\n newLine: ts.NewLineKind.LineFeed,\n removeComments: false,\n noEmitHelpers: true,\n})\n\n/**\n * Module-scoped source file used as the print target. `printList` only reads the source\n * file's compiler options / language version. It never mutates it.\n */\nconst PRINT_SOURCE_FILE = ts.createSourceFile('print.tsx', '', ts.ScriptTarget.ES2022, true, ts.ScriptKind.TSX)\n\n// Pre-warm the printer at module load. The first `printList` call lazily initializes\n// the printer's internal string-builder and identifier tables. Doing it once at import\n// time keeps that cost off the critical path for short-lived CLI builds.\nTS_PRINTER.printList(ts.ListFormat.MultiLine, factory.createNodeArray([]), PRINT_SOURCE_FILE)\n\n/**\n * Converts TypeScript/TSX AST nodes to a string using the TypeScript printer.\n */\nexport function print(...elements: Array<ts.Node>): string {\n const filtered = elements.filter(Boolean)\n if (filtered.length === 0) return ''\n\n const output = TS_PRINTER.printList(ts.ListFormat.MultiLine, factory.createNodeArray(filtered), PRINT_SOURCE_FILE)\n\n return output.replace(CRLF_PATTERN, '\\n')\n}\n\n/**\n * Converts a {@link JSDocNode} to a JSDoc comment block string.\n *\n * @example\n * ```ts\n * printJSDoc({ comments: ['@description A pet', '@deprecated'] })\n * // /**\n * // * @description A pet\n * // * @deprecated\n * // *\\/\n * ```\n */\nexport function printJSDoc(jsDoc: JSDocNode): string {\n const comments = (jsDoc.comments ?? []).filter((c) => c != null)\n if (comments.length === 0) return ''\n\n const lines = comments\n .flatMap((c) => c.split(/\\r?\\n/))\n .map((l) => l.replace(JSDOC_TERMINATOR_PATTERN, '* /').replace(CARRIAGE_RETURN_PATTERN, ''))\n .filter((l) => l.trim().length > 0)\n\n if (lines.length === 0) return ''\n\n return ['/**', ...lines.map((l) => ` * ${l}`), ' */'].join('\\n')\n}\n\n/**\n * Converts a {@link ConstNode} to a TypeScript `const` declaration string.\n *\n * Mirrors the `Const` component from `@kubb/renderer-jsx`.\n *\n * @example\n * ```ts\n * printConst(factory.createConst({ name: 'pet', export: true, nodes: ['{}'] }))\n * // 'export const pet = {}'\n * ```\n *\n * @example With type and `as const`\n * ```ts\n * printConst(factory.createConst({ name: 'pets', export: true, type: 'Pet[]', asConst: true, nodes: ['[]'] }))\n * // 'export const pets: Pet[] = [] as const'\n * ```\n */\nexport function printConst(node: ConstNode): string {\n const { name, export: canExport, type, JSDoc, asConst, nodes } = node\n\n const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''\n const body = printNodes(nodes)\n\n const parts: Array<string> = []\n if (canExport) parts.push('export ')\n parts.push('const ')\n parts.push(name)\n if (type) {\n parts.push(`: ${type}`)\n }\n parts.push(' = ')\n parts.push(body)\n if (asConst) parts.push(' as const')\n\n const declaration = parts.join('')\n return [jsDocStr, declaration].filter(Boolean).join('\\n')\n}\n\n/**\n * Converts a {@link TypeNode} to a TypeScript `type` alias declaration string.\n *\n * Mirrors the `Type` component from `@kubb/renderer-jsx`.\n *\n * @example\n * ```ts\n * printType(factory.createType({ name: 'Pet', export: true, nodes: ['{ id: number }'] }))\n * // 'export type Pet = { id: number }'\n * ```\n */\nexport function printType(node: TypeNode): string {\n const { name, export: canExport, JSDoc, nodes } = node\n\n const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''\n const body = printNodes(nodes)\n\n const parts: Array<string> = []\n if (canExport) parts.push('export ')\n parts.push('type ')\n parts.push(name)\n parts.push(' = ')\n parts.push(body)\n\n const declaration = parts.join('')\n return [jsDocStr, declaration].filter(Boolean).join('\\n')\n}\n\n/**\n * Converts a {@link FunctionNode} to a TypeScript `function` declaration string.\n *\n * Mirrors the `Function` component from `@kubb/renderer-jsx`.\n *\n * @example\n * ```ts\n * printFunction(factory.createFunction({ name: 'getPet', export: true, params: 'id: string', returnType: 'Pet', nodes: ['return fetch(id)'] }))\n * // 'export function getPet(id: string): Pet {\\n return fetch(id)\\n}'\n * ```\n *\n * @example Async with generics\n * ```ts\n * printFunction(factory.createFunction({ name: 'fetchPet', export: true, async: true, generics: ['T'], params: 'id: string', returnType: 'T' }))\n * // 'export async function fetchPet<T>(id: string): Promise<T> {\\n}'\n * ```\n */\nexport function printFunction(node: FunctionNode): string {\n const { name, default: isDefault, export: canExport, async: isAsync, generics, params, returnType, JSDoc, nodes } = node\n\n const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''\n const body = printNodes(nodes)\n const indented = body ? indentLines(body) : ''\n\n const parts: Array<string> = []\n if (canExport) parts.push('export ')\n if (isDefault) parts.push('default ')\n if (isAsync) parts.push('async ')\n parts.push('function ')\n parts.push(name)\n parts.push(formatGenerics(generics))\n parts.push(`(${params ?? ''})`)\n parts.push(formatReturnType(returnType, isAsync))\n parts.push(' {')\n if (indented) {\n parts.push(`\\n${indented}\\n`)\n }\n parts.push('}')\n\n const declaration = parts.join('')\n return [jsDocStr, declaration].filter(Boolean).join('\\n')\n}\n\n/**\n * Converts an {@link ArrowFunctionNode} to a TypeScript arrow function declaration string.\n *\n * Mirrors the `Function.Arrow` component from `@kubb/renderer-jsx`.\n *\n * @example Multi-line arrow function\n * ```ts\n * printArrowFunction(factory.createArrowFunction({ name: 'getPet', export: true, params: 'id: string', nodes: ['return fetch(id)'] }))\n * // 'export const getPet = (id: string) => {\\n return fetch(id)\\n}'\n * ```\n *\n * @example Single-line arrow function\n * ```ts\n * printArrowFunction(factory.createArrowFunction({ name: 'double', params: 'n: number', singleLine: true, nodes: ['n * 2'] }))\n * // 'const double = (n: number) => n * 2'\n * ```\n */\nexport function printArrowFunction(node: ArrowFunctionNode): string {\n const { name, default: isDefault, export: canExport, async: isAsync, generics, params, returnType, JSDoc, nodes, singleLine } = node\n\n const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''\n const body = printNodes(nodes)\n const arrowBody = singleLine ? ` => ${body}` : body ? ` => {\\n${indentLines(body)}\\n}` : ' => {}'\n\n const parts: Array<string> = []\n if (canExport) parts.push('export ')\n if (isDefault) parts.push('default ')\n parts.push('const ')\n parts.push(name)\n parts.push(' = ')\n if (isAsync) parts.push('async ')\n parts.push(formatGenerics(generics))\n parts.push(`(${params ?? ''})`)\n parts.push(formatReturnType(returnType, isAsync))\n parts.push(arrowBody)\n\n const declaration = parts.join('')\n return [jsDocStr, declaration].filter(Boolean).join('\\n')\n}\n\n/**\n * Converts a {@link CodeNode} to its TypeScript string representation.\n *\n * Dispatches to the appropriate printer based on the node's `kind`.\n *\n * @example\n * ```ts\n * printCodeNode(factory.createConst({ name: 'x', nodes: ['1'] }))\n * // 'const x = 1'\n * ```\n */\nexport function printCodeNode(node: CodeNode): string {\n if (node.kind === 'Break') return ''\n if (node.kind === 'Text') return dedent((node as TextNode).value)\n if (node.kind === 'Jsx') return dedent((node as JsxNode).value)\n if (node.kind === 'Const') return printConst(node)\n if (node.kind === 'Type') return printType(node)\n if (node.kind === 'Function') return printFunction(node)\n if (node.kind === 'ArrowFunction') return printArrowFunction(node)\n return ''\n}\n\n/**\n * Converts a {@link SourceNode} to its TypeScript string representation.\n *\n * Iterates `nodes` in DOM order, rendering each {@link CodeNode} via\n * {@link printCodeNode}.\n *\n * Top-level declarations are separated by a blank line so the source reads\n * cleanly without an external formatter.\n *\n * @example From nodes\n * ```ts\n * printSource({ kind: 'Source', nodes: [factory.createConst({ name: 'x', nodes: [factory.createText('1')] }), factory.createText('x.toString()')] })\n * // 'const x = 1\\n\\nx.toString()'\n * ```\n */\nexport function printSource(node: SourceNode): string {\n const nodes = node.nodes\n\n if (!nodes || nodes.length === 0) return ''\n\n return nodes\n .map((child) => printCodeNode(child as CodeNode))\n .filter(Boolean)\n .join('\\n\\n')\n}\n\n/**\n * Wraps a module specifier in single quotes, escaping any embedded backslash or quote so the emitted\n * statement stays valid even for unusual paths.\n */\nfunction quoteModulePath(path: string): string {\n return `'${path.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\")}'`\n}\n\n/**\n * Renders an import declaration string in the repo style (single quotes, no semicolons), covering\n * default, namespace (`* as`), and named imports with `{ a as b }` aliases, each optionally\n * `type`-only. `path` is used verbatim, so resolve it first.\n *\n * @example\n * ```ts\n * printImport({ name: ['z'], path: './zod.ts' })\n * // \"import { z } from './zod.ts'\"\n * ```\n */\nexport function printImport({\n name,\n path,\n isTypeOnly = false,\n isNameSpace = false,\n}: {\n name: string | Array<string | { propertyName: string; name?: string }>\n path: string\n isTypeOnly?: boolean | null\n isNameSpace?: boolean | null\n}): string {\n const typePrefix = isTypeOnly ? 'type ' : ''\n const from = quoteModulePath(path)\n\n if (!Array.isArray(name)) {\n if (isNameSpace) return `import ${typePrefix}* as ${name} from ${from}`\n return `import ${typePrefix}${name} from ${from}`\n }\n\n const specifiers = name.map((item) => {\n if (typeof item === 'object') {\n return item.name ? `${item.propertyName} as ${item.name}` : item.propertyName\n }\n return item\n })\n\n return `import ${typePrefix}{ ${specifiers.join(', ')} } from ${from}`\n}\n\n/**\n * Renders an export declaration string in the repo style (single quotes, no semicolons), covering\n * named re-exports, namespace alias (`* as name`), and wildcard, each optionally `type`-only.\n * `path` is used verbatim, so resolve it first.\n *\n * @example\n * ```ts\n * printExport({ name: ['Pet', 'Order'], path: './models.ts' })\n * // \"export { Pet, Order } from './models.ts'\"\n * ```\n */\nexport function printExport({\n path,\n name,\n isTypeOnly = false,\n asAlias = false,\n}: {\n path: string\n name?: string | Array<ts.Identifier | string> | null\n isTypeOnly?: boolean | null\n asAlias?: boolean | null\n}): string {\n const typePrefix = isTypeOnly ? 'type ' : ''\n const from = quoteModulePath(path)\n\n if (Array.isArray(name)) {\n const specifiers = name.map((item) => (typeof item === 'string' ? item : item.text))\n return `export ${typePrefix}{ ${specifiers.join(', ')} } from ${from}`\n }\n\n if (asAlias && name) {\n const parsedName = LEADING_DIGIT_PATTERN.test(name) ? `_${name.slice(1)}` : name\n return `export ${typePrefix}* as ${parsedName} from ${from}`\n }\n\n if (name) {\n console.warn(`When using name as string, asAlias should be true: ${name}`)\n }\n\n return `export ${typePrefix}* from ${from}`\n}\n","import type { FileNode, SourceNode } from '@kubb/ast'\nimport { defineParser } from '@kubb/core'\nimport type * as ts from 'typescript'\nimport { getRelativePath, print, printExport, printImport, printSource, resolveOutputPath } from './utils.ts'\n\n/**\n * Default Kubb parser for `.ts` and `.js` files. Takes the universal AST\n * produced by an adapter and prints it as TypeScript source using the official\n * TypeScript compiler. Imports and exports are rewritten based on each file's\n * metadata.\n *\n * Used automatically when no `parsers` option is set on `defineConfig`. Use\n * `parserTsx` instead for React projects that emit JSX.\n *\n * @example\n * ```ts\n * import { defineConfig } from 'kubb'\n * import { adapterOas } from '@kubb/adapter-oas'\n * import { parserTs } from '@kubb/parser-ts'\n *\n * export default defineConfig({\n * input: { path: './petStore.yaml' },\n * output: { path: './src/gen' },\n * adapter: adapterOas(),\n * parsers: [parserTs],\n * plugins: [],\n * })\n * ```\n */\nexport const parserTs = defineParser({\n name: 'typescript',\n extNames: ['.ts', '.js'],\n print(...nodes: Array<ts.Node>) {\n return print(...nodes)\n },\n parse(file, options = { extname: '.ts' }) {\n const sourceParts: Array<string> = []\n for (const item of file.sources) {\n const sourceStr = printSource(item as SourceNode)\n if (sourceStr) {\n sourceParts.push(sourceStr.trimEnd())\n }\n }\n const source = sourceParts.join('\\n\\n')\n\n const importLines: Array<string> = []\n for (const item of (file as FileNode).imports) {\n const importPath = item.root ? getRelativePath(item.root, item.path) : item.path\n importLines.push(\n printImport({\n name: item.name as string | Array<string | { propertyName: string; name?: string }>,\n path: resolveOutputPath(importPath, options, Boolean(item.root)),\n isTypeOnly: item.isTypeOnly,\n isNameSpace: item.isNameSpace,\n }),\n )\n }\n\n const exportLines: Array<string> = []\n for (const item of (file as FileNode).exports) {\n exportLines.push(\n printExport({\n name: item.name as string | Array<ts.Identifier | string> | null | undefined,\n path: resolveOutputPath(item.path, options, true),\n isTypeOnly: item.isTypeOnly,\n asAlias: item.asAlias,\n }),\n )\n }\n\n const importExportBlock = [...importLines, ...exportLines].join('\\n')\n\n const parts = [file.banner, importExportBlock, source, file.footer].filter((segment): segment is string => Boolean(segment)).map((s) => s.trimEnd())\n\n return parts.join('\\n\\n')\n },\n})\n","import { defineParser } from '@kubb/core'\nimport type * as ts from 'typescript'\nimport { parserTs } from './parserTs.ts'\nimport { print } from './utils.ts'\n\n/**\n * Kubb parser for `.tsx` and `.jsx` files. Delegates to `parserTs` because the\n * TypeScript compiler handles JSX natively via `ScriptKind.TSX`.\n *\n * Add to the `parsers` array on `defineConfig` when generating components for\n * React (or any framework that emits JSX).\n *\n * @example\n * ```ts\n * import { defineConfig } from 'kubb'\n * import { adapterOas } from '@kubb/adapter-oas'\n * import { parserTsx } from '@kubb/parser-ts'\n *\n * export default defineConfig({\n * input: { path: './petStore.yaml' },\n * output: { path: './src/gen' },\n * adapter: adapterOas(),\n * parsers: [parserTsx],\n * plugins: [],\n * })\n * ```\n */\nexport const parserTsx = defineParser({\n name: 'tsx',\n extNames: ['.tsx', '.jsx'],\n print(...nodes: Array<ts.Node>) {\n return print(...nodes)\n },\n parse(file, options = { extname: '.tsx' }) {\n return parserTs.parse(file, options)\n },\n})\n"],"mappings":"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"}
+17
-10

@@ -0,14 +1,21 @@

MIT License
Copyright (c) 2026 Stijn Van Hulle
This repository contains software under two licenses:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
1. Most of the code in this repository is licensed under the
MIT License — see licenses/LICENSE-MIT for the full license text.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
2. The following components are licensed under the
GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later)
— see licenses/LICENSE-AGPL-3.0 for the full license text:
- packages/agent (published as @kubb/agent)
Each package's own LICENSE file or package.json specifies its applicable license.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
{
"name": "@kubb/parser-ts",
"version": "5.0.0-beta.75",
"description": "TypeScript and TSX file parser for Kubb, converting generated files to strings using the TypeScript compiler.",
"version": "5.0.0-beta.76",
"description": "TypeScript and TSX source file parser for Kubb. Converts AST nodes into formatted source strings using the TypeScript compiler API.",
"keywords": [
"code-generator",
"codegen",
"kubb",
"meta-framework",
"parser",

@@ -21,3 +21,2 @@ "tsx",

"files": [
"src",
"dist",

@@ -46,7 +45,7 @@ "!/**/**.test.**",

"typescript": "^6.0.3",
"@kubb/core": "5.0.0-beta.75"
"@kubb/core": "5.0.0-beta.76"
},
"devDependencies": {
"@internals/utils": "0.0.0",
"@kubb/ast": "5.0.0-beta.75"
"@kubb/ast": "5.0.0-beta.76"
},

@@ -58,3 +57,3 @@ "engines": {

"build": "tsdown",
"clean": "npx rimraf ./dist",
"clean": "node -e \"require('node:fs').rmSync('./dist', {recursive:true,force:true})\"",
"lint": "oxlint .",

@@ -64,2 +63,3 @@ "lint:fix": "oxlint --fix .",

"release:canary": "bash ../../.github/canary.sh && node ../../scripts/build.js canary && pnpm publish --no-git-check",
"release:stage": "pnpm stage publish --no-git-check",
"start": "tsdown --watch",

@@ -66,0 +66,0 @@ "test": "vitest --passWithNoTests",

//#region \0rolldown/runtime.js
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", {
value,
configurable: true
});
//#endregion
export { __name as t };
/**
* Number of spaces used to indent a nested block when pretty-printing.
*/
export const INDENT_SIZE = 2 as const
/**
* Matches the trailing `.<ext>` segment of a path (keeps segments like `foo.bar.ts`
* intact by only trimming the last run of non-`/`/`.` characters).
*/
export const FILE_EXTENSION_PATTERN = /\.[^/.]+$/
/**
* Matches Windows-style backslash path separators.
*/
export const WINDOWS_PATH_SEPARATOR = /\\/g
/**
* Matches `*\/` in free-form text so JSDoc bodies can neutralise premature
* comment terminators (`*\/` → `* /`).
*/
export const JSDOC_TERMINATOR_PATTERN = /\*\//g
/**
* Matches carriage returns for normalising CRLF/CR line endings to LF.
*/
export const CARRIAGE_RETURN_PATTERN = /\r/g
/**
* Matches CRLF sequences used when normalising TypeScript printer output.
*/
export const CRLF_PATTERN = /\r\n/g
/**
* Matches an identifier that starts with a digit — JavaScript disallows this
* so the printer prefixes such names with `_`.
*/
export const LEADING_DIGIT_PATTERN = /^\d/
/**
* Relative path prefix used to detect traversal segments (`../`).
*/
export const PARENT_DIRECTORY_PREFIX = '../' as const
/**
* Relative path prefix used when resolving imports within the output root.
*/
export const CURRENT_DIRECTORY_PREFIX = './' as const
export { createExport, createImport, parserTs, print, safePrint, validateNodes } from './parserTs.ts'
export { parserTsx } from './parserTsx.ts'
import { normalize, relative } from 'node:path'
import type { ArrowFunctionNode, CodeNode, ConstNode, FileNode, FunctionNode, JSDocNode, JsxNode, SourceNode, TextNode, TypeNode } from '@kubb/ast'
import type { Parser } from '@kubb/core'
import { defineParser } from '@kubb/core'
import ts from 'typescript'
import {
CARRIAGE_RETURN_PATTERN,
CRLF_PATTERN,
CURRENT_DIRECTORY_PREFIX,
FILE_EXTENSION_PATTERN,
INDENT_SIZE,
JSDOC_TERMINATOR_PATTERN,
LEADING_DIGIT_PATTERN,
PARENT_DIRECTORY_PREFIX,
WINDOWS_PATH_SEPARATOR,
} from './constants.ts'
const { factory } = ts
function slash(path: string): string {
return normalize(path).replaceAll(WINDOWS_PATH_SEPARATOR, '/').replace(PARENT_DIRECTORY_PREFIX, '')
}
/**
* Resolves `filePath` relative to `rootDir` and returns a POSIX-style path
* prefixed with `./` when the target sits inside the root, or `../` when it escapes it.
*/
function getRelativePath(rootDir: string, filePath: string): string {
const rel = relative(rootDir, filePath)
const slashed = slash(rel)
return slashed.startsWith(PARENT_DIRECTORY_PREFIX) ? slashed : `${CURRENT_DIRECTORY_PREFIX}${slashed}`
}
/**
* Strips the trailing file extension (for example `.ts`) from a path.
* Preserves intermediate dots like `foo.bar.ts` → `foo.bar`.
*/
function trimExtName(text: string): string {
return text.replace(FILE_EXTENSION_PATTERN, '')
}
/**
* Rewrites an import/export path so its extension matches the caller-supplied
* `options.extname`. When the source path has no extension the original is kept,
* so virtual/module-only paths flow through unchanged.
*/
function resolveOutputPath(path: string, options: { extname?: string } | undefined, rootAware: boolean): string {
const hasExtname = FILE_EXTENSION_PATTERN.test(path)
if (options?.extname && hasExtname) {
return `${trimExtName(path)}${options.extname}`
}
return rootAware ? trimExtName(path) : path
}
/**
* Validates TypeScript AST nodes before printing.
* Throws an error if any node has SyntaxKind.Unknown which would cause the
* TypeScript printer to crash.
*/
export function validateNodes(...nodes: ts.Node[]): void {
for (const node of nodes) {
if (!node) {
throw new Error('Attempted to print undefined or null TypeScript node')
}
if (node.kind === ts.SyntaxKind.Unknown) {
throw new Error(
'Invalid TypeScript AST node detected with SyntaxKind.Unknown. ' +
'This typically indicates a schema pattern that could not be properly converted to TypeScript. ' +
`Node: ${JSON.stringify(node, null, 2)}`,
)
}
}
}
/**
* Converts TypeScript/TSX AST nodes to a string using the TypeScript printer.
*/
export function print(...elements: Array<ts.Node>): string {
const sourceFile = ts.createSourceFile('print.tsx', '', ts.ScriptTarget.ES2022, true, ts.ScriptKind.TSX)
const printer = ts.createPrinter({
omitTrailingSemicolon: true,
newLine: ts.NewLineKind.LineFeed,
removeComments: false,
noEmitHelpers: true,
})
const output = printer.printList(ts.ListFormat.MultiLine, factory.createNodeArray(elements.filter(Boolean)), sourceFile)
return output.replace(CRLF_PATTERN, '\n')
}
/**
* Like `print` but validates nodes first to surface issues early.
*/
export function safePrint(...elements: Array<ts.Node>): string {
validateNodes(...elements)
return print(...elements)
}
export function createImport({
name,
path,
root,
isTypeOnly = false,
isNameSpace = false,
}: {
name: string | Array<string | { propertyName: string; name?: string }>
path: string
root?: string
/** @default false */
isTypeOnly?: boolean
/** @default false */
isNameSpace?: boolean
}): ts.ImportDeclaration {
const resolvePath = root ? getRelativePath(root, path) : path
if (!Array.isArray(name)) {
if (isNameSpace) {
return factory.createImportDeclaration(
undefined,
factory.createImportClause(isTypeOnly, undefined, factory.createNamespaceImport(factory.createIdentifier(name))),
factory.createStringLiteral(resolvePath),
undefined,
)
}
return factory.createImportDeclaration(
undefined,
factory.createImportClause(isTypeOnly, factory.createIdentifier(name), undefined),
factory.createStringLiteral(resolvePath),
undefined,
)
}
const specifiers = name.map((item) => {
if (typeof item === 'object') {
const { propertyName, name: alias } = item
return factory.createImportSpecifier(false, alias ? factory.createIdentifier(propertyName) : undefined, factory.createIdentifier(alias ?? propertyName))
}
return factory.createImportSpecifier(false, undefined, factory.createIdentifier(item))
})
return factory.createImportDeclaration(
undefined,
factory.createImportClause(isTypeOnly, undefined, factory.createNamedImports(specifiers)),
factory.createStringLiteral(resolvePath),
undefined,
)
}
export function createExport({
path,
asAlias,
isTypeOnly = false,
name,
}: {
path: string
/** @default false */
asAlias?: boolean
/** @default false */
isTypeOnly?: boolean
name?: string | Array<ts.Identifier | string>
}): ts.ExportDeclaration {
if (name && !Array.isArray(name) && !asAlias) {
console.warn(`When using name as string, asAlias should be true: ${name}`)
}
if (!Array.isArray(name)) {
const parsedName = name && LEADING_DIGIT_PATTERN.test(name) ? `_${name.slice(1)}` : name
return factory.createExportDeclaration(
undefined,
isTypeOnly,
asAlias && parsedName ? factory.createNamespaceExport(factory.createIdentifier(parsedName)) : undefined,
factory.createStringLiteral(path),
undefined,
)
}
return factory.createExportDeclaration(
undefined,
isTypeOnly,
factory.createNamedExports(
name.map((propertyName) =>
factory.createExportSpecifier(false, undefined, typeof propertyName === 'string' ? factory.createIdentifier(propertyName) : propertyName),
),
),
factory.createStringLiteral(path),
undefined,
)
}
/**
* Converts a {@link JSDocNode} to a JSDoc comment block string.
*
* @example
* ```ts
* printJSDoc({ comments: ['@description A pet', '@deprecated'] })
* // /**
* // * @description A pet
* // * @deprecated
* // *\/
* ```
*/
export function printJSDoc(jsDoc: JSDocNode): string {
const comments = (jsDoc.comments ?? []).filter((c) => c != null)
if (comments.length === 0) return ''
const lines = comments
.flatMap((c) => c.split(/\r?\n/))
.map((l) => l.replace(JSDOC_TERMINATOR_PATTERN, '* /').replace(CARRIAGE_RETURN_PATTERN, ''))
.filter((l) => l.trim().length > 0)
if (lines.length === 0) return ''
return ['/**', ...lines.map((l) => ` * ${l}`), ' */'].join('\n')
}
/**
* Serializes the body / value content from a `nodes` array.
*
* Each element is either a raw string or a structured {@link CodeNode}
* (recursively converted via {@link printCodeNode}).
* Elements are joined with `\n`.
*/
function printNodes(nodes: Array<CodeNode> | undefined): string {
if (!nodes || nodes.length === 0) return ''
return nodes.map(printCodeNode).join('\n')
}
/**
* Indents every non-empty line of `text` by `spaces` spaces.
*/
function indentLines(text: string, spaces: number = INDENT_SIZE): string {
if (!text) return ''
const pad = ' '.repeat(spaces)
return text
.split('\n')
.map((line) => (line.trim() ? `${pad}${line}` : ''))
.join('\n')
}
/**
* Renders the generic clause (`<T, U>`) shared by function and arrow-function nodes.
* Accepts either a raw string (rendered verbatim) or an array of type-parameter names.
*/
function formatGenerics(generics: FunctionNode['generics'] | ArrowFunctionNode['generics']): string {
if (!generics) return ''
return `<${Array.isArray(generics) ? generics.join(', ') : generics}>`
}
/**
* Renders the return-type suffix (`: T` or `: Promise<T>` when `isAsync` is true).
* Returns an empty string when no return type is provided.
*/
function formatReturnType(returnType: string | undefined, isAsync: boolean | undefined): string {
if (!returnType) return ''
return isAsync ? `: Promise<${returnType}>` : `: ${returnType}`
}
/**
* Converts a {@link ConstNode} to a TypeScript `const` declaration string.
*
* Mirrors the `Const` component from `@kubb/renderer-jsx`.
*
* @example
* ```ts
* printConst(createConst({ name: 'pet', export: true, nodes: ['{}'] }))
* // 'export const pet = {}'
* ```
*
* @example With type and `as const`
* ```ts
* printConst(createConst({ name: 'pets', export: true, type: 'Pet[]', asConst: true, nodes: ['[]'] }))
* // 'export const pets: Pet[] = [] as const'
* ```
*/
export function printConst(node: ConstNode): string {
const { name, export: canExport, type, JSDoc, asConst, nodes } = node
const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''
const body = printNodes(nodes)
const parts: string[] = []
if (canExport) parts.push('export ')
parts.push('const ')
parts.push(name)
if (type) {
parts.push(`: ${type}`)
}
parts.push(' = ')
parts.push(body)
if (asConst) parts.push(' as const')
const declaration = parts.join('')
return [jsDocStr, declaration].filter(Boolean).join('\n')
}
/**
* Converts a {@link TypeNode} to a TypeScript `type` alias declaration string.
*
* Mirrors the `Type` component from `@kubb/renderer-jsx`.
*
* @example
* ```ts
* printType(createType({ name: 'Pet', export: true, nodes: ['{ id: number }'] }))
* // 'export type Pet = { id: number }'
* ```
*/
export function printType(node: TypeNode): string {
const { name, export: canExport, JSDoc, nodes } = node
const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''
const body = printNodes(nodes)
const parts: string[] = []
if (canExport) parts.push('export ')
parts.push('type ')
parts.push(name)
parts.push(' = ')
parts.push(body)
const declaration = parts.join('')
return [jsDocStr, declaration].filter(Boolean).join('\n')
}
/**
* Converts a {@link FunctionNode} to a TypeScript `function` declaration string.
*
* Mirrors the `Function` component from `@kubb/renderer-jsx`.
*
* @example
* ```ts
* printFunction(createFunction({ name: 'getPet', export: true, params: 'id: string', returnType: 'Pet', nodes: ['return fetch(id)'] }))
* // 'export function getPet(id: string): Pet {\n return fetch(id)\n}'
* ```
*
* @example Async with generics
* ```ts
* printFunction(createFunction({ name: 'fetchPet', export: true, async: true, generics: ['T'], params: 'id: string', returnType: 'T' }))
* // 'export async function fetchPet<T>(id: string): Promise<T> {\n}'
* ```
*/
export function printFunction(node: FunctionNode): string {
const { name, default: isDefault, export: canExport, async: isAsync, generics, params, returnType, JSDoc, nodes } = node
const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''
const body = printNodes(nodes)
const indented = body ? indentLines(body) : ''
const parts: string[] = []
if (canExport) parts.push('export ')
if (isDefault) parts.push('default ')
if (isAsync) parts.push('async ')
parts.push('function ')
parts.push(name)
parts.push(formatGenerics(generics))
parts.push(`(${params ?? ''})`)
parts.push(formatReturnType(returnType, isAsync))
parts.push(' {')
if (indented) {
parts.push(`\n${indented}\n`)
}
parts.push('}')
const declaration = parts.join('')
return [jsDocStr, declaration].filter(Boolean).join('\n')
}
/**
* Converts an {@link ArrowFunctionNode} to a TypeScript arrow function declaration string.
*
* Mirrors the `Function.Arrow` component from `@kubb/renderer-jsx`.
*
* @example Multi-line arrow function
* ```ts
* printArrowFunction(createArrowFunction({ name: 'getPet', export: true, params: 'id: string', nodes: ['return fetch(id)'] }))
* // 'export const getPet = (id: string) => {\n return fetch(id)\n}'
* ```
*
* @example Single-line arrow function
* ```ts
* printArrowFunction(createArrowFunction({ name: 'double', params: 'n: number', singleLine: true, nodes: ['n * 2'] }))
* // 'const double = (n: number) => n * 2'
* ```
*/
export function printArrowFunction(node: ArrowFunctionNode): string {
const { name, default: isDefault, export: canExport, async: isAsync, generics, params, returnType, JSDoc, nodes, singleLine } = node
const jsDocStr = JSDoc ? printJSDoc(JSDoc) : ''
const body = printNodes(nodes)
const arrowBody = singleLine ? ` => ${body}` : body ? ` => {\n${indentLines(body)}\n}` : ' => {}'
const parts: string[] = []
if (canExport) parts.push('export ')
if (isDefault) parts.push('default ')
parts.push('const ')
parts.push(name)
parts.push(' = ')
if (isAsync) parts.push('async ')
parts.push(formatGenerics(generics))
parts.push(`(${params ?? ''})`)
parts.push(formatReturnType(returnType, isAsync))
parts.push(arrowBody)
const declaration = parts.join('')
return [jsDocStr, declaration].filter(Boolean).join('\n')
}
/**
* Converts a {@link CodeNode} to its TypeScript string representation.
*
* Dispatches to the appropriate printer based on the node's `kind`.
*
* @example
* ```ts
* printCodeNode(createConst({ name: 'x', nodes: ['1'] }))
* // 'const x = 1'
* ```
*/
export function printCodeNode(node: CodeNode): string {
switch (node.kind) {
case 'Break':
return ''
case 'Text':
return (node as TextNode).value
case 'Jsx':
return (node as JsxNode).value
case 'Const':
return printConst(node)
case 'Type':
return printType(node)
case 'Function':
return printFunction(node)
case 'ArrowFunction':
return printArrowFunction(node)
}
}
/**
* Converts a {@link SourceNode} to its TypeScript string representation.
*
* Iterates `nodes` in DOM order, rendering each {@link CodeNode} via
* {@link printCodeNode}.
*
* @example From nodes
* ```ts
* printSource({ kind: 'Source', nodes: [createConst({ name: 'x', nodes: [createText('1')] }), createText('x.toString()')] })
* // 'const x = 1\nx.toString()'
* ```
*/
export function printSource(node: SourceNode): string {
if (node.nodes && node.nodes.length > 0) {
return node.nodes.map(printCodeNode).join('\n')
}
return ''
}
/**
* Parser that converts `.ts` and `.js` files to strings using the TypeScript
* compiler. Handles import/export statement generation from file metadata.
*
* @default Used automatically when no `parsers` option is set in `defineConfig`.
*/
export const parserTs: Parser = defineParser({
name: 'typescript',
extNames: ['.ts', '.js'],
async parse(file, options = { extname: '.ts' }) {
const sourceParts: Array<string> = []
for (const item of file.sources) {
const sourceStr = printSource(item as SourceNode)
if (sourceStr) {
sourceParts.push(sourceStr.trimEnd())
}
}
const source = sourceParts.join('\n\n')
const importNodes: Array<ts.ImportDeclaration> = []
for (const item of (file as FileNode).imports) {
const importPath = item.root ? getRelativePath(item.root, item.path) : item.path
importNodes.push(
createImport({
name: item.name as string | Array<string | { propertyName: string; name?: string }>,
path: resolveOutputPath(importPath, options, Boolean(item.root)),
isTypeOnly: item.isTypeOnly,
isNameSpace: item.isNameSpace,
}),
)
}
const exportNodes: Array<ts.ExportDeclaration> = []
for (const item of (file as FileNode).exports) {
exportNodes.push(
createExport({
name: item.name as string | Array<ts.Identifier | string> | undefined,
path: resolveOutputPath(item.path, options, true),
isTypeOnly: item.isTypeOnly,
asAlias: item.asAlias,
}),
)
}
const parts = [file.banner, print(...importNodes, ...exportNodes), source, file.footer]
.filter((segment): segment is string => Boolean(segment))
.map((s) => s.trimEnd())
return parts.join('\n\n')
},
})
import type { Parser } from '@kubb/core'
import { defineParser } from '@kubb/core'
import { parserTs } from './parserTs.ts'
/**
* Parser that converts `.tsx` and `.jsx` files to strings.
* Delegates to `typescriptParser` since the TypeScript compiler natively
* supports JSX/TSX syntax via `ScriptKind.TSX`.
*
* Add this parser to the `parsers` option in `defineConfig` when generating `.tsx`/`.jsx` files.
*
* @default extname '.tsx'
*/
export const parserTsx: Parser = defineParser({
name: 'tsx',
extNames: ['.tsx', '.jsx'],
async parse(file, options = { extname: '.tsx' }) {
return parserTs.parse(file, options)
},
})