@kubb/core
Advanced tools
Sorry, the diff of this file is too big to display
| import "./rolldown-runtime-C0LytTxp.js"; | ||
| import { mkdir, readFile, rm, writeFile } from "node:fs/promises"; | ||
| import { dirname, resolve } from "node:path"; | ||
| import { ast, extractStringsFromNodes } from "@kubb/ast"; | ||
| import { EventEmitter } from "node:events"; | ||
| //#region ../../internals/utils/src/casing.ts | ||
| /** | ||
| * Shared implementation for camelCase and PascalCase conversion. | ||
| * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons) | ||
| * and capitalizes each word according to `pascal`. | ||
| * | ||
| * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are. | ||
| */ | ||
| function toCamelOrPascal(text, pascal) { | ||
| return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => { | ||
| if (word.length > 1 && word === word.toUpperCase()) return word; | ||
| return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1); | ||
| }).join("").replace(/[^a-zA-Z0-9]/g, ""); | ||
| } | ||
| /** | ||
| * Converts `text` to camelCase. | ||
| * | ||
| * @example Word boundaries | ||
| * `camelCase('hello-world') // 'helloWorld'` | ||
| * | ||
| * @example With a prefix | ||
| * `camelCase('tag', { prefix: 'create' }) // 'createTag'` | ||
| */ | ||
| function camelCase(text, { prefix = "", suffix = "" } = {}) { | ||
| return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/errors.ts | ||
| /** | ||
| * Thrown when one or more errors occur during a Kubb build. | ||
| * Carries the full list of underlying errors on `errors`. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * throw new BuildError('Build failed', { errors: [err1, err2] }) | ||
| * ``` | ||
| */ | ||
| var BuildError = class extends Error { | ||
| errors; | ||
| constructor(message, options) { | ||
| super(message, { cause: options.cause }); | ||
| this.name = "BuildError"; | ||
| this.errors = options.errors; | ||
| } | ||
| }; | ||
| /** | ||
| * Coerces an unknown thrown value to an `Error` instance. | ||
| * Returns the value as-is when it is already an `Error`; otherwise wraps it with `String(value)`. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * try { ... } catch(err) { | ||
| * throw new BuildError('Build failed', { cause: toError(err), errors: [] }) | ||
| * } | ||
| * ``` | ||
| */ | ||
| function toError(value) { | ||
| return value instanceof Error ? value : new Error(String(value)); | ||
| } | ||
| /** | ||
| * Extracts a human-readable message from any thrown value. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * getErrorMessage(new Error('oops')) // 'oops' | ||
| * getErrorMessage('plain string') // 'plain string' | ||
| * ``` | ||
| */ | ||
| function getErrorMessage(value) { | ||
| return value instanceof Error ? value.message : String(value); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/runtime.ts | ||
| /** | ||
| * Detects the JavaScript runtime executing the current process and exposes its name and version. | ||
| * | ||
| * Prefer the shared {@link runtime} instance over constructing your own. | ||
| */ | ||
| var Runtime = class { | ||
| /** | ||
| * `true` when the current process is running under Bun. | ||
| * | ||
| * Detection keys off the global `Bun` object rather than `process.versions`, | ||
| * because Bun polyfills `process.versions.node` for Node compatibility and would | ||
| * otherwise look like Node. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * if (runtime.isBun) { | ||
| * await Bun.write(path, data) | ||
| * } | ||
| * ``` | ||
| */ | ||
| get isBun() { | ||
| return typeof Bun !== "undefined"; | ||
| } | ||
| /** | ||
| * `true` when the current process is running under Deno. | ||
| */ | ||
| get isDeno() { | ||
| return typeof globalThis.Deno !== "undefined"; | ||
| } | ||
| /** | ||
| * `true` when the current process is running under Node. | ||
| * | ||
| * Bun and Deno are excluded first so a polyfilled `process` does not register as Node. | ||
| */ | ||
| get isNode() { | ||
| return !this.isBun && !this.isDeno && typeof process !== "undefined" && process.versions?.node != null; | ||
| } | ||
| /** | ||
| * Name of the runtime executing the current process. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * runtime.name // 'bun' when run with `bun kubb`, 'node' otherwise | ||
| * ``` | ||
| */ | ||
| get name() { | ||
| if (this.isBun) return "bun"; | ||
| if (this.isDeno) return "deno"; | ||
| return "node"; | ||
| } | ||
| /** | ||
| * Version of the active runtime, or an empty string when it cannot be read. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * runtime.version // '1.3.11' under Bun, '22.22.2' under Node | ||
| * ``` | ||
| */ | ||
| get version() { | ||
| if (this.isBun) return process.versions.bun ?? ""; | ||
| if (this.isDeno) return globalThis.Deno?.version?.deno ?? ""; | ||
| return process.versions?.node ?? ""; | ||
| } | ||
| }; | ||
| /** | ||
| * Shared {@link Runtime} instance describing the JavaScript runtime executing the current process. | ||
| */ | ||
| const runtime = new Runtime(); | ||
| //#endregion | ||
| //#region ../../internals/utils/src/fs.ts | ||
| /** | ||
| * Reads the file at `path` as a UTF-8 string. | ||
| * Uses `Bun.file().text()` when running under Bun, `fs.readFile` otherwise. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const source = await read('./src/Pet.ts') | ||
| * ``` | ||
| */ | ||
| async function read(path) { | ||
| if (runtime.isBun) return Bun.file(path).text(); | ||
| return readFile(path, { encoding: "utf8" }); | ||
| } | ||
| /** | ||
| * Writes `data` to `path`, trimming leading/trailing whitespace before saving. | ||
| * Skips the write when the trimmed content is empty or identical to what is already on disk. | ||
| * Creates any missing parent directories automatically. | ||
| * When `sanity` is `true`, re-reads the file after writing and throws if the content does not match. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * await write('./src/Pet.ts', source) // writes and returns trimmed content | ||
| * await write('./src/Pet.ts', source) // null — file unchanged | ||
| * await write('./src/Pet.ts', ' ') // null — empty content skipped | ||
| * ``` | ||
| */ | ||
| async function write(path, data, options = {}) { | ||
| const trimmed = data.trim(); | ||
| if (trimmed === "") return null; | ||
| const resolved = resolve(path); | ||
| if (runtime.isBun) { | ||
| const file = Bun.file(resolved); | ||
| if ((await file.exists() ? await file.text() : null) === trimmed) return null; | ||
| await Bun.write(resolved, trimmed); | ||
| return trimmed; | ||
| } | ||
| try { | ||
| if (await readFile(resolved, { encoding: "utf-8" }) === trimmed) return null; | ||
| } catch {} | ||
| await mkdir(dirname(resolved), { recursive: true }); | ||
| await writeFile(resolved, trimmed, { encoding: "utf-8" }); | ||
| if (options.sanity) { | ||
| const savedData = await readFile(resolved, { encoding: "utf-8" }); | ||
| if (savedData !== trimmed) throw new Error(`Sanity check failed for ${path}\n\nData[${data.length}]:\n${data}\n\nSaved[${savedData.length}]:\n${savedData}\n`); | ||
| return savedData; | ||
| } | ||
| return trimmed; | ||
| } | ||
| /** | ||
| * Recursively removes `path`. Silently succeeds when `path` does not exist. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * await clean('./dist') | ||
| * ``` | ||
| */ | ||
| async function clean(path) { | ||
| return rm(path, { | ||
| recursive: true, | ||
| force: true | ||
| }); | ||
| } | ||
| /** | ||
| * Converts a filesystem path to use POSIX (`/`) separators. | ||
| * | ||
| * Most of the codebase compares and composes paths as strings (prefix matching, joining for | ||
| * import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated | ||
| * paths, but on Windows it returns `\`-separated paths, which breaks every such comparison. | ||
| * | ||
| * Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the | ||
| * code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is | ||
| * exercisable from POSIX CI. | ||
| * | ||
| * @example | ||
| * toPosixPath('C:\\repo\\src\\pet.ts') // 'C:/repo/src/pet.ts' | ||
| */ | ||
| function toPosixPath(filePath) { | ||
| return filePath.replaceAll("\\", "/"); | ||
| } | ||
| /** | ||
| * Builds a nested file path from a dotted name. Splits on dots that precede a letter | ||
| * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases | ||
| * every earlier segment, applies `caseLast` to the final segment, and joins with `/`. | ||
| * | ||
| * Empty segments are dropped before joining. They arise when the name starts with a dot | ||
| * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to | ||
| * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an | ||
| * absolute path, letting generated files escape the configured output directory. | ||
| * | ||
| * @example Nested path from a dotted name | ||
| * `toFilePath('pet.petId') // 'pet/petId'` | ||
| * | ||
| * @example PascalCase the final segment | ||
| * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'` | ||
| * | ||
| * @example Suffix applied to the final segment only | ||
| * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'` | ||
| */ | ||
| function toFilePath(name, caseLast = camelCase) { | ||
| const parts = name.split(/\.(?=[a-zA-Z])/); | ||
| return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/"); | ||
| } | ||
| //#endregion | ||
| //#region src/Hookable.ts | ||
| /** | ||
| * Typed hook emitter that awaits all async listeners before resolving. | ||
| * Wraps Node's `EventEmitter` with full TypeScript hook-map inference. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const hooks = new Hookable<{ build: [name: string] }>() | ||
| * hooks.hook('build', async (name) => { console.log(name) }) | ||
| * await hooks.callHook('build', 'petstore') // all listeners awaited | ||
| * ``` | ||
| */ | ||
| var Hookable = class { | ||
| /** | ||
| * Maximum number of listeners per hook before Node emits a memory-leak warning. | ||
| * @default 10 | ||
| */ | ||
| constructor(maxListener = 10) { | ||
| this.#emitter.setMaxListeners(maxListener); | ||
| } | ||
| #emitter = new EventEmitter(); | ||
| /** | ||
| * Calls `hookName` and awaits all registered listeners sequentially. | ||
| * Throws if any listener rejects, wrapping the cause with the hook name and serialized arguments. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * await hooks.callHook('build', 'petstore') | ||
| * ``` | ||
| */ | ||
| callHook(hookName, ...hookArgs) { | ||
| const listeners = this.#emitter.listeners(hookName); | ||
| if (listeners.length === 0) return; | ||
| return this.#emitAll(hookName, listeners, hookArgs); | ||
| } | ||
| async #emitAll(hookName, listeners, hookArgs) { | ||
| for (const listener of listeners) try { | ||
| await listener(...hookArgs); | ||
| } catch (err) { | ||
| let serializedArgs; | ||
| try { | ||
| serializedArgs = JSON.stringify(hookArgs); | ||
| } catch { | ||
| serializedArgs = String(hookArgs); | ||
| } | ||
| throw new Error(`Error in async listener for "${hookName}" with hookArgs ${serializedArgs}`, { cause: toError(err) }); | ||
| } | ||
| } | ||
| /** | ||
| * Registers a persistent listener for `hookName` and returns a function that removes it. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const unhook = hooks.hook('build', async (name) => { console.log(name) }) | ||
| * unhook() // removes it | ||
| * ``` | ||
| */ | ||
| hook(hookName, handler) { | ||
| this.#emitter.on(hookName, handler); | ||
| return () => this.removeHook(hookName, handler); | ||
| } | ||
| /** | ||
| * Registers every handler in `configHooks` at once and returns a function that removes them | ||
| * all. Undefined entries are skipped, so a partial hook object registers only its present keys. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const unhook = hooks.addHooks({ build: onBuild, done: onDone }) | ||
| * unhook() // removes both | ||
| * ``` | ||
| */ | ||
| addHooks(configHooks) { | ||
| const unhooks = Object.keys(configHooks).filter((name) => configHooks[name]).map((name) => this.hook(name, configHooks[name])); | ||
| return () => { | ||
| for (const unhook of unhooks) unhook(); | ||
| }; | ||
| } | ||
| /** | ||
| * Removes a previously registered listener. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * hooks.removeHook('build', handler) | ||
| * ``` | ||
| */ | ||
| removeHook(hookName, handler) { | ||
| this.#emitter.off(hookName, handler); | ||
| } | ||
| /** | ||
| * Returns the number of listeners registered for `hookName`. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * hooks.hook('build', handler) | ||
| * hooks.listenerCount('build') // 1 | ||
| * ``` | ||
| */ | ||
| listenerCount(hookName) { | ||
| return this.#emitter.listenerCount(hookName); | ||
| } | ||
| /** | ||
| * Raises or lowers the per-hook listener ceiling before Node warns about a memory leak. | ||
| * Set this above the expected listener count when many listeners attach by design. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * hooks.setMaxListeners(40) | ||
| * ``` | ||
| */ | ||
| setMaxListeners(max) { | ||
| this.#emitter.setMaxListeners(max); | ||
| } | ||
| /** | ||
| * Removes all listeners from every hook channel. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * hooks.removeAllHooks() | ||
| * ``` | ||
| */ | ||
| removeAllHooks() { | ||
| this.#emitter.removeAllListeners(); | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region src/FileManager.ts | ||
| function joinSources(file) { | ||
| return file.sources.map((source) => extractStringsFromNodes(source.nodes)).filter(Boolean).join("\n\n"); | ||
| } | ||
| async function parseCopy(file) { | ||
| let content; | ||
| try { | ||
| content = await read(file.copy); | ||
| } catch (err) { | ||
| throw new Error(`[kubb] Could not copy file into output: ${file.copy}`, { cause: err }); | ||
| } | ||
| return [ | ||
| file.banner, | ||
| content, | ||
| file.footer | ||
| ].filter((segment) => Boolean(segment)).map((segment) => segment.trimEnd()).join("\n"); | ||
| } | ||
| function mergeFile(a, b) { | ||
| return { | ||
| ...a, | ||
| banner: b.banner, | ||
| footer: b.footer, | ||
| copy: b.copy ?? a.copy, | ||
| sources: a.sources.length ? b.sources.length ? [...a.sources, ...b.sources] : a.sources : b.sources, | ||
| imports: a.imports.length ? b.imports.length ? [...a.imports, ...b.imports] : a.imports : b.imports, | ||
| exports: a.exports.length ? b.exports.length ? [...a.exports, ...b.exports] : a.exports : b.exports | ||
| }; | ||
| } | ||
| function isIndexPath(path) { | ||
| return path.endsWith("/index.ts") || path === "index.ts"; | ||
| } | ||
| function compareFiles(a, b) { | ||
| const lenDiff = a.path.length - b.path.length; | ||
| if (lenDiff !== 0) return lenDiff; | ||
| const aIsIndex = isIndexPath(a.path); | ||
| const bIsIndex = isIndexPath(b.path); | ||
| if (aIsIndex && !bIsIndex) return 1; | ||
| if (!aIsIndex && bIsIndex) return -1; | ||
| return 0; | ||
| } | ||
| /** | ||
| * In-memory file store for generated files, and the writer that turns them into source | ||
| * strings on `storage`. Files sharing a `path` are merged (sources/imports/exports | ||
| * concatenated). The `files` getter is sorted by path length (barrel `index.ts` last | ||
| * within a bucket). | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const manager = new FileManager() | ||
| * manager.upsert(myFile) | ||
| * manager.files // sorted view | ||
| * await manager.write(manager.files, { storage: fsStorage() }) | ||
| * ``` | ||
| */ | ||
| var FileManager = class { | ||
| hooks = new Hookable(); | ||
| #cache = /* @__PURE__ */ new Map(); | ||
| #sorted = null; | ||
| add(...files) { | ||
| return this.#store(files, false); | ||
| } | ||
| upsert(...files) { | ||
| return this.#store(files, true); | ||
| } | ||
| #store(files, mergeExisting) { | ||
| const batch = files.length > 1 ? this.#dedupe(files) : files; | ||
| const resolved = []; | ||
| for (const file of batch) { | ||
| const existing = this.#cache.get(file.path); | ||
| const merged = existing && mergeExisting ? ast.factory.createFile(mergeFile(existing, file)) : ast.factory.createFile(file); | ||
| this.#cache.set(merged.path, merged); | ||
| resolved.push(merged); | ||
| } | ||
| if (resolved.length > 0) this.#sorted = null; | ||
| return resolved; | ||
| } | ||
| #dedupe(files) { | ||
| const seen = /* @__PURE__ */ new Map(); | ||
| for (const file of files) { | ||
| const prev = seen.get(file.path); | ||
| seen.set(file.path, prev ? mergeFile(prev, file) : file); | ||
| } | ||
| return [...seen.values()]; | ||
| } | ||
| clear() { | ||
| this.#cache.clear(); | ||
| this.#sorted = null; | ||
| } | ||
| /** | ||
| * Releases all stored files and clears every `hooks` listener. Called by the core after | ||
| * `kubb:build:end`. | ||
| */ | ||
| dispose() { | ||
| this.clear(); | ||
| this.hooks.removeAllHooks(); | ||
| } | ||
| /** | ||
| * All stored files in stable sort order (shortest path first, barrel files | ||
| * last within a length bucket). Returns a cached view, do not mutate. | ||
| */ | ||
| get files() { | ||
| return this.#sorted ??= [...this.#cache.values()].sort(compareFiles); | ||
| } | ||
| /** | ||
| * Converts a file's AST sources (or its `copy` source) into the final on-disk string. | ||
| */ | ||
| async parse(file, { parsers } = {}) { | ||
| if (file.copy) return parseCopy(file); | ||
| if (!parsers || !file.extname) return joinSources(file); | ||
| const parser = parsers.get(file.extname); | ||
| if (!parser) return joinSources(file); | ||
| return parser.parse(file); | ||
| } | ||
| /** | ||
| * Converts and writes every file at once, letting `storage.setItem` decide how much of | ||
| * that runs concurrently. | ||
| */ | ||
| async write(files, { storage, parsers }) { | ||
| if (files.length === 0) return; | ||
| await this.hooks.callHook("start", files); | ||
| const total = files.length; | ||
| let processed = 0; | ||
| await Promise.all(files.map(async (file) => { | ||
| const source = await this.parse(file, { parsers }); | ||
| processed++; | ||
| await this.hooks.callHook("update", { | ||
| file, | ||
| source, | ||
| processed, | ||
| total, | ||
| percentage: processed / total * 100 | ||
| }); | ||
| if (source) await storage.setItem(file.path, source); | ||
| })); | ||
| await this.hooks.callHook("end", files); | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region \0@oxc-project+runtime@0.138.0/helpers/esm/usingCtx.js | ||
| function _usingCtx() { | ||
| var r = "function" == typeof SuppressedError ? SuppressedError : function(r, e) { | ||
| var n = Error(); | ||
| return n.name = "SuppressedError", n.error = r, n.suppressed = e, n; | ||
| }; | ||
| var e = {}; | ||
| var n = []; | ||
| function using(r, e) { | ||
| if (null != e) { | ||
| if (Object(e) !== e) throw new TypeError("using declarations can only be used with objects, functions, null, or undefined."); | ||
| if (r) var o = e[Symbol.asyncDispose || Symbol["for"]("Symbol.asyncDispose")]; | ||
| if (void 0 === o && (o = e[Symbol.dispose || Symbol["for"]("Symbol.dispose")], r)) var t = o; | ||
| if ("function" != typeof o) throw new TypeError("Object is not disposable."); | ||
| t && (o = function o() { | ||
| try { | ||
| t.call(e); | ||
| } catch (r) { | ||
| return Promise.reject(r); | ||
| } | ||
| }), n.push({ | ||
| v: e, | ||
| d: o, | ||
| a: r | ||
| }); | ||
| } else r && n.push({ | ||
| d: e, | ||
| a: r | ||
| }); | ||
| return e; | ||
| } | ||
| return { | ||
| e, | ||
| u: using.bind(null, !1), | ||
| a: using.bind(null, !0), | ||
| d: function d() { | ||
| var o; | ||
| var t = this.e; | ||
| var s = 0; | ||
| function next() { | ||
| for (; o = n.pop();) try { | ||
| if (!o.a && 1 === s) return s = 0, n.push(o), Promise.resolve().then(next); | ||
| if (o.d) { | ||
| var r = o.d.call(o.v); | ||
| if (o.a) return s |= 2, Promise.resolve(r).then(next, err); | ||
| } else s |= 1; | ||
| } catch (r) { | ||
| return err(r); | ||
| } | ||
| if (1 === s) return t !== e ? Promise.reject(t) : Promise.resolve(); | ||
| if (t !== e) throw t; | ||
| } | ||
| function err(n) { | ||
| return t = t !== e ? new r(n, t) : n, next(); | ||
| } | ||
| return next(); | ||
| } | ||
| }; | ||
| } | ||
| //#endregion | ||
| export { toFilePath as a, BuildError as c, camelCase as d, clean as i, getErrorMessage as l, FileManager as n, toPosixPath as o, Hookable as r, write as s, _usingCtx as t, toError as u }; | ||
| //# sourceMappingURL=usingCtx-BriKju-v.js.map |
| {"version":3,"file":"usingCtx-BriKju-v.js","names":["#emitter","NodeEventEmitter","#emitAll","#cache","#store","#dedupe","#sorted"],"sources":["../../../internals/utils/src/casing.ts","../../../internals/utils/src/errors.ts","../../../internals/utils/src/runtime.ts","../../../internals/utils/src/fs.ts","../src/Hookable.ts","../src/FileManager.ts"],"sourcesContent":["type Options = {\n /**\n * Text prepended before casing is applied.\n */\n prefix?: string\n /**\n * Text appended before casing is applied.\n */\n suffix?: string\n}\n\n/**\n * Shared implementation for camelCase and PascalCase conversion.\n * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)\n * and capitalizes each word according to `pascal`.\n *\n * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.\n */\nfunction toCamelOrPascal(text: string, pascal: boolean): string {\n return text\n .trim()\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/(\\d)([a-z])/g, '$1 $2')\n .split(/[\\s\\-_./\\\\:]+/)\n .filter(Boolean)\n .map((word, i) => {\n if (word.length > 1 && word === word.toUpperCase()) return word\n const head = i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()\n return head + word.slice(1)\n })\n .join('')\n .replace(/[^a-zA-Z0-9]/g, '')\n}\n\n/**\n * Converts `text` to camelCase.\n *\n * @example Word boundaries\n * `camelCase('hello-world') // 'helloWorld'`\n *\n * @example With a prefix\n * `camelCase('tag', { prefix: 'create' }) // 'createTag'`\n */\nexport function camelCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false)\n}\n\n/**\n * Converts `text` to PascalCase.\n *\n * @example Word boundaries\n * `pascalCase('hello-world') // 'HelloWorld'`\n *\n * @example With a suffix\n * `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`\n */\nexport function pascalCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true)\n}\n","/**\n * Thrown when one or more errors occur during a Kubb build.\n * Carries the full list of underlying errors on `errors`.\n *\n * @example\n * ```ts\n * throw new BuildError('Build failed', { errors: [err1, err2] })\n * ```\n */\nexport class BuildError extends Error {\n errors: Array<Error>\n\n constructor(message: string, options: { cause?: Error; errors: Array<Error> }) {\n super(message, { cause: options.cause })\n this.name = 'BuildError'\n this.errors = options.errors\n }\n}\n\n/**\n * Coerces an unknown thrown value to an `Error` instance.\n * Returns the value as-is when it is already an `Error`; otherwise wraps it with `String(value)`.\n *\n * @example\n * ```ts\n * try { ... } catch(err) {\n * throw new BuildError('Build failed', { cause: toError(err), errors: [] })\n * }\n * ```\n */\nexport function toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value))\n}\n\n/**\n * Extracts a human-readable message from any thrown value.\n *\n * @example\n * ```ts\n * getErrorMessage(new Error('oops')) // 'oops'\n * getErrorMessage('plain string') // 'plain string'\n * ```\n */\nexport function getErrorMessage(value: unknown): string {\n return value instanceof Error ? value.message : String(value)\n}\n\n/**\n * Extracts the `.cause` of an `Error` as an `Error`, or `undefined` when absent or not an `Error`.\n *\n * @example\n * ```ts\n * const cause = toCause(buildError) // Error | undefined\n * ```\n */\nexport function toCause(error: Error): Error | undefined {\n return error.cause instanceof Error ? error.cause : undefined\n}\n","/**\n * Name of the JavaScript runtime executing the current process.\n */\ntype RuntimeName = 'bun' | 'deno' | 'node'\n\n/**\n * Detects the JavaScript runtime executing the current process and exposes its name and version.\n *\n * Prefer the shared {@link runtime} instance over constructing your own.\n */\nclass Runtime {\n /**\n * `true` when the current process is running under Bun.\n *\n * Detection keys off the global `Bun` object rather than `process.versions`,\n * because Bun polyfills `process.versions.node` for Node compatibility and would\n * otherwise look like Node.\n *\n * @example\n * ```ts\n * if (runtime.isBun) {\n * await Bun.write(path, data)\n * }\n * ```\n */\n get isBun(): boolean {\n return typeof Bun !== 'undefined'\n }\n\n /**\n * `true` when the current process is running under Deno.\n */\n get isDeno(): boolean {\n return typeof (globalThis as { Deno?: unknown }).Deno !== 'undefined'\n }\n\n /**\n * `true` when the current process is running under Node.\n *\n * Bun and Deno are excluded first so a polyfilled `process` does not register as Node.\n */\n get isNode(): boolean {\n return !this.isBun && !this.isDeno && typeof process !== 'undefined' && process.versions?.node != null\n }\n\n /**\n * Name of the runtime executing the current process.\n *\n * @example\n * ```ts\n * runtime.name // 'bun' when run with `bun kubb`, 'node' otherwise\n * ```\n */\n get name(): RuntimeName {\n if (this.isBun) return 'bun'\n if (this.isDeno) return 'deno'\n\n return 'node'\n }\n\n /**\n * Version of the active runtime, or an empty string when it cannot be read.\n *\n * @example\n * ```ts\n * runtime.version // '1.3.11' under Bun, '22.22.2' under Node\n * ```\n */\n get version(): string {\n if (this.isBun) return process.versions.bun ?? ''\n if (this.isDeno) return (globalThis as { Deno?: { version?: { deno?: string } } }).Deno?.version?.deno ?? ''\n\n return process.versions?.node ?? ''\n }\n}\n\n/**\n * Shared {@link Runtime} instance describing the JavaScript runtime executing the current process.\n */\nexport const runtime = new Runtime()\n","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","import { EventEmitter as NodeEventEmitter } from 'node:events'\nimport { toError } from '../../../internals/utils/src/errors.ts'\n\n/**\n * A function that can be registered as a hook listener, synchronous or async. Any return value is\n * allowed and ignored, so handlers that return a result for their own callers still register.\n */\ntype AsyncListener<TArgs extends Array<unknown>> = (...args: TArgs) => unknown\n\n/**\n * Typed hook emitter that awaits all async listeners before resolving.\n * Wraps Node's `EventEmitter` with full TypeScript hook-map inference.\n *\n * @example\n * ```ts\n * const hooks = new Hookable<{ build: [name: string] }>()\n * hooks.hook('build', async (name) => { console.log(name) })\n * await hooks.callHook('build', 'petstore') // all listeners awaited\n * ```\n */\nexport class Hookable<THooks extends { [K in keyof THooks]: Array<unknown> }> {\n /**\n * Maximum number of listeners per hook before Node emits a memory-leak warning.\n * @default 10\n */\n constructor(maxListener = 10) {\n this.#emitter.setMaxListeners(maxListener)\n }\n\n #emitter = new NodeEventEmitter()\n\n /**\n * Calls `hookName` and awaits all registered listeners sequentially.\n * Throws if any listener rejects, wrapping the cause with the hook name and serialized arguments.\n *\n * @example\n * ```ts\n * await hooks.callHook('build', 'petstore')\n * ```\n */\n callHook<THookName extends keyof THooks & string>(hookName: THookName, ...hookArgs: THooks[THookName]): Promise<void> | void {\n const listeners = this.#emitter.listeners(hookName) as Array<AsyncListener<THooks[THookName]>>\n\n if (listeners.length === 0) {\n return\n }\n\n return this.#emitAll(hookName, listeners, hookArgs)\n }\n\n async #emitAll<THookName extends keyof THooks & string>(\n hookName: THookName,\n listeners: Array<AsyncListener<THooks[THookName]>>,\n hookArgs: THooks[THookName],\n ): Promise<void> {\n for (const listener of listeners) {\n try {\n await listener(...hookArgs)\n } catch (err) {\n let serializedArgs: string\n try {\n serializedArgs = JSON.stringify(hookArgs)\n } catch {\n serializedArgs = String(hookArgs)\n }\n throw new Error(`Error in async listener for \"${hookName}\" with hookArgs ${serializedArgs}`, { cause: toError(err) })\n }\n }\n }\n\n /**\n * Registers a persistent listener for `hookName` and returns a function that removes it.\n *\n * @example\n * ```ts\n * const unhook = hooks.hook('build', async (name) => { console.log(name) })\n * unhook() // removes it\n * ```\n */\n hook<THookName extends keyof THooks & string>(hookName: THookName, handler: AsyncListener<THooks[THookName]>): () => void {\n this.#emitter.on(hookName, handler as AsyncListener<Array<unknown>>)\n return () => this.removeHook(hookName, handler)\n }\n\n /**\n * Registers every handler in `configHooks` at once and returns a function that removes them\n * all. Undefined entries are skipped, so a partial hook object registers only its present keys.\n *\n * @example\n * ```ts\n * const unhook = hooks.addHooks({ build: onBuild, done: onDone })\n * unhook() // removes both\n * ```\n */\n addHooks(configHooks: Partial<{ [K in keyof THooks & string]: AsyncListener<THooks[K]> }>): () => void {\n const unhooks = (Object.keys(configHooks) as Array<keyof THooks & string>)\n .filter((name) => configHooks[name])\n .map((name) => this.hook(name, configHooks[name]!))\n\n return () => {\n for (const unhook of unhooks) unhook()\n }\n }\n\n /**\n * Removes a previously registered listener.\n *\n * @example\n * ```ts\n * hooks.removeHook('build', handler)\n * ```\n */\n removeHook<THookName extends keyof THooks & string>(hookName: THookName, handler: AsyncListener<THooks[THookName]>): void {\n this.#emitter.off(hookName, handler as AsyncListener<Array<unknown>>)\n }\n\n /**\n * Returns the number of listeners registered for `hookName`.\n *\n * @example\n * ```ts\n * hooks.hook('build', handler)\n * hooks.listenerCount('build') // 1\n * ```\n */\n listenerCount<THookName extends keyof THooks & string>(hookName: THookName): number {\n return this.#emitter.listenerCount(hookName)\n }\n\n /**\n * Raises or lowers the per-hook listener ceiling before Node warns about a memory leak.\n * Set this above the expected listener count when many listeners attach by design.\n *\n * @example\n * ```ts\n * hooks.setMaxListeners(40)\n * ```\n */\n setMaxListeners(max: number): void {\n this.#emitter.setMaxListeners(max)\n }\n\n /**\n * Removes all listeners from every hook channel.\n *\n * @example\n * ```ts\n * hooks.removeAllHooks()\n * ```\n */\n removeAllHooks(): void {\n this.#emitter.removeAllListeners()\n }\n}\n","import { read } from '@internals/utils'\nimport { ast, extractStringsFromNodes, type CodeNode, type FileNode } from '@kubb/ast'\nimport type { Storage } from './createStorage.ts'\nimport type { Parser } from './defineParser.ts'\nimport { Hookable } from './Hookable.ts'\n\n/**\n * Hooks fired around a `FileManager#write` batch: `start` before it, `update` per file, `end` after.\n */\nexport type FileManagerHooks = {\n start: [files: Array<FileNode>]\n update: [params: { file: FileNode; source?: string; processed: number; total: number; percentage: number }]\n end: [files: Array<FileNode>]\n}\n\ntype ParseOptions = {\n parsers?: Map<FileNode['extname'], Parser>\n}\n\ntype WriteOptions = ParseOptions & {\n storage: Storage\n}\n\nfunction joinSources(file: FileNode): string {\n return file.sources\n .map((source) => extractStringsFromNodes(source.nodes as Array<CodeNode>))\n .filter(Boolean)\n .join('\\n\\n')\n}\n\nasync function parseCopy(file: FileNode): Promise<string> {\n let content: string\n try {\n content = await read(file.copy as string)\n } catch (err) {\n throw new Error(`[kubb] Could not copy file into output: ${file.copy}`, { cause: err })\n }\n\n return [file.banner, content, file.footer]\n .filter((segment): segment is string => Boolean(segment))\n .map((segment) => segment.trimEnd())\n .join('\\n')\n}\n\nfunction mergeFile<TMeta extends object = object>(a: FileNode<TMeta>, b: FileNode<TMeta>): FileNode<TMeta> {\n return {\n ...a,\n // Incoming file (b) takes precedence for banner/footer so a barrel file (whose\n // banner/footer the barrel plugin resolves last) wins over a plugin-generated\n // file at the same path.\n banner: b.banner,\n footer: b.footer,\n // A verbatim-copy file cannot be merged with rendered content; the incoming `copy` wins.\n copy: b.copy ?? a.copy,\n sources: a.sources.length ? (b.sources.length ? [...a.sources, ...b.sources] : a.sources) : b.sources,\n imports: a.imports.length ? (b.imports.length ? [...a.imports, ...b.imports] : a.imports) : b.imports,\n exports: a.exports.length ? (b.exports.length ? [...a.exports, ...b.exports] : a.exports) : b.exports,\n }\n}\n\nfunction isIndexPath(path: string): boolean {\n return path.endsWith('/index.ts') || path === 'index.ts'\n}\n\n// Sort order: shortest path first. Within a length bucket, index.ts barrels last.\nfunction compareFiles(a: FileNode, b: FileNode): number {\n const lenDiff = a.path.length - b.path.length\n if (lenDiff !== 0) return lenDiff\n const aIsIndex = isIndexPath(a.path)\n const bIsIndex = isIndexPath(b.path)\n if (aIsIndex && !bIsIndex) return 1\n if (!aIsIndex && bIsIndex) return -1\n\n return 0\n}\n\n/**\n * In-memory file store for generated files, and the writer that turns them into source\n * strings on `storage`. Files sharing a `path` are merged (sources/imports/exports\n * concatenated). The `files` getter is sorted by path length (barrel `index.ts` last\n * within a bucket).\n *\n * @example\n * ```ts\n * const manager = new FileManager()\n * manager.upsert(myFile)\n * manager.files // sorted view\n * await manager.write(manager.files, { storage: fsStorage() })\n * ```\n */\nexport class FileManager {\n readonly hooks = new Hookable<FileManagerHooks>()\n readonly #cache = new Map<string, FileNode>()\n // Cached sorted view. Null means stale and rebuilt lazily on next `files` read.\n // Nulled (not mutated) on every write so callers holding a prior reference keep\n // their snapshot. `dispose()` must not silently empty an array the consumer\n // already holds.\n #sorted: Array<FileNode> | null = null\n\n add(...files: Array<FileNode>): Array<FileNode> {\n return this.#store(files, false)\n }\n\n upsert(...files: Array<FileNode>): Array<FileNode> {\n return this.#store(files, true)\n }\n\n #store(files: ReadonlyArray<FileNode>, mergeExisting: boolean): Array<FileNode> {\n const batch = files.length > 1 ? this.#dedupe(files) : files\n const resolved: Array<FileNode> = []\n\n for (const file of batch) {\n const existing = this.#cache.get(file.path)\n const merged = existing && mergeExisting ? ast.factory.createFile(mergeFile(existing, file)) : ast.factory.createFile(file)\n this.#cache.set(merged.path, merged)\n resolved.push(merged)\n }\n\n if (resolved.length > 0) this.#sorted = null\n return resolved\n }\n\n // Merges same-path entries within a batch so the cache update loop stays\n // uniform. Only called for multi-file batches.\n #dedupe(files: ReadonlyArray<FileNode>): Array<FileNode> {\n const seen = new Map<string, FileNode>()\n for (const file of files) {\n const prev = seen.get(file.path)\n seen.set(file.path, prev ? mergeFile(prev, file) : file)\n }\n return [...seen.values()]\n }\n\n clear(): void {\n this.#cache.clear()\n this.#sorted = null\n }\n\n /**\n * Releases all stored files and clears every `hooks` listener. Called by the core after\n * `kubb:build:end`.\n */\n dispose(): void {\n this.clear()\n this.hooks.removeAllHooks()\n }\n\n /**\n * All stored files in stable sort order (shortest path first, barrel files\n * last within a length bucket). Returns a cached view, do not mutate.\n */\n get files(): Array<FileNode> {\n return (this.#sorted ??= [...this.#cache.values()].sort(compareFiles))\n }\n\n /**\n * Converts a file's AST sources (or its `copy` source) into the final on-disk string.\n */\n async parse(file: FileNode, { parsers }: ParseOptions = {}): Promise<string> {\n if (file.copy) {\n return parseCopy(file)\n }\n\n if (!parsers || !file.extname) {\n return joinSources(file)\n }\n\n const parser = parsers.get(file.extname)\n\n if (!parser) {\n return joinSources(file)\n }\n\n return parser.parse(file)\n }\n\n /**\n * Converts and writes every file at once, letting `storage.setItem` decide how much of\n * that runs concurrently.\n */\n async write(files: Array<FileNode>, { storage, parsers }: WriteOptions): Promise<void> {\n if (files.length === 0) return\n\n await this.hooks.callHook('start', files)\n\n const total = files.length\n let processed = 0\n await Promise.all(\n files.map(async (file) => {\n const source = await this.parse(file, { parsers })\n processed++\n await this.hooks.callHook('update', { file, source, processed, total, percentage: (processed / total) * 100 })\n if (source) await storage.setItem(file.path, source)\n }),\n )\n\n await this.hooks.callHook('end', files)\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAkBA,SAAS,gBAAgB,MAAc,QAAyB;CAC9D,OAAO,KACJ,KAAK,CAAC,CACN,QAAQ,qBAAqB,OAAO,CAAC,CACrC,QAAQ,yBAAyB,OAAO,CAAC,CACzC,QAAQ,gBAAgB,OAAO,CAAC,CAChC,MAAM,eAAe,CAAC,CACtB,OAAO,OAAO,CAAC,CACf,KAAK,MAAM,MAAM;EAChB,IAAI,KAAK,SAAS,KAAK,SAAS,KAAK,YAAY,GAAG,OAAO;EAE3D,QADa,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,KAC9E,KAAK,MAAM,CAAC;CAC5B,CAAC,CAAC,CACD,KAAK,EAAE,CAAC,CACR,QAAQ,iBAAiB,EAAE;AAChC;;;;;;;;;;AAWA,SAAgB,UAAU,MAAc,EAAE,SAAS,IAAI,SAAS,OAAgB,CAAC,GAAW;CAC1F,OAAO,gBAAgB,GAAG,OAAO,GAAG,KAAK,GAAG,UAAU,KAAK;AAC7D;;;;;;;;;;;;ACrCA,IAAa,aAAb,cAAgC,MAAM;CACpC;CAEA,YAAY,SAAiB,SAAkD;EAC7E,MAAM,SAAS,EAAE,OAAO,QAAQ,MAAM,CAAC;EACvC,KAAK,OAAO;EACZ,KAAK,SAAS,QAAQ;CACxB;AACF;;;;;;;;;;;;AAaA,SAAgB,QAAQ,OAAuB;CAC7C,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AACjE;;;;;;;;;;AAWA,SAAgB,gBAAgB,OAAwB;CACtD,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;;;;;;;;ACnCA,IAAM,UAAN,MAAc;;;;;;;;;;;;;;;CAeZ,IAAI,QAAiB;EACnB,OAAO,OAAO,QAAQ;CACxB;;;;CAKA,IAAI,SAAkB;EACpB,OAAO,OAAQ,WAAkC,SAAS;CAC5D;;;;;;CAOA,IAAI,SAAkB;EACpB,OAAO,CAAC,KAAK,SAAS,CAAC,KAAK,UAAU,OAAO,YAAY,eAAe,QAAQ,UAAU,QAAQ;CACpG;;;;;;;;;CAUA,IAAI,OAAoB;EACtB,IAAI,KAAK,OAAO,OAAO;EACvB,IAAI,KAAK,QAAQ,OAAO;EAExB,OAAO;CACT;;;;;;;;;CAUA,IAAI,UAAkB;EACpB,IAAI,KAAK,OAAO,OAAO,QAAQ,SAAS,OAAO;EAC/C,IAAI,KAAK,QAAQ,OAAQ,WAA0D,MAAM,SAAS,QAAQ;EAE1G,OAAO,QAAQ,UAAU,QAAQ;CACnC;AACF;;;;AAKA,MAAa,UAAU,IAAI,QAAQ;;;;;;;;;;;;ACQnC,eAAsB,KAAK,MAA+B;CACxD,IAAI,QAAQ,OACV,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,KAAK;CAE7B,OAAO,SAAS,MAAM,EAAE,UAAU,OAAO,CAAC;AAC5C;;;;;;;;;;;;;;AAuBA,eAAsB,MAAM,MAAc,MAAc,UAAwB,CAAC,GAA2B;CAC1G,MAAM,UAAU,KAAK,KAAK;CAC1B,IAAI,YAAY,IAAI,OAAO;CAE3B,MAAM,WAAW,QAAQ,IAAI;CAE7B,IAAI,QAAQ,OAAO;EACjB,MAAM,OAAO,IAAI,KAAK,QAAQ;EAE9B,KADoB,MAAM,KAAK,OAAO,IAAK,MAAM,KAAK,KAAK,IAAI,UAC5C,SAAS,OAAO;EACnC,MAAM,IAAI,MAAM,UAAU,OAAO;EACjC,OAAO;CACT;CAEA,IAAI;EAEF,IAAI,MADqB,SAAS,UAAU,EAAE,UAAU,QAAQ,CAAC,MAC9C,SAAS,OAAO;CACrC,QAAQ,CAER;CAEA,MAAM,MAAM,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;CAClD,MAAM,UAAU,UAAU,SAAS,EAAE,UAAU,QAAQ,CAAC;CAExD,IAAI,QAAQ,QAAQ;EAClB,MAAM,YAAY,MAAM,SAAS,UAAU,EAAE,UAAU,QAAQ,CAAC;EAChE,IAAI,cAAc,SAChB,MAAM,IAAI,MAAM,2BAA2B,KAAK,WAAW,KAAK,OAAO,MAAM,KAAK,YAAY,UAAU,OAAO,MAAM,UAAU,GAAG;EAEpI,OAAO;CACT;CAEA,OAAO;AACT;;;;;;;;;AAUA,eAAsB,MAAM,MAA6B;CACvD,OAAO,GAAG,MAAM;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC;AAClD;;;;;;;;;;;;;;;AAgBA,SAAgB,YAAY,UAA0B;CACpD,OAAO,SAAS,WAAW,MAAM,GAAG;AACtC;;;;;;;;;;;;;;;;;;;;AAuCA,SAAgB,WAAW,MAAc,WAAqC,WAAmB;CAC/F,MAAM,QAAQ,KAAK,MAAM,gBAAgB;CACzC,OAAO,MACJ,KAAK,MAAM,MAAO,MAAM,MAAM,SAAS,IAAI,SAAS,IAAI,IAAI,UAAU,IAAI,CAAE,CAAC,CAC7E,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;AACb;;;;;;;;;;;;;;AC3MA,IAAa,WAAb,MAA8E;;;;;CAK5E,YAAY,cAAc,IAAI;EAC5B,KAAKA,SAAS,gBAAgB,WAAW;CAC3C;CAEA,WAAW,IAAIC,aAAiB;;;;;;;;;;CAWhC,SAAkD,UAAqB,GAAG,UAAmD;EAC3H,MAAM,YAAY,KAAKD,SAAS,UAAU,QAAQ;EAElD,IAAI,UAAU,WAAW,GACvB;EAGF,OAAO,KAAKE,SAAS,UAAU,WAAW,QAAQ;CACpD;CAEA,MAAMA,SACJ,UACA,WACA,UACe;EACf,KAAK,MAAM,YAAY,WACrB,IAAI;GACF,MAAM,SAAS,GAAG,QAAQ;EAC5B,SAAS,KAAK;GACZ,IAAI;GACJ,IAAI;IACF,iBAAiB,KAAK,UAAU,QAAQ;GAC1C,QAAQ;IACN,iBAAiB,OAAO,QAAQ;GAClC;GACA,MAAM,IAAI,MAAM,gCAAgC,SAAS,kBAAkB,kBAAkB,EAAE,OAAO,QAAQ,GAAG,EAAE,CAAC;EACtH;CAEJ;;;;;;;;;;CAWA,KAA8C,UAAqB,SAAuD;EACxH,KAAKF,SAAS,GAAG,UAAU,OAAwC;EACnE,aAAa,KAAK,WAAW,UAAU,OAAO;CAChD;;;;;;;;;;;CAYA,SAAS,aAA8F;EACrG,MAAM,UAAW,OAAO,KAAK,WAAW,CAAC,CACtC,QAAQ,SAAS,YAAY,KAAK,CAAC,CACnC,KAAK,SAAS,KAAK,KAAK,MAAM,YAAY,KAAM,CAAC;EAEpD,aAAa;GACX,KAAK,MAAM,UAAU,SAAS,OAAO;EACvC;CACF;;;;;;;;;CAUA,WAAoD,UAAqB,SAAiD;EACxH,KAAKA,SAAS,IAAI,UAAU,OAAwC;CACtE;;;;;;;;;;CAWA,cAAuD,UAA6B;EAClF,OAAO,KAAKA,SAAS,cAAc,QAAQ;CAC7C;;;;;;;;;;CAWA,gBAAgB,KAAmB;EACjC,KAAKA,SAAS,gBAAgB,GAAG;CACnC;;;;;;;;;CAUA,iBAAuB;EACrB,KAAKA,SAAS,mBAAmB;CACnC;AACF;;;AClIA,SAAS,YAAY,MAAwB;CAC3C,OAAO,KAAK,QACT,KAAK,WAAW,wBAAwB,OAAO,KAAwB,CAAC,CAAC,CACzE,OAAO,OAAO,CAAC,CACf,KAAK,MAAM;AAChB;AAEA,eAAe,UAAU,MAAiC;CACxD,IAAI;CACJ,IAAI;EACF,UAAU,MAAM,KAAK,KAAK,IAAc;CAC1C,SAAS,KAAK;EACZ,MAAM,IAAI,MAAM,2CAA2C,KAAK,QAAQ,EAAE,OAAO,IAAI,CAAC;CACxF;CAEA,OAAO;EAAC,KAAK;EAAQ;EAAS,KAAK;CAAM,CAAC,CACvC,QAAQ,YAA+B,QAAQ,OAAO,CAAC,CAAC,CACxD,KAAK,YAAY,QAAQ,QAAQ,CAAC,CAAC,CACnC,KAAK,IAAI;AACd;AAEA,SAAS,UAAyC,GAAoB,GAAqC;CACzG,OAAO;EACL,GAAG;EAIH,QAAQ,EAAE;EACV,QAAQ,EAAE;EAEV,MAAM,EAAE,QAAQ,EAAE;EAClB,SAAS,EAAE,QAAQ,SAAU,EAAE,QAAQ,SAAS,CAAC,GAAG,EAAE,SAAS,GAAG,EAAE,OAAO,IAAI,EAAE,UAAW,EAAE;EAC9F,SAAS,EAAE,QAAQ,SAAU,EAAE,QAAQ,SAAS,CAAC,GAAG,EAAE,SAAS,GAAG,EAAE,OAAO,IAAI,EAAE,UAAW,EAAE;EAC9F,SAAS,EAAE,QAAQ,SAAU,EAAE,QAAQ,SAAS,CAAC,GAAG,EAAE,SAAS,GAAG,EAAE,OAAO,IAAI,EAAE,UAAW,EAAE;CAChG;AACF;AAEA,SAAS,YAAY,MAAuB;CAC1C,OAAO,KAAK,SAAS,WAAW,KAAK,SAAS;AAChD;AAGA,SAAS,aAAa,GAAa,GAAqB;CACtD,MAAM,UAAU,EAAE,KAAK,SAAS,EAAE,KAAK;CACvC,IAAI,YAAY,GAAG,OAAO;CAC1B,MAAM,WAAW,YAAY,EAAE,IAAI;CACnC,MAAM,WAAW,YAAY,EAAE,IAAI;CACnC,IAAI,YAAY,CAAC,UAAU,OAAO;CAClC,IAAI,CAAC,YAAY,UAAU,OAAO;CAElC,OAAO;AACT;;;;;;;;;;;;;;;AAgBA,IAAa,cAAb,MAAyB;CACvB,QAAiB,IAAI,SAA2B;CAChD,yBAAkB,IAAI,IAAsB;CAK5C,UAAkC;CAElC,IAAI,GAAG,OAAyC;EAC9C,OAAO,KAAKI,OAAO,OAAO,KAAK;CACjC;CAEA,OAAO,GAAG,OAAyC;EACjD,OAAO,KAAKA,OAAO,OAAO,IAAI;CAChC;CAEA,OAAO,OAAgC,eAAyC;EAC9E,MAAM,QAAQ,MAAM,SAAS,IAAI,KAAKC,QAAQ,KAAK,IAAI;EACvD,MAAM,WAA4B,CAAC;EAEnC,KAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,WAAW,KAAKF,OAAO,IAAI,KAAK,IAAI;GAC1C,MAAM,SAAS,YAAY,gBAAgB,IAAI,QAAQ,WAAW,UAAU,UAAU,IAAI,CAAC,IAAI,IAAI,QAAQ,WAAW,IAAI;GAC1H,KAAKA,OAAO,IAAI,OAAO,MAAM,MAAM;GACnC,SAAS,KAAK,MAAM;EACtB;EAEA,IAAI,SAAS,SAAS,GAAG,KAAKG,UAAU;EACxC,OAAO;CACT;CAIA,QAAQ,OAAiD;EACvD,MAAM,uBAAO,IAAI,IAAsB;EACvC,KAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,OAAO,KAAK,IAAI,KAAK,IAAI;GAC/B,KAAK,IAAI,KAAK,MAAM,OAAO,UAAU,MAAM,IAAI,IAAI,IAAI;EACzD;EACA,OAAO,CAAC,GAAG,KAAK,OAAO,CAAC;CAC1B;CAEA,QAAc;EACZ,KAAKH,OAAO,MAAM;EAClB,KAAKG,UAAU;CACjB;;;;;CAMA,UAAgB;EACd,KAAK,MAAM;EACX,KAAK,MAAM,eAAe;CAC5B;;;;;CAMA,IAAI,QAAyB;EAC3B,OAAQ,KAAKA,YAAY,CAAC,GAAG,KAAKH,OAAO,OAAO,CAAC,CAAC,CAAC,KAAK,YAAY;CACtE;;;;CAKA,MAAM,MAAM,MAAgB,EAAE,YAA0B,CAAC,GAAoB;EAC3E,IAAI,KAAK,MACP,OAAO,UAAU,IAAI;EAGvB,IAAI,CAAC,WAAW,CAAC,KAAK,SACpB,OAAO,YAAY,IAAI;EAGzB,MAAM,SAAS,QAAQ,IAAI,KAAK,OAAO;EAEvC,IAAI,CAAC,QACH,OAAO,YAAY,IAAI;EAGzB,OAAO,OAAO,MAAM,IAAI;CAC1B;;;;;CAMA,MAAM,MAAM,OAAwB,EAAE,SAAS,WAAwC;EACrF,IAAI,MAAM,WAAW,GAAG;EAExB,MAAM,KAAK,MAAM,SAAS,SAAS,KAAK;EAExC,MAAM,QAAQ,MAAM;EACpB,IAAI,YAAY;EAChB,MAAM,QAAQ,IACZ,MAAM,IAAI,OAAO,SAAS;GACxB,MAAM,SAAS,MAAM,KAAK,MAAM,MAAM,EAAE,QAAQ,CAAC;GACjD;GACA,MAAM,KAAK,MAAM,SAAS,UAAU;IAAE;IAAM;IAAQ;IAAW;IAAO,YAAa,YAAY,QAAS;GAAI,CAAC;GAC7G,IAAI,QAAQ,MAAM,QAAQ,QAAQ,KAAK,MAAM,MAAM;EACrD,CAAC,CACH;EAEA,MAAM,KAAK,MAAM,SAAS,OAAO,KAAK;CACxC;AACF"} |
| //#region \0rolldown/runtime.js | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __name = (target, value) => __defProp(target, "name", { | ||
| value, | ||
| configurable: true | ||
| }); | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { | ||
| key = keys[i]; | ||
| if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { | ||
| get: ((k) => from[k]).bind(null, key), | ||
| enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable | ||
| }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { | ||
| value: mod, | ||
| enumerable: true | ||
| }) : target, mod)); | ||
| //#endregion | ||
| let node_fs_promises = require("node:fs/promises"); | ||
| let node_path = require("node:path"); | ||
| let _kubb_ast = require("@kubb/ast"); | ||
| let node_events = require("node:events"); | ||
| //#region ../../internals/utils/src/casing.ts | ||
| /** | ||
| * Shared implementation for camelCase and PascalCase conversion. | ||
| * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons) | ||
| * and capitalizes each word according to `pascal`. | ||
| * | ||
| * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are. | ||
| */ | ||
| function toCamelOrPascal(text, pascal) { | ||
| return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => { | ||
| if (word.length > 1 && word === word.toUpperCase()) return word; | ||
| return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1); | ||
| }).join("").replace(/[^a-zA-Z0-9]/g, ""); | ||
| } | ||
| /** | ||
| * Converts `text` to camelCase. | ||
| * | ||
| * @example Word boundaries | ||
| * `camelCase('hello-world') // 'helloWorld'` | ||
| * | ||
| * @example With a prefix | ||
| * `camelCase('tag', { prefix: 'create' }) // 'createTag'` | ||
| */ | ||
| function camelCase(text, { prefix = "", suffix = "" } = {}) { | ||
| return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/errors.ts | ||
| /** | ||
| * Thrown when one or more errors occur during a Kubb build. | ||
| * Carries the full list of underlying errors on `errors`. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * throw new BuildError('Build failed', { errors: [err1, err2] }) | ||
| * ``` | ||
| */ | ||
| var BuildError = class extends Error { | ||
| errors; | ||
| constructor(message, options) { | ||
| super(message, { cause: options.cause }); | ||
| this.name = "BuildError"; | ||
| this.errors = options.errors; | ||
| } | ||
| }; | ||
| /** | ||
| * Coerces an unknown thrown value to an `Error` instance. | ||
| * Returns the value as-is when it is already an `Error`; otherwise wraps it with `String(value)`. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * try { ... } catch(err) { | ||
| * throw new BuildError('Build failed', { cause: toError(err), errors: [] }) | ||
| * } | ||
| * ``` | ||
| */ | ||
| function toError(value) { | ||
| return value instanceof Error ? value : new Error(String(value)); | ||
| } | ||
| /** | ||
| * Extracts a human-readable message from any thrown value. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * getErrorMessage(new Error('oops')) // 'oops' | ||
| * getErrorMessage('plain string') // 'plain string' | ||
| * ``` | ||
| */ | ||
| function getErrorMessage(value) { | ||
| return value instanceof Error ? value.message : String(value); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/runtime.ts | ||
| /** | ||
| * Detects the JavaScript runtime executing the current process and exposes its name and version. | ||
| * | ||
| * Prefer the shared {@link runtime} instance over constructing your own. | ||
| */ | ||
| var Runtime = class { | ||
| /** | ||
| * `true` when the current process is running under Bun. | ||
| * | ||
| * Detection keys off the global `Bun` object rather than `process.versions`, | ||
| * because Bun polyfills `process.versions.node` for Node compatibility and would | ||
| * otherwise look like Node. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * if (runtime.isBun) { | ||
| * await Bun.write(path, data) | ||
| * } | ||
| * ``` | ||
| */ | ||
| get isBun() { | ||
| return typeof Bun !== "undefined"; | ||
| } | ||
| /** | ||
| * `true` when the current process is running under Deno. | ||
| */ | ||
| get isDeno() { | ||
| return typeof globalThis.Deno !== "undefined"; | ||
| } | ||
| /** | ||
| * `true` when the current process is running under Node. | ||
| * | ||
| * Bun and Deno are excluded first so a polyfilled `process` does not register as Node. | ||
| */ | ||
| get isNode() { | ||
| return !this.isBun && !this.isDeno && typeof process !== "undefined" && process.versions?.node != null; | ||
| } | ||
| /** | ||
| * Name of the runtime executing the current process. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * runtime.name // 'bun' when run with `bun kubb`, 'node' otherwise | ||
| * ``` | ||
| */ | ||
| get name() { | ||
| if (this.isBun) return "bun"; | ||
| if (this.isDeno) return "deno"; | ||
| return "node"; | ||
| } | ||
| /** | ||
| * Version of the active runtime, or an empty string when it cannot be read. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * runtime.version // '1.3.11' under Bun, '22.22.2' under Node | ||
| * ``` | ||
| */ | ||
| get version() { | ||
| if (this.isBun) return process.versions.bun ?? ""; | ||
| if (this.isDeno) return globalThis.Deno?.version?.deno ?? ""; | ||
| return process.versions?.node ?? ""; | ||
| } | ||
| }; | ||
| /** | ||
| * Shared {@link Runtime} instance describing the JavaScript runtime executing the current process. | ||
| */ | ||
| const runtime = new Runtime(); | ||
| //#endregion | ||
| //#region ../../internals/utils/src/fs.ts | ||
| /** | ||
| * Reads the file at `path` as a UTF-8 string. | ||
| * Uses `Bun.file().text()` when running under Bun, `fs.readFile` otherwise. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const source = await read('./src/Pet.ts') | ||
| * ``` | ||
| */ | ||
| async function read(path) { | ||
| if (runtime.isBun) return Bun.file(path).text(); | ||
| return (0, node_fs_promises.readFile)(path, { encoding: "utf8" }); | ||
| } | ||
| /** | ||
| * Writes `data` to `path`, trimming leading/trailing whitespace before saving. | ||
| * Skips the write when the trimmed content is empty or identical to what is already on disk. | ||
| * Creates any missing parent directories automatically. | ||
| * When `sanity` is `true`, re-reads the file after writing and throws if the content does not match. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * await write('./src/Pet.ts', source) // writes and returns trimmed content | ||
| * await write('./src/Pet.ts', source) // null — file unchanged | ||
| * await write('./src/Pet.ts', ' ') // null — empty content skipped | ||
| * ``` | ||
| */ | ||
| async function write(path, data, options = {}) { | ||
| const trimmed = data.trim(); | ||
| if (trimmed === "") return null; | ||
| const resolved = (0, node_path.resolve)(path); | ||
| if (runtime.isBun) { | ||
| const file = Bun.file(resolved); | ||
| if ((await file.exists() ? await file.text() : null) === trimmed) return null; | ||
| await Bun.write(resolved, trimmed); | ||
| return trimmed; | ||
| } | ||
| try { | ||
| if (await (0, node_fs_promises.readFile)(resolved, { encoding: "utf-8" }) === trimmed) return null; | ||
| } catch {} | ||
| await (0, node_fs_promises.mkdir)((0, node_path.dirname)(resolved), { recursive: true }); | ||
| await (0, node_fs_promises.writeFile)(resolved, trimmed, { encoding: "utf-8" }); | ||
| if (options.sanity) { | ||
| const savedData = await (0, node_fs_promises.readFile)(resolved, { encoding: "utf-8" }); | ||
| if (savedData !== trimmed) throw new Error(`Sanity check failed for ${path}\n\nData[${data.length}]:\n${data}\n\nSaved[${savedData.length}]:\n${savedData}\n`); | ||
| return savedData; | ||
| } | ||
| return trimmed; | ||
| } | ||
| /** | ||
| * Recursively removes `path`. Silently succeeds when `path` does not exist. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * await clean('./dist') | ||
| * ``` | ||
| */ | ||
| async function clean(path) { | ||
| return (0, node_fs_promises.rm)(path, { | ||
| recursive: true, | ||
| force: true | ||
| }); | ||
| } | ||
| /** | ||
| * Converts a filesystem path to use POSIX (`/`) separators. | ||
| * | ||
| * Most of the codebase compares and composes paths as strings (prefix matching, joining for | ||
| * import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated | ||
| * paths, but on Windows it returns `\`-separated paths, which breaks every such comparison. | ||
| * | ||
| * Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the | ||
| * code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is | ||
| * exercisable from POSIX CI. | ||
| * | ||
| * @example | ||
| * toPosixPath('C:\\repo\\src\\pet.ts') // 'C:/repo/src/pet.ts' | ||
| */ | ||
| function toPosixPath(filePath) { | ||
| return filePath.replaceAll("\\", "/"); | ||
| } | ||
| /** | ||
| * Builds a nested file path from a dotted name. Splits on dots that precede a letter | ||
| * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases | ||
| * every earlier segment, applies `caseLast` to the final segment, and joins with `/`. | ||
| * | ||
| * Empty segments are dropped before joining. They arise when the name starts with a dot | ||
| * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to | ||
| * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an | ||
| * absolute path, letting generated files escape the configured output directory. | ||
| * | ||
| * @example Nested path from a dotted name | ||
| * `toFilePath('pet.petId') // 'pet/petId'` | ||
| * | ||
| * @example PascalCase the final segment | ||
| * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'` | ||
| * | ||
| * @example Suffix applied to the final segment only | ||
| * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'` | ||
| */ | ||
| function toFilePath(name, caseLast = camelCase) { | ||
| const parts = name.split(/\.(?=[a-zA-Z])/); | ||
| return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/"); | ||
| } | ||
| //#endregion | ||
| //#region src/Hookable.ts | ||
| /** | ||
| * Typed hook emitter that awaits all async listeners before resolving. | ||
| * Wraps Node's `EventEmitter` with full TypeScript hook-map inference. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const hooks = new Hookable<{ build: [name: string] }>() | ||
| * hooks.hook('build', async (name) => { console.log(name) }) | ||
| * await hooks.callHook('build', 'petstore') // all listeners awaited | ||
| * ``` | ||
| */ | ||
| var Hookable = class { | ||
| /** | ||
| * Maximum number of listeners per hook before Node emits a memory-leak warning. | ||
| * @default 10 | ||
| */ | ||
| constructor(maxListener = 10) { | ||
| this.#emitter.setMaxListeners(maxListener); | ||
| } | ||
| #emitter = new node_events.EventEmitter(); | ||
| /** | ||
| * Calls `hookName` and awaits all registered listeners sequentially. | ||
| * Throws if any listener rejects, wrapping the cause with the hook name and serialized arguments. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * await hooks.callHook('build', 'petstore') | ||
| * ``` | ||
| */ | ||
| callHook(hookName, ...hookArgs) { | ||
| const listeners = this.#emitter.listeners(hookName); | ||
| if (listeners.length === 0) return; | ||
| return this.#emitAll(hookName, listeners, hookArgs); | ||
| } | ||
| async #emitAll(hookName, listeners, hookArgs) { | ||
| for (const listener of listeners) try { | ||
| await listener(...hookArgs); | ||
| } catch (err) { | ||
| let serializedArgs; | ||
| try { | ||
| serializedArgs = JSON.stringify(hookArgs); | ||
| } catch { | ||
| serializedArgs = String(hookArgs); | ||
| } | ||
| throw new Error(`Error in async listener for "${hookName}" with hookArgs ${serializedArgs}`, { cause: toError(err) }); | ||
| } | ||
| } | ||
| /** | ||
| * Registers a persistent listener for `hookName` and returns a function that removes it. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const unhook = hooks.hook('build', async (name) => { console.log(name) }) | ||
| * unhook() // removes it | ||
| * ``` | ||
| */ | ||
| hook(hookName, handler) { | ||
| this.#emitter.on(hookName, handler); | ||
| return () => this.removeHook(hookName, handler); | ||
| } | ||
| /** | ||
| * Registers every handler in `configHooks` at once and returns a function that removes them | ||
| * all. Undefined entries are skipped, so a partial hook object registers only its present keys. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const unhook = hooks.addHooks({ build: onBuild, done: onDone }) | ||
| * unhook() // removes both | ||
| * ``` | ||
| */ | ||
| addHooks(configHooks) { | ||
| const unhooks = Object.keys(configHooks).filter((name) => configHooks[name]).map((name) => this.hook(name, configHooks[name])); | ||
| return () => { | ||
| for (const unhook of unhooks) unhook(); | ||
| }; | ||
| } | ||
| /** | ||
| * Removes a previously registered listener. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * hooks.removeHook('build', handler) | ||
| * ``` | ||
| */ | ||
| removeHook(hookName, handler) { | ||
| this.#emitter.off(hookName, handler); | ||
| } | ||
| /** | ||
| * Returns the number of listeners registered for `hookName`. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * hooks.hook('build', handler) | ||
| * hooks.listenerCount('build') // 1 | ||
| * ``` | ||
| */ | ||
| listenerCount(hookName) { | ||
| return this.#emitter.listenerCount(hookName); | ||
| } | ||
| /** | ||
| * Raises or lowers the per-hook listener ceiling before Node warns about a memory leak. | ||
| * Set this above the expected listener count when many listeners attach by design. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * hooks.setMaxListeners(40) | ||
| * ``` | ||
| */ | ||
| setMaxListeners(max) { | ||
| this.#emitter.setMaxListeners(max); | ||
| } | ||
| /** | ||
| * Removes all listeners from every hook channel. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * hooks.removeAllHooks() | ||
| * ``` | ||
| */ | ||
| removeAllHooks() { | ||
| this.#emitter.removeAllListeners(); | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region src/FileManager.ts | ||
| function joinSources(file) { | ||
| return file.sources.map((source) => (0, _kubb_ast.extractStringsFromNodes)(source.nodes)).filter(Boolean).join("\n\n"); | ||
| } | ||
| async function parseCopy(file) { | ||
| let content; | ||
| try { | ||
| content = await read(file.copy); | ||
| } catch (err) { | ||
| throw new Error(`[kubb] Could not copy file into output: ${file.copy}`, { cause: err }); | ||
| } | ||
| return [ | ||
| file.banner, | ||
| content, | ||
| file.footer | ||
| ].filter((segment) => Boolean(segment)).map((segment) => segment.trimEnd()).join("\n"); | ||
| } | ||
| function mergeFile(a, b) { | ||
| return { | ||
| ...a, | ||
| banner: b.banner, | ||
| footer: b.footer, | ||
| copy: b.copy ?? a.copy, | ||
| sources: a.sources.length ? b.sources.length ? [...a.sources, ...b.sources] : a.sources : b.sources, | ||
| imports: a.imports.length ? b.imports.length ? [...a.imports, ...b.imports] : a.imports : b.imports, | ||
| exports: a.exports.length ? b.exports.length ? [...a.exports, ...b.exports] : a.exports : b.exports | ||
| }; | ||
| } | ||
| function isIndexPath(path) { | ||
| return path.endsWith("/index.ts") || path === "index.ts"; | ||
| } | ||
| function compareFiles(a, b) { | ||
| const lenDiff = a.path.length - b.path.length; | ||
| if (lenDiff !== 0) return lenDiff; | ||
| const aIsIndex = isIndexPath(a.path); | ||
| const bIsIndex = isIndexPath(b.path); | ||
| if (aIsIndex && !bIsIndex) return 1; | ||
| if (!aIsIndex && bIsIndex) return -1; | ||
| return 0; | ||
| } | ||
| /** | ||
| * In-memory file store for generated files, and the writer that turns them into source | ||
| * strings on `storage`. Files sharing a `path` are merged (sources/imports/exports | ||
| * concatenated). The `files` getter is sorted by path length (barrel `index.ts` last | ||
| * within a bucket). | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const manager = new FileManager() | ||
| * manager.upsert(myFile) | ||
| * manager.files // sorted view | ||
| * await manager.write(manager.files, { storage: fsStorage() }) | ||
| * ``` | ||
| */ | ||
| var FileManager = class { | ||
| hooks = new Hookable(); | ||
| #cache = /* @__PURE__ */ new Map(); | ||
| #sorted = null; | ||
| add(...files) { | ||
| return this.#store(files, false); | ||
| } | ||
| upsert(...files) { | ||
| return this.#store(files, true); | ||
| } | ||
| #store(files, mergeExisting) { | ||
| const batch = files.length > 1 ? this.#dedupe(files) : files; | ||
| const resolved = []; | ||
| for (const file of batch) { | ||
| const existing = this.#cache.get(file.path); | ||
| const merged = existing && mergeExisting ? _kubb_ast.ast.factory.createFile(mergeFile(existing, file)) : _kubb_ast.ast.factory.createFile(file); | ||
| this.#cache.set(merged.path, merged); | ||
| resolved.push(merged); | ||
| } | ||
| if (resolved.length > 0) this.#sorted = null; | ||
| return resolved; | ||
| } | ||
| #dedupe(files) { | ||
| const seen = /* @__PURE__ */ new Map(); | ||
| for (const file of files) { | ||
| const prev = seen.get(file.path); | ||
| seen.set(file.path, prev ? mergeFile(prev, file) : file); | ||
| } | ||
| return [...seen.values()]; | ||
| } | ||
| clear() { | ||
| this.#cache.clear(); | ||
| this.#sorted = null; | ||
| } | ||
| /** | ||
| * Releases all stored files and clears every `hooks` listener. Called by the core after | ||
| * `kubb:build:end`. | ||
| */ | ||
| dispose() { | ||
| this.clear(); | ||
| this.hooks.removeAllHooks(); | ||
| } | ||
| /** | ||
| * All stored files in stable sort order (shortest path first, barrel files | ||
| * last within a length bucket). Returns a cached view, do not mutate. | ||
| */ | ||
| get files() { | ||
| return this.#sorted ??= [...this.#cache.values()].sort(compareFiles); | ||
| } | ||
| /** | ||
| * Converts a file's AST sources (or its `copy` source) into the final on-disk string. | ||
| */ | ||
| async parse(file, { parsers } = {}) { | ||
| if (file.copy) return parseCopy(file); | ||
| if (!parsers || !file.extname) return joinSources(file); | ||
| const parser = parsers.get(file.extname); | ||
| if (!parser) return joinSources(file); | ||
| return parser.parse(file); | ||
| } | ||
| /** | ||
| * Converts and writes every file at once, letting `storage.setItem` decide how much of | ||
| * that runs concurrently. | ||
| */ | ||
| async write(files, { storage, parsers }) { | ||
| if (files.length === 0) return; | ||
| await this.hooks.callHook("start", files); | ||
| const total = files.length; | ||
| let processed = 0; | ||
| await Promise.all(files.map(async (file) => { | ||
| const source = await this.parse(file, { parsers }); | ||
| processed++; | ||
| await this.hooks.callHook("update", { | ||
| file, | ||
| source, | ||
| processed, | ||
| total, | ||
| percentage: processed / total * 100 | ||
| }); | ||
| if (source) await storage.setItem(file.path, source); | ||
| })); | ||
| await this.hooks.callHook("end", files); | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region \0@oxc-project+runtime@0.138.0/helpers/esm/usingCtx.js | ||
| function _usingCtx() { | ||
| var r = "function" == typeof SuppressedError ? SuppressedError : function(r, e) { | ||
| var n = Error(); | ||
| return n.name = "SuppressedError", n.error = r, n.suppressed = e, n; | ||
| }; | ||
| var e = {}; | ||
| var n = []; | ||
| function using(r, e) { | ||
| if (null != e) { | ||
| if (Object(e) !== e) throw new TypeError("using declarations can only be used with objects, functions, null, or undefined."); | ||
| if (r) var o = e[Symbol.asyncDispose || Symbol["for"]("Symbol.asyncDispose")]; | ||
| if (void 0 === o && (o = e[Symbol.dispose || Symbol["for"]("Symbol.dispose")], r)) var t = o; | ||
| if ("function" != typeof o) throw new TypeError("Object is not disposable."); | ||
| t && (o = function o() { | ||
| try { | ||
| t.call(e); | ||
| } catch (r) { | ||
| return Promise.reject(r); | ||
| } | ||
| }), n.push({ | ||
| v: e, | ||
| d: o, | ||
| a: r | ||
| }); | ||
| } else r && n.push({ | ||
| d: e, | ||
| a: r | ||
| }); | ||
| return e; | ||
| } | ||
| return { | ||
| e, | ||
| u: using.bind(null, !1), | ||
| a: using.bind(null, !0), | ||
| d: function d() { | ||
| var o; | ||
| var t = this.e; | ||
| var s = 0; | ||
| function next() { | ||
| for (; o = n.pop();) try { | ||
| if (!o.a && 1 === s) return s = 0, n.push(o), Promise.resolve().then(next); | ||
| if (o.d) { | ||
| var r = o.d.call(o.v); | ||
| if (o.a) return s |= 2, Promise.resolve(r).then(next, err); | ||
| } else s |= 1; | ||
| } catch (r) { | ||
| return err(r); | ||
| } | ||
| if (1 === s) return t !== e ? Promise.reject(t) : Promise.resolve(); | ||
| if (t !== e) throw t; | ||
| } | ||
| function err(n) { | ||
| return t = t !== e ? new r(n, t) : n, next(); | ||
| } | ||
| return next(); | ||
| } | ||
| }; | ||
| } | ||
| //#endregion | ||
| Object.defineProperty(exports, "BuildError", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return BuildError; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "FileManager", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return FileManager; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "Hookable", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return Hookable; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "__name", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return __name; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "__toESM", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return __toESM; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "_usingCtx", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return _usingCtx; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "camelCase", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return camelCase; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "clean", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return clean; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "getErrorMessage", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return getErrorMessage; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "toError", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return toError; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "toFilePath", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return toFilePath; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "toPosixPath", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return toPosixPath; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "write", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return write; | ||
| } | ||
| }); | ||
| //# sourceMappingURL=usingCtx-eyNeehd2.cjs.map |
| {"version":3,"file":"usingCtx-eyNeehd2.cjs","names":["#emitter","NodeEventEmitter","#emitAll","#cache","#store","#dedupe","ast","#sorted"],"sources":["../../../internals/utils/src/casing.ts","../../../internals/utils/src/errors.ts","../../../internals/utils/src/runtime.ts","../../../internals/utils/src/fs.ts","../src/Hookable.ts","../src/FileManager.ts"],"sourcesContent":["type Options = {\n /**\n * Text prepended before casing is applied.\n */\n prefix?: string\n /**\n * Text appended before casing is applied.\n */\n suffix?: string\n}\n\n/**\n * Shared implementation for camelCase and PascalCase conversion.\n * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)\n * and capitalizes each word according to `pascal`.\n *\n * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.\n */\nfunction toCamelOrPascal(text: string, pascal: boolean): string {\n return text\n .trim()\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/(\\d)([a-z])/g, '$1 $2')\n .split(/[\\s\\-_./\\\\:]+/)\n .filter(Boolean)\n .map((word, i) => {\n if (word.length > 1 && word === word.toUpperCase()) return word\n const head = i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()\n return head + word.slice(1)\n })\n .join('')\n .replace(/[^a-zA-Z0-9]/g, '')\n}\n\n/**\n * Converts `text` to camelCase.\n *\n * @example Word boundaries\n * `camelCase('hello-world') // 'helloWorld'`\n *\n * @example With a prefix\n * `camelCase('tag', { prefix: 'create' }) // 'createTag'`\n */\nexport function camelCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false)\n}\n\n/**\n * Converts `text` to PascalCase.\n *\n * @example Word boundaries\n * `pascalCase('hello-world') // 'HelloWorld'`\n *\n * @example With a suffix\n * `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`\n */\nexport function pascalCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true)\n}\n","/**\n * Thrown when one or more errors occur during a Kubb build.\n * Carries the full list of underlying errors on `errors`.\n *\n * @example\n * ```ts\n * throw new BuildError('Build failed', { errors: [err1, err2] })\n * ```\n */\nexport class BuildError extends Error {\n errors: Array<Error>\n\n constructor(message: string, options: { cause?: Error; errors: Array<Error> }) {\n super(message, { cause: options.cause })\n this.name = 'BuildError'\n this.errors = options.errors\n }\n}\n\n/**\n * Coerces an unknown thrown value to an `Error` instance.\n * Returns the value as-is when it is already an `Error`; otherwise wraps it with `String(value)`.\n *\n * @example\n * ```ts\n * try { ... } catch(err) {\n * throw new BuildError('Build failed', { cause: toError(err), errors: [] })\n * }\n * ```\n */\nexport function toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value))\n}\n\n/**\n * Extracts a human-readable message from any thrown value.\n *\n * @example\n * ```ts\n * getErrorMessage(new Error('oops')) // 'oops'\n * getErrorMessage('plain string') // 'plain string'\n * ```\n */\nexport function getErrorMessage(value: unknown): string {\n return value instanceof Error ? value.message : String(value)\n}\n\n/**\n * Extracts the `.cause` of an `Error` as an `Error`, or `undefined` when absent or not an `Error`.\n *\n * @example\n * ```ts\n * const cause = toCause(buildError) // Error | undefined\n * ```\n */\nexport function toCause(error: Error): Error | undefined {\n return error.cause instanceof Error ? error.cause : undefined\n}\n","/**\n * Name of the JavaScript runtime executing the current process.\n */\ntype RuntimeName = 'bun' | 'deno' | 'node'\n\n/**\n * Detects the JavaScript runtime executing the current process and exposes its name and version.\n *\n * Prefer the shared {@link runtime} instance over constructing your own.\n */\nclass Runtime {\n /**\n * `true` when the current process is running under Bun.\n *\n * Detection keys off the global `Bun` object rather than `process.versions`,\n * because Bun polyfills `process.versions.node` for Node compatibility and would\n * otherwise look like Node.\n *\n * @example\n * ```ts\n * if (runtime.isBun) {\n * await Bun.write(path, data)\n * }\n * ```\n */\n get isBun(): boolean {\n return typeof Bun !== 'undefined'\n }\n\n /**\n * `true` when the current process is running under Deno.\n */\n get isDeno(): boolean {\n return typeof (globalThis as { Deno?: unknown }).Deno !== 'undefined'\n }\n\n /**\n * `true` when the current process is running under Node.\n *\n * Bun and Deno are excluded first so a polyfilled `process` does not register as Node.\n */\n get isNode(): boolean {\n return !this.isBun && !this.isDeno && typeof process !== 'undefined' && process.versions?.node != null\n }\n\n /**\n * Name of the runtime executing the current process.\n *\n * @example\n * ```ts\n * runtime.name // 'bun' when run with `bun kubb`, 'node' otherwise\n * ```\n */\n get name(): RuntimeName {\n if (this.isBun) return 'bun'\n if (this.isDeno) return 'deno'\n\n return 'node'\n }\n\n /**\n * Version of the active runtime, or an empty string when it cannot be read.\n *\n * @example\n * ```ts\n * runtime.version // '1.3.11' under Bun, '22.22.2' under Node\n * ```\n */\n get version(): string {\n if (this.isBun) return process.versions.bun ?? ''\n if (this.isDeno) return (globalThis as { Deno?: { version?: { deno?: string } } }).Deno?.version?.deno ?? ''\n\n return process.versions?.node ?? ''\n }\n}\n\n/**\n * Shared {@link Runtime} instance describing the JavaScript runtime executing the current process.\n */\nexport const runtime = new Runtime()\n","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","import { EventEmitter as NodeEventEmitter } from 'node:events'\nimport { toError } from '../../../internals/utils/src/errors.ts'\n\n/**\n * A function that can be registered as a hook listener, synchronous or async. Any return value is\n * allowed and ignored, so handlers that return a result for their own callers still register.\n */\ntype AsyncListener<TArgs extends Array<unknown>> = (...args: TArgs) => unknown\n\n/**\n * Typed hook emitter that awaits all async listeners before resolving.\n * Wraps Node's `EventEmitter` with full TypeScript hook-map inference.\n *\n * @example\n * ```ts\n * const hooks = new Hookable<{ build: [name: string] }>()\n * hooks.hook('build', async (name) => { console.log(name) })\n * await hooks.callHook('build', 'petstore') // all listeners awaited\n * ```\n */\nexport class Hookable<THooks extends { [K in keyof THooks]: Array<unknown> }> {\n /**\n * Maximum number of listeners per hook before Node emits a memory-leak warning.\n * @default 10\n */\n constructor(maxListener = 10) {\n this.#emitter.setMaxListeners(maxListener)\n }\n\n #emitter = new NodeEventEmitter()\n\n /**\n * Calls `hookName` and awaits all registered listeners sequentially.\n * Throws if any listener rejects, wrapping the cause with the hook name and serialized arguments.\n *\n * @example\n * ```ts\n * await hooks.callHook('build', 'petstore')\n * ```\n */\n callHook<THookName extends keyof THooks & string>(hookName: THookName, ...hookArgs: THooks[THookName]): Promise<void> | void {\n const listeners = this.#emitter.listeners(hookName) as Array<AsyncListener<THooks[THookName]>>\n\n if (listeners.length === 0) {\n return\n }\n\n return this.#emitAll(hookName, listeners, hookArgs)\n }\n\n async #emitAll<THookName extends keyof THooks & string>(\n hookName: THookName,\n listeners: Array<AsyncListener<THooks[THookName]>>,\n hookArgs: THooks[THookName],\n ): Promise<void> {\n for (const listener of listeners) {\n try {\n await listener(...hookArgs)\n } catch (err) {\n let serializedArgs: string\n try {\n serializedArgs = JSON.stringify(hookArgs)\n } catch {\n serializedArgs = String(hookArgs)\n }\n throw new Error(`Error in async listener for \"${hookName}\" with hookArgs ${serializedArgs}`, { cause: toError(err) })\n }\n }\n }\n\n /**\n * Registers a persistent listener for `hookName` and returns a function that removes it.\n *\n * @example\n * ```ts\n * const unhook = hooks.hook('build', async (name) => { console.log(name) })\n * unhook() // removes it\n * ```\n */\n hook<THookName extends keyof THooks & string>(hookName: THookName, handler: AsyncListener<THooks[THookName]>): () => void {\n this.#emitter.on(hookName, handler as AsyncListener<Array<unknown>>)\n return () => this.removeHook(hookName, handler)\n }\n\n /**\n * Registers every handler in `configHooks` at once and returns a function that removes them\n * all. Undefined entries are skipped, so a partial hook object registers only its present keys.\n *\n * @example\n * ```ts\n * const unhook = hooks.addHooks({ build: onBuild, done: onDone })\n * unhook() // removes both\n * ```\n */\n addHooks(configHooks: Partial<{ [K in keyof THooks & string]: AsyncListener<THooks[K]> }>): () => void {\n const unhooks = (Object.keys(configHooks) as Array<keyof THooks & string>)\n .filter((name) => configHooks[name])\n .map((name) => this.hook(name, configHooks[name]!))\n\n return () => {\n for (const unhook of unhooks) unhook()\n }\n }\n\n /**\n * Removes a previously registered listener.\n *\n * @example\n * ```ts\n * hooks.removeHook('build', handler)\n * ```\n */\n removeHook<THookName extends keyof THooks & string>(hookName: THookName, handler: AsyncListener<THooks[THookName]>): void {\n this.#emitter.off(hookName, handler as AsyncListener<Array<unknown>>)\n }\n\n /**\n * Returns the number of listeners registered for `hookName`.\n *\n * @example\n * ```ts\n * hooks.hook('build', handler)\n * hooks.listenerCount('build') // 1\n * ```\n */\n listenerCount<THookName extends keyof THooks & string>(hookName: THookName): number {\n return this.#emitter.listenerCount(hookName)\n }\n\n /**\n * Raises or lowers the per-hook listener ceiling before Node warns about a memory leak.\n * Set this above the expected listener count when many listeners attach by design.\n *\n * @example\n * ```ts\n * hooks.setMaxListeners(40)\n * ```\n */\n setMaxListeners(max: number): void {\n this.#emitter.setMaxListeners(max)\n }\n\n /**\n * Removes all listeners from every hook channel.\n *\n * @example\n * ```ts\n * hooks.removeAllHooks()\n * ```\n */\n removeAllHooks(): void {\n this.#emitter.removeAllListeners()\n }\n}\n","import { read } from '@internals/utils'\nimport { ast, extractStringsFromNodes, type CodeNode, type FileNode } from '@kubb/ast'\nimport type { Storage } from './createStorage.ts'\nimport type { Parser } from './defineParser.ts'\nimport { Hookable } from './Hookable.ts'\n\n/**\n * Hooks fired around a `FileManager#write` batch: `start` before it, `update` per file, `end` after.\n */\nexport type FileManagerHooks = {\n start: [files: Array<FileNode>]\n update: [params: { file: FileNode; source?: string; processed: number; total: number; percentage: number }]\n end: [files: Array<FileNode>]\n}\n\ntype ParseOptions = {\n parsers?: Map<FileNode['extname'], Parser>\n}\n\ntype WriteOptions = ParseOptions & {\n storage: Storage\n}\n\nfunction joinSources(file: FileNode): string {\n return file.sources\n .map((source) => extractStringsFromNodes(source.nodes as Array<CodeNode>))\n .filter(Boolean)\n .join('\\n\\n')\n}\n\nasync function parseCopy(file: FileNode): Promise<string> {\n let content: string\n try {\n content = await read(file.copy as string)\n } catch (err) {\n throw new Error(`[kubb] Could not copy file into output: ${file.copy}`, { cause: err })\n }\n\n return [file.banner, content, file.footer]\n .filter((segment): segment is string => Boolean(segment))\n .map((segment) => segment.trimEnd())\n .join('\\n')\n}\n\nfunction mergeFile<TMeta extends object = object>(a: FileNode<TMeta>, b: FileNode<TMeta>): FileNode<TMeta> {\n return {\n ...a,\n // Incoming file (b) takes precedence for banner/footer so a barrel file (whose\n // banner/footer the barrel plugin resolves last) wins over a plugin-generated\n // file at the same path.\n banner: b.banner,\n footer: b.footer,\n // A verbatim-copy file cannot be merged with rendered content; the incoming `copy` wins.\n copy: b.copy ?? a.copy,\n sources: a.sources.length ? (b.sources.length ? [...a.sources, ...b.sources] : a.sources) : b.sources,\n imports: a.imports.length ? (b.imports.length ? [...a.imports, ...b.imports] : a.imports) : b.imports,\n exports: a.exports.length ? (b.exports.length ? [...a.exports, ...b.exports] : a.exports) : b.exports,\n }\n}\n\nfunction isIndexPath(path: string): boolean {\n return path.endsWith('/index.ts') || path === 'index.ts'\n}\n\n// Sort order: shortest path first. Within a length bucket, index.ts barrels last.\nfunction compareFiles(a: FileNode, b: FileNode): number {\n const lenDiff = a.path.length - b.path.length\n if (lenDiff !== 0) return lenDiff\n const aIsIndex = isIndexPath(a.path)\n const bIsIndex = isIndexPath(b.path)\n if (aIsIndex && !bIsIndex) return 1\n if (!aIsIndex && bIsIndex) return -1\n\n return 0\n}\n\n/**\n * In-memory file store for generated files, and the writer that turns them into source\n * strings on `storage`. Files sharing a `path` are merged (sources/imports/exports\n * concatenated). The `files` getter is sorted by path length (barrel `index.ts` last\n * within a bucket).\n *\n * @example\n * ```ts\n * const manager = new FileManager()\n * manager.upsert(myFile)\n * manager.files // sorted view\n * await manager.write(manager.files, { storage: fsStorage() })\n * ```\n */\nexport class FileManager {\n readonly hooks = new Hookable<FileManagerHooks>()\n readonly #cache = new Map<string, FileNode>()\n // Cached sorted view. Null means stale and rebuilt lazily on next `files` read.\n // Nulled (not mutated) on every write so callers holding a prior reference keep\n // their snapshot. `dispose()` must not silently empty an array the consumer\n // already holds.\n #sorted: Array<FileNode> | null = null\n\n add(...files: Array<FileNode>): Array<FileNode> {\n return this.#store(files, false)\n }\n\n upsert(...files: Array<FileNode>): Array<FileNode> {\n return this.#store(files, true)\n }\n\n #store(files: ReadonlyArray<FileNode>, mergeExisting: boolean): Array<FileNode> {\n const batch = files.length > 1 ? this.#dedupe(files) : files\n const resolved: Array<FileNode> = []\n\n for (const file of batch) {\n const existing = this.#cache.get(file.path)\n const merged = existing && mergeExisting ? ast.factory.createFile(mergeFile(existing, file)) : ast.factory.createFile(file)\n this.#cache.set(merged.path, merged)\n resolved.push(merged)\n }\n\n if (resolved.length > 0) this.#sorted = null\n return resolved\n }\n\n // Merges same-path entries within a batch so the cache update loop stays\n // uniform. Only called for multi-file batches.\n #dedupe(files: ReadonlyArray<FileNode>): Array<FileNode> {\n const seen = new Map<string, FileNode>()\n for (const file of files) {\n const prev = seen.get(file.path)\n seen.set(file.path, prev ? mergeFile(prev, file) : file)\n }\n return [...seen.values()]\n }\n\n clear(): void {\n this.#cache.clear()\n this.#sorted = null\n }\n\n /**\n * Releases all stored files and clears every `hooks` listener. Called by the core after\n * `kubb:build:end`.\n */\n dispose(): void {\n this.clear()\n this.hooks.removeAllHooks()\n }\n\n /**\n * All stored files in stable sort order (shortest path first, barrel files\n * last within a length bucket). Returns a cached view, do not mutate.\n */\n get files(): Array<FileNode> {\n return (this.#sorted ??= [...this.#cache.values()].sort(compareFiles))\n }\n\n /**\n * Converts a file's AST sources (or its `copy` source) into the final on-disk string.\n */\n async parse(file: FileNode, { parsers }: ParseOptions = {}): Promise<string> {\n if (file.copy) {\n return parseCopy(file)\n }\n\n if (!parsers || !file.extname) {\n return joinSources(file)\n }\n\n const parser = parsers.get(file.extname)\n\n if (!parser) {\n return joinSources(file)\n }\n\n return parser.parse(file)\n }\n\n /**\n * Converts and writes every file at once, letting `storage.setItem` decide how much of\n * that runs concurrently.\n */\n async write(files: Array<FileNode>, { storage, parsers }: WriteOptions): Promise<void> {\n if (files.length === 0) return\n\n await this.hooks.callHook('start', files)\n\n const total = files.length\n let processed = 0\n await Promise.all(\n files.map(async (file) => {\n const source = await this.parse(file, { parsers })\n processed++\n await this.hooks.callHook('update', { file, source, processed, total, percentage: (processed / total) * 100 })\n if (source) await storage.setItem(file.path, source)\n }),\n )\n\n await this.hooks.callHook('end', files)\n }\n}\n"],"mappings":"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"} |
+52
-4
| import { t as __name } from "./rolldown-runtime-C0LytTxp.js"; | ||
| import { $ as Include, A as KubbHookStartContext, At as Reporter, B as Kubb, C as KubbFilesProcessingEndContext, Ct as ResolverPathParams, D as KubbGenerationStartContext, Dt as Storage, E as KubbGenerationEndContext, Et as createRenderer, F as KubbSuccessContext, Ft as logLevel, G as KubbDriver, H as Generator, I as KubbWarnContext, It as Adapter, J as Parser, K as FileManagerHooks, L as PossibleConfig, Lt as AdapterFactoryOptions, M as KubbInfoContext, Mt as ReporterName, N as KubbLifecycleStartContext, Nt as UserReporter, O as KubbHookEndContext, Ot as createStorage, P as KubbPluginsEndContext, Pt as createReporter, Q as Group, R as UserConfig, Rt as AdapterSource, S as KubbFileProcessingUpdate, St as ResolverPatch, T as KubbFilesProcessingUpdateContext, Tt as RendererFactory, U as GeneratorContext, V as createKubb, W as defineGenerator, X as Exclude, Y as defineParser, Z as Filter, _ as InputPath, _t as Resolver, a as DiagnosticLocation, at as OutputMode, b as KubbDiagnosticContext, bt as ResolverFileParams, c as PerformanceDiagnostic, ct as Plugin, d as SerializedDiagnostic, dt as BannerMeta, et as KubbPluginEndContext, f as UpdateDiagnostic, ft as ResolveBannerContext, g as InputData, gt as ResolvePathOptions, h as Config, ht as ResolveOptionsContext, i as DiagnosticKind, it as Output, j as KubbHooks, jt as ReporterContext, k as KubbHookLineContext, kt as GenerationResult, l as ProblemCode, lt as PluginFactoryOptions, m as CLIOptions, mt as ResolveFileOptions, n as DiagnosticByCode, nt as KubbPluginStartContext, o as DiagnosticSeverity, ot as OutputOptions, p as BuildOutput, pt as ResolveBannerFile, q as Hookable, r as DiagnosticDoc, rt as NormalizedPlugin, s as Diagnostics, st as Override, t as Diagnostic, tt as KubbPluginSetupContext, u as ProblemDiagnostic, ut as definePlugin, v as KubbBuildEndContext, vt as ResolverDefault, w as KubbFilesProcessingStartContext, wt as Renderer, x as KubbErrorContext, xt as ResolverFilePathParams, y as KubbBuildStartContext, yt as ResolverFile, z as CreateKubbOptions, zt as createAdapter } from "./Diagnostics-CM0-Ae30.js"; | ||
| import { $ as ResolveBannerFile, A as GeneratorContext, At as ProblemCode, B as KubbPluginEndContext, C as KubbWarnContext, Ct as DiagnosticByCode, D as Kubb, Dt as DiagnosticSeverity, E as CreateKubbOptions, Et as DiagnosticLocation, F as defineParser, Ft as Adapter, G as OutputMode, H as KubbPluginStartContext, I as Exclude, It as AdapterFactoryOptions, J as Plugin, K as OutputOptions, L as Filter, Lt as AdapterSource, M as KubbDriver, Mt as SerializedDiagnostic, N as FileManagerHooks, Nt as UpdateDiagnostic, O as createKubb, Ot as Diagnostics, P as Parser, Pt as Hookable, Q as ResolveBannerContext, R as Group, Rt as createAdapter, S as KubbSuccessContext, St as Diagnostic, T as UserConfig, Tt as DiagnosticKind, U as NormalizedPlugin, V as KubbPluginSetupContext, W as Output, X as definePlugin, Y as PluginFactoryOptions, Z as BannerMeta, _ as KubbHookStartContext, _t as ReporterContext, a as KubbBuildEndContext, at as ResolverFile, b as KubbLifecycleStartContext, bt as createReporter, c as KubbErrorContext, ct as ResolverPatch, d as KubbFilesProcessingStartContext, dt as RendererFactory, et as ResolveFileOptions, f as KubbFilesProcessingUpdateContext, ft as createRenderer, g as KubbHookLineContext, gt as Reporter, h as KubbHookEndContext, ht as GenerationResult, i as Input, it as ResolverDefault, j as defineGenerator, jt as ProblemDiagnostic, k as Generator, kt as PerformanceDiagnostic, l as KubbFileProcessingUpdate, lt as ResolverPathParams, m as KubbGenerationStartContext, mt as createStorage, n as CLIOptions, nt as ResolvePathOptions, o as KubbBuildStartContext, ot as ResolverFileParams, p as KubbGenerationEndContext, pt as Storage, q as Override, r as Config, rt as Resolver, s as KubbDiagnosticContext, st as ResolverFilePathParams, t as BuildOutput, tt as ResolveOptionsContext, u as KubbFilesProcessingEndContext, ut as Renderer, v as KubbHooks, vt as ReporterName, w as PossibleConfig, wt as DiagnosticDoc, x as KubbPluginsEndContext, xt as logLevel, y as KubbInfoContext, yt as UserReporter, z as Include } from "./types-aNebW3Ui.js"; | ||
| //#region src/applyConfigDefaults.d.ts | ||
| type ApplyConfigDefaultsOptions<TOutput> = { | ||
| defaultAdapter: Adapter; | ||
| barrelPlugin: Plugin; | ||
| barrelPluginName: string; /** Output fields to fill in when the user's config leaves them unset. */ | ||
| defaultOutput: Partial<TOutput>; | ||
| }; | ||
| /** | ||
| * Fills in the config defaults shared by `defineConfig` and the unplugin factory: the fallback | ||
| * adapter, `defaultOutput`'s fields, and appending the barrel plugin when it's not already | ||
| * registered. Both entry points construct their own adapter, barrel plugin, and output defaults | ||
| * (`barrel` is a `@kubb/plugin-barrel` extension field core doesn't know about) and pass them in, | ||
| * so `@kubb/core` doesn't need to depend on `@kubb/adapter-oas` or `@kubb/plugin-barrel`. | ||
| */ | ||
| declare function applyConfigDefaults<TOutput extends Config['output'] = Config['output']>(config: { | ||
| adapter?: Adapter; | ||
| output: TOutput; | ||
| plugins?: Array<Plugin>; | ||
| }, { | ||
| defaultAdapter, | ||
| barrelPlugin, | ||
| barrelPluginName, | ||
| defaultOutput | ||
| }: ApplyConfigDefaultsOptions<TOutput>): { | ||
| adapter: Adapter; | ||
| output: TOutput; | ||
| plugins: Array<Plugin>; | ||
| }; | ||
| //#endregion | ||
| //#region src/reporters/cliReporter.d.ts | ||
@@ -91,2 +120,21 @@ /** | ||
| //#endregion | ||
| //#region src/input.d.ts | ||
| /** | ||
| * What an `input` value points at, once Kubb has looked at it. | ||
| * | ||
| * - `file` is a local file path, absolute or relative to the config file. | ||
| * - `url` is a remote document to fetch. | ||
| * - `inline` is OpenAPI content held in the string itself (JSON or YAML). | ||
| * - `object` is an already-parsed spec. | ||
| */ | ||
| type InputKind = 'file' | 'url' | 'inline' | 'object'; | ||
| /** | ||
| * Classifies an `input` value so callers branch on it once instead of repeating the checks. | ||
| * | ||
| * A non-string is a parsed spec (`object`). A string is `inline` when it holds OpenAPI content, | ||
| * meaning it starts with `{` or `[`, spans multiple lines, or opens with a YAML `openapi:` or | ||
| * `swagger:` key. Otherwise a string is a `url` when it parses as one, or a `file` path. | ||
| */ | ||
| declare function getInputKind(input: NonNullable<Input>): InputKind; | ||
| //#endregion | ||
| //#region src/storages/fsStorage.d.ts | ||
@@ -114,3 +162,3 @@ /** | ||
| * export default defineConfig({ | ||
| * input: { path: './petStore.yaml' }, | ||
| * input: './petStore.yaml', | ||
| * output: { path: './src/gen' }, | ||
@@ -137,3 +185,3 @@ * storage: fsStorage(), | ||
| * export default defineConfig({ | ||
| * input: { path: './petStore.yaml' }, | ||
| * input: './petStore.yaml', | ||
| * output: { path: './src/gen' }, | ||
@@ -146,3 +194,3 @@ * storage: memoryStorage(), | ||
| //#endregion | ||
| export { type Adapter, type AdapterFactoryOptions, type AdapterSource, type BannerMeta, BuildOutput, CLIOptions, Config, type CreateKubbOptions, type Diagnostic, type DiagnosticByCode, type DiagnosticDoc, type DiagnosticKind, type DiagnosticLocation, type DiagnosticSeverity, Diagnostics, type Exclude, type FileManagerHooks, type Filter, type GenerationResult, type Generator, type GeneratorContext, type Group, Hookable, type Include, InputData, InputPath, type Kubb, KubbBuildEndContext, KubbBuildStartContext, KubbDiagnosticContext, KubbDriver, KubbErrorContext, KubbFileProcessingUpdate, KubbFilesProcessingEndContext, KubbFilesProcessingStartContext, KubbFilesProcessingUpdateContext, KubbGenerationEndContext, KubbGenerationStartContext, KubbHookEndContext, KubbHookLineContext, KubbHookStartContext, KubbHooks, KubbInfoContext, KubbLifecycleStartContext, type KubbPluginEndContext, type KubbPluginSetupContext, type KubbPluginStartContext, KubbPluginsEndContext, KubbSuccessContext, KubbWarnContext, type NormalizedPlugin, type Output, type OutputMode, type OutputOptions, type Override, type Parser, type PerformanceDiagnostic, type Plugin, type PluginFactoryOptions, PossibleConfig, type ProblemCode, type ProblemDiagnostic, type Renderer, type RendererFactory, type Reporter, type ReporterContext, type ReporterName, type ResolveBannerContext, type ResolveBannerFile, type ResolveFileOptions, type ResolveOptionsContext, type ResolvePathOptions, Resolver, type ResolverDefault, type ResolverFile, type ResolverFileParams, type ResolverFilePathParams, type ResolverPatch, type ResolverPathParams, type SerializedDiagnostic, type Storage, type UpdateDiagnostic, UserConfig, type UserReporter, cliReporter, createAdapter, createKubb, createRenderer, createReporter, createResolver, createStorage, defineGenerator, defineParser, definePlugin, fileReporter, fsStorage, jsonReporter, logLevel, memoryStorage }; | ||
| export { type Adapter, type AdapterFactoryOptions, type AdapterSource, type BannerMeta, BuildOutput, CLIOptions, Config, type CreateKubbOptions, type Diagnostic, type DiagnosticByCode, type DiagnosticDoc, type DiagnosticKind, type DiagnosticLocation, type DiagnosticSeverity, Diagnostics, type Exclude, type FileManagerHooks, type Filter, type GenerationResult, type Generator, type GeneratorContext, type Group, Hookable, type Include, Input, type InputKind, type Kubb, KubbBuildEndContext, KubbBuildStartContext, KubbDiagnosticContext, KubbDriver, KubbErrorContext, KubbFileProcessingUpdate, KubbFilesProcessingEndContext, KubbFilesProcessingStartContext, KubbFilesProcessingUpdateContext, KubbGenerationEndContext, KubbGenerationStartContext, KubbHookEndContext, KubbHookLineContext, KubbHookStartContext, KubbHooks, KubbInfoContext, KubbLifecycleStartContext, type KubbPluginEndContext, type KubbPluginSetupContext, type KubbPluginStartContext, KubbPluginsEndContext, KubbSuccessContext, KubbWarnContext, type NormalizedPlugin, type Output, type OutputMode, type OutputOptions, type Override, type Parser, type PerformanceDiagnostic, type Plugin, type PluginFactoryOptions, PossibleConfig, type ProblemCode, type ProblemDiagnostic, type Renderer, type RendererFactory, type Reporter, type ReporterContext, type ReporterName, type ResolveBannerContext, type ResolveBannerFile, type ResolveFileOptions, type ResolveOptionsContext, type ResolvePathOptions, Resolver, type ResolverDefault, type ResolverFile, type ResolverFileParams, type ResolverFilePathParams, type ResolverPatch, type ResolverPathParams, type SerializedDiagnostic, type Storage, type UpdateDiagnostic, UserConfig, type UserReporter, applyConfigDefaults, cliReporter, createAdapter, createKubb, createRenderer, createReporter, createResolver, createStorage, defineGenerator, defineParser, definePlugin, fileReporter, fsStorage, getInputKind, jsonReporter, logLevel, memoryStorage }; | ||
| //# sourceMappingURL=index.d.ts.map |
+1
-1
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const require_usingCtx = require("./usingCtx-BN2OKJRx.cjs"); | ||
| const require_usingCtx = require("./usingCtx-eyNeehd2.cjs"); | ||
| let node_path = require("node:path"); | ||
@@ -4,0 +4,0 @@ node_path = require_usingCtx.__toESM(node_path, 1); |
+1
-1
| import { t as __name } from "./rolldown-runtime-C0LytTxp.js"; | ||
| import { G as KubbDriver, H as Generator, It as Adapter, J as Parser, Lt as AdapterFactoryOptions, h as Config, lt as PluginFactoryOptions, rt as NormalizedPlugin } from "./Diagnostics-CM0-Ae30.js"; | ||
| import { Ft as Adapter, It as AdapterFactoryOptions, M as KubbDriver, P as Parser, U as NormalizedPlugin, Y as PluginFactoryOptions, k as Generator, r as Config } from "./types-aNebW3Ui.js"; | ||
| import { FileNode, InputMeta, Macro, OperationNode, SchemaNode } from "@kubb/ast"; | ||
@@ -4,0 +4,0 @@ |
+1
-1
| import "./rolldown-runtime-C0LytTxp.js"; | ||
| import { d as camelCase, n as FileManager, t as _usingCtx } from "./usingCtx-Cnrm3TcM.js"; | ||
| import { d as camelCase, n as FileManager, t as _usingCtx } from "./usingCtx-BriKju-v.js"; | ||
| import path, { resolve } from "node:path"; | ||
@@ -4,0 +4,0 @@ import { applyMacros } from "@kubb/ast"; |
+2
-2
| { | ||
| "name": "@kubb/core", | ||
| "version": "5.0.0-beta.89", | ||
| "version": "5.0.0-beta.91", | ||
| "description": "Core engine for Kubb. Provides the plugin driver, file manager and build orchestration used by every Kubb plugin.", | ||
@@ -58,3 +58,3 @@ "keywords": [ | ||
| "dependencies": { | ||
| "@kubb/ast": "5.0.0-beta.89" | ||
| "@kubb/ast": "5.0.0-beta.91" | ||
| }, | ||
@@ -61,0 +61,0 @@ "devDependencies": { |
Sorry, the diff of this file is too big to display
| //#region \0rolldown/runtime.js | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __name = (target, value) => __defProp(target, "name", { | ||
| value, | ||
| configurable: true | ||
| }); | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { | ||
| key = keys[i]; | ||
| if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { | ||
| get: ((k) => from[k]).bind(null, key), | ||
| enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable | ||
| }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { | ||
| value: mod, | ||
| enumerable: true | ||
| }) : target, mod)); | ||
| //#endregion | ||
| let node_fs_promises = require("node:fs/promises"); | ||
| let node_path = require("node:path"); | ||
| let _kubb_ast = require("@kubb/ast"); | ||
| let node_events = require("node:events"); | ||
| //#region ../../internals/utils/src/casing.ts | ||
| /** | ||
| * Shared implementation for camelCase and PascalCase conversion. | ||
| * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons) | ||
| * and capitalizes each word according to `pascal`. | ||
| * | ||
| * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are. | ||
| */ | ||
| function toCamelOrPascal(text, pascal) { | ||
| return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => { | ||
| if (word.length > 1 && word === word.toUpperCase()) return word; | ||
| return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1); | ||
| }).join("").replace(/[^a-zA-Z0-9]/g, ""); | ||
| } | ||
| /** | ||
| * Converts `text` to camelCase. | ||
| * | ||
| * @example Word boundaries | ||
| * `camelCase('hello-world') // 'helloWorld'` | ||
| * | ||
| * @example With a prefix | ||
| * `camelCase('tag', { prefix: 'create' }) // 'createTag'` | ||
| */ | ||
| function camelCase(text, { prefix = "", suffix = "" } = {}) { | ||
| return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/errors.ts | ||
| /** | ||
| * Thrown when one or more errors occur during a Kubb build. | ||
| * Carries the full list of underlying errors on `errors`. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * throw new BuildError('Build failed', { errors: [err1, err2] }) | ||
| * ``` | ||
| */ | ||
| var BuildError = class extends Error { | ||
| errors; | ||
| constructor(message, options) { | ||
| super(message, { cause: options.cause }); | ||
| this.name = "BuildError"; | ||
| this.errors = options.errors; | ||
| } | ||
| }; | ||
| /** | ||
| * Coerces an unknown thrown value to an `Error` instance. | ||
| * Returns the value as-is when it is already an `Error`; otherwise wraps it with `String(value)`. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * try { ... } catch(err) { | ||
| * throw new BuildError('Build failed', { cause: toError(err), errors: [] }) | ||
| * } | ||
| * ``` | ||
| */ | ||
| function toError(value) { | ||
| return value instanceof Error ? value : new Error(String(value)); | ||
| } | ||
| /** | ||
| * Extracts a human-readable message from any thrown value. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * getErrorMessage(new Error('oops')) // 'oops' | ||
| * getErrorMessage('plain string') // 'plain string' | ||
| * ``` | ||
| */ | ||
| function getErrorMessage(value) { | ||
| return value instanceof Error ? value.message : String(value); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/runtime.ts | ||
| /** | ||
| * Detects the JavaScript runtime executing the current process and exposes its name and version. | ||
| * | ||
| * Prefer the shared {@link runtime} instance over constructing your own. | ||
| */ | ||
| var Runtime = class { | ||
| /** | ||
| * `true` when the current process is running under Bun. | ||
| * | ||
| * Detection keys off the global `Bun` object rather than `process.versions`, | ||
| * because Bun polyfills `process.versions.node` for Node compatibility and would | ||
| * otherwise look like Node. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * if (runtime.isBun) { | ||
| * await Bun.write(path, data) | ||
| * } | ||
| * ``` | ||
| */ | ||
| get isBun() { | ||
| return typeof Bun !== "undefined"; | ||
| } | ||
| /** | ||
| * `true` when the current process is running under Deno. | ||
| */ | ||
| get isDeno() { | ||
| return typeof globalThis.Deno !== "undefined"; | ||
| } | ||
| /** | ||
| * `true` when the current process is running under Node. | ||
| * | ||
| * Bun and Deno are excluded first so a polyfilled `process` does not register as Node. | ||
| */ | ||
| get isNode() { | ||
| return !this.isBun && !this.isDeno && typeof process !== "undefined" && process.versions?.node != null; | ||
| } | ||
| /** | ||
| * Name of the runtime executing the current process. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * runtime.name // 'bun' when run with `bun kubb`, 'node' otherwise | ||
| * ``` | ||
| */ | ||
| get name() { | ||
| if (this.isBun) return "bun"; | ||
| if (this.isDeno) return "deno"; | ||
| return "node"; | ||
| } | ||
| /** | ||
| * Version of the active runtime, or an empty string when it cannot be read. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * runtime.version // '1.3.11' under Bun, '22.22.2' under Node | ||
| * ``` | ||
| */ | ||
| get version() { | ||
| if (this.isBun) return process.versions.bun ?? ""; | ||
| if (this.isDeno) return globalThis.Deno?.version?.deno ?? ""; | ||
| return process.versions?.node ?? ""; | ||
| } | ||
| }; | ||
| /** | ||
| * Shared {@link Runtime} instance describing the JavaScript runtime executing the current process. | ||
| */ | ||
| const runtime = new Runtime(); | ||
| //#endregion | ||
| //#region ../../internals/utils/src/fs.ts | ||
| /** | ||
| * Reads the file at `path` as a UTF-8 string. | ||
| * Uses `Bun.file().text()` when running under Bun, `fs.readFile` otherwise. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const source = await read('./src/Pet.ts') | ||
| * ``` | ||
| */ | ||
| async function read(path) { | ||
| if (runtime.isBun) return Bun.file(path).text(); | ||
| return (0, node_fs_promises.readFile)(path, { encoding: "utf8" }); | ||
| } | ||
| /** | ||
| * Writes `data` to `path`, trimming leading/trailing whitespace before saving. | ||
| * Skips the write when the trimmed content is empty or identical to what is already on disk. | ||
| * Creates any missing parent directories automatically. | ||
| * When `sanity` is `true`, re-reads the file after writing and throws if the content does not match. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * await write('./src/Pet.ts', source) // writes and returns trimmed content | ||
| * await write('./src/Pet.ts', source) // null — file unchanged | ||
| * await write('./src/Pet.ts', ' ') // null — empty content skipped | ||
| * ``` | ||
| */ | ||
| async function write(path, data, options = {}) { | ||
| const trimmed = data.trim(); | ||
| if (trimmed === "") return null; | ||
| const resolved = (0, node_path.resolve)(path); | ||
| if (runtime.isBun) { | ||
| const file = Bun.file(resolved); | ||
| if ((await file.exists() ? await file.text() : null) === trimmed) return null; | ||
| await Bun.write(resolved, trimmed); | ||
| return trimmed; | ||
| } | ||
| try { | ||
| if (await (0, node_fs_promises.readFile)(resolved, { encoding: "utf-8" }) === trimmed) return null; | ||
| } catch {} | ||
| await (0, node_fs_promises.mkdir)((0, node_path.dirname)(resolved), { recursive: true }); | ||
| await (0, node_fs_promises.writeFile)(resolved, trimmed, { encoding: "utf-8" }); | ||
| if (options.sanity) { | ||
| const savedData = await (0, node_fs_promises.readFile)(resolved, { encoding: "utf-8" }); | ||
| if (savedData !== trimmed) throw new Error(`Sanity check failed for ${path}\n\nData[${data.length}]:\n${data}\n\nSaved[${savedData.length}]:\n${savedData}\n`); | ||
| return savedData; | ||
| } | ||
| return trimmed; | ||
| } | ||
| /** | ||
| * Recursively removes `path`. Silently succeeds when `path` does not exist. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * await clean('./dist') | ||
| * ``` | ||
| */ | ||
| async function clean(path) { | ||
| return (0, node_fs_promises.rm)(path, { | ||
| recursive: true, | ||
| force: true | ||
| }); | ||
| } | ||
| /** | ||
| * Converts a filesystem path to use POSIX (`/`) separators. | ||
| * | ||
| * Most of the codebase compares and composes paths as strings (prefix matching, joining for | ||
| * import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated | ||
| * paths, but on Windows it returns `\`-separated paths, which breaks every such comparison. | ||
| * | ||
| * Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the | ||
| * code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is | ||
| * exercisable from POSIX CI. | ||
| * | ||
| * @example | ||
| * toPosixPath('C:\\repo\\src\\pet.ts') // 'C:/repo/src/pet.ts' | ||
| */ | ||
| function toPosixPath(filePath) { | ||
| return filePath.replaceAll("\\", "/"); | ||
| } | ||
| /** | ||
| * Builds a nested file path from a dotted name. Splits on dots that precede a letter | ||
| * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases | ||
| * every earlier segment, applies `caseLast` to the final segment, and joins with `/`. | ||
| * | ||
| * Empty segments are dropped before joining. They arise when the name starts with a dot | ||
| * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to | ||
| * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an | ||
| * absolute path, letting generated files escape the configured output directory. | ||
| * | ||
| * @example Nested path from a dotted name | ||
| * `toFilePath('pet.petId') // 'pet/petId'` | ||
| * | ||
| * @example PascalCase the final segment | ||
| * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'` | ||
| * | ||
| * @example Suffix applied to the final segment only | ||
| * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'` | ||
| */ | ||
| function toFilePath(name, caseLast = camelCase) { | ||
| const parts = name.split(/\.(?=[a-zA-Z])/); | ||
| return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/"); | ||
| } | ||
| //#endregion | ||
| //#region src/Hookable.ts | ||
| /** | ||
| * Typed hook emitter that awaits all async listeners before resolving. | ||
| * Wraps Node's `EventEmitter` with full TypeScript hook-map inference. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const hooks = new Hookable<{ build: [name: string] }>() | ||
| * hooks.hook('build', async (name) => { console.log(name) }) | ||
| * await hooks.callHook('build', 'petstore') // all listeners awaited | ||
| * ``` | ||
| */ | ||
| var Hookable = class { | ||
| /** | ||
| * Maximum number of listeners per hook before Node emits a memory-leak warning. | ||
| * @default 10 | ||
| */ | ||
| constructor(maxListener = 10) { | ||
| this.#emitter.setMaxListeners(maxListener); | ||
| } | ||
| #emitter = new node_events.EventEmitter(); | ||
| /** | ||
| * Calls `hookName` and awaits all registered listeners sequentially. | ||
| * Throws if any listener rejects, wrapping the cause with the hook name and serialized arguments. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * await hooks.callHook('build', 'petstore') | ||
| * ``` | ||
| */ | ||
| callHook(hookName, ...hookArgs) { | ||
| const listeners = this.#emitter.listeners(hookName); | ||
| if (listeners.length === 0) return; | ||
| return this.#emitAll(hookName, listeners, hookArgs); | ||
| } | ||
| async #emitAll(hookName, listeners, hookArgs) { | ||
| for (const listener of listeners) try { | ||
| await listener(...hookArgs); | ||
| } catch (err) { | ||
| let serializedArgs; | ||
| try { | ||
| serializedArgs = JSON.stringify(hookArgs); | ||
| } catch { | ||
| serializedArgs = String(hookArgs); | ||
| } | ||
| throw new Error(`Error in async listener for "${hookName}" with hookArgs ${serializedArgs}`, { cause: toError(err) }); | ||
| } | ||
| } | ||
| /** | ||
| * Registers a persistent listener for `hookName` and returns a function that removes it. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const unhook = hooks.hook('build', async (name) => { console.log(name) }) | ||
| * unhook() // removes it | ||
| * ``` | ||
| */ | ||
| hook(hookName, handler) { | ||
| this.#emitter.on(hookName, handler); | ||
| return () => this.removeHook(hookName, handler); | ||
| } | ||
| /** | ||
| * Registers every handler in `configHooks` at once and returns a function that removes them | ||
| * all. Undefined entries are skipped, so a partial hook object registers only its present keys. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const unhook = hooks.addHooks({ build: onBuild, done: onDone }) | ||
| * unhook() // removes both | ||
| * ``` | ||
| */ | ||
| addHooks(configHooks) { | ||
| const unhooks = Object.keys(configHooks).filter((name) => configHooks[name]).map((name) => this.hook(name, configHooks[name])); | ||
| return () => { | ||
| for (const unhook of unhooks) unhook(); | ||
| }; | ||
| } | ||
| /** | ||
| * Removes a previously registered listener. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * hooks.removeHook('build', handler) | ||
| * ``` | ||
| */ | ||
| removeHook(hookName, handler) { | ||
| this.#emitter.off(hookName, handler); | ||
| } | ||
| /** | ||
| * Returns the number of listeners registered for `hookName`. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * hooks.hook('build', handler) | ||
| * hooks.listenerCount('build') // 1 | ||
| * ``` | ||
| */ | ||
| listenerCount(hookName) { | ||
| return this.#emitter.listenerCount(hookName); | ||
| } | ||
| /** | ||
| * Raises or lowers the per-hook listener ceiling before Node warns about a memory leak. | ||
| * Set this above the expected listener count when many listeners attach by design. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * hooks.setMaxListeners(40) | ||
| * ``` | ||
| */ | ||
| setMaxListeners(max) { | ||
| this.#emitter.setMaxListeners(max); | ||
| } | ||
| /** | ||
| * Removes all listeners from every hook channel. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * hooks.removeAllHooks() | ||
| * ``` | ||
| */ | ||
| removeAllHooks() { | ||
| this.#emitter.removeAllListeners(); | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region src/FileManager.ts | ||
| function joinSources(file) { | ||
| return file.sources.map((source) => (0, _kubb_ast.extractStringsFromNodes)(source.nodes)).filter(Boolean).join("\n\n"); | ||
| } | ||
| async function parseCopy(file) { | ||
| let content; | ||
| try { | ||
| content = await read(file.copy); | ||
| } catch (err) { | ||
| throw new Error(`[kubb] Could not copy file into output: ${file.copy}`, { cause: err }); | ||
| } | ||
| return [ | ||
| file.banner, | ||
| content, | ||
| file.footer | ||
| ].filter((segment) => Boolean(segment)).map((segment) => segment.trimEnd()).join("\n"); | ||
| } | ||
| function mergeFile(a, b) { | ||
| return { | ||
| ...a, | ||
| banner: b.banner, | ||
| footer: b.footer, | ||
| copy: b.copy ?? a.copy, | ||
| sources: a.sources.length ? b.sources.length ? [...a.sources, ...b.sources] : a.sources : b.sources, | ||
| imports: a.imports.length ? b.imports.length ? [...a.imports, ...b.imports] : a.imports : b.imports, | ||
| exports: a.exports.length ? b.exports.length ? [...a.exports, ...b.exports] : a.exports : b.exports | ||
| }; | ||
| } | ||
| function isIndexPath(path) { | ||
| return path.endsWith("/index.ts") || path === "index.ts"; | ||
| } | ||
| function compareFiles(a, b) { | ||
| const lenDiff = a.path.length - b.path.length; | ||
| if (lenDiff !== 0) return lenDiff; | ||
| const aIsIndex = isIndexPath(a.path); | ||
| const bIsIndex = isIndexPath(b.path); | ||
| if (aIsIndex && !bIsIndex) return 1; | ||
| if (!aIsIndex && bIsIndex) return -1; | ||
| return 0; | ||
| } | ||
| /** | ||
| * In-memory file store for generated files, and the writer that turns them into source | ||
| * strings on `storage`. Files sharing a `path` are merged (sources/imports/exports | ||
| * concatenated). The `files` getter is sorted by path length (barrel `index.ts` last | ||
| * within a bucket). | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const manager = new FileManager() | ||
| * manager.upsert(myFile) | ||
| * manager.files // sorted view | ||
| * await manager.write(manager.files, { storage: fsStorage() }) | ||
| * ``` | ||
| */ | ||
| var FileManager = class { | ||
| hooks = new Hookable(); | ||
| #cache = /* @__PURE__ */ new Map(); | ||
| #sorted = null; | ||
| add(...files) { | ||
| return this.#store(files, false); | ||
| } | ||
| upsert(...files) { | ||
| return this.#store(files, true); | ||
| } | ||
| #store(files, mergeExisting) { | ||
| const batch = files.length > 1 ? this.#dedupe(files) : files; | ||
| const resolved = []; | ||
| for (const file of batch) { | ||
| const existing = this.#cache.get(file.path); | ||
| const merged = existing && mergeExisting ? _kubb_ast.ast.factory.createFile(mergeFile(existing, file)) : _kubb_ast.ast.factory.createFile(file); | ||
| this.#cache.set(merged.path, merged); | ||
| resolved.push(merged); | ||
| } | ||
| if (resolved.length > 0) this.#sorted = null; | ||
| return resolved; | ||
| } | ||
| #dedupe(files) { | ||
| const seen = /* @__PURE__ */ new Map(); | ||
| for (const file of files) { | ||
| const prev = seen.get(file.path); | ||
| seen.set(file.path, prev ? mergeFile(prev, file) : file); | ||
| } | ||
| return [...seen.values()]; | ||
| } | ||
| clear() { | ||
| this.#cache.clear(); | ||
| this.#sorted = null; | ||
| } | ||
| /** | ||
| * Releases all stored files and clears every `hooks` listener. Called by the core after | ||
| * `kubb:build:end`. | ||
| */ | ||
| dispose() { | ||
| this.clear(); | ||
| this.hooks.removeAllHooks(); | ||
| } | ||
| /** | ||
| * All stored files in stable sort order (shortest path first, barrel files | ||
| * last within a length bucket). Returns a cached view, do not mutate. | ||
| */ | ||
| get files() { | ||
| return this.#sorted ??= [...this.#cache.values()].sort(compareFiles); | ||
| } | ||
| /** | ||
| * Converts a file's AST sources (or its `copy` source) into the final on-disk string. | ||
| */ | ||
| async parse(file, { parsers, extension } = {}) { | ||
| if (file.copy) return parseCopy(file); | ||
| const parseExtName = extension?.[file.extname] || void 0; | ||
| if (!parsers || !file.extname) return joinSources(file); | ||
| const parser = parsers.get(file.extname); | ||
| if (!parser) return joinSources(file); | ||
| return parser.parse(file, { extname: parseExtName }); | ||
| } | ||
| /** | ||
| * Converts and writes every file at once, letting `storage.setItem` decide how much of | ||
| * that runs concurrently. | ||
| */ | ||
| async write(files, { storage, parsers, extension }) { | ||
| if (files.length === 0) return; | ||
| await this.hooks.callHook("start", files); | ||
| const total = files.length; | ||
| let processed = 0; | ||
| await Promise.all(files.map(async (file) => { | ||
| const source = await this.parse(file, { | ||
| parsers, | ||
| extension | ||
| }); | ||
| processed++; | ||
| await this.hooks.callHook("update", { | ||
| file, | ||
| source, | ||
| processed, | ||
| total, | ||
| percentage: processed / total * 100 | ||
| }); | ||
| if (source) await storage.setItem(file.path, source); | ||
| })); | ||
| await this.hooks.callHook("end", files); | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region \0@oxc-project+runtime@0.138.0/helpers/esm/usingCtx.js | ||
| function _usingCtx() { | ||
| var r = "function" == typeof SuppressedError ? SuppressedError : function(r, e) { | ||
| var n = Error(); | ||
| return n.name = "SuppressedError", n.error = r, n.suppressed = e, n; | ||
| }; | ||
| var e = {}; | ||
| var n = []; | ||
| function using(r, e) { | ||
| if (null != e) { | ||
| if (Object(e) !== e) throw new TypeError("using declarations can only be used with objects, functions, null, or undefined."); | ||
| if (r) var o = e[Symbol.asyncDispose || Symbol["for"]("Symbol.asyncDispose")]; | ||
| if (void 0 === o && (o = e[Symbol.dispose || Symbol["for"]("Symbol.dispose")], r)) var t = o; | ||
| if ("function" != typeof o) throw new TypeError("Object is not disposable."); | ||
| t && (o = function o() { | ||
| try { | ||
| t.call(e); | ||
| } catch (r) { | ||
| return Promise.reject(r); | ||
| } | ||
| }), n.push({ | ||
| v: e, | ||
| d: o, | ||
| a: r | ||
| }); | ||
| } else r && n.push({ | ||
| d: e, | ||
| a: r | ||
| }); | ||
| return e; | ||
| } | ||
| return { | ||
| e, | ||
| u: using.bind(null, !1), | ||
| a: using.bind(null, !0), | ||
| d: function d() { | ||
| var o; | ||
| var t = this.e; | ||
| var s = 0; | ||
| function next() { | ||
| for (; o = n.pop();) try { | ||
| if (!o.a && 1 === s) return s = 0, n.push(o), Promise.resolve().then(next); | ||
| if (o.d) { | ||
| var r = o.d.call(o.v); | ||
| if (o.a) return s |= 2, Promise.resolve(r).then(next, err); | ||
| } else s |= 1; | ||
| } catch (r) { | ||
| return err(r); | ||
| } | ||
| if (1 === s) return t !== e ? Promise.reject(t) : Promise.resolve(); | ||
| if (t !== e) throw t; | ||
| } | ||
| function err(n) { | ||
| return t = t !== e ? new r(n, t) : n, next(); | ||
| } | ||
| return next(); | ||
| } | ||
| }; | ||
| } | ||
| //#endregion | ||
| Object.defineProperty(exports, "BuildError", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return BuildError; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "FileManager", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return FileManager; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "Hookable", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return Hookable; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "__name", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return __name; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "__toESM", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return __toESM; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "_usingCtx", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return _usingCtx; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "camelCase", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return camelCase; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "clean", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return clean; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "getErrorMessage", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return getErrorMessage; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "toError", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return toError; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "toFilePath", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return toFilePath; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "toPosixPath", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return toPosixPath; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "write", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return write; | ||
| } | ||
| }); | ||
| //# sourceMappingURL=usingCtx-BN2OKJRx.cjs.map |
| {"version":3,"file":"usingCtx-BN2OKJRx.cjs","names":["#emitter","NodeEventEmitter","#emitAll","#cache","#store","#dedupe","ast","#sorted"],"sources":["../../../internals/utils/src/casing.ts","../../../internals/utils/src/errors.ts","../../../internals/utils/src/runtime.ts","../../../internals/utils/src/fs.ts","../src/Hookable.ts","../src/FileManager.ts"],"sourcesContent":["type Options = {\n /**\n * Text prepended before casing is applied.\n */\n prefix?: string\n /**\n * Text appended before casing is applied.\n */\n suffix?: string\n}\n\n/**\n * Shared implementation for camelCase and PascalCase conversion.\n * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)\n * and capitalizes each word according to `pascal`.\n *\n * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.\n */\nfunction toCamelOrPascal(text: string, pascal: boolean): string {\n return text\n .trim()\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/(\\d)([a-z])/g, '$1 $2')\n .split(/[\\s\\-_./\\\\:]+/)\n .filter(Boolean)\n .map((word, i) => {\n if (word.length > 1 && word === word.toUpperCase()) return word\n const head = i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()\n return head + word.slice(1)\n })\n .join('')\n .replace(/[^a-zA-Z0-9]/g, '')\n}\n\n/**\n * Converts `text` to camelCase.\n *\n * @example Word boundaries\n * `camelCase('hello-world') // 'helloWorld'`\n *\n * @example With a prefix\n * `camelCase('tag', { prefix: 'create' }) // 'createTag'`\n */\nexport function camelCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false)\n}\n\n/**\n * Converts `text` to PascalCase.\n *\n * @example Word boundaries\n * `pascalCase('hello-world') // 'HelloWorld'`\n *\n * @example With a suffix\n * `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`\n */\nexport function pascalCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true)\n}\n","/**\n * Thrown when one or more errors occur during a Kubb build.\n * Carries the full list of underlying errors on `errors`.\n *\n * @example\n * ```ts\n * throw new BuildError('Build failed', { errors: [err1, err2] })\n * ```\n */\nexport class BuildError extends Error {\n errors: Array<Error>\n\n constructor(message: string, options: { cause?: Error; errors: Array<Error> }) {\n super(message, { cause: options.cause })\n this.name = 'BuildError'\n this.errors = options.errors\n }\n}\n\n/**\n * Coerces an unknown thrown value to an `Error` instance.\n * Returns the value as-is when it is already an `Error`; otherwise wraps it with `String(value)`.\n *\n * @example\n * ```ts\n * try { ... } catch(err) {\n * throw new BuildError('Build failed', { cause: toError(err), errors: [] })\n * }\n * ```\n */\nexport function toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value))\n}\n\n/**\n * Extracts a human-readable message from any thrown value.\n *\n * @example\n * ```ts\n * getErrorMessage(new Error('oops')) // 'oops'\n * getErrorMessage('plain string') // 'plain string'\n * ```\n */\nexport function getErrorMessage(value: unknown): string {\n return value instanceof Error ? value.message : String(value)\n}\n\n/**\n * Extracts the `.cause` of an `Error` as an `Error`, or `undefined` when absent or not an `Error`.\n *\n * @example\n * ```ts\n * const cause = toCause(buildError) // Error | undefined\n * ```\n */\nexport function toCause(error: Error): Error | undefined {\n return error.cause instanceof Error ? error.cause : undefined\n}\n","/**\n * Name of the JavaScript runtime executing the current process.\n */\ntype RuntimeName = 'bun' | 'deno' | 'node'\n\n/**\n * Detects the JavaScript runtime executing the current process and exposes its name and version.\n *\n * Prefer the shared {@link runtime} instance over constructing your own.\n */\nclass Runtime {\n /**\n * `true` when the current process is running under Bun.\n *\n * Detection keys off the global `Bun` object rather than `process.versions`,\n * because Bun polyfills `process.versions.node` for Node compatibility and would\n * otherwise look like Node.\n *\n * @example\n * ```ts\n * if (runtime.isBun) {\n * await Bun.write(path, data)\n * }\n * ```\n */\n get isBun(): boolean {\n return typeof Bun !== 'undefined'\n }\n\n /**\n * `true` when the current process is running under Deno.\n */\n get isDeno(): boolean {\n return typeof (globalThis as { Deno?: unknown }).Deno !== 'undefined'\n }\n\n /**\n * `true` when the current process is running under Node.\n *\n * Bun and Deno are excluded first so a polyfilled `process` does not register as Node.\n */\n get isNode(): boolean {\n return !this.isBun && !this.isDeno && typeof process !== 'undefined' && process.versions?.node != null\n }\n\n /**\n * Name of the runtime executing the current process.\n *\n * @example\n * ```ts\n * runtime.name // 'bun' when run with `bun kubb`, 'node' otherwise\n * ```\n */\n get name(): RuntimeName {\n if (this.isBun) return 'bun'\n if (this.isDeno) return 'deno'\n\n return 'node'\n }\n\n /**\n * Version of the active runtime, or an empty string when it cannot be read.\n *\n * @example\n * ```ts\n * runtime.version // '1.3.11' under Bun, '22.22.2' under Node\n * ```\n */\n get version(): string {\n if (this.isBun) return process.versions.bun ?? ''\n if (this.isDeno) return (globalThis as { Deno?: { version?: { deno?: string } } }).Deno?.version?.deno ?? ''\n\n return process.versions?.node ?? ''\n }\n}\n\n/**\n * Shared {@link Runtime} instance describing the JavaScript runtime executing the current process.\n */\nexport const runtime = new Runtime()\n","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","import { EventEmitter as NodeEventEmitter } from 'node:events'\nimport { toError } from '../../../internals/utils/src/errors.ts'\n\n/**\n * A function that can be registered as a hook listener, synchronous or async. Any return value is\n * allowed and ignored, so handlers that return a result for their own callers still register.\n */\ntype AsyncListener<TArgs extends Array<unknown>> = (...args: TArgs) => unknown\n\n/**\n * Typed hook emitter that awaits all async listeners before resolving.\n * Wraps Node's `EventEmitter` with full TypeScript hook-map inference.\n *\n * @example\n * ```ts\n * const hooks = new Hookable<{ build: [name: string] }>()\n * hooks.hook('build', async (name) => { console.log(name) })\n * await hooks.callHook('build', 'petstore') // all listeners awaited\n * ```\n */\nexport class Hookable<THooks extends { [K in keyof THooks]: Array<unknown> }> {\n /**\n * Maximum number of listeners per hook before Node emits a memory-leak warning.\n * @default 10\n */\n constructor(maxListener = 10) {\n this.#emitter.setMaxListeners(maxListener)\n }\n\n #emitter = new NodeEventEmitter()\n\n /**\n * Calls `hookName` and awaits all registered listeners sequentially.\n * Throws if any listener rejects, wrapping the cause with the hook name and serialized arguments.\n *\n * @example\n * ```ts\n * await hooks.callHook('build', 'petstore')\n * ```\n */\n callHook<THookName extends keyof THooks & string>(hookName: THookName, ...hookArgs: THooks[THookName]): Promise<void> | void {\n const listeners = this.#emitter.listeners(hookName) as Array<AsyncListener<THooks[THookName]>>\n\n if (listeners.length === 0) {\n return\n }\n\n return this.#emitAll(hookName, listeners, hookArgs)\n }\n\n async #emitAll<THookName extends keyof THooks & string>(\n hookName: THookName,\n listeners: Array<AsyncListener<THooks[THookName]>>,\n hookArgs: THooks[THookName],\n ): Promise<void> {\n for (const listener of listeners) {\n try {\n await listener(...hookArgs)\n } catch (err) {\n let serializedArgs: string\n try {\n serializedArgs = JSON.stringify(hookArgs)\n } catch {\n serializedArgs = String(hookArgs)\n }\n throw new Error(`Error in async listener for \"${hookName}\" with hookArgs ${serializedArgs}`, { cause: toError(err) })\n }\n }\n }\n\n /**\n * Registers a persistent listener for `hookName` and returns a function that removes it.\n *\n * @example\n * ```ts\n * const unhook = hooks.hook('build', async (name) => { console.log(name) })\n * unhook() // removes it\n * ```\n */\n hook<THookName extends keyof THooks & string>(hookName: THookName, handler: AsyncListener<THooks[THookName]>): () => void {\n this.#emitter.on(hookName, handler as AsyncListener<Array<unknown>>)\n return () => this.removeHook(hookName, handler)\n }\n\n /**\n * Registers every handler in `configHooks` at once and returns a function that removes them\n * all. Undefined entries are skipped, so a partial hook object registers only its present keys.\n *\n * @example\n * ```ts\n * const unhook = hooks.addHooks({ build: onBuild, done: onDone })\n * unhook() // removes both\n * ```\n */\n addHooks(configHooks: Partial<{ [K in keyof THooks & string]: AsyncListener<THooks[K]> }>): () => void {\n const unhooks = (Object.keys(configHooks) as Array<keyof THooks & string>)\n .filter((name) => configHooks[name])\n .map((name) => this.hook(name, configHooks[name]!))\n\n return () => {\n for (const unhook of unhooks) unhook()\n }\n }\n\n /**\n * Removes a previously registered listener.\n *\n * @example\n * ```ts\n * hooks.removeHook('build', handler)\n * ```\n */\n removeHook<THookName extends keyof THooks & string>(hookName: THookName, handler: AsyncListener<THooks[THookName]>): void {\n this.#emitter.off(hookName, handler as AsyncListener<Array<unknown>>)\n }\n\n /**\n * Returns the number of listeners registered for `hookName`.\n *\n * @example\n * ```ts\n * hooks.hook('build', handler)\n * hooks.listenerCount('build') // 1\n * ```\n */\n listenerCount<THookName extends keyof THooks & string>(hookName: THookName): number {\n return this.#emitter.listenerCount(hookName)\n }\n\n /**\n * Raises or lowers the per-hook listener ceiling before Node warns about a memory leak.\n * Set this above the expected listener count when many listeners attach by design.\n *\n * @example\n * ```ts\n * hooks.setMaxListeners(40)\n * ```\n */\n setMaxListeners(max: number): void {\n this.#emitter.setMaxListeners(max)\n }\n\n /**\n * Removes all listeners from every hook channel.\n *\n * @example\n * ```ts\n * hooks.removeAllHooks()\n * ```\n */\n removeAllHooks(): void {\n this.#emitter.removeAllListeners()\n }\n}\n","import { read } from '@internals/utils'\nimport { ast, extractStringsFromNodes, type CodeNode, type FileNode } from '@kubb/ast'\nimport type { Storage } from './createStorage.ts'\nimport type { Parser } from './defineParser.ts'\nimport { Hookable } from './Hookable.ts'\n\n/**\n * Hooks fired around a `FileManager#write` batch: `start` before it, `update` per file, `end` after.\n */\nexport type FileManagerHooks = {\n start: [files: Array<FileNode>]\n update: [params: { file: FileNode; source?: string; processed: number; total: number; percentage: number }]\n end: [files: Array<FileNode>]\n}\n\ntype ParseOptions = {\n parsers?: Map<FileNode['extname'], Parser>\n extension?: Record<FileNode['extname'], FileNode['extname'] | ''>\n}\n\ntype WriteOptions = ParseOptions & {\n storage: Storage\n}\n\nfunction joinSources(file: FileNode): string {\n return file.sources\n .map((source) => extractStringsFromNodes(source.nodes as Array<CodeNode>))\n .filter(Boolean)\n .join('\\n\\n')\n}\n\nasync function parseCopy(file: FileNode): Promise<string> {\n let content: string\n try {\n content = await read(file.copy as string)\n } catch (err) {\n throw new Error(`[kubb] Could not copy file into output: ${file.copy}`, { cause: err })\n }\n\n return [file.banner, content, file.footer]\n .filter((segment): segment is string => Boolean(segment))\n .map((segment) => segment.trimEnd())\n .join('\\n')\n}\n\nfunction mergeFile<TMeta extends object = object>(a: FileNode<TMeta>, b: FileNode<TMeta>): FileNode<TMeta> {\n return {\n ...a,\n // Incoming file (b) takes precedence for banner/footer so a barrel file (whose\n // banner/footer the barrel plugin resolves last) wins over a plugin-generated\n // file at the same path.\n banner: b.banner,\n footer: b.footer,\n // A verbatim-copy file cannot be merged with rendered content; the incoming `copy` wins.\n copy: b.copy ?? a.copy,\n sources: a.sources.length ? (b.sources.length ? [...a.sources, ...b.sources] : a.sources) : b.sources,\n imports: a.imports.length ? (b.imports.length ? [...a.imports, ...b.imports] : a.imports) : b.imports,\n exports: a.exports.length ? (b.exports.length ? [...a.exports, ...b.exports] : a.exports) : b.exports,\n }\n}\n\nfunction isIndexPath(path: string): boolean {\n return path.endsWith('/index.ts') || path === 'index.ts'\n}\n\n// Sort order: shortest path first. Within a length bucket, index.ts barrels last.\nfunction compareFiles(a: FileNode, b: FileNode): number {\n const lenDiff = a.path.length - b.path.length\n if (lenDiff !== 0) return lenDiff\n const aIsIndex = isIndexPath(a.path)\n const bIsIndex = isIndexPath(b.path)\n if (aIsIndex && !bIsIndex) return 1\n if (!aIsIndex && bIsIndex) return -1\n\n return 0\n}\n\n/**\n * In-memory file store for generated files, and the writer that turns them into source\n * strings on `storage`. Files sharing a `path` are merged (sources/imports/exports\n * concatenated). The `files` getter is sorted by path length (barrel `index.ts` last\n * within a bucket).\n *\n * @example\n * ```ts\n * const manager = new FileManager()\n * manager.upsert(myFile)\n * manager.files // sorted view\n * await manager.write(manager.files, { storage: fsStorage() })\n * ```\n */\nexport class FileManager {\n readonly hooks = new Hookable<FileManagerHooks>()\n readonly #cache = new Map<string, FileNode>()\n // Cached sorted view. Null means stale and rebuilt lazily on next `files` read.\n // Nulled (not mutated) on every write so callers holding a prior reference keep\n // their snapshot. `dispose()` must not silently empty an array the consumer\n // already holds.\n #sorted: Array<FileNode> | null = null\n\n add(...files: Array<FileNode>): Array<FileNode> {\n return this.#store(files, false)\n }\n\n upsert(...files: Array<FileNode>): Array<FileNode> {\n return this.#store(files, true)\n }\n\n #store(files: ReadonlyArray<FileNode>, mergeExisting: boolean): Array<FileNode> {\n const batch = files.length > 1 ? this.#dedupe(files) : files\n const resolved: Array<FileNode> = []\n\n for (const file of batch) {\n const existing = this.#cache.get(file.path)\n const merged = existing && mergeExisting ? ast.factory.createFile(mergeFile(existing, file)) : ast.factory.createFile(file)\n this.#cache.set(merged.path, merged)\n resolved.push(merged)\n }\n\n if (resolved.length > 0) this.#sorted = null\n return resolved\n }\n\n // Merges same-path entries within a batch so the cache update loop stays\n // uniform. Only called for multi-file batches.\n #dedupe(files: ReadonlyArray<FileNode>): Array<FileNode> {\n const seen = new Map<string, FileNode>()\n for (const file of files) {\n const prev = seen.get(file.path)\n seen.set(file.path, prev ? mergeFile(prev, file) : file)\n }\n return [...seen.values()]\n }\n\n clear(): void {\n this.#cache.clear()\n this.#sorted = null\n }\n\n /**\n * Releases all stored files and clears every `hooks` listener. Called by the core after\n * `kubb:build:end`.\n */\n dispose(): void {\n this.clear()\n this.hooks.removeAllHooks()\n }\n\n /**\n * All stored files in stable sort order (shortest path first, barrel files\n * last within a length bucket). Returns a cached view, do not mutate.\n */\n get files(): Array<FileNode> {\n return (this.#sorted ??= [...this.#cache.values()].sort(compareFiles))\n }\n\n /**\n * Converts a file's AST sources (or its `copy` source) into the final on-disk string.\n */\n async parse(file: FileNode, { parsers, extension }: ParseOptions = {}): Promise<string> {\n if (file.copy) {\n return parseCopy(file)\n }\n\n const parseExtName = extension?.[file.extname] || undefined\n\n if (!parsers || !file.extname) {\n return joinSources(file)\n }\n\n const parser = parsers.get(file.extname)\n\n if (!parser) {\n return joinSources(file)\n }\n\n return parser.parse(file, { extname: parseExtName })\n }\n\n /**\n * Converts and writes every file at once, letting `storage.setItem` decide how much of\n * that runs concurrently.\n */\n async write(files: Array<FileNode>, { storage, parsers, extension }: WriteOptions): Promise<void> {\n if (files.length === 0) return\n\n await this.hooks.callHook('start', files)\n\n const total = files.length\n let processed = 0\n await Promise.all(\n files.map(async (file) => {\n const source = await this.parse(file, { parsers, extension })\n processed++\n await this.hooks.callHook('update', { file, source, processed, total, percentage: (processed / total) * 100 })\n if (source) await storage.setItem(file.path, source)\n }),\n )\n\n await this.hooks.callHook('end', files)\n }\n}\n"],"mappings":"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"} |
| import "./rolldown-runtime-C0LytTxp.js"; | ||
| import { mkdir, readFile, rm, writeFile } from "node:fs/promises"; | ||
| import { dirname, resolve } from "node:path"; | ||
| import { ast, extractStringsFromNodes } from "@kubb/ast"; | ||
| import { EventEmitter } from "node:events"; | ||
| //#region ../../internals/utils/src/casing.ts | ||
| /** | ||
| * Shared implementation for camelCase and PascalCase conversion. | ||
| * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons) | ||
| * and capitalizes each word according to `pascal`. | ||
| * | ||
| * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are. | ||
| */ | ||
| function toCamelOrPascal(text, pascal) { | ||
| return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => { | ||
| if (word.length > 1 && word === word.toUpperCase()) return word; | ||
| return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1); | ||
| }).join("").replace(/[^a-zA-Z0-9]/g, ""); | ||
| } | ||
| /** | ||
| * Converts `text` to camelCase. | ||
| * | ||
| * @example Word boundaries | ||
| * `camelCase('hello-world') // 'helloWorld'` | ||
| * | ||
| * @example With a prefix | ||
| * `camelCase('tag', { prefix: 'create' }) // 'createTag'` | ||
| */ | ||
| function camelCase(text, { prefix = "", suffix = "" } = {}) { | ||
| return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/errors.ts | ||
| /** | ||
| * Thrown when one or more errors occur during a Kubb build. | ||
| * Carries the full list of underlying errors on `errors`. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * throw new BuildError('Build failed', { errors: [err1, err2] }) | ||
| * ``` | ||
| */ | ||
| var BuildError = class extends Error { | ||
| errors; | ||
| constructor(message, options) { | ||
| super(message, { cause: options.cause }); | ||
| this.name = "BuildError"; | ||
| this.errors = options.errors; | ||
| } | ||
| }; | ||
| /** | ||
| * Coerces an unknown thrown value to an `Error` instance. | ||
| * Returns the value as-is when it is already an `Error`; otherwise wraps it with `String(value)`. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * try { ... } catch(err) { | ||
| * throw new BuildError('Build failed', { cause: toError(err), errors: [] }) | ||
| * } | ||
| * ``` | ||
| */ | ||
| function toError(value) { | ||
| return value instanceof Error ? value : new Error(String(value)); | ||
| } | ||
| /** | ||
| * Extracts a human-readable message from any thrown value. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * getErrorMessage(new Error('oops')) // 'oops' | ||
| * getErrorMessage('plain string') // 'plain string' | ||
| * ``` | ||
| */ | ||
| function getErrorMessage(value) { | ||
| return value instanceof Error ? value.message : String(value); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/runtime.ts | ||
| /** | ||
| * Detects the JavaScript runtime executing the current process and exposes its name and version. | ||
| * | ||
| * Prefer the shared {@link runtime} instance over constructing your own. | ||
| */ | ||
| var Runtime = class { | ||
| /** | ||
| * `true` when the current process is running under Bun. | ||
| * | ||
| * Detection keys off the global `Bun` object rather than `process.versions`, | ||
| * because Bun polyfills `process.versions.node` for Node compatibility and would | ||
| * otherwise look like Node. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * if (runtime.isBun) { | ||
| * await Bun.write(path, data) | ||
| * } | ||
| * ``` | ||
| */ | ||
| get isBun() { | ||
| return typeof Bun !== "undefined"; | ||
| } | ||
| /** | ||
| * `true` when the current process is running under Deno. | ||
| */ | ||
| get isDeno() { | ||
| return typeof globalThis.Deno !== "undefined"; | ||
| } | ||
| /** | ||
| * `true` when the current process is running under Node. | ||
| * | ||
| * Bun and Deno are excluded first so a polyfilled `process` does not register as Node. | ||
| */ | ||
| get isNode() { | ||
| return !this.isBun && !this.isDeno && typeof process !== "undefined" && process.versions?.node != null; | ||
| } | ||
| /** | ||
| * Name of the runtime executing the current process. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * runtime.name // 'bun' when run with `bun kubb`, 'node' otherwise | ||
| * ``` | ||
| */ | ||
| get name() { | ||
| if (this.isBun) return "bun"; | ||
| if (this.isDeno) return "deno"; | ||
| return "node"; | ||
| } | ||
| /** | ||
| * Version of the active runtime, or an empty string when it cannot be read. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * runtime.version // '1.3.11' under Bun, '22.22.2' under Node | ||
| * ``` | ||
| */ | ||
| get version() { | ||
| if (this.isBun) return process.versions.bun ?? ""; | ||
| if (this.isDeno) return globalThis.Deno?.version?.deno ?? ""; | ||
| return process.versions?.node ?? ""; | ||
| } | ||
| }; | ||
| /** | ||
| * Shared {@link Runtime} instance describing the JavaScript runtime executing the current process. | ||
| */ | ||
| const runtime = new Runtime(); | ||
| //#endregion | ||
| //#region ../../internals/utils/src/fs.ts | ||
| /** | ||
| * Reads the file at `path` as a UTF-8 string. | ||
| * Uses `Bun.file().text()` when running under Bun, `fs.readFile` otherwise. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const source = await read('./src/Pet.ts') | ||
| * ``` | ||
| */ | ||
| async function read(path) { | ||
| if (runtime.isBun) return Bun.file(path).text(); | ||
| return readFile(path, { encoding: "utf8" }); | ||
| } | ||
| /** | ||
| * Writes `data` to `path`, trimming leading/trailing whitespace before saving. | ||
| * Skips the write when the trimmed content is empty or identical to what is already on disk. | ||
| * Creates any missing parent directories automatically. | ||
| * When `sanity` is `true`, re-reads the file after writing and throws if the content does not match. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * await write('./src/Pet.ts', source) // writes and returns trimmed content | ||
| * await write('./src/Pet.ts', source) // null — file unchanged | ||
| * await write('./src/Pet.ts', ' ') // null — empty content skipped | ||
| * ``` | ||
| */ | ||
| async function write(path, data, options = {}) { | ||
| const trimmed = data.trim(); | ||
| if (trimmed === "") return null; | ||
| const resolved = resolve(path); | ||
| if (runtime.isBun) { | ||
| const file = Bun.file(resolved); | ||
| if ((await file.exists() ? await file.text() : null) === trimmed) return null; | ||
| await Bun.write(resolved, trimmed); | ||
| return trimmed; | ||
| } | ||
| try { | ||
| if (await readFile(resolved, { encoding: "utf-8" }) === trimmed) return null; | ||
| } catch {} | ||
| await mkdir(dirname(resolved), { recursive: true }); | ||
| await writeFile(resolved, trimmed, { encoding: "utf-8" }); | ||
| if (options.sanity) { | ||
| const savedData = await readFile(resolved, { encoding: "utf-8" }); | ||
| if (savedData !== trimmed) throw new Error(`Sanity check failed for ${path}\n\nData[${data.length}]:\n${data}\n\nSaved[${savedData.length}]:\n${savedData}\n`); | ||
| return savedData; | ||
| } | ||
| return trimmed; | ||
| } | ||
| /** | ||
| * Recursively removes `path`. Silently succeeds when `path` does not exist. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * await clean('./dist') | ||
| * ``` | ||
| */ | ||
| async function clean(path) { | ||
| return rm(path, { | ||
| recursive: true, | ||
| force: true | ||
| }); | ||
| } | ||
| /** | ||
| * Converts a filesystem path to use POSIX (`/`) separators. | ||
| * | ||
| * Most of the codebase compares and composes paths as strings (prefix matching, joining for | ||
| * import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated | ||
| * paths, but on Windows it returns `\`-separated paths, which breaks every such comparison. | ||
| * | ||
| * Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the | ||
| * code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is | ||
| * exercisable from POSIX CI. | ||
| * | ||
| * @example | ||
| * toPosixPath('C:\\repo\\src\\pet.ts') // 'C:/repo/src/pet.ts' | ||
| */ | ||
| function toPosixPath(filePath) { | ||
| return filePath.replaceAll("\\", "/"); | ||
| } | ||
| /** | ||
| * Builds a nested file path from a dotted name. Splits on dots that precede a letter | ||
| * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases | ||
| * every earlier segment, applies `caseLast` to the final segment, and joins with `/`. | ||
| * | ||
| * Empty segments are dropped before joining. They arise when the name starts with a dot | ||
| * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to | ||
| * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an | ||
| * absolute path, letting generated files escape the configured output directory. | ||
| * | ||
| * @example Nested path from a dotted name | ||
| * `toFilePath('pet.petId') // 'pet/petId'` | ||
| * | ||
| * @example PascalCase the final segment | ||
| * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'` | ||
| * | ||
| * @example Suffix applied to the final segment only | ||
| * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'` | ||
| */ | ||
| function toFilePath(name, caseLast = camelCase) { | ||
| const parts = name.split(/\.(?=[a-zA-Z])/); | ||
| return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/"); | ||
| } | ||
| //#endregion | ||
| //#region src/Hookable.ts | ||
| /** | ||
| * Typed hook emitter that awaits all async listeners before resolving. | ||
| * Wraps Node's `EventEmitter` with full TypeScript hook-map inference. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const hooks = new Hookable<{ build: [name: string] }>() | ||
| * hooks.hook('build', async (name) => { console.log(name) }) | ||
| * await hooks.callHook('build', 'petstore') // all listeners awaited | ||
| * ``` | ||
| */ | ||
| var Hookable = class { | ||
| /** | ||
| * Maximum number of listeners per hook before Node emits a memory-leak warning. | ||
| * @default 10 | ||
| */ | ||
| constructor(maxListener = 10) { | ||
| this.#emitter.setMaxListeners(maxListener); | ||
| } | ||
| #emitter = new EventEmitter(); | ||
| /** | ||
| * Calls `hookName` and awaits all registered listeners sequentially. | ||
| * Throws if any listener rejects, wrapping the cause with the hook name and serialized arguments. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * await hooks.callHook('build', 'petstore') | ||
| * ``` | ||
| */ | ||
| callHook(hookName, ...hookArgs) { | ||
| const listeners = this.#emitter.listeners(hookName); | ||
| if (listeners.length === 0) return; | ||
| return this.#emitAll(hookName, listeners, hookArgs); | ||
| } | ||
| async #emitAll(hookName, listeners, hookArgs) { | ||
| for (const listener of listeners) try { | ||
| await listener(...hookArgs); | ||
| } catch (err) { | ||
| let serializedArgs; | ||
| try { | ||
| serializedArgs = JSON.stringify(hookArgs); | ||
| } catch { | ||
| serializedArgs = String(hookArgs); | ||
| } | ||
| throw new Error(`Error in async listener for "${hookName}" with hookArgs ${serializedArgs}`, { cause: toError(err) }); | ||
| } | ||
| } | ||
| /** | ||
| * Registers a persistent listener for `hookName` and returns a function that removes it. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const unhook = hooks.hook('build', async (name) => { console.log(name) }) | ||
| * unhook() // removes it | ||
| * ``` | ||
| */ | ||
| hook(hookName, handler) { | ||
| this.#emitter.on(hookName, handler); | ||
| return () => this.removeHook(hookName, handler); | ||
| } | ||
| /** | ||
| * Registers every handler in `configHooks` at once and returns a function that removes them | ||
| * all. Undefined entries are skipped, so a partial hook object registers only its present keys. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const unhook = hooks.addHooks({ build: onBuild, done: onDone }) | ||
| * unhook() // removes both | ||
| * ``` | ||
| */ | ||
| addHooks(configHooks) { | ||
| const unhooks = Object.keys(configHooks).filter((name) => configHooks[name]).map((name) => this.hook(name, configHooks[name])); | ||
| return () => { | ||
| for (const unhook of unhooks) unhook(); | ||
| }; | ||
| } | ||
| /** | ||
| * Removes a previously registered listener. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * hooks.removeHook('build', handler) | ||
| * ``` | ||
| */ | ||
| removeHook(hookName, handler) { | ||
| this.#emitter.off(hookName, handler); | ||
| } | ||
| /** | ||
| * Returns the number of listeners registered for `hookName`. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * hooks.hook('build', handler) | ||
| * hooks.listenerCount('build') // 1 | ||
| * ``` | ||
| */ | ||
| listenerCount(hookName) { | ||
| return this.#emitter.listenerCount(hookName); | ||
| } | ||
| /** | ||
| * Raises or lowers the per-hook listener ceiling before Node warns about a memory leak. | ||
| * Set this above the expected listener count when many listeners attach by design. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * hooks.setMaxListeners(40) | ||
| * ``` | ||
| */ | ||
| setMaxListeners(max) { | ||
| this.#emitter.setMaxListeners(max); | ||
| } | ||
| /** | ||
| * Removes all listeners from every hook channel. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * hooks.removeAllHooks() | ||
| * ``` | ||
| */ | ||
| removeAllHooks() { | ||
| this.#emitter.removeAllListeners(); | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region src/FileManager.ts | ||
| function joinSources(file) { | ||
| return file.sources.map((source) => extractStringsFromNodes(source.nodes)).filter(Boolean).join("\n\n"); | ||
| } | ||
| async function parseCopy(file) { | ||
| let content; | ||
| try { | ||
| content = await read(file.copy); | ||
| } catch (err) { | ||
| throw new Error(`[kubb] Could not copy file into output: ${file.copy}`, { cause: err }); | ||
| } | ||
| return [ | ||
| file.banner, | ||
| content, | ||
| file.footer | ||
| ].filter((segment) => Boolean(segment)).map((segment) => segment.trimEnd()).join("\n"); | ||
| } | ||
| function mergeFile(a, b) { | ||
| return { | ||
| ...a, | ||
| banner: b.banner, | ||
| footer: b.footer, | ||
| copy: b.copy ?? a.copy, | ||
| sources: a.sources.length ? b.sources.length ? [...a.sources, ...b.sources] : a.sources : b.sources, | ||
| imports: a.imports.length ? b.imports.length ? [...a.imports, ...b.imports] : a.imports : b.imports, | ||
| exports: a.exports.length ? b.exports.length ? [...a.exports, ...b.exports] : a.exports : b.exports | ||
| }; | ||
| } | ||
| function isIndexPath(path) { | ||
| return path.endsWith("/index.ts") || path === "index.ts"; | ||
| } | ||
| function compareFiles(a, b) { | ||
| const lenDiff = a.path.length - b.path.length; | ||
| if (lenDiff !== 0) return lenDiff; | ||
| const aIsIndex = isIndexPath(a.path); | ||
| const bIsIndex = isIndexPath(b.path); | ||
| if (aIsIndex && !bIsIndex) return 1; | ||
| if (!aIsIndex && bIsIndex) return -1; | ||
| return 0; | ||
| } | ||
| /** | ||
| * In-memory file store for generated files, and the writer that turns them into source | ||
| * strings on `storage`. Files sharing a `path` are merged (sources/imports/exports | ||
| * concatenated). The `files` getter is sorted by path length (barrel `index.ts` last | ||
| * within a bucket). | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const manager = new FileManager() | ||
| * manager.upsert(myFile) | ||
| * manager.files // sorted view | ||
| * await manager.write(manager.files, { storage: fsStorage() }) | ||
| * ``` | ||
| */ | ||
| var FileManager = class { | ||
| hooks = new Hookable(); | ||
| #cache = /* @__PURE__ */ new Map(); | ||
| #sorted = null; | ||
| add(...files) { | ||
| return this.#store(files, false); | ||
| } | ||
| upsert(...files) { | ||
| return this.#store(files, true); | ||
| } | ||
| #store(files, mergeExisting) { | ||
| const batch = files.length > 1 ? this.#dedupe(files) : files; | ||
| const resolved = []; | ||
| for (const file of batch) { | ||
| const existing = this.#cache.get(file.path); | ||
| const merged = existing && mergeExisting ? ast.factory.createFile(mergeFile(existing, file)) : ast.factory.createFile(file); | ||
| this.#cache.set(merged.path, merged); | ||
| resolved.push(merged); | ||
| } | ||
| if (resolved.length > 0) this.#sorted = null; | ||
| return resolved; | ||
| } | ||
| #dedupe(files) { | ||
| const seen = /* @__PURE__ */ new Map(); | ||
| for (const file of files) { | ||
| const prev = seen.get(file.path); | ||
| seen.set(file.path, prev ? mergeFile(prev, file) : file); | ||
| } | ||
| return [...seen.values()]; | ||
| } | ||
| clear() { | ||
| this.#cache.clear(); | ||
| this.#sorted = null; | ||
| } | ||
| /** | ||
| * Releases all stored files and clears every `hooks` listener. Called by the core after | ||
| * `kubb:build:end`. | ||
| */ | ||
| dispose() { | ||
| this.clear(); | ||
| this.hooks.removeAllHooks(); | ||
| } | ||
| /** | ||
| * All stored files in stable sort order (shortest path first, barrel files | ||
| * last within a length bucket). Returns a cached view, do not mutate. | ||
| */ | ||
| get files() { | ||
| return this.#sorted ??= [...this.#cache.values()].sort(compareFiles); | ||
| } | ||
| /** | ||
| * Converts a file's AST sources (or its `copy` source) into the final on-disk string. | ||
| */ | ||
| async parse(file, { parsers, extension } = {}) { | ||
| if (file.copy) return parseCopy(file); | ||
| const parseExtName = extension?.[file.extname] || void 0; | ||
| if (!parsers || !file.extname) return joinSources(file); | ||
| const parser = parsers.get(file.extname); | ||
| if (!parser) return joinSources(file); | ||
| return parser.parse(file, { extname: parseExtName }); | ||
| } | ||
| /** | ||
| * Converts and writes every file at once, letting `storage.setItem` decide how much of | ||
| * that runs concurrently. | ||
| */ | ||
| async write(files, { storage, parsers, extension }) { | ||
| if (files.length === 0) return; | ||
| await this.hooks.callHook("start", files); | ||
| const total = files.length; | ||
| let processed = 0; | ||
| await Promise.all(files.map(async (file) => { | ||
| const source = await this.parse(file, { | ||
| parsers, | ||
| extension | ||
| }); | ||
| processed++; | ||
| await this.hooks.callHook("update", { | ||
| file, | ||
| source, | ||
| processed, | ||
| total, | ||
| percentage: processed / total * 100 | ||
| }); | ||
| if (source) await storage.setItem(file.path, source); | ||
| })); | ||
| await this.hooks.callHook("end", files); | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region \0@oxc-project+runtime@0.138.0/helpers/esm/usingCtx.js | ||
| function _usingCtx() { | ||
| var r = "function" == typeof SuppressedError ? SuppressedError : function(r, e) { | ||
| var n = Error(); | ||
| return n.name = "SuppressedError", n.error = r, n.suppressed = e, n; | ||
| }; | ||
| var e = {}; | ||
| var n = []; | ||
| function using(r, e) { | ||
| if (null != e) { | ||
| if (Object(e) !== e) throw new TypeError("using declarations can only be used with objects, functions, null, or undefined."); | ||
| if (r) var o = e[Symbol.asyncDispose || Symbol["for"]("Symbol.asyncDispose")]; | ||
| if (void 0 === o && (o = e[Symbol.dispose || Symbol["for"]("Symbol.dispose")], r)) var t = o; | ||
| if ("function" != typeof o) throw new TypeError("Object is not disposable."); | ||
| t && (o = function o() { | ||
| try { | ||
| t.call(e); | ||
| } catch (r) { | ||
| return Promise.reject(r); | ||
| } | ||
| }), n.push({ | ||
| v: e, | ||
| d: o, | ||
| a: r | ||
| }); | ||
| } else r && n.push({ | ||
| d: e, | ||
| a: r | ||
| }); | ||
| return e; | ||
| } | ||
| return { | ||
| e, | ||
| u: using.bind(null, !1), | ||
| a: using.bind(null, !0), | ||
| d: function d() { | ||
| var o; | ||
| var t = this.e; | ||
| var s = 0; | ||
| function next() { | ||
| for (; o = n.pop();) try { | ||
| if (!o.a && 1 === s) return s = 0, n.push(o), Promise.resolve().then(next); | ||
| if (o.d) { | ||
| var r = o.d.call(o.v); | ||
| if (o.a) return s |= 2, Promise.resolve(r).then(next, err); | ||
| } else s |= 1; | ||
| } catch (r) { | ||
| return err(r); | ||
| } | ||
| if (1 === s) return t !== e ? Promise.reject(t) : Promise.resolve(); | ||
| if (t !== e) throw t; | ||
| } | ||
| function err(n) { | ||
| return t = t !== e ? new r(n, t) : n, next(); | ||
| } | ||
| return next(); | ||
| } | ||
| }; | ||
| } | ||
| //#endregion | ||
| export { toFilePath as a, BuildError as c, camelCase as d, clean as i, getErrorMessage as l, FileManager as n, toPosixPath as o, Hookable as r, write as s, _usingCtx as t, toError as u }; | ||
| //# sourceMappingURL=usingCtx-Cnrm3TcM.js.map |
| {"version":3,"file":"usingCtx-Cnrm3TcM.js","names":["#emitter","NodeEventEmitter","#emitAll","#cache","#store","#dedupe","#sorted"],"sources":["../../../internals/utils/src/casing.ts","../../../internals/utils/src/errors.ts","../../../internals/utils/src/runtime.ts","../../../internals/utils/src/fs.ts","../src/Hookable.ts","../src/FileManager.ts"],"sourcesContent":["type Options = {\n /**\n * Text prepended before casing is applied.\n */\n prefix?: string\n /**\n * Text appended before casing is applied.\n */\n suffix?: string\n}\n\n/**\n * Shared implementation for camelCase and PascalCase conversion.\n * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)\n * and capitalizes each word according to `pascal`.\n *\n * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.\n */\nfunction toCamelOrPascal(text: string, pascal: boolean): string {\n return text\n .trim()\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/(\\d)([a-z])/g, '$1 $2')\n .split(/[\\s\\-_./\\\\:]+/)\n .filter(Boolean)\n .map((word, i) => {\n if (word.length > 1 && word === word.toUpperCase()) return word\n const head = i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()\n return head + word.slice(1)\n })\n .join('')\n .replace(/[^a-zA-Z0-9]/g, '')\n}\n\n/**\n * Converts `text` to camelCase.\n *\n * @example Word boundaries\n * `camelCase('hello-world') // 'helloWorld'`\n *\n * @example With a prefix\n * `camelCase('tag', { prefix: 'create' }) // 'createTag'`\n */\nexport function camelCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false)\n}\n\n/**\n * Converts `text` to PascalCase.\n *\n * @example Word boundaries\n * `pascalCase('hello-world') // 'HelloWorld'`\n *\n * @example With a suffix\n * `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`\n */\nexport function pascalCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true)\n}\n","/**\n * Thrown when one or more errors occur during a Kubb build.\n * Carries the full list of underlying errors on `errors`.\n *\n * @example\n * ```ts\n * throw new BuildError('Build failed', { errors: [err1, err2] })\n * ```\n */\nexport class BuildError extends Error {\n errors: Array<Error>\n\n constructor(message: string, options: { cause?: Error; errors: Array<Error> }) {\n super(message, { cause: options.cause })\n this.name = 'BuildError'\n this.errors = options.errors\n }\n}\n\n/**\n * Coerces an unknown thrown value to an `Error` instance.\n * Returns the value as-is when it is already an `Error`; otherwise wraps it with `String(value)`.\n *\n * @example\n * ```ts\n * try { ... } catch(err) {\n * throw new BuildError('Build failed', { cause: toError(err), errors: [] })\n * }\n * ```\n */\nexport function toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value))\n}\n\n/**\n * Extracts a human-readable message from any thrown value.\n *\n * @example\n * ```ts\n * getErrorMessage(new Error('oops')) // 'oops'\n * getErrorMessage('plain string') // 'plain string'\n * ```\n */\nexport function getErrorMessage(value: unknown): string {\n return value instanceof Error ? value.message : String(value)\n}\n\n/**\n * Extracts the `.cause` of an `Error` as an `Error`, or `undefined` when absent or not an `Error`.\n *\n * @example\n * ```ts\n * const cause = toCause(buildError) // Error | undefined\n * ```\n */\nexport function toCause(error: Error): Error | undefined {\n return error.cause instanceof Error ? error.cause : undefined\n}\n","/**\n * Name of the JavaScript runtime executing the current process.\n */\ntype RuntimeName = 'bun' | 'deno' | 'node'\n\n/**\n * Detects the JavaScript runtime executing the current process and exposes its name and version.\n *\n * Prefer the shared {@link runtime} instance over constructing your own.\n */\nclass Runtime {\n /**\n * `true` when the current process is running under Bun.\n *\n * Detection keys off the global `Bun` object rather than `process.versions`,\n * because Bun polyfills `process.versions.node` for Node compatibility and would\n * otherwise look like Node.\n *\n * @example\n * ```ts\n * if (runtime.isBun) {\n * await Bun.write(path, data)\n * }\n * ```\n */\n get isBun(): boolean {\n return typeof Bun !== 'undefined'\n }\n\n /**\n * `true` when the current process is running under Deno.\n */\n get isDeno(): boolean {\n return typeof (globalThis as { Deno?: unknown }).Deno !== 'undefined'\n }\n\n /**\n * `true` when the current process is running under Node.\n *\n * Bun and Deno are excluded first so a polyfilled `process` does not register as Node.\n */\n get isNode(): boolean {\n return !this.isBun && !this.isDeno && typeof process !== 'undefined' && process.versions?.node != null\n }\n\n /**\n * Name of the runtime executing the current process.\n *\n * @example\n * ```ts\n * runtime.name // 'bun' when run with `bun kubb`, 'node' otherwise\n * ```\n */\n get name(): RuntimeName {\n if (this.isBun) return 'bun'\n if (this.isDeno) return 'deno'\n\n return 'node'\n }\n\n /**\n * Version of the active runtime, or an empty string when it cannot be read.\n *\n * @example\n * ```ts\n * runtime.version // '1.3.11' under Bun, '22.22.2' under Node\n * ```\n */\n get version(): string {\n if (this.isBun) return process.versions.bun ?? ''\n if (this.isDeno) return (globalThis as { Deno?: { version?: { deno?: string } } }).Deno?.version?.deno ?? ''\n\n return process.versions?.node ?? ''\n }\n}\n\n/**\n * Shared {@link Runtime} instance describing the JavaScript runtime executing the current process.\n */\nexport const runtime = new Runtime()\n","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","import { EventEmitter as NodeEventEmitter } from 'node:events'\nimport { toError } from '../../../internals/utils/src/errors.ts'\n\n/**\n * A function that can be registered as a hook listener, synchronous or async. Any return value is\n * allowed and ignored, so handlers that return a result for their own callers still register.\n */\ntype AsyncListener<TArgs extends Array<unknown>> = (...args: TArgs) => unknown\n\n/**\n * Typed hook emitter that awaits all async listeners before resolving.\n * Wraps Node's `EventEmitter` with full TypeScript hook-map inference.\n *\n * @example\n * ```ts\n * const hooks = new Hookable<{ build: [name: string] }>()\n * hooks.hook('build', async (name) => { console.log(name) })\n * await hooks.callHook('build', 'petstore') // all listeners awaited\n * ```\n */\nexport class Hookable<THooks extends { [K in keyof THooks]: Array<unknown> }> {\n /**\n * Maximum number of listeners per hook before Node emits a memory-leak warning.\n * @default 10\n */\n constructor(maxListener = 10) {\n this.#emitter.setMaxListeners(maxListener)\n }\n\n #emitter = new NodeEventEmitter()\n\n /**\n * Calls `hookName` and awaits all registered listeners sequentially.\n * Throws if any listener rejects, wrapping the cause with the hook name and serialized arguments.\n *\n * @example\n * ```ts\n * await hooks.callHook('build', 'petstore')\n * ```\n */\n callHook<THookName extends keyof THooks & string>(hookName: THookName, ...hookArgs: THooks[THookName]): Promise<void> | void {\n const listeners = this.#emitter.listeners(hookName) as Array<AsyncListener<THooks[THookName]>>\n\n if (listeners.length === 0) {\n return\n }\n\n return this.#emitAll(hookName, listeners, hookArgs)\n }\n\n async #emitAll<THookName extends keyof THooks & string>(\n hookName: THookName,\n listeners: Array<AsyncListener<THooks[THookName]>>,\n hookArgs: THooks[THookName],\n ): Promise<void> {\n for (const listener of listeners) {\n try {\n await listener(...hookArgs)\n } catch (err) {\n let serializedArgs: string\n try {\n serializedArgs = JSON.stringify(hookArgs)\n } catch {\n serializedArgs = String(hookArgs)\n }\n throw new Error(`Error in async listener for \"${hookName}\" with hookArgs ${serializedArgs}`, { cause: toError(err) })\n }\n }\n }\n\n /**\n * Registers a persistent listener for `hookName` and returns a function that removes it.\n *\n * @example\n * ```ts\n * const unhook = hooks.hook('build', async (name) => { console.log(name) })\n * unhook() // removes it\n * ```\n */\n hook<THookName extends keyof THooks & string>(hookName: THookName, handler: AsyncListener<THooks[THookName]>): () => void {\n this.#emitter.on(hookName, handler as AsyncListener<Array<unknown>>)\n return () => this.removeHook(hookName, handler)\n }\n\n /**\n * Registers every handler in `configHooks` at once and returns a function that removes them\n * all. Undefined entries are skipped, so a partial hook object registers only its present keys.\n *\n * @example\n * ```ts\n * const unhook = hooks.addHooks({ build: onBuild, done: onDone })\n * unhook() // removes both\n * ```\n */\n addHooks(configHooks: Partial<{ [K in keyof THooks & string]: AsyncListener<THooks[K]> }>): () => void {\n const unhooks = (Object.keys(configHooks) as Array<keyof THooks & string>)\n .filter((name) => configHooks[name])\n .map((name) => this.hook(name, configHooks[name]!))\n\n return () => {\n for (const unhook of unhooks) unhook()\n }\n }\n\n /**\n * Removes a previously registered listener.\n *\n * @example\n * ```ts\n * hooks.removeHook('build', handler)\n * ```\n */\n removeHook<THookName extends keyof THooks & string>(hookName: THookName, handler: AsyncListener<THooks[THookName]>): void {\n this.#emitter.off(hookName, handler as AsyncListener<Array<unknown>>)\n }\n\n /**\n * Returns the number of listeners registered for `hookName`.\n *\n * @example\n * ```ts\n * hooks.hook('build', handler)\n * hooks.listenerCount('build') // 1\n * ```\n */\n listenerCount<THookName extends keyof THooks & string>(hookName: THookName): number {\n return this.#emitter.listenerCount(hookName)\n }\n\n /**\n * Raises or lowers the per-hook listener ceiling before Node warns about a memory leak.\n * Set this above the expected listener count when many listeners attach by design.\n *\n * @example\n * ```ts\n * hooks.setMaxListeners(40)\n * ```\n */\n setMaxListeners(max: number): void {\n this.#emitter.setMaxListeners(max)\n }\n\n /**\n * Removes all listeners from every hook channel.\n *\n * @example\n * ```ts\n * hooks.removeAllHooks()\n * ```\n */\n removeAllHooks(): void {\n this.#emitter.removeAllListeners()\n }\n}\n","import { read } from '@internals/utils'\nimport { ast, extractStringsFromNodes, type CodeNode, type FileNode } from '@kubb/ast'\nimport type { Storage } from './createStorage.ts'\nimport type { Parser } from './defineParser.ts'\nimport { Hookable } from './Hookable.ts'\n\n/**\n * Hooks fired around a `FileManager#write` batch: `start` before it, `update` per file, `end` after.\n */\nexport type FileManagerHooks = {\n start: [files: Array<FileNode>]\n update: [params: { file: FileNode; source?: string; processed: number; total: number; percentage: number }]\n end: [files: Array<FileNode>]\n}\n\ntype ParseOptions = {\n parsers?: Map<FileNode['extname'], Parser>\n extension?: Record<FileNode['extname'], FileNode['extname'] | ''>\n}\n\ntype WriteOptions = ParseOptions & {\n storage: Storage\n}\n\nfunction joinSources(file: FileNode): string {\n return file.sources\n .map((source) => extractStringsFromNodes(source.nodes as Array<CodeNode>))\n .filter(Boolean)\n .join('\\n\\n')\n}\n\nasync function parseCopy(file: FileNode): Promise<string> {\n let content: string\n try {\n content = await read(file.copy as string)\n } catch (err) {\n throw new Error(`[kubb] Could not copy file into output: ${file.copy}`, { cause: err })\n }\n\n return [file.banner, content, file.footer]\n .filter((segment): segment is string => Boolean(segment))\n .map((segment) => segment.trimEnd())\n .join('\\n')\n}\n\nfunction mergeFile<TMeta extends object = object>(a: FileNode<TMeta>, b: FileNode<TMeta>): FileNode<TMeta> {\n return {\n ...a,\n // Incoming file (b) takes precedence for banner/footer so a barrel file (whose\n // banner/footer the barrel plugin resolves last) wins over a plugin-generated\n // file at the same path.\n banner: b.banner,\n footer: b.footer,\n // A verbatim-copy file cannot be merged with rendered content; the incoming `copy` wins.\n copy: b.copy ?? a.copy,\n sources: a.sources.length ? (b.sources.length ? [...a.sources, ...b.sources] : a.sources) : b.sources,\n imports: a.imports.length ? (b.imports.length ? [...a.imports, ...b.imports] : a.imports) : b.imports,\n exports: a.exports.length ? (b.exports.length ? [...a.exports, ...b.exports] : a.exports) : b.exports,\n }\n}\n\nfunction isIndexPath(path: string): boolean {\n return path.endsWith('/index.ts') || path === 'index.ts'\n}\n\n// Sort order: shortest path first. Within a length bucket, index.ts barrels last.\nfunction compareFiles(a: FileNode, b: FileNode): number {\n const lenDiff = a.path.length - b.path.length\n if (lenDiff !== 0) return lenDiff\n const aIsIndex = isIndexPath(a.path)\n const bIsIndex = isIndexPath(b.path)\n if (aIsIndex && !bIsIndex) return 1\n if (!aIsIndex && bIsIndex) return -1\n\n return 0\n}\n\n/**\n * In-memory file store for generated files, and the writer that turns them into source\n * strings on `storage`. Files sharing a `path` are merged (sources/imports/exports\n * concatenated). The `files` getter is sorted by path length (barrel `index.ts` last\n * within a bucket).\n *\n * @example\n * ```ts\n * const manager = new FileManager()\n * manager.upsert(myFile)\n * manager.files // sorted view\n * await manager.write(manager.files, { storage: fsStorage() })\n * ```\n */\nexport class FileManager {\n readonly hooks = new Hookable<FileManagerHooks>()\n readonly #cache = new Map<string, FileNode>()\n // Cached sorted view. Null means stale and rebuilt lazily on next `files` read.\n // Nulled (not mutated) on every write so callers holding a prior reference keep\n // their snapshot. `dispose()` must not silently empty an array the consumer\n // already holds.\n #sorted: Array<FileNode> | null = null\n\n add(...files: Array<FileNode>): Array<FileNode> {\n return this.#store(files, false)\n }\n\n upsert(...files: Array<FileNode>): Array<FileNode> {\n return this.#store(files, true)\n }\n\n #store(files: ReadonlyArray<FileNode>, mergeExisting: boolean): Array<FileNode> {\n const batch = files.length > 1 ? this.#dedupe(files) : files\n const resolved: Array<FileNode> = []\n\n for (const file of batch) {\n const existing = this.#cache.get(file.path)\n const merged = existing && mergeExisting ? ast.factory.createFile(mergeFile(existing, file)) : ast.factory.createFile(file)\n this.#cache.set(merged.path, merged)\n resolved.push(merged)\n }\n\n if (resolved.length > 0) this.#sorted = null\n return resolved\n }\n\n // Merges same-path entries within a batch so the cache update loop stays\n // uniform. Only called for multi-file batches.\n #dedupe(files: ReadonlyArray<FileNode>): Array<FileNode> {\n const seen = new Map<string, FileNode>()\n for (const file of files) {\n const prev = seen.get(file.path)\n seen.set(file.path, prev ? mergeFile(prev, file) : file)\n }\n return [...seen.values()]\n }\n\n clear(): void {\n this.#cache.clear()\n this.#sorted = null\n }\n\n /**\n * Releases all stored files and clears every `hooks` listener. Called by the core after\n * `kubb:build:end`.\n */\n dispose(): void {\n this.clear()\n this.hooks.removeAllHooks()\n }\n\n /**\n * All stored files in stable sort order (shortest path first, barrel files\n * last within a length bucket). Returns a cached view, do not mutate.\n */\n get files(): Array<FileNode> {\n return (this.#sorted ??= [...this.#cache.values()].sort(compareFiles))\n }\n\n /**\n * Converts a file's AST sources (or its `copy` source) into the final on-disk string.\n */\n async parse(file: FileNode, { parsers, extension }: ParseOptions = {}): Promise<string> {\n if (file.copy) {\n return parseCopy(file)\n }\n\n const parseExtName = extension?.[file.extname] || undefined\n\n if (!parsers || !file.extname) {\n return joinSources(file)\n }\n\n const parser = parsers.get(file.extname)\n\n if (!parser) {\n return joinSources(file)\n }\n\n return parser.parse(file, { extname: parseExtName })\n }\n\n /**\n * Converts and writes every file at once, letting `storage.setItem` decide how much of\n * that runs concurrently.\n */\n async write(files: Array<FileNode>, { storage, parsers, extension }: WriteOptions): Promise<void> {\n if (files.length === 0) return\n\n await this.hooks.callHook('start', files)\n\n const total = files.length\n let processed = 0\n await Promise.all(\n files.map(async (file) => {\n const source = await this.parse(file, { parsers, extension })\n processed++\n await this.hooks.callHook('update', { file, source, processed, total, percentage: (processed / total) * 100 })\n if (source) await storage.setItem(file.path, source)\n }),\n )\n\n await this.hooks.callHook('end', files)\n }\n}\n"],"mappings":"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"} |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
833756
1.59%9877
1.05%+ Added
- Removed
Updated