@kubb/core 5.0.0-beta.10 → 5.0.0-beta.11

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.
@@ -354,6 +354,88 @@ type DevtoolsOptions = {
354
354
  ast?: boolean;
355
355
  };
356
356
  //#endregion
357
+ //#region src/defineParser.d.ts
358
+ type PrintOptions = {
359
+ extname?: FileNode['extname'];
360
+ };
361
+ type Parser<TMeta extends object = any> = {
362
+ name: string;
363
+ /**
364
+ * File extensions this parser handles.
365
+ * Use `undefined` to create a catch-all fallback parser.
366
+ *
367
+ * @example Handled extensions
368
+ * `['.ts', '.js']`
369
+ */
370
+ extNames: Array<FileNode['extname']> | undefined;
371
+ /**
372
+ * Convert a resolved file to a string.
373
+ */
374
+ parse(file: FileNode<TMeta>, options?: PrintOptions): Promise<string> | string;
375
+ };
376
+ /**
377
+ * Defines a parser with type safety. Creates parsers that transform generated files to strings based on their extension.
378
+ *
379
+ * @note Call the returned factory with optional options to instantiate the parser.
380
+ *
381
+ * @example
382
+ * ```ts
383
+ * import { defineParser } from '@kubb/core'
384
+ *
385
+ * export const jsonParser = defineParser({
386
+ * name: 'json',
387
+ * extNames: ['.json'],
388
+ * parse(file) {
389
+ * const { extractStringsFromNodes } = await import('@kubb/ast')
390
+ * return file.sources.map((s) => extractStringsFromNodes(s.nodes ?? [])).join('\n')
391
+ * },
392
+ * })
393
+ * ```
394
+ */
395
+ declare function defineParser<TMeta extends object = any>(parser: Parser<TMeta>): Parser<TMeta>;
396
+ //#endregion
397
+ //#region src/FileProcessor.d.ts
398
+ type ParseOptions = {
399
+ parsers?: Map<FileNode['extname'], Parser>;
400
+ extension?: Record<FileNode['extname'], FileNode['extname'] | ''>;
401
+ };
402
+ type RunOptions = ParseOptions & {
403
+ /**
404
+ * @default 'sequential'
405
+ */
406
+ mode?: 'sequential' | 'parallel';
407
+ };
408
+ type FileProcessorEvents = {
409
+ start: [files: Array<FileNode>];
410
+ update: [params: {
411
+ file: FileNode;
412
+ source?: string;
413
+ processed: number;
414
+ total: number;
415
+ percentage: number;
416
+ }];
417
+ end: [files: Array<FileNode>];
418
+ };
419
+ /**
420
+ * Converts a single file to a string using the registered parsers.
421
+ * Falls back to joining source values when no matching parser is found.
422
+ *
423
+ * @internal
424
+ */
425
+ declare class FileProcessor {
426
+ #private;
427
+ readonly events: AsyncEventEmitter<FileProcessorEvents>;
428
+ parse(file: FileNode, {
429
+ parsers,
430
+ extension
431
+ }?: ParseOptions): Promise<string>;
432
+ run(files: Array<FileNode>, {
433
+ parsers,
434
+ mode,
435
+ extension
436
+ }?: RunOptions): Promise<Array<FileNode>>;
437
+ }
438
+ //#endregion
357
439
  //#region src/defineLogger.d.ts
