@kubb/parser-ts
Advanced tools
| //#region \0rolldown/runtime.js | ||
| var __defProp = Object.defineProperty; | ||
| var __name = (target, value) => __defProp(target, "name", { | ||
| value, | ||
| configurable: true | ||
| }); | ||
| //#endregion | ||
| export { __name as t }; |
+111
| <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":"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"} | ||
| {"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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"} |
+60
-55
@@ -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 |
+247
-130
@@ -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. |
+7
-7
| { | ||
| "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' |
-509
| 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) | ||
| }, | ||
| }) |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Copyleft License
LicenseCopyleft license information was found.
Mixed license
LicensePackage contains multiple licenses.
Non-permissive License
LicenseA license not known to be considered permissive was found.
121914
16.28%0
-100%100
42.86%0
-100%112
Infinity%9
-25%1132
-20.28%1
Infinity%+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
Updated