@kubb/core 5.0.0-beta.38 → 5.0.0-beta.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{diagnostics-CYfKPtbU.d.ts → diagnostics-DhfW8YpT.d.ts} +289 -347
- package/dist/index.cjs +553 -174
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +164 -119
- package/dist/index.js +532 -149
- package/dist/index.js.map +1 -1
- package/dist/{KubbDriver-CyNF-NIb.js → memoryStorage-CNQTs-YG.js} +240 -157
- package/dist/memoryStorage-CNQTs-YG.js.map +1 -0
- package/dist/{KubbDriver-BYBUfOZ8.cjs → memoryStorage-DHi1d0To.cjs} +255 -196
- package/dist/memoryStorage-DHi1d0To.cjs.map +1 -0
- package/dist/mocks.cjs +36 -6
- package/dist/mocks.cjs.map +1 -1
- package/dist/mocks.d.ts +30 -3
- package/dist/mocks.js +33 -5
- package/dist/mocks.js.map +1 -1
- package/package.json +4 -4
- package/src/KubbDriver.ts +21 -65
- package/src/Telemetry.ts +278 -0
- package/src/constants.ts +14 -21
- package/src/createKubb.ts +22 -50
- package/src/createReporter.ts +43 -13
- package/src/defineGenerator.ts +2 -6
- package/src/defineLogger.ts +13 -1
- package/src/defineResolver.ts +3 -4
- package/src/diagnostics.ts +130 -61
- package/src/index.ts +8 -16
- package/src/mocks.ts +57 -2
- package/src/reporters/cliReporter.ts +90 -0
- package/src/reporters/fileReporter.ts +103 -0
- package/src/reporters/jsonReporter.ts +20 -0
- package/src/reporters/report.ts +85 -0
- package/src/types.ts +0 -1
- package/dist/KubbDriver-BYBUfOZ8.cjs.map +0 -1
- package/dist/KubbDriver-CyNF-NIb.js.map +0 -1
- package/src/devtools.ts +0 -53
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { resolve } from 'node:path'
|
|
2
|
+
import { getElapsedMs } from '@internals/utils'
|
|
3
|
+
import type { GenerationResult } from '../createReporter.ts'
|
|
4
|
+
import { Diagnostics, type SerializedDiagnostic } from '../diagnostics.ts'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* One plugin's elapsed time, derived from a `performance` diagnostic.
|
|
8
|
+
*/
|
|
9
|
+
export type ReportTiming = {
|
|
10
|
+
plugin: string
|
|
11
|
+
durationMs: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The normalized result of generating one config, shared by every reporter. Each reporter renders
|
|
16
|
+
* the same {@link Report} in its own format (the `cli` summary, the `json` document, the `file`
|
|
17
|
+
* log), so they always agree on the numbers. Build it with {@link buildReport}.
|
|
18
|
+
*/
|
|
19
|
+
export type Report = {
|
|
20
|
+
/**
|
|
21
|
+
* The config name, or an empty string when it is unnamed.
|
|
22
|
+
*/
|
|
23
|
+
name: string
|
|
24
|
+
status: 'success' | 'failed'
|
|
25
|
+
plugins: {
|
|
26
|
+
passed: number
|
|
27
|
+
/**
|
|
28
|
+
* Names of the plugins that failed.
|
|
29
|
+
*/
|
|
30
|
+
failed: Array<string>
|
|
31
|
+
total: number
|
|
32
|
+
}
|
|
33
|
+
counts: {
|
|
34
|
+
errors: number
|
|
35
|
+
warnings: number
|
|
36
|
+
infos: number
|
|
37
|
+
}
|
|
38
|
+
filesCreated: number
|
|
39
|
+
/**
|
|
40
|
+
* Wall-clock time spent generating this config, in milliseconds.
|
|
41
|
+
*/
|
|
42
|
+
durationMs: number
|
|
43
|
+
/**
|
|
44
|
+
* Absolute output directory the files were written to.
|
|
45
|
+
*/
|
|
46
|
+
output: string
|
|
47
|
+
/**
|
|
48
|
+
* Per-plugin durations, slowest first.
|
|
49
|
+
*/
|
|
50
|
+
timings: Array<ReportTiming>
|
|
51
|
+
/**
|
|
52
|
+
* The build problems, serialized to their JSON-safe fields plus a `docsUrl`.
|
|
53
|
+
*/
|
|
54
|
+
diagnostics: Array<SerializedDiagnostic>
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Builds the normalized {@link Report} for one config from its {@link GenerationResult}. Splits the
|
|
59
|
+
* diagnostics into problems and per-plugin timings (slowest first) and derives the plugin and issue
|
|
60
|
+
* counts, so every reporter renders the same data.
|
|
61
|
+
*/
|
|
62
|
+
export function buildReport(result: GenerationResult): Report {
|
|
63
|
+
const { config, diagnostics, filesCreated, status, hrStart } = result
|
|
64
|
+
|
|
65
|
+
const failed = Diagnostics.failedPlugins(diagnostics)
|
|
66
|
+
const total = config.plugins?.length ?? 0
|
|
67
|
+
const counts = Diagnostics.count(diagnostics)
|
|
68
|
+
const problems = diagnostics.filter(Diagnostics.isProblem)
|
|
69
|
+
const timings = diagnostics
|
|
70
|
+
.filter(Diagnostics.isPerformance)
|
|
71
|
+
.sort((a, b) => b.duration - a.duration)
|
|
72
|
+
.map((diagnostic) => ({ plugin: diagnostic.plugin, durationMs: diagnostic.duration }))
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
name: config.name ?? '',
|
|
76
|
+
status,
|
|
77
|
+
plugins: { passed: total - failed.length, failed, total },
|
|
78
|
+
counts,
|
|
79
|
+
filesCreated,
|
|
80
|
+
durationMs: getElapsedMs(hrStart),
|
|
81
|
+
output: resolve(config.root, config.output.path),
|
|
82
|
+
timings,
|
|
83
|
+
diagnostics: problems.map((diagnostic) => Diagnostics.serialize(diagnostic)),
|
|
84
|
+
}
|
|
85
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"KubbDriver-BYBUfOZ8.cjs","names":["#emitter","NodeEventEmitter","#emitAll","#options","#transformParam","#eachParam","#reporterStorage","AsyncLocalStorage","path","#cache","#store","#dedupe","#sorted","#parsers","#storage","#extension","#pending","#runningFlush","#processAndWrite","#emitter","#entries","#visitors","#eventGeneratorPlugins","#resolvers","#defaultResolvers","#registry","#transforms","#normalizePlugin","#registerPlugin","#registerMiddleware","#studio","#parseInput","#filesPayload","#emitPluginEnd","#runGenerators","#getDefaultResolver","openInStudioFn"],"sources":["../../../internals/utils/src/errors.ts","../../../internals/utils/src/asyncEventEmitter.ts","../../../internals/utils/src/casing.ts","../../../internals/utils/src/time.ts","../../../internals/utils/src/promise.ts","../../../internals/utils/src/reserved.ts","../../../internals/utils/src/urlPath.ts","../src/constants.ts","../package.json","../src/diagnostics.ts","../src/definePlugin.ts","../src/defineResolver.ts","../src/devtools.ts","../src/FileManager.ts","../src/FileProcessor.ts","../src/HookRegistry.ts","../src/Transform.ts","../src/KubbDriver.ts"],"sourcesContent":["/**\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","import { EventEmitter as NodeEventEmitter } from 'node:events'\nimport { toError } from './errors.ts'\n\n/**\n * A function that can be registered as an event listener, synchronous or async.\n */\ntype AsyncListener<TArgs extends unknown[]> = (...args: TArgs) => void | Promise<void>\n\n/**\n * Typed `EventEmitter` that awaits all async listeners before resolving.\n * Wraps Node's `EventEmitter` with full TypeScript event-map inference.\n *\n * @example\n * ```ts\n * const emitter = new AsyncEventEmitter<{ build: [name: string] }>()\n * emitter.on('build', async (name) => { console.log(name) })\n * await emitter.emit('build', 'petstore') // all listeners awaited\n * ```\n */\nexport class AsyncEventEmitter<TEvents extends { [K in keyof TEvents]: unknown[] }> {\n /**\n * Maximum number of listeners per event 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 * Emits `eventName` and awaits all registered listeners sequentially.\n * Throws if any listener rejects, wrapping the cause with the event name and serialized arguments.\n *\n * @example\n * ```ts\n * await emitter.emit('build', 'petstore')\n * ```\n */\n emit<TEventName extends keyof TEvents & string>(eventName: TEventName, ...eventArgs: TEvents[TEventName]): Promise<void> | void {\n const listeners = this.#emitter.listeners(eventName) as Array<AsyncListener<TEvents[TEventName]>>\n\n if (listeners.length === 0) {\n return\n }\n\n return this.#emitAll(eventName, listeners, eventArgs)\n }\n\n async #emitAll<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listeners: Array<AsyncListener<TEvents[TEventName]>>,\n eventArgs: TEvents[TEventName],\n ): Promise<void> {\n for (const listener of listeners) {\n try {\n await listener(...eventArgs)\n } catch (err) {\n let serializedArgs: string\n try {\n serializedArgs = JSON.stringify(eventArgs)\n } catch {\n serializedArgs = String(eventArgs)\n }\n throw new Error(`Error in async listener for \"${eventName}\" with eventArgs ${serializedArgs}`, { cause: toError(err) })\n }\n }\n }\n\n /**\n * Registers a persistent listener for `eventName`.\n *\n * @example\n * ```ts\n * emitter.on('build', async (name) => { console.log(name) })\n * ```\n */\n on<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n this.#emitter.on(eventName, handler as AsyncListener<unknown[]>)\n }\n\n /**\n * Registers a one-shot listener that removes itself after the first invocation.\n *\n * @example\n * ```ts\n * emitter.onOnce('build', async (name) => { console.log(name) })\n * ```\n */\n onOnce<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n const wrapper: AsyncListener<TEvents[TEventName]> = (...args) => {\n this.off(eventName, wrapper)\n return handler(...args)\n }\n this.on(eventName, wrapper)\n }\n\n /**\n * Removes a previously registered listener.\n *\n * @example\n * ```ts\n * emitter.off('build', handler)\n * ```\n */\n off<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n this.#emitter.off(eventName, handler as AsyncListener<unknown[]>)\n }\n\n /**\n * Returns the number of listeners registered for `eventName`.\n *\n * @example\n * ```ts\n * emitter.on('build', handler)\n * emitter.listenerCount('build') // 1\n * ```\n */\n listenerCount<TEventName extends keyof TEvents & string>(eventName: TEventName): number {\n return this.#emitter.listenerCount(eventName)\n }\n\n /**\n * Raises or lowers the per-event 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 * emitter.setMaxListeners(40)\n * ```\n */\n setMaxListeners(max: number): void {\n this.#emitter.setMaxListeners(max)\n }\n\n /**\n * Returns the current per-event listener ceiling.\n */\n getMaxListeners(): number {\n return this.#emitter.getMaxListeners()\n }\n\n /**\n * Removes all listeners from every event channel.\n *\n * @example\n * ```ts\n * emitter.removeAll()\n * ```\n */\n removeAll(): void {\n this.#emitter.removeAllListeners()\n }\n}\n","type Options = {\n /**\n * When `true`, dot-separated segments are split on `.` and joined with `/` after casing.\n */\n isFile?: boolean\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 const normalized = 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\n const words = normalized.split(/[\\s\\-_./\\\\:]+/).filter(Boolean)\n\n return words\n .map((word, i) => {\n const allUpper = word.length > 1 && word === word.toUpperCase()\n if (allUpper) return word\n if (i === 0 && !pascal) return word.charAt(0).toLowerCase() + word.slice(1)\n return word.charAt(0).toUpperCase() + word.slice(1)\n })\n .join('')\n .replace(/[^a-zA-Z0-9]/g, '')\n}\n\n/**\n * Splits `text` on `.` and applies `transformPart` to each segment.\n * The last segment receives `isLast = true`, all earlier segments receive `false`.\n * Segments are joined with `/` to form a file path.\n *\n * Only splits on dots followed by a letter so that version numbers\n * embedded in operationIds (e.g. `v2025.0`) are kept intact.\n *\n * Empty segments are filtered before joining. They arise when the text starts with\n * a dot followed immediately by a letter (e.g. `..Schema` splits into `['..', 'Schema']`\n * and `'..'` transforms to an empty string). Without this filter the join would produce\n * a leading `/`, which `path.resolve` would interpret as an absolute path, allowing\n * generated files to escape the configured output directory.\n */\nfunction applyToFileParts(text: string, transformPart: (part: string, isLast: boolean) => string): string {\n const parts = text.split(/\\.(?=[a-zA-Z])/)\n return parts\n .map((part, i) => transformPart(part, i === parts.length - 1))\n .filter(Boolean)\n .join('/')\n}\n\n/**\n * Converts `text` to camelCase.\n * When `isFile` is `true`, dot-separated segments are each cased independently and joined with `/`.\n *\n * @example\n * camelCase('hello-world') // 'helloWorld'\n * camelCase('pet.petId', { isFile: true }) // 'pet/petId'\n */\nexport function camelCase(text: string, { isFile, prefix = '', suffix = '' }: Options = {}): string {\n if (isFile) {\n return applyToFileParts(text, (part, isLast) => camelCase(part, isLast ? { prefix, suffix } : {}))\n }\n\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false)\n}\n\n/**\n * Converts `text` to PascalCase.\n * When `isFile` is `true`, the last dot-separated segment is PascalCased and earlier segments are camelCased.\n *\n * @example\n * pascalCase('hello-world') // 'HelloWorld'\n * pascalCase('pet.petId', { isFile: true }) // 'pet/PetId'\n */\nexport function pascalCase(text: string, { isFile, prefix = '', suffix = '' }: Options = {}): string {\n if (isFile) {\n return applyToFileParts(text, (part, isLast) => (isLast ? pascalCase(part, { prefix, suffix }) : camelCase(part)))\n }\n\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true)\n}\n","/**\n * Calculates elapsed time in milliseconds from a high-resolution `process.hrtime` start time.\n * Rounds to 2 decimal places for sub-millisecond precision without noise.\n *\n * @example\n * ```ts\n * const start = process.hrtime()\n * doWork()\n * getElapsedMs(start) // 42.35\n * ```\n */\nexport function getElapsedMs(hrStart: [number, number]): number {\n const [seconds, nanoseconds] = process.hrtime(hrStart)\n const ms = seconds * 1000 + nanoseconds / 1e6\n return Math.round(ms * 100) / 100\n}\n\n/**\n * Converts a millisecond duration into a human-readable string (`ms`, `s`, or `m s`).\n *\n * @example\n * ```ts\n * formatMs(250) // '250ms'\n * formatMs(1500) // '1.50s'\n * formatMs(90000) // '1m 30.0s'\n * ```\n */\nexport function formatMs(ms: number): string {\n if (ms >= 60000) {\n const mins = Math.floor(ms / 60000)\n const secs = ((ms % 60000) / 1000).toFixed(1)\n return `${mins}m ${secs}s`\n }\n\n if (ms >= 1000) {\n return `${(ms / 1000).toFixed(2)}s`\n }\n return `${Math.round(ms)}ms`\n}\n\n/**\n * Formats the elapsed time since `hrStart` as a human-readable string.\n *\n * @example\n * ```ts\n * const start = process.hrtime()\n * doWork()\n * formatHrtime(start) // '1.50s'\n * ```\n */\nexport function formatHrtime(hrStart: [number, number]): string {\n return formatMs(getElapsedMs(hrStart))\n}\n","function* chunks<T>(arr: readonly T[], size: number): Generator<T[]> {\n for (let i = 0; i < arr.length; i += size) {\n yield arr.slice(i, i + size)\n }\n}\n\nexport type ForBatchesOptions = {\n /**\n * Maximum batch size handed to `process`.\n * Parallel dispatch within a batch is the caller's responsibility\n * (typically via `Promise.all(batch.map(...))`).\n */\n concurrency: number\n /**\n * Called after every batch.\n *\n * Use a cheap, idempotent callback (e.g. one that short-circuits when there\n * is nothing new to do). The helper does not coalesce calls — if you need\n * throttling, do it inside `flush` itself.\n */\n flush?: () => Promise<void>\n}\n\n/**\n * Slices `source` into batches of `concurrency` items and awaits `process` for each batch.\n * Accepts both plain arrays (sync) and `AsyncIterable` (streaming).\n *\n * `process` controls whether items inside a batch run in parallel; this helper only\n * controls batch size and per-batch flushing.\n *\n * @example\n * ```ts\n * // parallel dispatch inside each batch\n * await forBatches(schemas, (batch) => Promise.all(batch.map(process)), { concurrency: 8 })\n *\n * // async iterable with a flush after every batch\n * await forBatches(stream.schemas, (batch) => dispatch(batch), { concurrency: 8, flush })\n * ```\n */\nexport async function forBatches<T>(\n source: readonly T[] | AsyncIterable<T>,\n process: (batch: T[]) => Promise<unknown>,\n options: ForBatchesOptions,\n): Promise<void> {\n const { concurrency, flush } = options\n\n if (Array.isArray(source)) {\n for (const batch of chunks(source, concurrency)) {\n await process(batch)\n if (flush) await flush()\n }\n return\n }\n\n const batch: T[] = []\n for await (const item of source) {\n batch.push(item)\n if (batch.length >= concurrency) {\n await process(batch.splice(0))\n\n if (flush) await flush()\n }\n }\n if (batch.length > 0) {\n await process(batch.splice(0))\n\n if (flush) await flush()\n }\n}\n\n/**\n * Runs `work`, passing `flush` as its periodic-flush callback, then calls\n * `flush` once more to drain any items that did not cross a flush boundary.\n *\n * @example\n * ```ts\n * await withDrain(\n * (flush) => processItems(items, { flush }),\n * () => writeRemainingFiles(),\n * )\n * ```\n */\nexport async function withDrain(work: (flush: () => Promise<void>) => Promise<void>, flush: () => Promise<void>): Promise<void> {\n await work(flush)\n await flush()\n}\n\n/** A value that may already be resolved or still pending.\n *\n * @example\n * ```ts\n * function load(id: string): PossiblePromise<string> {\n * return cache.get(id) ?? fetchRemote(id)\n * }\n * ```\n */\nexport type PossiblePromise<T> = Promise<T> | T\n\n/** Returns `true` when `result` is a thenable `Promise`.\n *\n * @example\n * ```ts\n * isPromise(Promise.resolve(1)) // true\n * isPromise(42) // false\n * ```\n */\nexport function isPromise<T>(result: PossiblePromise<T>): result is Promise<T> {\n return result !== null && result !== undefined && typeof (result as Record<string, unknown>)['then'] === 'function'\n}\n\n/** Returns `true` when `result` is a rejected `Promise.allSettled` result with a typed `reason`.\n *\n * @example\n * ```ts\n * const results = await Promise.allSettled([p1, p2])\n * results.filter(isPromiseRejectedResult<Error>).map((r) => r.reason.message)\n * ```\n */\nexport function isPromiseRejectedResult<T>(result: PromiseSettledResult<unknown>): result is Omit<PromiseRejectedResult, 'reason'> & { reason: T } {\n return result.status === 'rejected'\n}\n\ntype Store<TKey, TValue> = {\n has(key: TKey): boolean\n get(key: TKey): TValue | undefined\n set(key: TKey, value: TValue): unknown\n}\n\n/**\n * Wraps `factory` with a keyed cache backed by the provided store.\n *\n * Pass a `WeakMap` for object keys (results are GC-eligible when the key is\n * collected) or a `Map` for primitive keys. For multi-argument functions,\n * nest two `memoize` calls — the outer keyed by the first argument, the\n * inner (created once per outer miss) keyed by the second.\n *\n * Because the cache is owned by the caller, it can be shared, inspected, or\n * cleared independently of the memoized function.\n *\n * @example Single WeakMap key\n * ```ts\n * const cache = new WeakMap<SchemaNode, Set<string>>()\n * const getRefs = memoize(cache, (node) => collectRefs(node))\n * ```\n *\n * @example Single Map key (primitive)\n * ```ts\n * const cache = new Map<string, Resolver>()\n * const getResolver = memoize(cache, (name) => buildResolver(name))\n * ```\n *\n * @example Two-level (object + primitive)\n * ```ts\n * const outer = new WeakMap<Params[], Map<string, Params[]>>()\n * const fn = memoize(outer, (params) => memoize(new Map(), (key) => transform(params, key)))\n * fn(params)('camelcase')\n * ```\n */\nexport function memoize<TKey, TValue>(store: Store<TKey, TValue>, factory: (key: TKey) => TValue): (key: TKey) => TValue {\n return (key: TKey): TValue => {\n if (store.has(key)) return store.get(key)!\n const value = factory(key)\n store.set(key, value)\n return value\n }\n}\n\n/**\n * Wraps a plain array in a reusable `AsyncIterable`.\n * Each `[Symbol.asyncIterator]()` call returns a fresh generator so the\n * iterable can be consumed multiple times (e.g. once per plugin pre-scan).\n *\n * @example\n * ```ts\n * const stream = arrayToAsyncIterable([1, 2, 3])\n * for await (const n of stream) console.log(n) // 1, 2, 3\n * ```\n */\nexport function arrayToAsyncIterable<T>(arr: readonly T[]): AsyncIterable<T> {\n return {\n [Symbol.asyncIterator]() {\n return (async function* () {\n yield* arr\n })()\n },\n }\n}\n","/**\n * JavaScript and Java reserved words.\n * @link https://github.com/jonschlinkert/reserved/blob/master/index.js\n */\nconst reservedWords = new Set([\n 'abstract',\n 'arguments',\n 'boolean',\n 'break',\n 'byte',\n 'case',\n 'catch',\n 'char',\n 'class',\n 'const',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'double',\n 'else',\n 'enum',\n 'eval',\n 'export',\n 'extends',\n 'false',\n 'final',\n 'finally',\n 'float',\n 'for',\n 'function',\n 'goto',\n 'if',\n 'implements',\n 'import',\n 'in',\n 'instanceof',\n 'int',\n 'interface',\n 'let',\n 'long',\n 'native',\n 'new',\n 'null',\n 'package',\n 'private',\n 'protected',\n 'public',\n 'return',\n 'short',\n 'static',\n 'super',\n 'switch',\n 'synchronized',\n 'this',\n 'throw',\n 'throws',\n 'transient',\n 'true',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'volatile',\n 'while',\n 'with',\n 'yield',\n 'Array',\n 'Date',\n 'hasOwnProperty',\n 'Infinity',\n 'isFinite',\n 'isNaN',\n 'isPrototypeOf',\n 'length',\n 'Math',\n 'name',\n 'NaN',\n 'Number',\n 'Object',\n 'prototype',\n 'String',\n 'toString',\n 'undefined',\n 'valueOf',\n] as const)\n\n/**\n * Prefixes `word` with `_` when it is a reserved JavaScript/Java identifier or starts with a digit.\n *\n * @example\n * ```ts\n * transformReservedWord('class') // '_class'\n * transformReservedWord('42foo') // '_42foo'\n * transformReservedWord('status') // 'status'\n * ```\n */\nexport function transformReservedWord(word: string): string {\n const firstChar = word.charCodeAt(0)\n if (word && (reservedWords.has(word as 'valueOf') || (firstChar >= 48 && firstChar <= 57))) {\n return `_${word}`\n }\n return word\n}\n\n/**\n * Returns `true` when `name` is a syntactically valid JavaScript variable name.\n *\n * @example\n * ```ts\n * isValidVarName('status') // true\n * isValidVarName('class') // false (reserved word)\n * isValidVarName('42foo') // false (starts with digit)\n * ```\n */\nexport function isValidVarName(name: string): boolean {\n if (!name || reservedWords.has(name as 'valueOf')) {\n return false\n }\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)\n}\n","import { camelCase } from './casing.ts'\nimport { isValidVarName } from './reserved.ts'\n\nexport type URLObject = {\n /**\n * The resolved URL string (Express-style or template literal, depending on context).\n */\n url: string\n /**\n * Extracted path parameters as a key-value map, or `undefined` when the path has none.\n */\n params?: Record<string, string>\n}\n\ntype ObjectOptions = {\n /**\n * Controls whether the `url` is rendered as an Express path or a template literal.\n * @default 'path'\n */\n type?: 'path' | 'template'\n /**\n * Optional transform applied to each extracted parameter name.\n */\n replacer?: (pathParam: string) => string\n /**\n * When `true`, the result is serialized to a string expression instead of a plain object.\n */\n stringify?: boolean\n}\n\n/**\n * Supported identifier casing strategies for path parameters.\n */\ntype PathCasing = 'camelcase'\n\ntype Options = {\n /**\n * Casing strategy applied to path parameter names.\n * @default undefined (original identifier preserved)\n */\n casing?: PathCasing\n}\n\n/**\n * Parses and transforms an OpenAPI/Swagger path string into various URL formats.\n *\n * @example\n * const p = new URLPath('/pet/{petId}')\n * p.URL // '/pet/:petId'\n * p.template // '`/pet/${petId}`'\n */\nexport class URLPath {\n /**\n * The raw OpenAPI/Swagger path string, e.g. `/pet/{petId}`.\n */\n path: string\n\n #options: Options\n\n constructor(path: string, options: Options = {}) {\n this.path = path\n this.#options = options\n }\n\n /** Converts the OpenAPI path to Express-style colon syntax, e.g. `/pet/{petId}` → `/pet/:petId`.\n *\n * @example\n * ```ts\n * new URLPath('/pet/{petId}').URL // '/pet/:petId'\n * ```\n */\n get URL(): string {\n return this.toURLPath()\n }\n\n /** Returns `true` when `path` is a fully-qualified URL (e.g. starts with `https://`).\n *\n * @example\n * ```ts\n * new URLPath('https://petstore.swagger.io/v2/pet').isURL // true\n * new URLPath('/pet/{petId}').isURL // false\n * ```\n */\n get isURL(): boolean {\n try {\n return !!new URL(this.path).href\n } catch {\n return false\n }\n }\n\n /**\n * Converts the OpenAPI path to a TypeScript template literal string.\n *\n * @example\n * new URLPath('/pet/{petId}').template // '`/pet/${petId}`'\n * new URLPath('/account/monetary-accountID').template // '`/account/${monetaryAccountId}`'\n */\n get template(): string {\n return this.toTemplateString()\n }\n\n /** Returns the path and its extracted params as a structured `URLObject`, or as a stringified expression when `stringify` is set.\n *\n * @example\n * ```ts\n * new URLPath('/pet/{petId}').object\n * // { url: '/pet/:petId', params: { petId: 'petId' } }\n * ```\n */\n get object(): URLObject | string {\n return this.toObject()\n }\n\n /** Returns a map of path parameter names, or `undefined` when the path has no parameters.\n *\n * @example\n * ```ts\n * new URLPath('/pet/{petId}').params // { petId: 'petId' }\n * new URLPath('/pet').params // undefined\n * ```\n */\n get params(): Record<string, string> | undefined {\n return this.getParams()\n }\n\n #transformParam(raw: string): string {\n const param = isValidVarName(raw) ? raw : camelCase(raw)\n return this.#options.casing === 'camelcase' ? camelCase(param) : param\n }\n\n /**\n * Iterates over every `{param}` token in `path`, calling `fn` with the raw token and transformed name.\n */\n #eachParam(fn: (raw: string, param: string) => void): void {\n for (const match of this.path.matchAll(/\\{([^}]+)\\}/g)) {\n const raw = match[1]!\n fn(raw, this.#transformParam(raw))\n }\n }\n\n toObject({ type = 'path', replacer, stringify }: ObjectOptions = {}): URLObject | string {\n const object = {\n url: type === 'path' ? this.toURLPath() : this.toTemplateString({ replacer }),\n params: this.getParams(),\n }\n\n if (stringify) {\n if (type === 'template') {\n return JSON.stringify(object).replaceAll(\"'\", '').replaceAll(`\"`, '')\n }\n\n if (object.params) {\n return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll(\"'\", '').replaceAll(`\"`, '')} }`\n }\n\n return `{ url: '${object.url}' }`\n }\n\n return object\n }\n\n /**\n * Converts the OpenAPI path to a TypeScript template literal string.\n * An optional `replacer` can transform each extracted parameter name before interpolation.\n *\n * @example\n * new URLPath('/pet/{petId}').toTemplateString() // '`/pet/${petId}`'\n */\n toTemplateString({\n prefix,\n replacer,\n }: {\n prefix?: string | null\n replacer?: (pathParam: string) => string\n } = {}): string {\n const parts = this.path.split(/\\{([^}]+)\\}/)\n const result = parts\n .map((part, i) => {\n if (i % 2 === 0) return part\n const param = this.#transformParam(part)\n return `\\${${replacer ? replacer(param) : param}}`\n })\n .join('')\n\n return `\\`${prefix ?? ''}${result}\\``\n }\n\n /**\n * Extracts all `{param}` segments from the path and returns them as a key-value map.\n * An optional `replacer` transforms each parameter name in both key and value positions.\n * Returns `undefined` when no path parameters are found.\n *\n * @example\n * ```ts\n * new URLPath('/pet/{petId}/tag/{tagId}').getParams()\n * // { petId: 'petId', tagId: 'tagId' }\n * ```\n */\n getParams(replacer?: (pathParam: string) => string): Record<string, string> | undefined {\n const params: Record<string, string> = {}\n\n this.#eachParam((_raw, param) => {\n const key = replacer ? replacer(param) : param\n params[key] = key\n })\n\n return Object.keys(params).length > 0 ? params : undefined\n }\n\n /** Converts the OpenAPI path to Express-style colon syntax.\n *\n * @example\n * ```ts\n * new URLPath('/pet/{petId}').toURLPath() // '/pet/:petId'\n * ```\n */\n toURLPath(): string {\n return this.path.replace(/\\{([^}]+)\\}/g, ':$1')\n }\n}\n","/**\n * Base URL for the Kubb Studio web app.\n */\nexport const DEFAULT_STUDIO_URL = 'https://kubb.studio' as const\n\n/**\n * Number of file writes to batch in parallel during `flushPendingFiles`.\n */\nexport const STREAM_FLUSH_EVERY = 50\n\n/**\n * Number of schema/operation nodes to dispatch concurrently during generation.\n */\nexport const SCHEMA_PARALLEL = 8\n\n/**\n * Upper bound of hook listeners a single plugin can add to one event (its schema, operation,\n * and operations generators, plus lifecycle hooks). Used to size the hooks emitter's\n * max-listener ceiling so a multi-generator plugin set does not trip Node's leak warning.\n */\nexport const HOOK_LISTENERS_PER_PLUGIN = 4\n\n/**\n * Plugin `include` filter types that select operations directly. When one of these is set\n * without a `schemaName` include, the generate phase pre-scans operations to compute the set\n * of schemas they reach, so unreachable schemas can be pruned for that plugin.\n */\nexport const OPERATION_FILTER_TYPES: ReadonlySet<string> = new Set(['tag', 'operationId', 'path', 'method', 'contentType'])\n\n/**\n * Numeric log-level thresholds used internally to compare verbosity.\n *\n * Higher numbers are more verbose.\n */\nexport const logLevel = {\n silent: Number.NEGATIVE_INFINITY,\n error: 0,\n warn: 1,\n info: 3,\n verbose: 4,\n} as const\n\n/**\n * Stable codes Kubb attaches to a `Diagnostic`. Each maps to a known failure mode\n * and stays stable so it can be referenced in tooling and (later) docs. Reference\n * these instead of inlining the string at a throw site.\n */\nexport const diagnosticCode = {\n /**\n * Fallback for an unstructured error with no specific code.\n */\n unknown: 'KUBB_UNKNOWN',\n /**\n * The `input.path` file or URL could not be read.\n */\n inputNotFound: 'KUBB_INPUT_NOT_FOUND',\n /**\n * An adapter was configured without an `input`.\n */\n inputRequired: 'KUBB_INPUT_REQUIRED',\n /**\n * A `$ref` (or equivalent reference) could not be resolved in the source document.\n */\n refNotFound: 'KUBB_REF_NOT_FOUND',\n /**\n * A server variable value is not allowed by its `enum`.\n */\n invalidServerVariable: 'KUBB_INVALID_SERVER_VARIABLE',\n /**\n * A required plugin is missing from the config.\n */\n pluginNotFound: 'KUBB_PLUGIN_NOT_FOUND',\n /**\n * A plugin threw while generating.\n */\n pluginFailed: 'KUBB_PLUGIN_FAILED',\n /**\n * A plugin reported a non-fatal warning through `ctx.warn`.\n */\n pluginWarning: 'KUBB_PLUGIN_WARNING',\n /**\n * A plugin reported an informational message through `ctx.info`.\n */\n pluginInfo: 'KUBB_PLUGIN_INFO',\n /**\n * A schema uses a `format` Kubb does not map to a specific type. Reserved for\n * adapters to emit as a `warning`.\n */\n unsupportedFormat: 'KUBB_UNSUPPORTED_FORMAT',\n /**\n * A referenced schema or operation is marked `deprecated`. Reserved for adapters\n * to emit as an `info`.\n */\n deprecated: 'KUBB_DEPRECATED',\n /**\n * An adapter is required but the config has none. The build cannot read the input\n * without one.\n */\n adapterRequired: 'KUBB_ADAPTER_REQUIRED',\n /**\n * The `devtools` config is set to something other than an object.\n */\n devtoolsInvalid: 'KUBB_DEVTOOLS_INVALID',\n /**\n * A resolved output path escapes the output directory, which can stem from a path\n * traversal in the spec or a misconfigured `group.name`.\n */\n pathTraversal: 'KUBB_PATH_TRAVERSAL',\n /**\n * A post-generate shell hook (`hooks.done`) exited with a failure.\n */\n hookFailed: 'KUBB_HOOK_FAILED',\n /**\n * The formatter pass over the generated files failed.\n */\n formatFailed: 'KUBB_FORMAT_FAILED',\n /**\n * The linter pass over the generated files failed.\n */\n lintFailed: 'KUBB_LINT_FAILED',\n /**\n * Not a failure. Carries a plugin's elapsed time, summed into the run total.\n */\n performance: 'KUBB_PERFORMANCE',\n /**\n * Not a failure. A newer Kubb version is available on npm.\n */\n updateAvailable: 'KUBB_UPDATE_AVAILABLE',\n} as const\n\n/**\n * Union of the stable {@link diagnosticCode} values.\n */\nexport type DiagnosticCode = (typeof diagnosticCode)[keyof typeof diagnosticCode]\n","","import { AsyncLocalStorage } from 'node:async_hooks'\nimport type { AsyncEventEmitter } from '@internals/utils'\nimport { getErrorMessage } from '@internals/utils'\nimport { version } from '../package.json'\nimport { type DiagnosticCode, diagnosticCode } from './constants.ts'\nimport type { KubbHooks } from './createKubb.ts'\n\n/**\n * Docs major, derived from the package version so the link tracks the published major.\n */\nconst docsMajor = version.split('.')[0] ?? '5'\n\n/**\n * How serious a diagnostic is. `error` fails the build, `warning` and `info`\n * are reported but do not.\n */\nexport type DiagnosticSeverity = 'error' | 'warning' | 'info'\n\n/**\n * A human-readable explanation of a diagnostic code: a short title, what triggers it, and how\n * to resolve it. This is the single source of truth the kubb.dev `/diagnostics/<slug>` pages\n * mirror, so every code stays documented in one place. Typed as a total record over\n * {@link DiagnosticCode}, so adding a code without documenting it fails the build.\n */\nexport type DiagnosticDoc = {\n /**\n * Short title shown as the docs heading.\n */\n title: string\n /**\n * What triggers the diagnostic.\n */\n cause: string\n /**\n * The action that resolves it.\n */\n fix: string\n}\n\n/**\n * Points a diagnostic back into the source document. Inputs are parsed into an\n * object model with no line/column, so locations carry a JSON pointer the adapter\n * builds (the OAS adapter emits `#/components/schemas/Pet`). A `config` diagnostic\n * points at the Kubb config itself and so has no pointer.\n */\nexport type DiagnosticLocation =\n | {\n kind: 'schema'\n /**\n * RFC 6901 JSON pointer into the source document.\n */\n pointer: string\n /**\n * The original reference when the diagnostic stems from an unresolved one.\n */\n ref?: string\n }\n | {\n kind: 'operation' | 'document'\n /**\n * RFC 6901 JSON pointer into the source document.\n */\n pointer: string\n }\n | {\n kind: 'config'\n }\n\n/**\n * What a diagnostic carries.\n * - `problem` is a build issue shown to the user, and the only kind rendered as a problem.\n * - `performance` records a plugin's elapsed time.\n * - `update` is a version notice.\n */\nexport type DiagnosticKind = 'problem' | 'performance' | 'update'\n\n/**\n * Codes that describe a build problem: every {@link DiagnosticCode} except the\n * `performance` and `updateAvailable` codes, which ride on their own variants.\n */\nexport type ProblemCode = Exclude<DiagnosticCode, typeof diagnosticCode.performance | typeof diagnosticCode.updateAvailable>\n\n/**\n * A build problem collected during a run, gathered into the result instead of\n * aborting on the first failure. It carries a stable {@link ProblemCode}, a\n * `severity`, a `message`, and optionally a `location` into the source document,\n * a `help`, the `plugin` that produced it, and the `cause` it wraps.\n */\nexport type ProblemDiagnostic = {\n /**\n * @default 'problem'\n */\n kind?: 'problem'\n /**\n * Stable identifier for the problem, from the {@link diagnosticCode} catalog.\n */\n code: ProblemCode\n severity: DiagnosticSeverity\n message: string\n location?: DiagnosticLocation\n /**\n * A suggested fix, phrased as an action the user can take.\n */\n help?: string\n /**\n * Name of the plugin or subsystem that produced the diagnostic.\n */\n plugin?: string\n /**\n * The underlying error, when the diagnostic wraps a thrown one.\n */\n cause?: Error\n}\n\n/**\n * A per-plugin performance record, built with {@link Diagnostics.performance}. It carries the\n * `plugin` and its elapsed `duration`, and the `performance` kind keeps it out of the problem\n * list. It feeds the per-plugin timing bars, and reporters sum these into the run total.\n */\nexport type PerformanceDiagnostic = {\n kind: 'performance'\n code: typeof diagnosticCode.performance\n severity: 'info'\n message: string\n /**\n * The plugin this measurement belongs to.\n */\n plugin: string\n /**\n * Elapsed milliseconds.\n */\n duration: number\n}\n\n/**\n * A notice that a newer Kubb version is available on npm, built with {@link Diagnostics.update}.\n * It carries the running and latest versions and renders like any info diagnostic.\n */\nexport type UpdateDiagnostic = {\n kind: 'update'\n code: typeof diagnosticCode.updateAvailable\n severity: 'info'\n message: string\n /**\n * The running Kubb version.\n */\n currentVersion: string\n /**\n * The newest version published on npm.\n */\n latestVersion: string\n}\n\n/**\n * A structured record collected during a build, discriminated on `kind`: a\n * {@link ProblemDiagnostic} for an issue, a {@link PerformanceDiagnostic} for a per-plugin\n * timing, or an {@link UpdateDiagnostic} for a version notice.\n */\nexport type Diagnostic = ProblemDiagnostic | PerformanceDiagnostic | UpdateDiagnostic\n\n/**\n * Maps each {@link DiagnosticCode} to the variant it selects, for {@link narrowDiagnostic}.\n * Every {@link ProblemCode} selects a {@link ProblemDiagnostic}, and the two bookkeeping codes\n * select their own variant.\n */\nexport type DiagnosticByCode = Record<ProblemCode, ProblemDiagnostic> &\n Record<typeof diagnosticCode.performance, PerformanceDiagnostic> &\n Record<typeof diagnosticCode.updateAvailable, UpdateDiagnostic>\n\n/**\n * Narrows a {@link Diagnostic} to the variant for `code`, or `null` when it does not match.\n *\n * @example\n * ```ts\n * const update = narrowDiagnostic(diagnostic, diagnosticCode.updateAvailable)\n * if (update) {\n * console.log(update.latestVersion)\n * }\n * ```\n */\nexport function narrowDiagnostic<C extends DiagnosticCode>(diagnostic: Diagnostic, code: C): DiagnosticByCode[C] | null {\n return diagnostic.code === code ? (diagnostic as DiagnosticByCode[C]) : null\n}\n\n/**\n * Builds a type guard that narrows a {@link Diagnostic} to the variant for `kind`. A diagnostic\n * with no `kind` is treated as a `problem`.\n */\nfunction isKind<T extends Diagnostic>(kind: DiagnosticKind) {\n return (diagnostic: Diagnostic): diagnostic is T => (diagnostic.kind ?? 'problem') === kind\n}\n\n/**\n * Returns `true` when the diagnostic is a build {@link ProblemDiagnostic}.\n *\n * @example\n * ```ts\n * if (isProblemDiagnostic(diagnostic)) {\n * console.log(diagnostic.location)\n * }\n * ```\n */\nexport const isProblemDiagnostic = isKind<ProblemDiagnostic>('problem')\n\n/**\n * Returns `true` when the diagnostic is a per-plugin {@link PerformanceDiagnostic}.\n *\n * @example\n * ```ts\n * const timings = diagnostics.filter(isPerformanceDiagnostic)\n * ```\n */\nexport const isPerformanceDiagnostic = isKind<PerformanceDiagnostic>('performance')\n\n/**\n * Returns `true` when the diagnostic is a version-update {@link UpdateDiagnostic}.\n *\n * @example\n * ```ts\n * if (isUpdateDiagnostic(diagnostic)) {\n * console.log(diagnostic.latestVersion)\n * }\n * ```\n */\nexport const isUpdateDiagnostic = isKind<UpdateDiagnostic>('update')\n\n/**\n * A {@link Diagnostic} reduced to its JSON-safe fields plus a `docsUrl`, for\n * machine-readable output (the `--reporter json` report, the MCP tools). Drops the\n * non-serializable `cause` and the `timing`/`duration` bookkeeping.\n */\nexport type SerializedDiagnostic = {\n code: DiagnosticCode\n severity: DiagnosticSeverity\n message: string\n location?: DiagnosticLocation\n help?: string\n plugin?: string\n /**\n * The kubb.dev docs link for the code, omitted for the unknown fallback.\n */\n docsUrl?: string\n}\n\n/**\n * An `Error` that carries a {@link Diagnostic}, so structured problems can flow\n * through the existing throw/catch paths while keeping their code and location.\n *\n * @example\n * ```ts\n * throw new DiagnosticError({ code: diagnosticCode.refNotFound, severity: 'error', message: `Could not find ${ref}`, location: { kind: 'schema', pointer: ref, ref } })\n * ```\n */\nexport class DiagnosticError extends Error {\n diagnostic: ProblemDiagnostic\n\n constructor(diagnostic: ProblemDiagnostic) {\n super(diagnostic.message, { cause: diagnostic.cause })\n this.name = 'DiagnosticError'\n this.diagnostic = diagnostic\n }\n}\n\n/**\n * Structural check for a {@link DiagnosticError}, including one thrown from a duplicated\n * `@kubb/core` copy where `instanceof` fails. Matches on the `name` and a `diagnostic`\n * that carries a `code`.\n */\nfunction isDiagnosticError(error: unknown): error is DiagnosticError {\n if (error instanceof DiagnosticError) {\n return true\n }\n return (\n error instanceof Error &&\n error.name === 'DiagnosticError' &&\n 'diagnostic' in error &&\n typeof (error as { diagnostic?: unknown }).diagnostic === 'object' &&\n (error as { diagnostic?: Diagnostic }).diagnostic !== null &&\n typeof (error as { diagnostic?: { code?: unknown } }).diagnostic?.code === 'string'\n )\n}\n\n/**\n * Explanation for every {@link diagnosticCode}. Use {@link Diagnostics.explain} to look one up\n * and `Diagnostics.docsUrl` for the matching kubb.dev page.\n */\nexport const diagnosticCatalog: Record<DiagnosticCode, DiagnosticDoc> = {\n [diagnosticCode.unknown]: {\n title: 'Unknown error',\n cause: 'An error was thrown without a stable Kubb code, so it is reported as-is.',\n fix: 'Read the underlying message and stack. If it comes from a plugin or adapter, check its configuration; otherwise report it as a possible Kubb bug.',\n },\n [diagnosticCode.inputNotFound]: {\n title: 'Input not found',\n cause: 'The file or URL set in `input.path` (or passed as `kubb generate PATH`) could not be read.',\n fix: 'Check that the path or URL exists and is readable, then set it in `input.path` or pass it on the CLI.',\n },\n [diagnosticCode.inputRequired]: {\n title: 'Input required',\n cause: 'An adapter is configured but no `input` was provided.',\n fix: 'Set `input.path` (a file or URL) or `input.data` (an inline spec) in your Kubb config.',\n },\n [diagnosticCode.refNotFound]: {\n title: 'Reference not found',\n cause: 'A `$ref` could not be resolved in the source document.',\n fix: 'Add the missing definition (for example under `components.schemas`) or fix the `$ref`. Run `kubb validate` to check the spec.',\n },\n [diagnosticCode.invalidServerVariable]: {\n title: 'Invalid server variable',\n cause: 'A server variable value is not allowed by its `enum`.',\n fix: 'Use one of the values listed in the server variable `enum`, or update the spec.',\n },\n [diagnosticCode.pluginNotFound]: {\n title: 'Plugin not found',\n cause: 'A plugin that another plugin depends on is missing from the config.',\n fix: 'Add the required plugin to the `plugins` array in kubb.config.ts, or remove the dependency on it.',\n },\n [diagnosticCode.pluginFailed]: {\n title: 'Plugin failed',\n cause: 'A plugin threw while generating, or reported an error through `ctx.error`.',\n fix: 'Read the underlying error and check the plugin options and the schema or operation it failed on.',\n },\n [diagnosticCode.pluginWarning]: {\n title: 'Plugin warning',\n cause: 'A plugin reported a non-fatal warning through `ctx.warn`.',\n fix: 'Review the message. It does not fail the build; adjust the plugin options or input if the warning is unwanted.',\n },\n [diagnosticCode.pluginInfo]: {\n title: 'Plugin info',\n cause: 'A plugin reported an informational message through `ctx.info`.',\n fix: 'Informational only. No action is required.',\n },\n [diagnosticCode.unsupportedFormat]: {\n title: 'Unsupported format',\n cause: 'A schema uses a `format` Kubb does not map to a specific type, so it falls back to the base type.',\n fix: 'Use a format Kubb supports, or handle the custom format with a parser or plugin.',\n },\n [diagnosticCode.deprecated]: {\n title: 'Deprecated',\n cause: 'A referenced schema or operation is marked `deprecated`.',\n fix: 'Migrate off the deprecated definition if the warning is unwanted.',\n },\n [diagnosticCode.adapterRequired]: {\n title: 'Adapter required',\n cause: 'An action needs an adapter (for example opening Kubb Studio) but none is configured.',\n fix: 'Set `adapter` in kubb.config.ts, for example `adapterOas()`.',\n },\n [diagnosticCode.devtoolsInvalid]: {\n title: 'Invalid devtools config',\n cause: 'The `devtools` config is set to something other than an object.',\n fix: 'Set `devtools` to an options object, or remove it to disable Kubb Studio.',\n },\n [diagnosticCode.pathTraversal]: {\n title: 'Path traversal',\n cause: 'A resolved output path escaped the output directory, which can stem from a path traversal in the spec or a misconfigured `group.name`.',\n fix: 'Keep generated paths within the output directory. Review the `group.name` function and the names coming from the spec.',\n },\n [diagnosticCode.hookFailed]: {\n title: 'Hook failed',\n cause: 'A post-generate shell hook (`hooks.done`) exited with a non-zero status.',\n fix: 'Check the command is installed and correct, and run it manually to see the error.',\n },\n [diagnosticCode.formatFailed]: {\n title: 'Format failed',\n cause: 'The formatter pass over the generated files failed.',\n fix: 'Check the formatter (oxfmt, biome, or prettier) is installed and its config is valid, then run it manually on the output.',\n },\n [diagnosticCode.lintFailed]: {\n title: 'Lint failed',\n cause: 'The linter pass over the generated files failed.',\n fix: 'Check the linter (oxlint, biome, or eslint) is installed and its config is valid, then run it manually on the output.',\n },\n [diagnosticCode.performance]: {\n title: 'Performance',\n cause: 'Not a failure. Records a plugin’s elapsed time, summed into the run total.',\n fix: 'No action. This is an informational metric.',\n },\n [diagnosticCode.updateAvailable]: {\n title: 'Update available',\n cause: 'A newer Kubb version is published on npm than the one running.',\n fix: 'Update the `@kubb/*` packages, for example `npm install -g @kubb/cli`, to get the latest fixes.',\n },\n}\n\n/**\n * Static helpers for working with {@link Diagnostic}s, plus the run-scoped sink\n * that lets deep code report a diagnostic without threading a callback.\n *\n * The sink lives in a single `AsyncLocalStorage` in the `@kubb/core` bundle.\n * `Diagnostics.scope` activates it for a run, so anything inside that run (the\n * adapter parse, a lazily consumed stream, a generator) reports through\n * `Diagnostics.report` and lands in the same run.\n */\nexport class Diagnostics {\n static #reporterStorage = new AsyncLocalStorage<(diagnostic: Diagnostic) => void>()\n\n /**\n * Runs `fn` with `sink` as the active diagnostic sink for the whole async\n * subtree, so {@link Diagnostics.report} reaches it from anywhere inside.\n */\n static scope<T>(sink: (diagnostic: Diagnostic) => void, fn: () => T): T {\n return Diagnostics.#reporterStorage.run(sink, fn)\n }\n\n /**\n * Collects a diagnostic into the active build via the run-scoped sink, without throwing.\n * Returns `true` when a run consumed it, `false` when called outside a {@link Diagnostics.scope}\n * (so callers can fall back to throwing). Use a `warning`/`info` severity for non-fatal issues.\n * For rendering a diagnostic live on the hook bus, use {@link Diagnostics.emit} instead.\n */\n static report(diagnostic: Diagnostic): boolean {\n const sink = Diagnostics.#reporterStorage.getStore()\n if (!sink) {\n return false\n }\n sink(diagnostic)\n return true\n }\n\n /**\n * Emits a diagnostic on the run's `kubb:diagnostic` event so the loggers render it live.\n * Use it instead of calling `hooks.emit('kubb:diagnostic', ...)` directly. To collect a\n * diagnostic into the build result from deep in a run, use {@link Diagnostics.report} instead.\n */\n static async emit(hooks: AsyncEventEmitter<KubbHooks>, diagnostic: ProblemDiagnostic | UpdateDiagnostic): Promise<void> {\n await hooks.emit('kubb:diagnostic', { diagnostic })\n }\n\n /**\n * Coerces any thrown value into a {@link ProblemDiagnostic}. A {@link DiagnosticError}\n * keeps its structured data, and anything else becomes a `KUBB_UNKNOWN` error.\n */\n static from(error: unknown): ProblemDiagnostic {\n // The event emitter and BuildError wrap the original, so walk the cause chain to\n // recover a DiagnosticError thrown deeper down. `root` tracks the deepest error so\n // the unknown diagnostic reports the original message and stack, not the wrapper's.\n const seen = new Set<unknown>()\n let current: unknown = error\n let root: Error | undefined\n while (current instanceof Error && !seen.has(current)) {\n // Match structurally, not just by `instanceof`: a `DiagnosticError` thrown from a\n // duplicated `@kubb/core` copy (bundled into an adapter or plugin) is a different\n // class, but still carries the same `diagnostic`, so its code must survive.\n if (isDiagnosticError(current)) {\n return current.diagnostic\n }\n seen.add(current)\n root = current\n current = current.cause\n }\n\n return {\n code: diagnosticCode.unknown,\n severity: 'error',\n message: root ? root.message : getErrorMessage(error),\n cause: root,\n }\n }\n\n /**\n * Builds a per-plugin performance record. Reporters sum these into the run total.\n */\n static performance({ plugin, duration }: { plugin: string; duration: number }): PerformanceDiagnostic {\n return {\n kind: 'performance',\n code: diagnosticCode.performance,\n severity: 'info',\n message: `${plugin} generated in ${Math.round(duration)}ms`,\n plugin,\n duration,\n }\n }\n\n /**\n * Builds the version-update notice shown when a newer Kubb is published on npm.\n */\n static update({ currentVersion, latestVersion }: { currentVersion: string; latestVersion: string }): UpdateDiagnostic {\n return {\n kind: 'update',\n code: diagnosticCode.updateAvailable,\n severity: 'info',\n message: `Update available: v${currentVersion} → v${latestVersion}. Run \\`npm install -g @kubb/cli\\` to update.`,\n currentVersion,\n latestVersion,\n }\n }\n\n /**\n * True when any diagnostic is an error, the severity that fails a build. Non-error\n * diagnostics are ignored.\n */\n static hasError(diagnostics: ReadonlyArray<Diagnostic>): boolean {\n return diagnostics.some((diagnostic) => diagnostic.severity === 'error')\n }\n\n /**\n * Names of the plugins that failed, deduped, derived from the error diagnostics\n * that carry a `plugin`.\n */\n static failedPlugins(diagnostics: ReadonlyArray<Diagnostic>): Array<string> {\n const names = new Set<string>()\n for (const diagnostic of diagnostics) {\n if (diagnostic.severity === 'error' && diagnostic.plugin) {\n names.add(diagnostic.plugin)\n }\n }\n return [...names]\n }\n\n /**\n * Counts `problem` diagnostics by severity for the run summary. `timing`\n * diagnostics are ignored.\n */\n static count(diagnostics: ReadonlyArray<Diagnostic>): { errors: number; warnings: number; infos: number } {\n let errors = 0\n let warnings = 0\n let infos = 0\n for (const diagnostic of diagnostics) {\n if (!isProblemDiagnostic(diagnostic)) {\n continue\n }\n if (diagnostic.severity === 'error') {\n errors += 1\n } else if (diagnostic.severity === 'warning') {\n warnings += 1\n } else {\n infos += 1\n }\n }\n return { errors, warnings, infos }\n }\n\n /**\n * Drops duplicate `problem` diagnostics that share a code, location pointer, and\n * plugin, so the same issue reported across several passes is shown once. Non-problem\n * diagnostics are always kept.\n */\n static dedupe(diagnostics: ReadonlyArray<Diagnostic>): Array<Diagnostic> {\n const seen = new Set<string>()\n const result: Array<Diagnostic> = []\n for (const diagnostic of diagnostics) {\n if (!isProblemDiagnostic(diagnostic)) {\n result.push(diagnostic)\n continue\n }\n const pointer = diagnostic.location && 'pointer' in diagnostic.location ? diagnostic.location.pointer : ''\n const key = `${diagnostic.code} ${pointer} ${diagnostic.plugin ?? ''}`\n if (seen.has(key)) {\n continue\n }\n seen.add(key)\n result.push(diagnostic)\n }\n return result\n }\n\n /**\n * Builds the kubb.dev docs URL for a diagnostic code, e.g.\n * `KUBB_REF_NOT_FOUND` → `https://kubb.dev/docs/5.x/reference/diagnostics/kubb-ref-not-found`.\n */\n static docsUrl(code: string): string {\n const slug = code.toLowerCase().replaceAll('_', '-')\n return `https://kubb.dev/docs/${docsMajor}.x/reference/diagnostics/${slug}`\n }\n\n /**\n * The catalog entry for a code: its title, cause, and fix. Mirrors the kubb.dev\n * `/diagnostics/<slug>` page.\n */\n static explain(code: DiagnosticCode): DiagnosticDoc {\n return diagnosticCatalog[code]\n }\n\n /**\n * Reduces a diagnostic to its JSON-safe fields plus a `docsUrl`, for machine-readable\n * consumers. The `cause`, `kind`, and `duration` are dropped, and absent optional\n * fields are omitted rather than set to `undefined`.\n */\n static serialize(diagnostic: Diagnostic): SerializedDiagnostic {\n const problem = isProblemDiagnostic(diagnostic) ? diagnostic : undefined\n return {\n code: diagnostic.code,\n severity: diagnostic.severity,\n message: diagnostic.message,\n ...(problem?.location ? { location: problem.location } : {}),\n ...(problem?.help ? { help: problem.help } : {}),\n ...(problem?.plugin ? { plugin: problem.plugin } : {}),\n ...(diagnostic.code === diagnosticCode.unknown ? {} : { docsUrl: Diagnostics.docsUrl(diagnostic.code) }),\n }\n }\n}\n","import { extname } from 'node:path'\nimport type { FileNode, HttpMethod, UserFileNode, Visitor } from '@kubb/ast'\nimport type { Generator } from './defineGenerator.ts'\nimport type { BannerMeta, Resolver } from './defineResolver.ts'\nimport type { Config, KubbHooks } from './types.ts'\n\n/**\n * Safely extracts a type from a registry, returning `{}` if the key doesn't exist.\n * Enables optional interface augmentation for `Kubb.ConfigOptionsRegistry` and `Kubb.PluginOptionsRegistry`\n * without requiring changes to core.\n *\n * @internal\n */\ntype ExtractRegistryKey<T, K extends PropertyKey> = K extends keyof T ? T[K] : {}\n\n/**\n * Output configuration shared by every plugin. Each plugin extends this with\n * its own keys via the `Kubb.PluginOptionsRegistry.output` interface merge.\n */\nexport type Output<_TOptions = unknown> = {\n /**\n * Folder (or single file) where the plugin writes its generated code.\n * Resolved against the global `output.path` set on `defineConfig`.\n */\n path: string\n /**\n * Text prepended to every generated file. Useful for license headers,\n * lint disables, or `@ts-nocheck` directives.\n *\n * A string is applied to every file (including barrel and aggregation re-export files).\n * Pass a function to compute the banner from the file's `BannerMeta` document metadata\n * plus per-file context (`isBarrel`, `isAggregation`, `filePath`, `baseName`), so you can\n * skip the banner on specific files.\n *\n * @example Add a directive to source files but not re-export files\n * `banner: (meta) => (meta.isBarrel || meta.isAggregation) ? '' : \"'use server'\"`\n */\n banner?: string | ((meta: BannerMeta) => string)\n /**\n * Text appended at the end of every generated file. Mirror of `banner`.\n * Pass a function to compute the footer from the file's `BannerMeta`.\n */\n footer?: string | ((meta: BannerMeta) => string)\n /**\n * Allows the plugin to overwrite hand-written files at the same path.\n * Defaults to `false` to protect manual edits.\n *\n * @default false\n */\n override?: boolean\n} & ExtractRegistryKey<Kubb.PluginOptionsRegistry, 'output'>\n\n/**\n * Groups generated files into subdirectories based on an OpenAPI tag or path\n * segment.\n */\nexport type Group = {\n /**\n * Property used to assign each operation to a group.\n * - `'tag'` uses the first tag (`operation.getTags().at(0)?.name`).\n * - `'path'` uses the first segment of the operation's URL.\n */\n type: 'tag' | 'path'\n /**\n * Returns the subdirectory name from the group key. Defaults to\n * `${camelCase(group)}Controller` for tags, or the first path segment.\n */\n name?: (context: { group: string }) => string\n}\n\ntype ByTag = {\n /**\n * Filter by OpenAPI `tags` field. Matches one or more tags assigned to operations.\n */\n type: 'tag'\n /**\n * Tag name to match (case-sensitive). Can be a literal string or regex pattern.\n */\n pattern: string | RegExp\n}\n\ntype ByOperationId = {\n /**\n * Filter by OpenAPI `operationId` field. Each operation (GET, POST, etc.) has a unique identifier.\n */\n type: 'operationId'\n /**\n * Operation ID to match (case-sensitive). Can be a literal string or regex pattern.\n */\n pattern: string | RegExp\n}\n\ntype ByPath = {\n /**\n * Filter by OpenAPI `path` (URL endpoint). Useful to group or filter by service segments like `/pets`, `/users`, etc.\n */\n type: 'path'\n /**\n * URL path to match (case-sensitive). Can be a literal string or regex pattern. Matches against the full path.\n */\n pattern: string | RegExp\n}\n\ntype ByMethod = {\n /**\n * Filter by HTTP method: `'get'`, `'post'`, `'put'`, `'delete'`, `'patch'`, `'head'`, `'options'`.\n */\n type: 'method'\n /**\n * HTTP method to match (case-insensitive when using string, or regex for dynamic matching).\n */\n pattern: HttpMethod | RegExp\n}\n\ntype BySchemaName = {\n /**\n * Filter by schema component name (TypeScript or JSON schema). Matches schemas in `#/components/schemas`.\n */\n type: 'schemaName'\n /**\n * Schema name to match (case-sensitive). Can be a literal string or regex pattern.\n */\n pattern: string | RegExp\n}\n\ntype ByContentType = {\n /**\n * Filter by response or request content type: `'application/json'`, `'application/xml'`, etc.\n */\n type: 'contentType'\n /**\n * Content type to match (case-sensitive). Can be a literal string or regex pattern.\n */\n pattern: string | RegExp\n}\n\n/**\n * Filter that skips matching operations or schemas during generation. Use it\n * to drop deprecated endpoints, internal-only schemas, or anything you do\n * not want code generated for.\n *\n * @example\n * ```ts\n * exclude: [\n * { type: 'tag', pattern: 'internal' },\n * { type: 'path', pattern: /^\\/admin/ },\n * { type: 'operationId', pattern: /^deprecated_/ },\n * ]\n * ```\n */\nexport type Exclude = ByTag | ByOperationId | ByPath | ByMethod | ByContentType | BySchemaName\n\n/**\n * Filter that restricts generation to operations or schemas matching at least\n * one entry. Useful for partial builds (one tag, one API version).\n *\n * @example\n * ```ts\n * include: [\n * { type: 'tag', pattern: 'public' },\n * { type: 'path', pattern: /^\\/api\\/v1/ },\n * ]\n * ```\n */\nexport type Include = ByTag | ByOperationId | ByPath | ByMethod | ByContentType | BySchemaName\n\n/**\n * Filter paired with a partial options object. When the filter matches, the\n * options are merged on top of the plugin defaults for that operation only.\n * Useful for \"this one tag goes to a different folder\" rules.\n *\n * Entries are evaluated top to bottom. The first matching entry wins.\n *\n * @example\n * ```ts\n * override: [\n * {\n * type: 'tag',\n * pattern: 'admin',\n * options: { output: { path: './src/gen/admin' } },\n * },\n * {\n * type: 'operationId',\n * pattern: 'listPets',\n * options: { enumType: 'literal' },\n * },\n * ]\n * ```\n */\nexport type Override<TOptions> = (ByTag | ByOperationId | ByPath | ByMethod | BySchemaName | ByContentType) & {\n options: Omit<Partial<TOptions>, 'override'>\n}\n\nexport type PluginFactoryOptions<\n /**\n * Unique plugin name.\n */\n TName extends string = string,\n /**\n * User-facing plugin options.\n */\n TOptions extends object = object,\n /**\n * Plugin options after defaults are applied.\n */\n TResolvedOptions extends object = TOptions,\n /**\n * Resolver that encapsulates naming and path-resolution helpers.\n * Define with `defineResolver` and export alongside the plugin.\n */\n TResolver extends Resolver = Resolver,\n> = {\n name: TName\n options: TOptions\n resolvedOptions: TResolvedOptions\n resolver: TResolver\n}\n\n/**\n * Context for hook-style plugin `kubb:plugin:setup` handler.\n * Provides methods to register generators, configure resolvers, transformers, and renderers.\n */\nexport type KubbPluginSetupContext<TFactory extends PluginFactoryOptions = PluginFactoryOptions> = {\n /**\n * Register a generator dynamically. Generators fire during the AST walk (schema/operation/operations)\n * just like generators declared statically on `createPlugin`.\n */\n addGenerator<TElement = unknown>(generator: Generator<TFactory, TElement>): void\n /**\n * Set or override the resolver for this plugin.\n * The resolver controls file naming and path resolution.\n */\n setResolver(resolver: Partial<TFactory['resolver']>): void\n /**\n * Set the AST transformer to pre-process nodes before they reach generators.\n */\n setTransformer(visitor: Visitor): void\n /**\n * Set resolved options merged into the normalized plugin's `options`.\n * Call this in `kubb:plugin:setup` to provide options generators need.\n */\n setOptions(options: TFactory['resolvedOptions']): void\n /**\n * Inject a raw file into the build output, bypassing the generation pipeline.\n */\n injectFile(userFileNode: UserFileNode): void\n /**\n * Merge a partial config update into the current build configuration.\n */\n updateConfig(config: Partial<Config>): void\n /**\n * The resolved build configuration at setup time.\n */\n config: Config\n /**\n * The plugin's user-provided options.\n */\n options: TFactory['options']\n}\n\n/**\n * A plugin object produced by `definePlugin`.\n * Instead of flat lifecycle methods, it groups all handlers under a `hooks:` property\n * (matching Astro's integration naming convention).\n *\n * @template TFactory - The plugin's `PluginFactoryOptions` type.\n */\nexport type Plugin<TFactory extends PluginFactoryOptions = PluginFactoryOptions> = {\n /**\n * Unique name for the plugin, following the same naming convention as `createPlugin`.\n */\n name: string\n /**\n * Plugins that must be registered before this plugin executes.\n * An error is thrown at startup when any listed dependency is missing.\n */\n dependencies?: Array<string>\n /**\n * Controls the execution order of this plugin relative to others.\n *\n * - `'pre'` runs before all normal plugins.\n * - `'post'` runs after all normal plugins.\n * - `undefined` (default), runs in declaration order among normal plugins.\n *\n * Dependency constraints always take precedence over `enforce`.\n */\n enforce?: 'pre' | 'post'\n /**\n * The options passed by the user when calling the plugin factory.\n */\n options?: TFactory['options']\n /**\n * Lifecycle event handlers for this plugin.\n * Any event from the global `KubbHooks` map can be subscribed to here.\n */\n hooks: {\n [K in keyof KubbHooks as K extends 'kubb:plugin:setup' ? never : K]?: (...args: KubbHooks[K]) => void | Promise<void>\n } & {\n 'kubb:plugin:setup'?(ctx: KubbPluginSetupContext<TFactory>): void | Promise<void>\n }\n}\n\n/**\n * Normalized plugin after setup, with runtime fields populated.\n * For internal use only, plugins use the public `Plugin` type externally.\n *\n * @internal\n */\nexport type NormalizedPlugin<TOptions extends PluginFactoryOptions = PluginFactoryOptions> = Plugin<TOptions> & {\n options: TOptions['resolvedOptions'] & {\n output: Output\n include?: Array<Include>\n exclude: Array<Exclude>\n override: Array<Override<TOptions['resolvedOptions']>>\n }\n resolver: TOptions['resolver']\n transformer?: Visitor\n generators?: Array<Generator>\n apply?: (config: Config) => boolean\n version?: string\n}\n\nexport type KubbPluginStartContext = {\n plugin: NormalizedPlugin\n}\n\nexport type KubbPluginEndContext = {\n plugin: NormalizedPlugin\n duration: number\n success: boolean\n error?: Error\n config: Config\n /**\n * Returns all files currently in the file manager (lazy snapshot).\n * Includes files added by plugins that have already run.\n */\n readonly files: ReadonlyArray<FileNode>\n /**\n * Upsert one or more files into the file manager.\n */\n upsertFile: (...files: Array<FileNode>) => void\n}\n\n/**\n * Wraps a plugin factory and returns a function that accepts user options and\n * yields a fully typed `Plugin`. Lifecycle handlers go inside a single\n * `hooks` object (inspired by Astro integrations).\n *\n * Pass a `PluginFactoryOptions` type parameter to get a typed `ctx` inside\n * `kubb:plugin:setup`. Plugin names should follow the `plugin-<feature>`\n * convention (`plugin-react-query`, `plugin-zod`, ...).\n *\n * @example\n * ```ts\n * import { definePlugin } from '@kubb/core'\n *\n * export const pluginTs = definePlugin((options: { prefix?: string } = {}) => ({\n * name: 'plugin-ts',\n * hooks: {\n * 'kubb:plugin:setup'(ctx) {\n * ctx.setResolver(resolverTs)\n * },\n * },\n * }))\n * ```\n */\nexport function definePlugin<TFactory extends PluginFactoryOptions = PluginFactoryOptions>(\n factory: (options: TFactory['options']) => Plugin<TFactory>,\n): (options?: TFactory['options']) => Plugin<TFactory> {\n return (options) => factory(options ?? ({} as TFactory['options']))\n}\n\n/**\n * Detects whether an output path points at a single file (`'single'`) or a\n * directory (`'split'`). Decided purely from the presence of a file extension.\n *\n * @example Directory\n * `getMode('./types') // 'split'`\n *\n * @example Single file\n * `getMode('./api.ts') // 'single'`\n */\nexport function getMode(fileOrFolder: string | undefined | null): 'single' | 'split' {\n if (!fileOrFolder) return 'split'\n return extname(fileOrFolder) ? 'single' : 'split'\n}\n","import path from 'node:path'\nimport { camelCase, pascalCase } from '@internals/utils'\nimport type { FileNode, InputMeta, Node, OperationNode, SchemaNode } from '@kubb/ast'\nimport { createFile, isOperationNode, isSchemaNode } from '@kubb/ast'\nimport { diagnosticCode } from './constants.ts'\nimport { DiagnosticError } from './diagnostics.ts'\nimport type { PluginFactoryOptions } from './definePlugin.ts'\nimport { getMode } from './definePlugin.ts'\nimport type { Config, Group, Output } from './types.ts'\n\n/**\n * Type/string pattern filter for include/exclude/override matching.\n */\ntype PatternFilter = {\n type: string\n pattern: string | RegExp\n}\n\n/**\n * Pattern filter with partial option overrides applied when the pattern matches.\n */\ntype PatternOverride<TOptions> = PatternFilter & {\n options: Omit<Partial<TOptions>, 'override'>\n}\n\n/**\n * Context for resolving filtered options for a given operation or schema node.\n *\n * @internal\n */\nexport type ResolveOptionsContext<TOptions> = {\n options: TOptions\n exclude?: Array<PatternFilter>\n include?: Array<PatternFilter>\n override?: Array<PatternOverride<TOptions>>\n}\n\n/**\n * Base constraint for all plugin resolver objects.\n *\n * `default`, `resolveOptions`, `resolvePath`, `resolveFile`, `resolveBanner`, and `resolveFooter`\n * are injected automatically by `defineResolver`. Extend this type to add custom resolution methods.\n *\n * @example\n * ```ts\n * type MyResolver = Resolver & {\n * resolveName(node: SchemaNode): string\n * resolveTypedName(node: SchemaNode): string\n * }\n * ```\n */\nexport type Resolver = {\n name: string\n pluginName: string\n default(name: string, type?: 'file' | 'function' | 'type' | 'const'): string\n resolveOptions<TOptions>(node: Node, context: ResolveOptionsContext<TOptions>): TOptions | null\n resolvePath(params: ResolverPathParams, context: ResolverContext): string\n resolveFile(params: ResolverFileParams, context: ResolverContext): FileNode\n resolveBanner(meta: InputMeta | undefined, context: ResolveBannerContext): string | null\n resolveFooter(meta: InputMeta | undefined, context: ResolveBannerContext): string | null\n}\n\n/**\n * File-specific parameters for `Resolver.resolvePath`.\n *\n * Pass alongside a `ResolverContext` to identify which file to resolve.\n * Provide `tag` for tag-based grouping or `path` for path-based grouping.\n *\n * @example\n * ```ts\n * resolver.resolvePath(\n * { baseName: 'petTypes.ts', tag: 'pets' },\n * { root: '/src', output: { path: 'types' }, group: { type: 'tag' } },\n * )\n * // → '/src/types/petsController/petTypes.ts'\n * ```\n */\nexport type ResolverPathParams = {\n baseName: FileNode['baseName']\n pathMode?: 'single' | 'split'\n /**\n * Tag value used when `group.type === 'tag'`.\n */\n tag?: string\n /**\n * Path value used when `group.type === 'path'`.\n */\n path?: string\n}\n\n/**\n * Shared context passed as the second argument to `Resolver.resolvePath` and `Resolver.resolveFile`.\n *\n * Describes where on disk output is rooted, which output config is active, and the optional\n * grouping strategy that controls subdirectory layout.\n *\n * @example\n * ```ts\n * const context: ResolverContext = {\n * root: config.root,\n * output,\n * group,\n * }\n * ```\n */\nexport type ResolverContext = {\n root: string\n output: Output\n group?: Group\n /**\n * Plugin name used to populate `meta.pluginName` on the resolved file.\n */\n pluginName?: string\n}\n\n/**\n * File-specific parameters for `Resolver.resolveFile`.\n *\n * Pass alongside a `ResolverContext` to fully describe the file to resolve.\n * `tag` and `path` are used only when a matching `group` is present in the context.\n *\n * @example\n * ```ts\n * resolver.resolveFile(\n * { name: 'listPets', extname: '.ts', tag: 'pets' },\n * { root: '/src', output: { path: 'types' }, group: { type: 'tag' } },\n * )\n * // → { baseName: 'listPets.ts', path: '/src/types/petsController/listPets.ts', ... }\n * ```\n */\nexport type ResolverFileParams = {\n name: string\n extname: FileNode['extname']\n /**\n * Tag value used when `group.type === 'tag'`.\n */\n tag?: string\n /**\n * Path value used when `group.type === 'path'`.\n */\n path?: string\n}\n\n/**\n * Per-file context describing the file a banner/footer is being resolved for.\n *\n * Supplied by the generator (or the barrel middleware) at resolve-time and merged\n * into `BannerMeta` so a `banner`/`footer` function can branch on the file kind,\n * e.g. omit a `'use server'` directive on re-export files.\n */\nexport type ResolveBannerFile = {\n /**\n * Full output path of the file being generated.\n */\n path: string\n /**\n * File name only, e.g. `'stocks.ts'`.\n */\n baseName: string\n /**\n * `true` for `index.ts` re-export barrels.\n */\n isBarrel?: boolean\n /**\n * `true` for group `[dir]/[dir].ts` aggregation files.\n */\n isAggregation?: boolean\n}\n\n/**\n * Document metadata extended with per-file context, passed to a `banner`/`footer` function.\n *\n * Carries everything in {@link InputMeta} plus the file the banner is rendered into, so a\n * single function can decide per file (e.g. skip a directive on barrel/aggregation files).\n *\n * @example Skip a directive on re-export files\n * `banner: (meta) => (meta.isBarrel || meta.isAggregation) ? '' : \"'use server'\"`\n */\nexport type BannerMeta = InputMeta & {\n /**\n * Full output path of the file being generated.\n */\n filePath: string\n /**\n * File name only, e.g. `'stocks.ts'`.\n */\n baseName: string\n /**\n * `true` for `index.ts` re-export barrels.\n */\n isBarrel: boolean\n /**\n * `true` for group `[dir]/[dir].ts` aggregation files.\n */\n isAggregation: boolean\n}\n\n/**\n * Context passed to `Resolver.resolveBanner` and `Resolver.resolveFooter`.\n *\n * `output` is optional, since not every plugin configures a banner/footer.\n * `config` carries the global Kubb config, used to derive the default Kubb banner.\n * `file` carries per-file context forwarded to a `banner`/`footer` function.\n *\n * @example\n * ```ts\n * resolver.resolveBanner(meta, { output: { banner: '// generated' }, config })\n * // → '// generated'\n * ```\n */\nexport type ResolveBannerContext = {\n output?: Pick<Output, 'banner' | 'footer'>\n config: Config\n file?: ResolveBannerFile\n}\n\n/**\n * Merges document `meta` with per-file `file` context into the `BannerMeta` passed to a\n * `banner`/`footer` function. Missing fields default to empty/`false` so the object shape\n * is stable even when a caller (e.g. the barrel middleware) has no document metadata.\n */\nfunction buildBannerMeta({ meta, file }: { meta: InputMeta | undefined; file: ResolveBannerFile | undefined }): BannerMeta {\n return {\n title: meta?.title,\n description: meta?.description,\n version: meta?.version,\n baseURL: meta?.baseURL,\n circularNames: meta?.circularNames ?? [],\n enumNames: meta?.enumNames ?? [],\n filePath: file?.path ?? '',\n baseName: file?.baseName ?? '',\n isBarrel: file?.isBarrel ?? false,\n isAggregation: file?.isAggregation ?? false,\n }\n}\n\n/**\n * Builder type for the plugin-specific resolver fields.\n *\n * `default`, `resolveOptions`, `resolvePath`, `resolveFile`, `resolveBanner`, and `resolveFooter`\n * are optional, with built-in fallbacks injected when omitted.\n *\n * Methods in the returned object can call sibling resolver methods via `this`.\n */\ntype ResolverBuilder<T extends PluginFactoryOptions> = () => Omit<\n T['resolver'],\n 'default' | 'resolveOptions' | 'resolvePath' | 'resolveFile' | 'resolveBanner' | 'resolveFooter' | 'name' | 'pluginName'\n> &\n Partial<Pick<T['resolver'], 'default' | 'resolveOptions' | 'resolvePath' | 'resolveFile' | 'resolveBanner' | 'resolveFooter'>> & {\n name: string\n pluginName: T['name']\n } & ThisType<T['resolver']>\n\n// String patterns are compiled lazily and cached, so the same filter is reused for every node.\nconst stringPatternCache = new Map<string, RegExp>()\n\nfunction testPattern(value: string, pattern: string | RegExp): boolean {\n if (typeof pattern === 'string') {\n let regex = stringPatternCache.get(pattern)\n if (!regex) {\n regex = new RegExp(pattern)\n stringPatternCache.set(pattern, regex)\n }\n return regex.test(value)\n }\n // Use .match() for user-supplied RegExp to preserve semantics regardless of `g`/`y` flags.\n return value.match(pattern) !== null\n}\n\n/**\n * Checks if an operation matches a pattern for a given filter type (`tag`, `operationId`, `path`, `method`).\n */\nfunction matchesOperationPattern(node: OperationNode, type: string, pattern: string | RegExp): boolean {\n if (type === 'tag') return node.tags.some((tag) => testPattern(tag, pattern))\n if (type === 'operationId') return testPattern(node.operationId, pattern)\n if (type === 'path') return node.path !== undefined && testPattern(node.path, pattern)\n if (type === 'method') return node.method !== undefined && testPattern(node.method.toLowerCase(), pattern)\n if (type === 'contentType') return node.requestBody?.content?.some((c) => testPattern(c.contentType, pattern)) ?? false\n return false\n}\n\n/**\n * Checks if a schema matches a pattern for a given filter type (`schemaName`).\n *\n * Returns `null` when the filter type doesn't apply to schemas.\n */\nfunction matchesSchemaPattern(node: SchemaNode, type: string, pattern: string | RegExp): boolean | null {\n if (type === 'schemaName') return node.name ? testPattern(node.name, pattern) : false\n return null\n}\n\n/**\n * Default name resolver used by `defineResolver`.\n *\n * - `camelCase` for `function` and `file` types.\n * - `PascalCase` for `type`.\n * - `camelCase` for everything else.\n */\nfunction defaultResolver(name: string, type?: 'file' | 'function' | 'type' | 'const'): string {\n if (type === 'file' || type === 'function') return camelCase(name, { isFile: type === 'file' })\n if (type === 'type') return pascalCase(name)\n return camelCase(name)\n}\n\n/**\n * Default option resolver. Applies include/exclude filters and merges matching override options.\n *\n * Returns `null` when the node is filtered out by an `exclude` rule or not matched by any `include` rule.\n *\n * @example Include/exclude filtering\n * ```ts\n * const options = defaultResolveOptions(operationNode, {\n * options: { output: 'types' },\n * exclude: [{ type: 'tag', pattern: 'internal' }],\n * })\n * // → null when node has tag 'internal'\n * ```\n *\n * @example Override merging\n * ```ts\n * const options = defaultResolveOptions(operationNode, {\n * options: { enumType: 'asConst' },\n * override: [{ type: 'operationId', pattern: 'listPets', options: { enumType: 'enum' } }],\n * })\n * // → { enumType: 'enum' } when operationId matches\n * ```\n */\nconst resolveOptionsCache = new WeakMap<object, WeakMap<Node, { value: unknown }>>()\n\nfunction computeOptions<TOptions>(\n node: Node,\n options: TOptions,\n exclude: Array<PatternFilter>,\n include: Array<PatternFilter> | undefined,\n override: Array<PatternOverride<TOptions>>,\n): TOptions | null {\n if (isOperationNode(node)) {\n if (exclude.some(({ type, pattern }) => matchesOperationPattern(node, type, pattern))) return null\n if (include && !include.some(({ type, pattern }) => matchesOperationPattern(node, type, pattern))) return null\n\n const overrideOptions = override.find(({ type, pattern }) => matchesOperationPattern(node, type, pattern))?.options\n\n return { ...options, ...overrideOptions }\n }\n\n if (isSchemaNode(node)) {\n if (exclude.some(({ type, pattern }) => matchesSchemaPattern(node, type, pattern) === true)) return null\n if (include) {\n const results = include.map(({ type, pattern }) => matchesSchemaPattern(node, type, pattern))\n const applicable = results.filter((result) => result !== null)\n\n if (applicable.length > 0 && !applicable.includes(true)) return null\n }\n const overrideOptions = override.find(({ type, pattern }) => matchesSchemaPattern(node, type, pattern) === true)?.options\n\n return { ...options, ...overrideOptions }\n }\n\n return options\n}\n\nexport function defaultResolveOptions<TOptions>(\n node: Node,\n { options, exclude = [], include, override = [] }: ResolveOptionsContext<TOptions>,\n): TOptions | null {\n const optionsKey = options as object\n let byOptions = resolveOptionsCache.get(optionsKey)\n if (!byOptions) {\n byOptions = new WeakMap()\n resolveOptionsCache.set(optionsKey, byOptions)\n }\n const cached = byOptions.get(node)\n if (cached !== undefined) return cached.value as TOptions | null\n\n const result = computeOptions(node, options, exclude, include, override)\n\n byOptions.set(node, { value: result })\n\n return result\n}\n\n/**\n * Default path resolver used by `defineResolver`.\n *\n * - Returns the output directory in `single` mode.\n * - Resolves into a tag- or path-based subdirectory when `group` and a `tag`/`path` value are provided.\n * - Falls back to a flat `output/baseName` path otherwise.\n *\n * A custom `group.name` function overrides the default subdirectory naming.\n * For `tag` groups the default is `${camelCase(tag)}Controller`.\n * For `path` groups the default is the first path segment after `/`.\n *\n * @example Flat output\n * ```ts\n * defaultResolvePath({ baseName: 'petTypes.ts' }, { root: '/src', output: { path: 'types' } })\n * // → '/src/types/petTypes.ts'\n * ```\n *\n * @example Tag-based grouping\n * ```ts\n * defaultResolvePath(\n * { baseName: 'petTypes.ts', tag: 'pets' },\n * { root: '/src', output: { path: 'types' }, group: { type: 'tag' } },\n * )\n * // → '/src/types/petsController/petTypes.ts'\n * ```\n *\n * @example Path-based grouping\n * ```ts\n * defaultResolvePath(\n * { baseName: 'petTypes.ts', path: '/pets/list' },\n * { root: '/src', output: { path: 'types' }, group: { type: 'path' } },\n * )\n * // → '/src/types/pets/petTypes.ts'\n * ```\n *\n * @example Single-file mode\n * ```ts\n * defaultResolvePath(\n * { baseName: 'petTypes.ts', pathMode: 'single' },\n * { root: '/src', output: { path: 'types' } },\n * )\n * // → '/src/types'\n * ```\n */\nexport function defaultResolvePath({ baseName, pathMode, tag, path: groupPath }: ResolverPathParams, { root, output, group }: ResolverContext): string {\n const mode = pathMode ?? getMode(path.resolve(root, output.path))\n\n if (mode === 'single') {\n return path.resolve(root, output.path)\n }\n\n const result: string = (() => {\n if (group && (groupPath || tag)) {\n const groupValue = group.type === 'path' ? groupPath! : tag!\n const defaultName =\n group.type === 'tag'\n ? ({ group: groupName }: { group: string }) => `${camelCase(groupName)}Controller`\n : ({ group: groupName }: { group: string }) => {\n // Strip traversal components (empty, '.', '..') before taking the first meaningful segment.\n // When every segment is a traversal component (e.g. '../../') we fall back to '' so the\n // file is placed directly in the output root, and the boundary check below ensures safety.\n const segment = groupName.split('/').filter((part) => part !== '' && part !== '.' && part !== '..')[0]\n return segment ? camelCase(segment) : ''\n }\n const resolveName = group.name ?? defaultName\n return path.resolve(root, output.path, resolveName({ group: groupValue }), baseName)\n }\n return path.resolve(root, output.path, baseName)\n })()\n\n // Ensure the resolved path stays within the configured output directory.\n // This prevents path traversal from malicious OpenAPI specs or custom group.name functions.\n // `result === outputDir` is intentionally permitted: it matches single-file mode paths and\n // edge cases where baseName resolves to the output directory itself.\n const outputDir = path.resolve(root, output.path)\n const outputDirWithSep = outputDir.endsWith(path.sep) ? outputDir : `${outputDir}${path.sep}`\n if (result !== outputDir && !result.startsWith(outputDirWithSep)) {\n throw new DiagnosticError({\n code: diagnosticCode.pathTraversal,\n severity: 'error',\n message: `Resolved path \"${result}\" is outside the output directory \"${outputDir}\".`,\n help: 'This can stem from a path traversal in the OpenAPI specification or a misconfigured `group.name` function. Keep generated paths within the output directory.',\n location: { kind: 'config' },\n })\n }\n\n return result\n}\n\n/**\n * Default file resolver used by `defineResolver`.\n *\n * Resolves a `FileNode` by combining name resolution (`resolver.default`) with\n * path resolution (`resolver.resolvePath`). The resolved file always has empty\n * `sources`, `imports`, and `exports` arrays, which consumers populate separately.\n *\n * In `single` mode the name is omitted and the file sits directly in the output directory.\n *\n * @example Resolve a schema file\n * ```ts\n * const file = defaultResolveFile.call(\n * resolver,\n * { name: 'pet', extname: '.ts' },\n * { root: '/src', output: { path: 'types' } },\n * )\n * // → { baseName: 'pet.ts', path: '/src/types/pet.ts', sources: [], ... }\n * ```\n *\n * @example Resolve an operation file with tag grouping\n * ```ts\n * const file = defaultResolveFile.call(\n * resolver,\n * { name: 'listPets', extname: '.ts', tag: 'pets' },\n * { root: '/src', output: { path: 'types' }, group: { type: 'tag' } },\n * )\n * // → { baseName: 'listPets.ts', path: '/src/types/petsController/listPets.ts', ... }\n * ```\n */\nexport function defaultResolveFile(this: Resolver, { name, extname, tag, path: groupPath }: ResolverFileParams, context: ResolverContext): FileNode {\n const pathMode = getMode(path.resolve(context.root, context.output.path))\n const resolvedName = pathMode === 'single' ? '' : this.default(name, 'file')\n const baseName = `${resolvedName}${extname}` as FileNode['baseName']\n const filePath = this.resolvePath({ baseName, pathMode, tag, path: groupPath }, context)\n\n return createFile({\n path: filePath,\n baseName: path.basename(filePath) as `${string}.${string}`,\n meta: {\n pluginName: this.pluginName,\n },\n sources: [],\n imports: [],\n exports: [],\n })\n}\n\n/**\n * Generates the default \"Generated by Kubb\" banner from config and optional node metadata.\n */\nexport function buildDefaultBanner({\n title,\n description,\n version,\n config,\n}: {\n title?: string\n description?: string\n version?: string\n config: Config\n}): string {\n try {\n const source = (() => {\n if (Array.isArray(config.input)) {\n const first = config.input[0]\n if (first && 'path' in first) return path.basename(first.path)\n return ''\n }\n if (config.input && 'path' in config.input) return path.basename(config.input.path)\n if (config.input && 'data' in config.input) return 'text content'\n return ''\n })()\n\n let banner = '/**\\n* Generated by Kubb (https://kubb.dev/).\\n* Do not edit manually.\\n'\n\n if (config.output.defaultBanner === 'simple') {\n banner += '*/\\n'\n return banner\n }\n\n if (source) {\n banner += `* Source: ${source}\\n`\n }\n\n if (title) {\n banner += `* Title: ${title}\\n`\n }\n\n if (description) {\n const formattedDescription = description.replace(/\\n/gm, '\\n* ')\n banner += `* Description: ${formattedDescription}\\n`\n }\n\n if (version) {\n banner += `* OpenAPI spec version: ${version}\\n`\n }\n\n banner += '*/\\n'\n return banner\n } catch (_error) {\n return '/**\\n* Generated by Kubb (https://kubb.dev/).\\n* Do not edit manually.\\n*/'\n }\n}\n\n/**\n * Default banner resolver. Returns the banner string for a generated file.\n *\n * A user-supplied `output.banner` overrides the default Kubb \"Generated by Kubb\" notice.\n * When no `output.banner` is set, the Kubb notice is used (including `title` and `version`\n * from the document metadata when `meta` is provided).\n *\n * - When `output.banner` is a function, calls it with the file's `BannerMeta` and returns the result.\n * - When `output.banner` is a string, returns it directly.\n * - When `config.output.defaultBanner` is `false`, returns `undefined`.\n * - Otherwise returns the Kubb \"Generated by Kubb\" notice.\n *\n * @example String banner overrides default\n * ```ts\n * defaultResolveBanner(undefined, { output: { banner: '// my banner' }, config })\n * // → '// my banner'\n * ```\n *\n * @example Function banner with metadata\n * ```ts\n * defaultResolveBanner(meta, { output: { banner: (m) => `// v${m.version}` }, config })\n * // → '// v3.0.0'\n * ```\n *\n * @example Function banner skips re-export files\n * ```ts\n * defaultResolveBanner(meta, { output: { banner: (m) => (m.isBarrel ? '' : \"'use server'\") }, config, file: { path, baseName, isBarrel: true } })\n * // → ''\n * ```\n *\n * @example No user banner, Kubb notice with OAS metadata\n * ```ts\n * defaultResolveBanner(meta, { config })\n * // → '/** Generated by Kubb ... Title: Pet Store ... *\\/'\n * ```\n *\n * @example Disabled default banner\n * ```ts\n * defaultResolveBanner(undefined, { config: { output: { defaultBanner: false }, ...config } })\n * // → null\n * ```\n */\nexport function defaultResolveBanner(meta: InputMeta | undefined, { output, config, file }: ResolveBannerContext): string | null {\n if (typeof output?.banner === 'function') {\n return output.banner(buildBannerMeta({ meta, file }))\n }\n\n if (typeof output?.banner === 'string') {\n return output.banner\n }\n\n if (config.output.defaultBanner === false) {\n return null\n }\n\n return buildDefaultBanner({\n title: meta?.title,\n version: meta?.version,\n config,\n })\n}\n\n/**\n * Default footer resolver. Returns the footer string for a generated file.\n *\n * - When `output.footer` is a function, calls it with the file's `BannerMeta` and returns the result.\n * - When `output.footer` is a string, returns it directly.\n * - Otherwise returns `undefined`.\n *\n * @example String footer\n * ```ts\n * defaultResolveFooter(undefined, { output: { footer: '// end of file' }, config })\n * // → '// end of file'\n * ```\n *\n * @example Function footer with metadata\n * ```ts\n * defaultResolveFooter(meta, { output: { footer: (m) => `// ${m.title}` }, config })\n * // → '// Pet Store'\n * ```\n */\nexport function defaultResolveFooter(meta: InputMeta | undefined, { output, file }: ResolveBannerContext): string | null {\n if (typeof output?.footer === 'function') {\n return output.footer(buildBannerMeta({ meta, file }))\n }\n if (typeof output?.footer === 'string') {\n return output.footer\n }\n return null\n}\n\n/**\n * Defines a plugin resolver. The resolver is the object that decides what\n * every generated symbol and file path is called. Built-in defaults handle\n * name casing, include/exclude/override filtering, output path computation,\n * and file construction. Supply your own to override any of them:\n *\n * - `default` sets the name casing strategy (camelCase or PascalCase).\n * - `resolveOptions` does include/exclude/override filtering.\n * - `resolvePath` computes the output path.\n * - `resolveFile` builds the full `FileNode`.\n * - `resolveBanner` and `resolveFooter` produce the top and bottom of file text.\n *\n * Methods in the returned object can call sibling resolver methods via `this`,\n * which keeps custom rules small (`this.default(name, 'type')` to delegate).\n *\n * @example Basic resolver with naming helpers\n * ```ts\n * export const resolverTs = defineResolver<PluginTs>(() => ({\n * name: 'default',\n * resolveName(name) {\n * return this.default(name, 'function')\n * },\n * resolveTypeName(name) {\n * return this.default(name, 'type')\n * },\n * }))\n * ```\n *\n * @example Custom output path\n * ```ts\n * import path from 'node:path'\n *\n * export const resolverTs = defineResolver<PluginTs>(() => ({\n * name: 'custom',\n * resolvePath({ baseName }, { root, output }) {\n * return path.resolve(root, output.path, 'generated', baseName)\n * },\n * }))\n * ```\n */\nexport function defineResolver<T extends PluginFactoryOptions>(build: ResolverBuilder<T>): T['resolver'] {\n // `resolver` is kept so the default `resolveFile` wrapper can reference the fully assembled\n // object via `.call(resolver, ...)` at call-time, after the result is assigned below.\n let resolver: T['resolver']\n\n const result = {\n default: defaultResolver,\n resolveOptions: defaultResolveOptions,\n resolvePath: defaultResolvePath,\n resolveFile: (params: ResolverFileParams, context: ResolverContext) => defaultResolveFile.call(resolver as Resolver, params, context),\n resolveBanner: defaultResolveBanner,\n resolveFooter: defaultResolveFooter,\n ...build(),\n } as T['resolver']\n\n resolver = result\n\n return resolver\n}\n","import type { InputNode } from '@kubb/ast'\nimport { deflateSync } from 'fflate'\nimport { x } from 'tinyexec'\n\nexport type DevtoolsOptions = {\n /**\n * Open the AST inspector in Kubb Studio (`/ast`). Defaults to the main Studio page.\n * @default false\n */\n ast?: boolean\n}\n\n/**\n * Encodes an `InputNode` as a compressed, URL-safe string.\n *\n * The JSON representation is deflate-compressed with {@link deflateSync} before\n * base64url encoding, which typically reduces payload size by 70, 80 % and\n * keeps URLs well within browser and server path-length limits.\n */\nexport function encodeAst(input: InputNode): string {\n const compressed = deflateSync(new TextEncoder().encode(JSON.stringify(input)))\n return Buffer.from(compressed).toString('base64url')\n}\n\n/**\n * Constructs the Kubb Studio URL for the given `InputNode`.\n * When `options.ast` is `true`, navigates to the AST inspector (`/ast`).\n * The `input` is encoded and attached as the `?root=` query parameter so Studio\n * can decode and render it without a round-trip to any server.\n */\nexport function getStudioUrl(input: InputNode, studioUrl: string, options: DevtoolsOptions = {}): string {\n const baseUrl = studioUrl.replace(/\\/$/, '')\n const path = options.ast ? '/ast' : ''\n\n return `${baseUrl}${path}?root=${encodeAst(input)}`\n}\n\n/**\n * Opens the Kubb Studio URL for the given `InputNode` in the default browser, *\n * Falls back to printing the URL if the browser cannot be launched.\n */\nexport async function openInStudio(input: InputNode, studioUrl: string, options: DevtoolsOptions = {}): Promise<void> {\n const url = getStudioUrl(input, studioUrl, options)\n\n const cmd = process.platform === 'win32' ? 'cmd' : process.platform === 'darwin' ? 'open' : 'xdg-open'\n const args = process.platform === 'win32' ? ['/c', 'start', '', url] : [url]\n\n try {\n await x(cmd, args)\n } catch {\n console.log(`\\n ${url}\\n`)\n }\n}\n","import { AsyncEventEmitter } from '@internals/utils'\nimport type { FileNode } from '@kubb/ast'\nimport { createFile } from '@kubb/ast'\n\n/**\n * Hooks fired by a `FileManager`.\n *\n * - `upsert` fires once per resolved file added through `add` or `upsert`.\n */\nexport type FileManagerHooks = {\n upsert: [file: FileNode]\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 middleware resolves last) wins over a plugin-generated\n // file at the same path.\n banner: b.banner,\n footer: b.footer,\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 return 0\n}\n\n/**\n * In-memory file store for generated files. Files sharing a `path` are merged\n * (sources/imports/exports concatenated). The `files` getter is sorted by\n * path length (barrel `index.ts` last within a bucket).\n *\n * @example\n * ```ts\n * const manager = new FileManager()\n * manager.upsert(myFile)\n * manager.files // sorted view\n * ```\n */\nexport class FileManager {\n /**\n * Subscribe to file-store changes. Listeners on `upsert` see each resolved file as it lands\n * through `add` or `upsert`.\n */\n readonly hooks = new AsyncEventEmitter<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\n // keep their snapshot, `dispose()` must not silently empty an array the\n // consumer 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 ? createFile(mergeFile(existing, file)) : createFile(file)\n this.#cache.set(merged.path, merged)\n resolved.push(merged)\n this.hooks.emit('upsert', 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 getByPath(path: string): FileNode | null {\n return this.#cache.get(path) ?? null\n }\n\n deleteByPath(path: string): void {\n if (!this.#cache.delete(path)) return\n this.#sorted = null\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.removeAll()\n }\n\n [Symbol.dispose](): void {\n this.dispose()\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","import { AsyncEventEmitter } from '@internals/utils'\nimport type { CodeNode, FileNode } from '@kubb/ast'\nimport { extractStringsFromNodes } from '@kubb/ast'\nimport { STREAM_FLUSH_EVERY } from './constants.ts'\nimport type { Storage } from './createStorage.ts'\nimport type { Parser } from './defineParser.ts'\n\n/**\n * Hooks fired by a `FileProcessor`.\n *\n * - `start` opens a batch, from `run` or a queue flush.\n * - `update` fires once per file as it is converted.\n * - `end` closes a batch.\n * - `enqueue` fires for every `enqueue` call.\n * - `drain` fires when `drain()` empties the queue with no in-flight batch left.\n */\nexport type FileProcessorHooks = {\n start: [files: Array<FileNode>]\n update: [params: { file: FileNode; source?: string; processed: number; total: number; percentage: number }]\n end: [files: Array<FileNode>]\n enqueue: [file: FileNode]\n drain: []\n}\n\n/**\n * Per-file progress record yielded by `stream` and surfaced through the `update` event.\n */\nexport type ParsedFile = {\n file: FileNode\n source: string\n processed: number\n total: number\n percentage: number\n}\n\ntype FileProcessorOptions = {\n /**\n * Storage destination for queued writes.\n */\n storage: Storage\n /**\n * Parsers indexed by file extension.\n */\n parsers?: Map<FileNode['extname'], Parser>\n /**\n * Output extname per source extname, applied during conversion.\n */\n extension?: Record<FileNode['extname'], FileNode['extname'] | ''>\n}\n\nfunction joinSources(file: FileNode): string {\n const sources = file.sources\n if (sources.length === 0) return ''\n const parts: Array<string> = []\n for (const source of sources) {\n const text = extractStringsFromNodes(source.nodes as Array<CodeNode>)\n if (text) parts.push(text)\n }\n return parts.join('\\n\\n')\n}\n\n/**\n * Turns `FileNode`s into source strings and writes them to storage.\n *\n * Two modes share the same instance. Stateless mode (`parse`, `stream`, `run`) just runs the\n * conversion. Queue mode (`enqueue`, `flush`, `drain`) buffers files deduped by path and\n * writes each batch through storage with up to `STREAM_FLUSH_EVERY` requests in flight.\n *\n * `flush` does not wait for its batch to finish, so dispatch can overlap with IO. The next\n * `flush` or `drain` picks the in-flight batch up. `drain` blocks until everything has been\n * written and is meant for the end of a build.\n *\n * To surface build-level hook signals (`kubb:files:processing:*` and friends) subscribe to\n * `hooks` and re-emit on the kubb bus.\n */\nexport class FileProcessor {\n readonly hooks = new AsyncEventEmitter<FileProcessorHooks>()\n readonly #parsers: Map<FileNode['extname'], Parser> | null\n readonly #storage: Storage\n readonly #extension: Record<FileNode['extname'], FileNode['extname'] | ''> | null\n readonly #pending = new Map<string, FileNode>()\n #runningFlush: Promise<void> | null = null\n\n constructor(options: FileProcessorOptions) {\n this.#parsers = options.parsers ?? null\n this.#storage = options.storage\n this.#extension = options.extension ?? null\n }\n\n /**\n * Files waiting in the queue.\n */\n get size(): number {\n return this.#pending.size\n }\n\n parse(file: FileNode): string {\n const parsers = this.#parsers\n const parseExtName = this.#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 *stream(files: ReadonlyArray<FileNode>): Generator<ParsedFile> {\n const total = files.length\n if (total === 0) return\n\n let processed = 0\n for (const file of files) {\n const source = this.parse(file)\n processed++\n\n yield { file, source, processed, total, percentage: (processed / total) * 100 }\n }\n }\n\n async run(files: Array<FileNode>): Promise<Array<FileNode>> {\n await this.hooks.emit('start', files)\n\n for (const { file, source, processed, total, percentage } of this.stream(files)) {\n await this.hooks.emit('update', { file, source, processed, percentage, total })\n }\n\n await this.hooks.emit('end', files)\n\n return files\n }\n\n /**\n * Adds a file to the next flush. A later `enqueue` for the same path replaces the previous\n * entry, matching `FileManager.upsert`. Fires the `enqueue` event.\n */\n enqueue(file: FileNode): void {\n this.#pending.set(file.path, file)\n this.hooks.emit('enqueue', file)\n }\n\n /**\n * Starts processing the queued files. Waits for any previous flush to finish (so two\n * batches never run together) and then returns without waiting for the new one. The next\n * `flush` or `drain` picks up the in-flight task.\n */\n async flush(): Promise<void> {\n if (this.#runningFlush) await this.#runningFlush\n if (this.#pending.size === 0) return\n\n const batch = [...this.#pending.values()]\n this.#pending.clear()\n\n this.#runningFlush = this.#processAndWrite(batch).finally(() => {\n this.#runningFlush = null\n })\n }\n\n /**\n * Waits for the in-flight flush and writes any files still queued. Fires the `drain` event\n * when both are done.\n */\n async drain(): Promise<void> {\n if (this.#runningFlush) await this.#runningFlush\n\n if (this.#pending.size > 0) {\n const batch = [...this.#pending.values()]\n this.#pending.clear()\n await this.#processAndWrite(batch)\n }\n\n await this.hooks.emit('drain')\n }\n\n async #processAndWrite(files: Array<FileNode>): Promise<void> {\n const storage = this.#storage\n\n await this.hooks.emit('start', files)\n\n const items = [...this.stream(files)]\n for (const item of items) {\n await this.hooks.emit('update', item)\n }\n\n const queue: Array<Promise<void>> = []\n for (const { file, source } of items) {\n if (source) {\n queue.push(storage.setItem(file.path, source))\n if (queue.length >= STREAM_FLUSH_EVERY) await Promise.all(queue.splice(0))\n }\n }\n await Promise.all(queue)\n\n await this.hooks.emit('end', files)\n }\n\n /**\n * Clears every listener and the pending queue.\n */\n dispose(): void {\n this.hooks.removeAll()\n this.#pending.clear()\n }\n\n [Symbol.dispose](): void {\n this.dispose()\n }\n}\n","import type { AsyncEventEmitter } from '@internals/utils'\n\nexport type HookSource = 'plugin' | 'middleware' | 'driver'\n\nexport type HookListener<TArgs extends Array<unknown>, TResult = void> = (...args: TArgs) => TResult | Promise<TResult>\n\ntype AnyEntry = {\n event: string\n handler: HookListener<Array<unknown>, unknown>\n source: HookSource\n}\n\n/**\n * Listener bookkeeping around an `AsyncEventEmitter`. Listeners attached through `register`\n * stay on the emitter but are tracked so `dispose()` removes only them, listeners attached\n * directly via `emitter.on(...)` survive.\n */\nexport class HookRegistry<TEvents extends { [K in keyof TEvents]: Array<unknown> }> {\n readonly #emitter: AsyncEventEmitter<TEvents>\n readonly #entries = new Set<AnyEntry>()\n\n constructor(options: { emitter: AsyncEventEmitter<TEvents> }) {\n this.#emitter = options.emitter\n }\n\n get emitter(): AsyncEventEmitter<TEvents> {\n return this.#emitter\n }\n\n get size(): number {\n return this.#entries.size\n }\n\n register<K extends keyof TEvents & string>(options: { event: K; handler: HookListener<TEvents[K], unknown>; source: HookSource }): void {\n this.#emitter.on(options.event, options.handler as HookListener<TEvents[K]>)\n this.#entries.add(options as unknown as AnyEntry)\n }\n\n dispose(): void {\n for (const entry of this.#entries) {\n this.#emitter.off(entry.event as keyof TEvents & string, entry.handler as HookListener<Array<unknown>>)\n }\n this.#entries.clear()\n }\n}\n","import type { OperationNode, SchemaNode, Visitor } from '@kubb/ast'\nimport { transform } from '@kubb/ast'\n\n/**\n * Holds one `Visitor` per plugin, keyed by plugin name. Each plugin's transformer runs in\n * isolation on the original adapter node. `applyTo` is a lookup, not a chain, so plugin A's\n * visitor never sees plugin B's output. When no transformer is registered, `applyTo` returns\n * the original node reference, and the `@kubb/ast` `transform` primitive does the same when\n * its visitor leaves the tree untouched. Callers can compare by identity to detect a no-op.\n *\n * Registration order matches the order setup hooks fire, which the driver has already sorted\n * by `enforce` and dependency edges. The registry does not re-order anything.\n */\nexport class Transform {\n readonly #visitors = new Map<string, Visitor>()\n\n /**\n * Number of plugins with a registered transformer.\n */\n get size(): number {\n return this.#visitors.size\n }\n\n /**\n * Records `visitor` as the transformer for `pluginName`. A second call for the same plugin\n * replaces the first.\n */\n register(pluginName: string, visitor: Visitor): void {\n this.#visitors.set(pluginName, visitor)\n }\n\n /**\n * Looks up the transformer for `pluginName`. The generator context uses this so plugins can\n * read their own visitor through `ctx.transformer`.\n */\n get(pluginName: string): Visitor | undefined {\n return this.#visitors.get(pluginName)\n }\n\n /**\n * Runs the plugin's transformer on `node`. Returns the original node reference when the\n * plugin has no transformer, so callers can compare by identity to detect a no-op.\n */\n applyTo<TNode extends SchemaNode | OperationNode>(pluginName: string, node: TNode): TNode {\n const visitor = this.#visitors.get(pluginName)\n if (!visitor) return node\n\n return transform(node, visitor) as TNode\n }\n\n /**\n * Clears every registration. Called from the driver's `dispose()` so visitors do not leak\n * across builds.\n */\n dispose(): void {\n this.#visitors.clear()\n }\n}\n","import { resolve } from 'node:path'\nimport { arrayToAsyncIterable, type AsyncEventEmitter, forBatches, getElapsedMs, isPromise, memoize, URLPath } from '@internals/utils'\nimport { collectUsedSchemaNames, createFile, createStreamInput } from '@kubb/ast'\nimport type { FileNode, InputMeta, InputNode, InputStreamNode, OperationNode, SchemaNode } from '@kubb/ast'\nimport { DEFAULT_STUDIO_URL, diagnosticCode, OPERATION_FILTER_TYPES, SCHEMA_PARALLEL } from './constants.ts'\nimport { type Diagnostic, DiagnosticError, Diagnostics, type ProblemDiagnostic } from './diagnostics.ts'\nimport type { RendererFactory } from './createRenderer.ts'\nimport type { Storage } from './createStorage.ts'\nimport type { Generator } from './defineGenerator.ts'\nimport type { Parser } from './defineParser.ts'\nimport type { Plugin } from './definePlugin.ts'\nimport { getMode } from './definePlugin.ts'\nimport { defineResolver } from './defineResolver.ts'\nimport { openInStudio as openInStudioFn } from './devtools.ts'\nimport { FileManager } from './FileManager.ts'\nimport { FileProcessor } from './FileProcessor.ts'\nimport { type HookListener, HookRegistry } from './HookRegistry.ts'\nimport { Transform } from './Transform.ts'\n\nimport type {\n Adapter,\n AdapterSource,\n Config,\n DevtoolsOptions,\n GeneratorContext,\n KubbHooks,\n KubbPluginSetupContext,\n Middleware,\n NormalizedPlugin,\n PluginFactoryOptions,\n Resolver,\n} from './types.ts'\n\ntype Options = {\n hooks: AsyncEventEmitter<KubbHooks>\n}\n\nfunction enforceOrder(enforce: 'pre' | 'post' | undefined): number {\n return enforce === 'pre' ? -1 : enforce === 'post' ? 1 : 0\n}\n\nexport class KubbDriver {\n readonly config: Config\n readonly options: Options\n\n /**\n * Returns `'single'` when `fileOrFolder` has a file extension, `'split'` otherwise.\n *\n * @example\n * ```ts\n * KubbDriver.getMode('src/gen/types.ts') // 'single'\n * KubbDriver.getMode('src/gen/types') // 'split'\n * ```\n */\n static getMode(fileOrFolder: string | undefined | null): 'single' | 'split' {\n return getMode(fileOrFolder)\n }\n\n /**\n * The streaming `InputStreamNode` produced by the adapter.\n * Always set after adapter setup, parse-only adapters are wrapped automatically.\n */\n inputNode: InputStreamNode | null = null\n adapter: Adapter | null = null\n /**\n * Studio session state, kept together so `dispose()` can reset it atomically.\n *\n * - `source` holds the raw adapter source so `adapter.parse()` can be called lazily.\n * Intentionally outlives the build, cleared by `dispose()`.\n * - `isOpen` prevents opening the studio more than once per build.\n * - `inputNode` caches the parse promise so `adapter.parse()` is called at most once\n * per studio session, even when `openInStudio()` is called multiple times.\n */\n #studio: { source: AdapterSource | null; isOpen: boolean; inputNode: Promise<InputNode> | null } = {\n source: null,\n isOpen: false,\n inputNode: null,\n }\n\n /**\n * Central file store for all generated files.\n * Plugins should use `this.addFile()` / `this.upsertFile()` (via their context) to\n * add files. This property gives direct read/write access when needed.\n */\n readonly fileManager = new FileManager()\n readonly plugins = new Map<string, NormalizedPlugin>()\n\n /**\n * Tracks which plugins have generators registered via `addGenerator()` (event-based path).\n * Used by the build loop to decide whether to emit generator events for a given plugin.\n */\n readonly #eventGeneratorPlugins = new Set<string>()\n readonly #resolvers = new Map<string, Resolver>()\n readonly #defaultResolvers = new Map<string, Resolver>()\n\n /**\n * Tracks every listener the driver added (plugin, middleware, generator) so `dispose()` can\n * remove them in one pass. Middleware registers after plugins, so it fires last via `Set`\n * insertion order. External `hooks.on(...)` listeners are not tracked.\n */\n readonly #registry: HookRegistry<KubbHooks>\n\n /**\n * Transform registry. Plugins populate it during `kubb:plugin:setup` via `setTransformer`,\n * and `#runGenerators` reads it once per `(plugin, node)` pair through `applyTo`.\n */\n readonly #transforms = new Transform()\n\n constructor(config: Config, options: Options) {\n this.config = config\n this.options = options\n this.adapter = config.adapter ?? null\n this.#registry = new HookRegistry({ emitter: options.hooks })\n }\n\n async setup() {\n const normalized: Array<NormalizedPlugin> = this.config.plugins.map((rawPlugin) => this.#normalizePlugin(rawPlugin as Plugin))\n\n normalized.sort((a, b) => {\n if (b.dependencies?.includes(a.name)) return -1\n if (a.dependencies?.includes(b.name)) return 1\n\n return enforceOrder(a.enforce) - enforceOrder(b.enforce)\n })\n\n for (const plugin of normalized) {\n if (plugin.apply) {\n plugin.apply(this.config)\n }\n\n this.#registerPlugin(plugin)\n this.plugins.set(plugin.name, plugin)\n }\n\n if (this.config.middleware) {\n for (const middleware of this.config.middleware) {\n for (const event of Object.keys(middleware.hooks) as Array<keyof KubbHooks & string>) {\n this.#registerMiddleware(event, middleware.hooks)\n }\n }\n }\n if (this.config.adapter) {\n this.#studio.source = inputToAdapterSource(this.config)\n }\n }\n\n get hooks() {\n return this.options.hooks\n }\n\n /**\n * Creates an `NormalizedPlugin` from a hook-style plugin and registers\n * its lifecycle handlers on the `AsyncEventEmitter`.\n */\n #normalizePlugin(plugin: Plugin): NormalizedPlugin {\n const normalized: NormalizedPlugin = {\n name: plugin.name,\n dependencies: plugin.dependencies,\n enforce: plugin.enforce,\n hooks: plugin.hooks,\n options: plugin.options ?? { output: { path: '.' }, exclude: [], override: [] },\n } as NormalizedPlugin\n\n if ('apply' in plugin && typeof plugin.apply === 'function') {\n normalized.apply = plugin.apply as (config: Config) => boolean\n }\n\n return normalized\n }\n\n /**\n * Parses the adapter source into `this.inputNode`. Idempotent, so repeated calls from\n * `run` or the studio path do not re-parse. Adapters with `stream()` are used directly.\n * Adapters with only `parse()` are wrapped via `createStreamInput` so the dispatch loop\n * stays stream-only.\n */\n async #parseInput(): Promise<void> {\n if (this.inputNode || !this.adapter || !this.#studio.source) return\n\n const adapter = this.adapter\n const source = this.#studio.source\n\n if (adapter.stream) {\n this.inputNode = await adapter.stream(source)\n return\n }\n\n const parsed = await adapter.parse(source)\n this.inputNode = createStreamInput(arrayToAsyncIterable(parsed.schemas), arrayToAsyncIterable(parsed.operations), parsed.meta)\n }\n\n #registerMiddleware<K extends keyof KubbHooks & string>(event: K, middlewareHooks: Middleware['hooks']) {\n const handler = middlewareHooks[event]\n\n if (!handler) {\n return\n }\n\n this.#registry.register({ event, handler, source: 'middleware' })\n }\n\n /**\n * Registers a hook-style plugin's lifecycle handlers on the shared `AsyncEventEmitter`.\n *\n * The `kubb:plugin:setup` listener wraps the global context in a plugin-specific one so\n * `addGenerator`, `setResolver`, and `setTransformer` target the right `normalizedPlugin`.\n * Every other `KubbHooks` event registers as a pass-through listener that external tooling\n * can observe via `hooks.on(...)`.\n *\n * @internal\n */\n #registerPlugin(plugin: NormalizedPlugin): void {\n const { hooks } = plugin\n\n if (!hooks) return\n\n // kubb:plugin:setup gets special treatment: the globally emitted context is wrapped with\n // plugin-specific implementations so that addGenerator / setResolver / etc. target\n // this plugin's normalizedPlugin entry rather than being no-ops.\n if (hooks['kubb:plugin:setup']) {\n const setupHandler = (globalCtx: KubbPluginSetupContext) => {\n const pluginCtx: KubbPluginSetupContext = {\n ...globalCtx,\n options: plugin.options ?? {},\n addGenerator: (gen) => {\n this.registerGenerator(plugin.name, gen)\n },\n setResolver: (resolver) => {\n this.setPluginResolver(plugin.name, resolver)\n },\n setTransformer: (visitor) => {\n this.#transforms.register(plugin.name, visitor)\n },\n setOptions: (opts) => {\n plugin.options = { ...plugin.options, ...opts }\n },\n injectFile: (userFileNode) => {\n this.fileManager.add(createFile(userFileNode))\n },\n }\n return hooks['kubb:plugin:setup']!(pluginCtx)\n }\n\n this.#registry.register({ event: 'kubb:plugin:setup', handler: setupHandler, source: 'plugin' })\n }\n\n // All other hooks are registered as direct pass-through listeners on the shared emitter.\n for (const event of Object.keys(hooks) as Array<keyof KubbHooks & string>) {\n if (event === 'kubb:plugin:setup') continue\n const handler = hooks[event]\n if (!handler) continue\n\n this.#registry.register({\n event,\n handler: handler as HookListener<KubbHooks[typeof event], unknown>,\n source: 'plugin',\n })\n }\n }\n\n /**\n * Emits the `kubb:plugin:setup` event so that all registered hook-style plugin listeners\n * can configure generators, resolvers, transformers and renderers before `buildStart` runs.\n *\n * Call this once from `safeBuild` before the plugin execution loop begins.\n */\n async emitSetupHooks(): Promise<void> {\n const noop = () => {}\n\n await this.hooks.emit('kubb:plugin:setup', {\n config: this.config,\n options: {},\n addGenerator: noop,\n setResolver: noop,\n setTransformer: noop,\n setOptions: noop,\n injectFile: noop,\n updateConfig: noop,\n })\n }\n\n /**\n * Registers a generator for the given plugin on the shared event emitter.\n *\n * The generator's `schema`, `operation`, and `operations` methods are registered as\n * listeners on `kubb:generate:schema`, `kubb:generate:operation`, and `kubb:generate:operations`\n * respectively. Each listener is scoped to the owning plugin via a `ctx.plugin.name` check\n * so that generators from different plugins do not cross-fire.\n *\n * The renderer comes from `generator.renderer`. Set `generator.renderer = null` (or leave it\n * unset) to opt out of rendering.\n *\n * Call this method inside `addGenerator()` (in `kubb:plugin:setup`) to wire up a generator.\n */\n registerGenerator(pluginName: string, generator: Generator): void {\n if (generator.schema) {\n const schemaHandler = async (node: SchemaNode, ctx: GeneratorContext) => {\n if (ctx.plugin.name !== pluginName) return\n const result = await generator.schema!(node, ctx)\n\n await this.dispatch({ result, renderer: generator.renderer })\n }\n\n this.#registry.register({ event: 'kubb:generate:schema', handler: schemaHandler, source: 'driver' })\n }\n\n if (generator.operation) {\n const operationHandler = async (node: OperationNode, ctx: GeneratorContext) => {\n if (ctx.plugin.name !== pluginName) return\n\n const result = await generator.operation!(node, ctx)\n await this.dispatch({ result, renderer: generator.renderer })\n }\n\n this.#registry.register({ event: 'kubb:generate:operation', handler: operationHandler, source: 'driver' })\n }\n\n if (generator.operations) {\n const operationsHandler = async (nodes: Array<OperationNode>, ctx: GeneratorContext) => {\n if (ctx.plugin.name !== pluginName) return\n const result = await generator.operations!(nodes, ctx)\n await this.dispatch({ result, renderer: generator.renderer })\n }\n\n this.#registry.register({ event: 'kubb:generate:operations', handler: operationsHandler, source: 'driver' })\n }\n\n this.#eventGeneratorPlugins.add(pluginName)\n }\n\n /**\n * Returns `true` when at least one generator was registered for the given plugin\n * via `addGenerator()` in `kubb:plugin:setup` (event-based path).\n *\n * Used by the build loop to decide whether to walk the AST and emit generator events\n * for a plugin that has no static `plugin.generators`.\n */\n hasEventGenerators(pluginName: string): boolean {\n return this.#eventGeneratorPlugins.has(pluginName)\n }\n\n /**\n * Runs the full plugin pipeline. Returns the diagnostics collected so far even\n * when an outer hook throws, since the orchestrator preserves partial state by capturing\n * the failure as a {@link Diagnostic} instead of propagating. Each plugin also\n * contributes a `timing` diagnostic for the run summary.\n */\n async run({ storage }: { storage: Storage }): Promise<{ diagnostics: Array<Diagnostic> }> {\n const { hooks, config } = this\n const diagnostics: Array<Diagnostic> = []\n const parsersMap = new Map<FileNode['extname'], Parser>()\n\n for (const parser of config.parsers) {\n if (parser.extNames) {\n for (const ext of parser.extNames) parsersMap.set(ext, parser)\n }\n }\n\n const processor = new FileProcessor({ parsers: parsersMap, storage, extension: config.output.extension })\n // Bridge processor lifecycle to the user-facing kubb hooks so existing listeners on\n // kubb:files:processing:* keep firing.\n processor.hooks.on('start', async (files) => {\n await hooks.emit('kubb:files:processing:start', { files })\n })\n const updateBuffer: Array<{ file: FileNode; source?: string; processed: number; total: number; percentage: number }> = []\n processor.hooks.on('update', (item) => {\n updateBuffer.push(item)\n })\n processor.hooks.on('end', async (files) => {\n await hooks.emit('kubb:files:processing:update', {\n files: updateBuffer.map((item) => ({ ...item, config })),\n })\n updateBuffer.length = 0\n await hooks.emit('kubb:files:processing:end', { files })\n })\n const onFileUpsert = (file: FileNode): void => {\n processor.enqueue(file)\n }\n this.fileManager.hooks.on('upsert', onFileUpsert)\n\n // Make `diagnostics` the active sink so deep code (adapter parse, lazily consumed\n // streams, generators) can report into this run via `Diagnostics.report`.\n return Diagnostics.scope(\n (diagnostic) => diagnostics.push(diagnostic),\n async () => {\n try {\n // Parse the adapter source into the streaming `InputNode`.\n await this.#parseInput()\n // Emit `kubb:plugin:setup` so plugins can register transformers via `setTransformer`.\n // Each call writes into `this.#transforms`, which `#runGenerators` later reads through\n // `transforms.applyTo`.\n await this.emitSetupHooks()\n\n if (this.adapter && this.inputNode) {\n await hooks.emit(\n 'kubb:build:start',\n Object.assign({ config, adapter: this.adapter, meta: this.inputNode.meta, getPlugin: this.getPlugin.bind(this) }, this.#filesPayload()),\n )\n }\n\n const generatorPlugins: Array<{ plugin: NormalizedPlugin; context: Omit<GeneratorContext, 'options'>; hrStart: ReturnType<typeof process.hrtime> }> =\n []\n\n for (const plugin of this.plugins.values()) {\n const context = this.getContext(plugin)\n const hrStart = process.hrtime()\n\n try {\n await hooks.emit('kubb:plugin:start', { plugin })\n } catch (caughtError) {\n const error = caughtError as Error\n const duration = getElapsedMs(hrStart)\n\n await this.#emitPluginEnd({ plugin, duration, success: false, error })\n\n diagnostics.push({ ...Diagnostics.from(error), plugin: plugin.name }, Diagnostics.performance({ plugin: plugin.name, duration }))\n\n continue\n }\n\n if (this.hasEventGenerators(plugin.name)) {\n generatorPlugins.push({ plugin, context, hrStart })\n\n continue\n }\n\n const duration = getElapsedMs(hrStart)\n diagnostics.push(Diagnostics.performance({ plugin: plugin.name, duration }))\n\n await this.#emitPluginEnd({ plugin, duration, success: true })\n }\n\n // Stream every node through the transform registry and into each plugin's generators.\n // Handles the empty-entries and missing-`inputNode` cases by closing out each entry's\n // `kubb:plugin:end` directly.\n diagnostics.push(...(await this.#runGenerators(generatorPlugins, () => processor.flush())))\n // Wait for the last in-flight batch and write anything still pending.\n await processor.drain()\n\n await hooks.emit('kubb:plugins:end', Object.assign({ config }, this.#filesPayload()))\n\n // Plugins-end listeners (barrel middleware etc.) may have queued more files.\n await processor.drain()\n\n await hooks.emit('kubb:build:end', { files: this.fileManager.files, config, outputDir: resolve(config.root, config.output.path) })\n\n return { diagnostics: Diagnostics.dedupe(diagnostics) }\n } catch (caughtError) {\n diagnostics.push(Diagnostics.from(caughtError))\n return { diagnostics: Diagnostics.dedupe(diagnostics) }\n } finally {\n this.fileManager.hooks.off('upsert', onFileUpsert)\n }\n },\n )\n }\n\n // Returns a fresh object with a lazy `files` getter and a bound `upsertFile`.\n // Caller must use `Object.assign(extra, this.#filesPayload())`, not object spread.\n // Spread would eagerly invoke the getter and freeze a stale snapshot into the payload.\n #filesPayload(): { readonly files: Array<FileNode>; upsertFile: (...files: Array<FileNode>) => Array<FileNode> } {\n const driver = this\n\n return {\n get files() {\n return driver.fileManager.files\n },\n upsertFile: (...files: Array<FileNode>) => driver.fileManager.upsert(...files),\n }\n }\n\n #emitPluginEnd({ plugin, duration, success, error }: { plugin: NormalizedPlugin; duration: number; success: boolean; error?: Error }): Promise<void> | void {\n return this.hooks.emit(\n 'kubb:plugin:end',\n Object.assign({ plugin, duration, success, ...(error ? { error } : {}), config: this.config }, this.#filesPayload()),\n )\n }\n\n /**\n * Streams schemas and operations through every plugin's generators. Each node is run\n * through the plugin's transformer (from `this.#transforms`) before the generator sees it,\n * so plugins stay isolated and the hot path stays per-node. Schemas run before operations\n * because the two passes share `flushPending` and the FileProcessor's event emitter.\n * A failing plugin contributes an error diagnostic so the rest of the build continues.\n * Every plugin also contributes a `timing` diagnostic.\n *\n * When `entries` is empty or `this.inputNode` is `null`, every entry still gets a\n * `kubb:plugin:end` so middleware listeners (the barrel writer and friends) complete.\n */\n async #runGenerators(\n entries: Array<{ plugin: NormalizedPlugin; context: Omit<GeneratorContext, 'options'>; hrStart: ReturnType<typeof process.hrtime> }>,\n flushPending: () => Promise<void>,\n ): Promise<Array<Diagnostic>> {\n const diagnostics: Array<Diagnostic> = []\n\n if (entries.length === 0) return diagnostics\n\n if (!this.inputNode) {\n for (const { plugin, hrStart } of entries) {\n const duration = getElapsedMs(hrStart)\n diagnostics.push(Diagnostics.performance({ plugin: plugin.name, duration }))\n await this.#emitPluginEnd({ plugin, duration, success: true })\n }\n return diagnostics\n }\n\n const transforms = this.#transforms\n const { schemas, operations } = this.inputNode\n\n type PluginState = {\n plugin: NormalizedPlugin\n generatorContext: Omit<GeneratorContext, 'options'>\n generators: Array<Generator>\n hrStart: ReturnType<typeof process.hrtime>\n failed: boolean\n error: Error | null\n optionsAreStatic: boolean\n allowedSchemaNames: Set<string> | null\n }\n\n const states: Array<PluginState> = entries.map(({ plugin, context, hrStart }) => {\n const { exclude, include, override } = plugin.options\n const hasExclude = Array.isArray(exclude) && exclude.length > 0\n const hasInclude = Array.isArray(include) && include.length > 0\n const hasOverride = Array.isArray(override) && override.length > 0\n return {\n plugin,\n generatorContext: { ...context, resolver: this.getResolver(plugin.name) },\n generators: plugin.generators ?? [],\n hrStart,\n failed: false,\n error: null,\n optionsAreStatic: !hasExclude && !hasInclude && !hasOverride,\n allowedSchemaNames: null,\n }\n })\n\n const emitsSchemaHook = this.hooks.listenerCount('kubb:generate:schema') > 0\n const emitsOperationHook = this.hooks.listenerCount('kubb:generate:operation') > 0\n\n // Pre-scan: plugins with operation-based includes (but no schemaName include) need\n // the reachable schema set. This requires the full schema graph in memory at once,\n // since transitive reachability can't be derived from a single node. `allSchemas` is\n // released as soon as the pre-scan returns, so the main passes get fresh iterators.\n const pruningStates = states.filter(({ plugin }) => {\n const { include } = plugin.options\n return (include?.some(({ type }) => OPERATION_FILTER_TYPES.has(type)) ?? false) && !(include?.some(({ type }) => type === 'schemaName') ?? false)\n })\n\n if (pruningStates.length > 0) {\n const allSchemas: Array<SchemaNode> = []\n for await (const schema of schemas) allSchemas.push(schema)\n\n const includedOpsByState = new Map<PluginState, Array<OperationNode>>(pruningStates.map((state) => [state, []]))\n for await (const operation of operations) {\n for (const state of pruningStates) {\n const { exclude, include, override } = state.plugin.options\n const options = state.generatorContext.resolver.resolveOptions(operation, { options: state.plugin.options, exclude, include, override })\n if (options !== null) includedOpsByState.get(state)?.push(operation)\n }\n }\n\n for (const state of pruningStates) {\n state.allowedSchemaNames = collectUsedSchemaNames(includedOpsByState.get(state) ?? [], allSchemas)\n includedOpsByState.delete(state)\n }\n }\n\n // Apply the plugin's transformer, then resolve options (skipping the resolver when\n // optionsAreStatic). Returns null when include/exclude/override rules out the node.\n // The per-node dispatch and the collected-operations tail both go through this so\n // they agree on what a plugin sees.\n const resolveForPlugin = <TNode extends SchemaNode | OperationNode>(\n state: PluginState,\n node: TNode,\n ): { transformedNode: TNode; options: NormalizedPlugin['options'] } | null => {\n const { plugin, generatorContext } = state\n const transformedNode = transforms.applyTo(plugin.name, node)\n if (state.optionsAreStatic) return { transformedNode, options: plugin.options }\n\n const { exclude, include, override } = plugin.options\n const options = generatorContext.resolver.resolveOptions(transformedNode, { options: plugin.options, exclude, include, override })\n if (options === null) return null\n return { transformedNode, options }\n }\n\n // Schema and operation passes share this body. They differ only in which generator\n // method runs, which hook is emitted, and the schema-only `allowedSchemaNames` prune\n // (operations don't carry that constraint).\n const dispatchNode = async <TNode extends SchemaNode | OperationNode>(\n state: PluginState,\n node: TNode,\n dispatch: {\n method: 'schema' | 'operation'\n checkAllowedNames: boolean\n emit: ((node: TNode, ctx: GeneratorContext) => Promise<void> | void) | null\n },\n ): Promise<void> => {\n if (state.failed) return\n try {\n const resolved = resolveForPlugin(state, node)\n if (!resolved) return\n\n const { transformedNode, options } = resolved\n if (\n dispatch.checkAllowedNames &&\n state.allowedSchemaNames !== null &&\n 'name' in transformedNode &&\n transformedNode.name &&\n !state.allowedSchemaNames.has(transformedNode.name)\n ) {\n return\n }\n\n const ctx = { ...state.generatorContext, options }\n for (const gen of state.generators) {\n const run = gen[dispatch.method] as ((node: TNode, ctx: GeneratorContext) => unknown) | undefined\n if (!run) continue\n const raw = run(transformedNode, ctx)\n const result = isPromise(raw) ? await raw : raw\n const applied = this.dispatch({ result, renderer: gen.renderer })\n if (isPromise(applied)) await applied\n }\n if (dispatch.emit) await dispatch.emit(transformedNode, ctx)\n } catch (caughtError) {\n state.failed = true\n state.error = caughtError as Error\n }\n }\n\n const schemaDispatch = {\n method: 'schema',\n checkAllowedNames: true,\n emit: emitsSchemaHook ? (node: SchemaNode, ctx: GeneratorContext) => this.hooks.emit('kubb:generate:schema', node, ctx) : null,\n } as const\n const operationDispatch = {\n method: 'operation',\n checkAllowedNames: false,\n emit: emitsOperationHook ? (node: OperationNode, ctx: GeneratorContext) => this.hooks.emit('kubb:generate:operation', node, ctx) : null,\n } as const\n\n // Skip building the aggregated operations array when nothing consumes it. Saves an\n // N-sized allocation on the common path where plugins only define per-node `gen.operation`.\n const needsCollectedOperations =\n this.hooks.listenerCount('kubb:generate:operations') > 0 || states.some((state) => state.generators.some((gen) => !!gen.operations))\n const collectedOperations: Array<OperationNode> | undefined = needsCollectedOperations ? [] : undefined\n\n // Run schemas before operations: the two passes share `flushPending` and the\n // FileProcessor's event emitter, so running them concurrently would interleave\n // `kubb:files:processing:start|end` events and race on the shared dirty list.\n await forBatches(schemas, (nodes) => Promise.all(nodes.flatMap((node) => states.map((state) => dispatchNode(state, node, schemaDispatch)))), {\n concurrency: SCHEMA_PARALLEL,\n flush: flushPending,\n })\n\n await forBatches(\n operations,\n (nodes) => {\n if (needsCollectedOperations) collectedOperations?.push(...nodes)\n return Promise.all(nodes.flatMap((node) => states.map((state) => dispatchNode(state, node, operationDispatch))))\n },\n { concurrency: SCHEMA_PARALLEL, flush: flushPending },\n )\n\n for (const state of states) {\n if (!state.failed && needsCollectedOperations) {\n try {\n const { plugin, generatorContext, generators } = state\n const ctx = { ...generatorContext, options: plugin.options }\n // Match what the per-node dispatch passes to gen.operation(): the transformed node,\n // already filtered by excludes/includes/overrides.\n const ops = collectedOperations ?? []\n const pluginOperations = ops.reduce<Array<OperationNode>>((acc, node) => {\n const resolved = resolveForPlugin(state, node)\n if (resolved) acc.push(resolved.transformedNode)\n return acc\n }, [])\n for (const gen of generators) {\n if (!gen.operations) continue\n const result = await gen.operations(pluginOperations, ctx)\n await this.dispatch({ result, renderer: gen.renderer })\n }\n await this.hooks.emit('kubb:generate:operations', pluginOperations, ctx)\n } catch (caughtError) {\n state.failed = true\n state.error = caughtError as Error\n }\n }\n\n const duration = getElapsedMs(state.hrStart)\n await this.#emitPluginEnd({ plugin: state.plugin, duration, success: !state.failed, error: state.failed && state.error ? state.error : undefined })\n\n if (state.failed && state.error) {\n diagnostics.push({ ...Diagnostics.from(state.error), plugin: state.plugin.name })\n }\n diagnostics.push(Diagnostics.performance({ plugin: state.plugin.name, duration }))\n }\n\n return diagnostics\n }\n\n /**\n * Stores whatever a generator method or `kubb:generate:*` hook returned.\n *\n * - An `Array<FileNode>` goes straight into `fileManager` via `upsert`.\n * - A renderer element runs through `renderer` (the renderer factory, e.g. JSX) and the\n * produced files go to `fileManager.upsert`.\n * - A falsy result is treated as a no-op. The generator wrote files itself via\n * `ctx.upsertFile`.\n *\n * Pass `renderer` when the result may be a renderer element. Generators that only return\n * `Array<FileNode>` do not need one.\n */\n async dispatch<TElement = unknown>({\n result,\n renderer,\n }: {\n result: TElement | Array<FileNode> | undefined | null\n renderer?: RendererFactory<TElement> | null\n }): Promise<void> {\n if (!result) return\n\n if (Array.isArray(result)) {\n this.fileManager.upsert(...(result as Array<FileNode>))\n return\n }\n\n if (!renderer) {\n return\n }\n\n using instance = renderer()\n if (instance.stream) {\n for (const file of instance.stream(result)) {\n this.fileManager.upsert(file)\n }\n return\n }\n\n await instance.render(result)\n this.fileManager.upsert(...instance.files)\n }\n\n /**\n * Removes every listener the driver added. Listeners attached directly to `hooks` from outside\n * the driver survive. Called at the end of a build to prevent leaks across repeated builds.\n *\n * @internal\n */\n dispose(): void {\n this.#registry.dispose()\n this.#eventGeneratorPlugins.clear()\n this.#transforms.dispose()\n // Release resolver closures. The driver is rebuilt for each build() call\n // so there is no value in retaining these maps after disposal.\n this.#resolvers.clear()\n this.#defaultResolvers.clear()\n // Release the FileNode cache, parsed adapter graph, and studio state so\n // memory is reclaimed between builds. The returned `BuildOutput.files`\n // array still references any FileNodes the caller needs to inspect.\n this.fileManager.dispose()\n this.inputNode = null\n this.#studio = { source: null, isOpen: false, inputNode: null }\n }\n\n [Symbol.dispose](): void {\n this.dispose()\n }\n\n #getDefaultResolver = memoize(\n this.#defaultResolvers,\n (pluginName: string): Resolver => defineResolver<PluginFactoryOptions>(() => ({ name: 'default', pluginName })),\n )\n\n /**\n * Merges `partial` with the plugin's default resolver and stores the result.\n * Also mirrors it onto `plugin.resolver` so callers using `getPlugin(name).resolver`\n * get the up-to-date resolver without going through `getResolver()`.\n */\n setPluginResolver(pluginName: string, partial: Partial<Resolver>): void {\n const defaultResolver = this.#getDefaultResolver(pluginName)\n const merged = { ...defaultResolver, ...partial }\n this.#resolvers.set(pluginName, merged)\n const plugin = this.plugins.get(pluginName)\n if (plugin) {\n plugin.resolver = merged\n }\n }\n\n /**\n * Returns the resolver for the given plugin.\n *\n * Resolution order: dynamic resolver set via `setPluginResolver` → static resolver on the\n * plugin → lazily created default resolver (identity name, no path transforms).\n */\n getResolver<TName extends keyof Kubb.PluginRegistry>(pluginName: TName): Kubb.PluginRegistry[TName]['resolver']\n getResolver<TResolver extends Resolver = Resolver>(pluginName: string): TResolver\n getResolver(pluginName: string): Resolver {\n return this.#resolvers.get(pluginName) ?? this.plugins.get(pluginName)?.resolver ?? this.#getDefaultResolver(pluginName)\n }\n\n getContext<TOptions extends PluginFactoryOptions>(plugin: NormalizedPlugin<TOptions>): Omit<GeneratorContext<TOptions>, 'options'> {\n const driver = this\n\n // Collect into the active build only. The host renders each collected diagnostic once after the\n // build (the CLI via `Diagnostics.emit`, the agent via its post-build loop), so emitting a live\n // `kubb:error`/`kubb:warn`/`kubb:info` here would render it twice.\n const report = (diagnostic: Omit<ProblemDiagnostic, 'plugin'>): void => {\n Diagnostics.report({ ...diagnostic, plugin: plugin.name })\n }\n\n return {\n config: driver.config,\n get root(): string {\n return resolve(driver.config.root, driver.config.output.path)\n },\n getMode(output: { path: string }): 'single' | 'split' {\n return KubbDriver.getMode(resolve(driver.config.root, driver.config.output.path, output.path))\n },\n hooks: driver.hooks,\n plugin,\n getPlugin: driver.getPlugin.bind(driver),\n requirePlugin: driver.requirePlugin.bind(driver),\n getResolver: driver.getResolver.bind(driver),\n driver,\n addFile: async (...files: Array<FileNode>) => {\n driver.fileManager.add(...files)\n },\n upsertFile: async (...files: Array<FileNode>) => {\n driver.fileManager.upsert(...files)\n },\n get meta(): InputMeta {\n return driver.inputNode?.meta ?? { circularNames: [], enumNames: [] }\n },\n get adapter(): Adapter {\n // Generators only read `adapter` during AST hooks, which run after the\n // adapter is set, so it is guaranteed defined at read time.\n return driver.adapter!\n },\n get resolver() {\n return driver.getResolver(plugin.name)\n },\n get transformer() {\n return driver.#transforms.get(plugin.name)\n },\n warn(message: string) {\n report({ code: diagnosticCode.pluginWarning, severity: 'warning', message })\n },\n error(error: string | Error) {\n const cause = typeof error === 'string' ? undefined : error\n report({ code: diagnosticCode.pluginFailed, severity: 'error', message: typeof error === 'string' ? error : error.message, cause })\n },\n info(message: string) {\n report({ code: diagnosticCode.pluginInfo, severity: 'info', message })\n },\n async openInStudio(options?: DevtoolsOptions) {\n if (!driver.config.devtools || driver.#studio.isOpen) {\n return\n }\n\n if (typeof driver.config.devtools !== 'object') {\n throw new DiagnosticError({\n code: diagnosticCode.devtoolsInvalid,\n severity: 'error',\n message: 'The `devtools` config must be an object.',\n help: 'Set `devtools` to an options object, or remove it to disable Kubb Studio.',\n location: { kind: 'config' },\n })\n }\n\n if (!driver.adapter || !driver.#studio.source) {\n throw new DiagnosticError({\n code: diagnosticCode.adapterRequired,\n severity: 'error',\n message: 'An adapter is required to open Kubb Studio, but none is configured.',\n help: 'Set `adapter` in kubb.config.ts (for example `adapterOas()`).',\n location: { kind: 'config' },\n })\n }\n\n driver.#studio.isOpen = true\n\n const studioUrl = driver.config.devtools?.studioUrl ?? DEFAULT_STUDIO_URL\n driver.#studio.inputNode ??= Promise.resolve(driver.adapter.parse(driver.#studio.source))\n const inputNode = await driver.#studio.inputNode\n\n return openInStudioFn(inputNode, studioUrl, options)\n },\n }\n }\n\n getPlugin<TName extends keyof Kubb.PluginRegistry>(pluginName: TName): Plugin<Kubb.PluginRegistry[TName]> | undefined\n getPlugin<TOptions extends PluginFactoryOptions = PluginFactoryOptions>(pluginName: string): Plugin<TOptions> | undefined\n getPlugin(pluginName: string): Plugin | undefined {\n return this.plugins.get(pluginName)\n }\n\n /**\n * Like `getPlugin` but throws a descriptive error when the plugin is not found.\n */\n requirePlugin<TName extends keyof Kubb.PluginRegistry>(pluginName: TName): Plugin<Kubb.PluginRegistry[TName]>\n requirePlugin<TOptions extends PluginFactoryOptions = PluginFactoryOptions>(pluginName: string): Plugin<TOptions>\n requirePlugin(pluginName: string): Plugin {\n const plugin = this.plugins.get(pluginName)\n if (!plugin) {\n throw new DiagnosticError({\n code: diagnosticCode.pluginNotFound,\n severity: 'error',\n message: `Plugin \"${pluginName}\" is required but not found. Make sure it is included in your Kubb config.`,\n help: `Add \"${pluginName}\" to the \\`plugins\\` array in kubb.config.ts, or remove the dependency on it.`,\n location: { kind: 'config' },\n })\n }\n return plugin\n }\n}\n\nfunction inputToAdapterSource(config: Config): AdapterSource {\n const input = config.input\n if (!input) {\n throw new DiagnosticError({\n code: diagnosticCode.inputRequired,\n severity: 'error',\n message: 'An adapter is configured without an input.',\n help: 'Provide `input.path` (a file or URL) or `input.data` (an inline spec) in your Kubb config.',\n location: { kind: 'config' },\n })\n }\n\n if ('data' in input) {\n return { type: 'data', data: input.data }\n }\n\n if (new URLPath(input.path).isURL) {\n return { type: 'path', path: input.path }\n }\n\n const resolved = resolve(config.root, input.path)\n\n return { type: 'path', path: resolved }\n}\n"],"mappings":"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"}
|