358
440
  type LoggerOptions = {
359
441
  /**
@@ -459,46 +541,6 @@ type Middleware = {
459
541
  */
460
542
  declare function defineMiddleware<TOptions extends object = object>(factory: (options: TOptions) => Middleware): (options?: TOptions) => Middleware;
461
543
  //#endregion
462
- //#region src/defineParser.d.ts
463
- type PrintOptions = {
464
- extname?: FileNode['extname'];
465
- };
466
- type Parser<TMeta extends object = any> = {
467
- name: string;
468
- /**
469
- * File extensions this parser handles.
470
- * Use `undefined` to create a catch-all fallback parser.
471
- *
472
- * @example Handled extensions
473
- * `['.ts', '.js']`
474
- */
475
- extNames: Array<FileNode['extname']> | undefined;
476
- /**
477
- * Convert a resolved file to a string.
478
- */
479
- parse(file: FileNode<TMeta>, options?: PrintOptions): Promise<string> | string;
480
- };
481
- /**
482
- * Defines a parser with type safety. Creates parsers that transform generated files to strings based on their extension.
483
- *
484
- * @note Call the returned factory with optional options to instantiate the parser.
485
- *
486
- * @example
487
- * ```ts
488
- * import { defineParser } from '@kubb/core'
489
- *
490
- * export const jsonParser = defineParser({
491
- * name: 'json',
492
- * extNames: ['.json'],
493
- * parse(file) {
494
- * const { extractStringsFromNodes } = await import('@kubb/ast')
495
- * return file.sources.map((s) => extractStringsFromNodes(s.nodes ?? [])).join('\n')
496
- * },
497
- * })
498
- * ```
499
- */
500
- declare function defineParser<TMeta extends object = any>(parser: Parser<TMeta>): Parser<TMeta>;
501
- //#endregion
502
544
  //#region src/defineResolver.d.ts
503
545
  /**
504
546
  * Type/string pattern filter for include/exclude/override matching.
@@ -1093,6 +1135,11 @@ declare class FileManager {
1093
1135
  getByPath(path: string): FileNode | null;
1094
1136
  deleteByPath(path: string): void;
1095
1137
  clear(): void;
1138
+ /**
1139
+ * Releases all stored files. Called by the core after `kubb:build:end` to
1140
+ * free the per-plugin FileNode caches for the rest of the process lifetime.
1141
+ */
1142
+ dispose(): void;
1096
1143
  /**
1097
1144
  * All stored files, sorted by path length (shorter paths first).
1098
1145
  */
@@ -1908,8 +1955,25 @@ type KubbGenerationStartContext = {
1908
1955
  };
1909
1956
  type KubbGenerationEndContext = {
1910
1957
  config: Config;
1911
- files: Array<FileNode>;
1912
- sources: Map<string, string>;
1958
+ /**
1959
+ * Read-only view of the files Kubb wrote during this build.
1960
+ *
1961
+ * Keys are scoped to this run; files from earlier builds are not included.
1962
+ * Reads go directly to `config.storage`, so nothing is buffered in memory.
1963
+ *
1964
+ * @example Read a generated file
1965
+ * ```ts
1966
+ * const code = await storage.getItem('/src/gen/pet.ts')
1967
+ * ```
1968
+ *
1969
+ * @example Walk every generated file
1970
+ * ```ts
1971
+ * for (const path of await storage.getKeys()) {
1972
+ * const code = await storage.getItem(path)
1973
+ * }
1974
+ * ```
1975
+ */
1976
+ storage: Storage;
1913
1977
  };
1914
1978
  type KubbGenerationSummaryContext = {
1915
1979
  config: Config;
@@ -2005,9 +2069,22 @@ type BuildOutput = {
2005
2069
  pluginTimings: Map<string, number>;
2006
2070
  error?: Error;
2007
2071
  /**
2008
- * Raw generated source, keyed by absolute file path.
2072
+ * Read-only view of every file written during this build.
2073
+ *
2074
+ * Keys are limited to this run. Reads go straight to `config.storage`,
2075
+ * so nothing extra is held in memory.
2076
+ *
2077
+ * @example Read a generated file
2078
+ * ```ts
2079
+ * const code = await buildOutput.storage.getItem('/src/gen/pet.ts')
2080
+ * ```
2081
+ *
2082
+ * @example List all generated file paths
2083
+ * ```ts
2084
+ * const paths = await buildOutput.storage.getKeys()
2085
+ * ```
2009
2086
  */
2010
- sources: Map<string, string>;
2087
+ storage: Storage;
2011
2088
  };
2012
2089
  /**
2013
2090
  * Kubb code generation instance returned by {@link createKubb}.
@@ -2021,17 +2098,34 @@ type Kubb$1 = {
2021
2098
  */
2022
2099
  readonly hooks: AsyncEventEmitter<KubbHooks>;
2023
2100
  /**
2024
- * Generated source code keyed by absolute file path. Available after `build()` or `safeBuild()` completes.
2101
+ * Read-only view of the files from the most recent `build()` or `safeBuild()` call.
2102
+ * Only populated after the build completes.
2103
+ *
2104
+ * Keys are scoped to the current run. Reads go straight to `config.storage`,
2105
+ * so nothing extra is held in memory.
2106
+ *
2107
+ * @example Read a generated file
2108
+ * ```ts
2109
+ * const { storage } = await kubb.safeBuild()
2110
+ * const code = await storage.getItem('/src/gen/pet.ts')
2111
+ * ```
2112
+ *
2113
+ * @example Walk every generated file
2114
+ * ```ts
2115
+ * for (const path of await kubb.storage.getKeys()) {
2116
+ * const code = await kubb.storage.getItem(path)
2117
+ * }
2118
+ * ```
2025
2119
  */
2026
- readonly sources: Map<string, string>;
2120
+ readonly storage: Storage;
2027
2121
  /**
2028
2122
  * Plugin driver managing all plugins. Available after `setup()` completes.
2029
2123
  */
2030
- readonly driver: PluginDriver | undefined;
2124
+ readonly driver: PluginDriver;
2031
2125
  /**
2032
2126
  * Resolved configuration with defaults applied. Available after `setup()` completes.
2033
2127
  */
2034
- readonly config: Config | undefined;
2128
+ readonly config: Config;
2035
2129
  /**
2036
2130
  * Resolves config and initializes the driver. `build()` calls this automatically.
2037
2131
  */
@@ -2061,7 +2155,7 @@ type CreateKubbOptions = {
2061
2155
  * Creates a Kubb instance bound to a single config entry.
2062
2156
  *
2063
2157
  * Accepts a user-facing config shape and resolves it to a full {@link Config} during
2064
- * `setup()`. The instance then holds shared state (`hooks`, `sources`, `driver`, `config`)
2158
+ * `setup()`. The instance then holds shared state (`hooks`, `storage`, `driver`, `config`)
2065
2159
  * across the `setup → build` lifecycle. Attach event listeners to `kubb.hooks` before
2066
2160
  * calling `setup()` or `build()`.
2067
2161
  *
@@ -2078,5 +2172,5 @@ type CreateKubbOptions = {
2078
2172
  */
2079
2173
  declare function createKubb(userConfig: UserConfig, options?: CreateKubbOptions): Kubb$1;
2080
2174
  //#endregion
2081
- export { ResolverPathParams as $, isInputPath as A, KubbPluginSetupContext as B, KubbPluginsEndContext as C, PossibleConfig as D, KubbWarnContext as E, FileManager as F, Plugin as G, NormalizedPlugin as H, Exclude as I, ResolveBannerContext as J, PluginFactoryOptions as K, Group as L, GeneratorContext as M, defineGenerator as N, UserConfig as O, PluginDriver as P, ResolverFileParams as Q, Include as R, KubbLifecycleStartContext as S, KubbVersionNewContext as T, Output as U, KubbPluginStartContext as V, Override as W, Resolver as X, ResolveOptionsContext as Y, ResolverContext as Z, KubbGenerationSummaryContext as _, AdapterFactoryOptions as _t, InputPath as a, Logger as at, KubbHooks as b, logLevel as bt, KubbBuildStartContext as c, UserLogger as ct, KubbErrorContext as d, Storage as dt, defineResolver as et, KubbFileProcessingUpdateContext as f, createStorage as ft, KubbGenerationStartContext as g, Adapter as gt, KubbGenerationEndContext as h, createRenderer as ht, InputData as i, defineMiddleware as it, Generator as j, createKubb as k, KubbConfigEndContext as l, defineLogger as lt, KubbFilesProcessingStartContext as m, RendererFactory as mt, CLIOptions as n, defineParser as nt, Kubb$1 as o, LoggerContext as ot, KubbFilesProcessingEndContext as p, Renderer as pt, definePlugin as q, Config as r, Middleware as rt, KubbBuildEndContext as s, LoggerOptions as st, BuildOutput as t, Parser as tt, KubbDebugContext as u, DevtoolsOptions as ut, KubbHookEndContext as v, AdapterSource as vt, KubbSuccessContext as w, KubbInfoContext as x, AsyncEventEmitter as xt, KubbHookStartContext as y, createAdapter as yt, KubbPluginEndContext as z };
2082
- //# sourceMappingURL=createKubb-ALdb8lmq.d.ts.map
2175
+ export { ResolverPathParams as $, isInputPath as A, KubbPluginSetupContext as B, KubbPluginsEndContext as C, AsyncEventEmitter as Ct, PossibleConfig as D, KubbWarnContext as E, FileManager as F, Plugin as G, NormalizedPlugin as H, Exclude as I, ResolveBannerContext as J, PluginFactoryOptions as K, Group as L, GeneratorContext as M, defineGenerator as N, UserConfig as O, PluginDriver as P, ResolverFileParams as Q, Include as R, KubbLifecycleStartContext as S, logLevel as St, KubbVersionNewContext as T, Output as U, KubbPluginStartContext as V, Override as W, Resolver as X, ResolveOptionsContext as Y, ResolverContext as Z, KubbGenerationSummaryContext as _, createRenderer as _t, InputPath as a, LoggerOptions as at, KubbHooks as b, AdapterSource as bt, KubbBuildStartContext as c, FileProcessor as ct, KubbErrorContext as d, defineParser as dt, defineResolver as et, KubbFileProcessingUpdateContext as f, DevtoolsOptions as ft, KubbGenerationStartContext as g, RendererFactory as gt, KubbGenerationEndContext as h, Renderer as ht, InputData as i, LoggerContext as it, Generator as j, createKubb as k, KubbConfigEndContext as l, FileProcessorEvents as lt, KubbFilesProcessingStartContext as m, createStorage as mt, CLIOptions as n, defineMiddleware as nt, Kubb$1 as o, UserLogger as ot, KubbFilesProcessingEndContext as p, Storage as pt, definePlugin as q, Config as r, Logger as rt, KubbBuildEndContext as s, defineLogger as st, BuildOutput as t, Middleware as tt, KubbDebugContext as u, Parser as ut, KubbHookEndContext as v, Adapter as vt, KubbSuccessContext as w, KubbInfoContext as x, createAdapter as xt, KubbHookStartContext as y, AdapterFactoryOptions as yt, KubbPluginEndContext as z };
2176
+ //# sourceMappingURL=createKubb-BSfMDBwR.d.ts.map
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_PluginDriver = require("./PluginDriver-Cu1Kj9S-.cjs");
2
+ const require_PluginDriver = require("./PluginDriver-C1OsqGBJ.cjs");
3
3
  let node_events = require("node:events");
4
4
  let node_fs_promises = require("node:fs/promises");
5
5
  let node_path = require("node:path");
@@ -525,7 +525,44 @@ function createAdapter(build) {
525
525
  }
526
526
  //#endregion
527
527
  //#region package.json
528
- var version = "5.0.0-beta.10";
528
+ var version = "5.0.0-beta.11";
529
+ //#endregion
530
+ //#region src/createStorage.ts
531
+ /**
532
+ * Factory for implementing custom storage backends that control where generated files are written.
533
+ *
534
+ * Takes a builder function `(options: TOptions) => Storage` and returns a factory `(options?: TOptions) => Storage`.
535
+ * Kubb provides filesystem and in-memory implementations out of the box.
536
+ *
537
+ * @note Call the returned factory with optional options to instantiate the storage adapter.
538
+ *
539
+ * @example
540
+ * ```ts
541
+ * import { createStorage } from '@kubb/core'
542
+ *
543
+ * export const memoryStorage = createStorage(() => {
544
+ * const store = new Map<string, string>()
545
+ * return {
546
+ * name: 'memory',
547
+ * async hasItem(key) { return store.has(key) },
548
+ * async getItem(key) { return store.get(key) ?? null },
549
+ * async setItem(key, value) { store.set(key, value) },
550
+ * async removeItem(key) { store.delete(key) },
551
+ * async getKeys(base) {
552
+ * const keys = [...store.keys()]
553
+ * return base ? keys.filter((k) => k.startsWith(base)) : keys
554
+ * },
555
+ * async clear(base) { if (!base) store.clear() },
556
+ * }
557
+ * })
558
+ *
559
+ * // Instantiate:
560
+ * const storage = memoryStorage()
561
+ * ```
562
+ */
563
+ function createStorage(build) {
564
+ return (options) => build(options ?? {});
565
+ }
529
566
  //#endregion
530
567
  //#region ../../node_modules/.pnpm/yocto-queue@1.2.2/node_modules/yocto-queue/index.js
531
568
  var Node = class {
@@ -665,7 +702,8 @@ function joinSources(file) {
665
702
  * @internal
666
703
  */
667
704
  var FileProcessor = class {
668
- #limit = pLimit(100);
705
+ events = new AsyncEventEmitter();
706
+ #limit = pLimit(16);
669
707
  async parse(file, { parsers, extension } = {}) {
670
708
  const parseExtName = extension?.[file.extname] || void 0;
671
709
  if (!parsers || !file.extname) return joinSources(file);
@@ -673,8 +711,8 @@ var FileProcessor = class {
673
711
  if (!parser) return joinSources(file);
674
712
  return parser.parse(file, { extname: parseExtName });
675
713
  }
676
- async run(files, { parsers, mode = "sequential", extension, onStart, onEnd, onUpdate } = {}) {
677
- await onStart?.(files);
714
+ async run(files, { parsers, mode = "sequential", extension } = {}) {
715
+ await this.events.emit("start", files);
678
716
  const total = files.length;
679
717
  let processed = 0;
680
718
  const processOne = async (file) => {
@@ -684,7 +722,7 @@ var FileProcessor = class {
684
722
  });
685
723
  const currentProcessed = ++processed;
686
724
  const percentage = currentProcessed / total * 100;
687
- await onUpdate?.({
725
+ await this.events.emit("update", {
688
726
  file,
689
727
  source,
690
728
  processed: currentProcessed,
@@ -694,48 +732,11 @@ var FileProcessor = class {
694
732
  };
695
733
  if (mode === "sequential") for (const file of files) await processOne(file);
696
734
  else await Promise.all(files.map((file) => this.#limit(() => processOne(file))));
697
- await onEnd?.(files);
735
+ await this.events.emit("end", files);
698
736
  return files;
699
737
  }
700
738
  };
701
739
  //#endregion
702
- //#region src/createStorage.ts
703
- /**
704
- * Factory for implementing custom storage backends that control where generated files are written.
705
- *
706
- * Takes a builder function `(options: TOptions) => Storage` and returns a factory `(options?: TOptions) => Storage`.
707
- * Kubb provides filesystem and in-memory implementations out of the box.
708
- *
709
- * @note Call the returned factory with optional options to instantiate the storage adapter.
710
- *
711
- * @example
712
- * ```ts
713
- * import { createStorage } from '@kubb/core'
714
- *
715
- * export const memoryStorage = createStorage(() => {
716
- * const store = new Map<string, string>()
717
- * return {
718
- * name: 'memory',
719
- * async hasItem(key) { return store.has(key) },
720
- * async getItem(key) { return store.get(key) ?? null },
721
- * async setItem(key, value) { store.set(key, value) },
722
- * async removeItem(key) { store.delete(key) },
723
- * async getKeys(base) {
724
- * const keys = [...store.keys()]
725
- * return base ? keys.filter((k) => k.startsWith(base)) : keys
726
- * },
727
- * async clear(base) { if (!base) store.clear() },
728
- * }
729
- * })
730
- *
731
- * // Instantiate:
732
- * const storage = memoryStorage()
733
- * ```
734
- */
735
- function createStorage(build) {
736
- return (options) => build(options ?? {});
737
- }
738
- //#endregion
739
740
  //#region src/storages/fsStorage.ts
740
741
  /**
741
742
  * Built-in filesystem storage driver.
@@ -811,6 +812,44 @@ const fsStorage = createStorage(() => ({
811
812
  }));
812
813
  //#endregion
813
814
  //#region src/createKubb.ts
815
+ /**
816
+ * Builds a `Storage` view scoped to the file paths produced by the current build.
817
+ *
818
+ * Reads delegate to the underlying `storage` (typically `fsStorage()`) so source bytes
819
+ * stay where they were written instead of being held in an extra in-memory map.
820
+ * Writing via `setItem` stores the content in the underlying storage and registers the
821
+ * key so subsequent reads and `getKeys` are scoped to this build's output.
822
+ */
823
+ function createSourcesView(storage) {
824
+ const paths = /* @__PURE__ */ new Set();
825
+ return createStorage(() => ({
826
+ name: `${storage.name}:sources`,
827
+ async hasItem(key) {
828
+ return paths.has(key) && await storage.hasItem(key);
829
+ },
830
+ async getItem(key) {
831
+ return paths.has(key) ? storage.getItem(key) : null;
832
+ },
833
+ async setItem(key, value) {
834
+ paths.add(key);
835
+ await storage.setItem(key, value);
836
+ },
837
+ async removeItem(key) {
838
+ paths.delete(key);
839
+ await storage.removeItem(key);
840
+ },
841
+ async getKeys(base) {
842
+ if (!base) return [...paths];
843
+ const result = [];
844
+ for (const key of paths) if (key.startsWith(base)) result.push(key);
845
+ return result;
846
+ },
847
+ async clear() {
848
+ paths.clear();
849
+ await storage.clear();
850
+ }
851
+ }))();
852
+ }
814
853
  async function setup(userConfig, options = {}) {
815
854
  const hooks = options.hooks ?? new AsyncEventEmitter();
816
855
  const config = {
@@ -833,7 +872,7 @@ async function setup(userConfig, options = {}) {
833
872
  plugins: userConfig.plugins ?? []
834
873
  };
835
874
  const driver = new require_PluginDriver.PluginDriver(config, { hooks });
836
- const sources = /* @__PURE__ */ new Map();
875
+ const storage = createSourcesView(config.storage);
837
876
  const diagnosticInfo = getDiagnosticInfo();
838
877
  await hooks.emit("kubb:debug", {
839
878
  date: /* @__PURE__ */ new Date(),
@@ -898,7 +937,7 @@ async function setup(userConfig, options = {}) {
898
937
  config,
899
938
  hooks,
900
939
  driver,
901
- sources
940
+ storage
902
941
  };
903
942
  }
904
943
  /**
@@ -997,10 +1036,49 @@ async function runPluginAstHooks(plugin, context) {
997
1036
  }
998
1037
  }
999
1038
  async function safeBuild(setupResult) {
1000
- const { driver, hooks, sources } = setupResult;
1039
+ const { driver, hooks, storage } = setupResult;
1001
1040
  const failedPlugins = /* @__PURE__ */ new Set();
1002
1041
  const pluginTimings = /* @__PURE__ */ new Map();
1003
1042
  const config = driver.config;
1043
+ const writtenPaths = /* @__PURE__ */ new Set();
1044
+ const parsersMap = /* @__PURE__ */ new Map();
1045
+ for (const parser of config.parsers) if (parser.extNames) for (const extname of parser.extNames) parsersMap.set(extname, parser);
1046
+ const fileProcessor = new FileProcessor();
1047
+ fileProcessor.events.on("start", async (processingFiles) => {
1048
+ await hooks.emit("kubb:files:processing:start", { files: processingFiles });
1049
+ });
1050
+ fileProcessor.events.on("update", async ({ file, source, processed, total, percentage }) => {
1051
+ await hooks.emit("kubb:file:processing:update", {
1052
+ file,
1053
+ source,
1054
+ processed,
1055
+ total,
1056
+ percentage,
1057
+ config
1058
+ });
1059
+ if (source) await storage.setItem(file.path, source);
1060
+ });
1061
+ fileProcessor.events.on("end", async (processed) => {
1062
+ await hooks.emit("kubb:files:processing:end", { files: processed });
1063
+ await hooks.emit("kubb:debug", {
1064
+ date: /* @__PURE__ */ new Date(),
1065
+ logs: [`✓ File write process completed for ${processed.length} files`]
1066
+ });
1067
+ });
1068
+ async function flushPendingFiles() {
1069
+ const files = driver.fileManager.files.filter((f) => !writtenPaths.has(f.path));
1070
+ if (files.length === 0) return;
1071
+ await hooks.emit("kubb:debug", {
1072
+ date: /* @__PURE__ */ new Date(),
1073
+ logs: [`Writing ${files.length} files...`]
1074
+ });
1075
+ await fileProcessor.run(files, {
1076
+ parsers: parsersMap,
1077
+ mode: "parallel",
1078
+ extension: config.output.extension
1079
+ });
1080
+ for (const file of files) writtenPaths.add(file.path);
1081
+ }
1004
1082
  try {
1005
1083
  await driver.emitSetupHooks();
1006
1084
  if (driver.adapter && driver.inputNode) await hooks.emit("kubb:build:start", {
@@ -1036,6 +1114,7 @@ async function safeBuild(setupResult) {
1036
1114
  },
1037
1115
  upsertFile: (...files) => driver.fileManager.upsert(...files)
1038
1116
  });
1117
+ await flushPendingFiles();
1039
1118
  await hooks.emit("kubb:debug", {
1040
1119
  date: /* @__PURE__ */ new Date(),
1041
1120
  logs: [`✓ Plugin started successfully (${formatMs(duration)})`]
@@ -1055,6 +1134,7 @@ async function safeBuild(setupResult) {
1055
1134
  },
1056
1135
  upsertFile: (...files) => driver.fileManager.upsert(...files)
1057
1136
  });
1137
+ await flushPendingFiles();
1058
1138
  await hooks.emit("kubb:debug", {
1059
1139
  date: errorTimestamp,
1060
1140
  logs: [
@@ -1078,43 +1158,8 @@ async function safeBuild(setupResult) {
1078
1158
  },
1079
1159
  upsertFile: (...files) => driver.fileManager.upsert(...files)
1080
1160
  });
1161
+ await flushPendingFiles();
1081
1162
  const files = driver.fileManager.files;
1082
- const parsersMap = /* @__PURE__ */ new Map();
1083
- for (const parser of config.parsers) if (parser.extNames) for (const extname of parser.extNames) parsersMap.set(extname, parser);
1084
- const fileProcessor = new FileProcessor();
1085
- await hooks.emit("kubb:debug", {
1086
- date: /* @__PURE__ */ new Date(),
1087
- logs: [`Writing ${files.length} files...`]
1088
- });
1089
- await fileProcessor.run(files, {
1090
- parsers: parsersMap,
1091
- mode: "parallel",
1092
- extension: config.output.extension,
1093
- onStart: async (processingFiles) => {
1094
- await hooks.emit("kubb:files:processing:start", { files: processingFiles });
1095
- },
1096
- onUpdate: async ({ file, source, processed, total, percentage }) => {
1097
- await hooks.emit("kubb:file:processing:update", {
1098
- file,
1099
- source,
1100
- processed,
1101
- total,
1102
- percentage,
1103
- config
1104
- });
1105
- if (source) {
1106
- await config.storage.setItem(file.path, source);
1107
- sources.set(file.path, source);
1108
- }
1109
- },
1110
- onEnd: async (processedFiles) => {
1111
- await hooks.emit("kubb:files:processing:end", { files: processedFiles });
1112
- await hooks.emit("kubb:debug", {
1113
- date: /* @__PURE__ */ new Date(),
1114
- logs: [`✓ File write process completed for ${processedFiles.length} files`]
1115
- });
1116
- }
1117
- });
1118
1163
  await hooks.emit("kubb:build:end", {
1119
1164
  files,
1120
1165
  config,
@@ -1125,7 +1170,7 @@ async function safeBuild(setupResult) {
1125
1170
  files,
1126
1171
  driver,
1127
1172
  pluginTimings,
1128
- sources
1173
+ storage
1129
1174
  };
1130
1175
  } catch (error) {
1131
1176
  return {
@@ -1134,14 +1179,14 @@ async function safeBuild(setupResult) {
1134
1179
  driver,
1135
1180
  pluginTimings,
1136
1181
  error,
1137
- sources
1182
+ storage
1138
1183
  };
1139
1184
  } finally {
1140
1185
  driver.dispose();
1141
1186
  }
1142
1187
  }
1143
1188
  async function build(setupResult) {
1144
- const { files, driver, failedPlugins, pluginTimings, error, sources } = await safeBuild(setupResult);
1189
+ const { files, driver, failedPlugins, pluginTimings, error, storage } = await safeBuild(setupResult);
1145
1190
  if (error) throw error;
1146
1191
  if (failedPlugins.size > 0) {
1147
1192
  const errors = [...failedPlugins].map(({ error }) => error);
@@ -1153,7 +1198,7 @@ async function build(setupResult) {
1153
1198
  driver,
1154
1199
  pluginTimings,
1155
1200
  error: void 0,
1156
- sources
1201
+ storage
1157
1202
  };
1158
1203
  }
1159
1204
  /**
@@ -1194,7 +1239,7 @@ function inputToAdapterSource(config) {
1194
1239
  * Creates a Kubb instance bound to a single config entry.
1195
1240
  *
1196
1241
  * Accepts a user-facing config shape and resolves it to a full {@link Config} during
1197
- * `setup()`. The instance then holds shared state (`hooks`, `sources`, `driver`, `config`)
1242
+ * `setup()`. The instance then holds shared state (`hooks`, `storage`, `driver`, `config`)
1198
1243
  * across the `setup → build` lifecycle. Attach event listeners to `kubb.hooks` before
1199
1244
  * calling `setup()` or `build()`.
1200
1245
  *
@@ -1216,14 +1261,17 @@ function createKubb(userConfig, options = {}) {
1216
1261
  get hooks() {
1217
1262
  return hooks;
1218
1263
  },
1219
- get sources() {
1220
- return setupResult?.sources ?? /* @__PURE__ */ new Map();
1264
+ get storage() {
1265
+ if (!setupResult) throw new Error("[kubb] setup() must be called before accessing storage");
1266
+ return setupResult.storage;
1221
1267
  },
1222
1268
  get driver() {
1223
- return setupResult?.driver;
1269
+ if (!setupResult) throw new Error("[kubb] setup() must be called before accessing driver");
1270
+ return setupResult.driver;
1224
1271
  },
1225
1272
  get config() {
1226
- return setupResult?.config;
1273
+ if (!setupResult) throw new Error("[kubb] setup() must be called before accessing config");
1274
+ return setupResult.config;
1227
1275
  },
1228
1276
  async setup() {
1229
1277
  setupResult = await setup(userConfig, { hooks });