@kubb/core 5.0.0-beta.1 → 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.
- package/README.md +9 -39
- package/dist/{PluginDriver-BXibeQk-.cjs → PluginDriver-C1OsqGBJ.cjs} +106 -56
- package/dist/PluginDriver-C1OsqGBJ.cjs.map +1 -0
- package/dist/{PluginDriver-DV3p2Hky.js → PluginDriver-CGypdXHg.js} +101 -57
- package/dist/PluginDriver-CGypdXHg.js.map +1 -0
- package/dist/{types-CuNocrbJ.d.ts → createKubb-BSfMDBwR.d.ts} +1533 -1505
- package/dist/index.cjs +249 -209
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -185
- package/dist/index.js +249 -209
- package/dist/index.js.map +1 -1
- package/dist/mocks.cjs +1 -1
- package/dist/mocks.cjs.map +1 -1
- package/dist/mocks.d.ts +1 -1
- package/dist/mocks.js +1 -1
- package/dist/mocks.js.map +1 -1
- package/package.json +5 -12
- package/src/FileManager.ts +8 -0
- package/src/FileProcessor.ts +12 -7
- package/src/PluginDriver.ts +49 -7
- package/src/constants.ts +6 -2
- package/src/createAdapter.ts +77 -1
- package/src/createKubb.ts +973 -141
- package/src/defineGenerator.ts +92 -4
- package/src/defineLogger.ts +42 -3
- package/src/defineMiddleware.ts +1 -1
- package/src/definePlugin.ts +304 -8
- package/src/defineResolver.ts +185 -52
- package/src/devtools.ts +8 -1
- package/src/index.ts +1 -1
- package/src/mocks.ts +1 -2
- package/src/storages/fsStorage.ts +6 -31
- package/src/types.ts +38 -1292
- package/dist/PluginDriver-BXibeQk-.cjs.map +0 -1
- package/dist/PluginDriver-DV3p2Hky.js.map +0 -1
- package/src/Kubb.ts +0 -300
- package/src/renderNode.ts +0 -35
- package/src/utils/diagnostics.ts +0 -18
- package/src/utils/isInputPath.ts +0 -10
- package/src/utils/packageJSON.ts +0 -99
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_PluginDriver = require("./PluginDriver-
|
|
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");
|
|
@@ -524,6 +524,46 @@ function createAdapter(build) {
|
|
|
524
524
|
return (options) => build(options ?? {});
|
|
525
525
|
}
|
|
526
526
|
//#endregion
|
|
527
|
+
//#region package.json
|
|
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
|
+
}
|
|
566
|
+
//#endregion
|
|
527
567
|
//#region ../../node_modules/.pnpm/yocto-queue@1.2.2/node_modules/yocto-queue/index.js
|
|
528
568
|
var Node = class {
|
|
529
569
|
value;
|
|
@@ -662,7 +702,8 @@ function joinSources(file) {
|
|
|
662
702
|
* @internal
|
|
663
703
|
*/
|
|
664
704
|
var FileProcessor = class {
|
|
665
|
-
|
|
705
|
+
events = new AsyncEventEmitter();
|
|
706
|
+
#limit = pLimit(16);
|
|
666
707
|
async parse(file, { parsers, extension } = {}) {
|
|
667
708
|
const parseExtName = extension?.[file.extname] || void 0;
|
|
668
709
|
if (!parsers || !file.extname) return joinSources(file);
|
|
@@ -670,8 +711,8 @@ var FileProcessor = class {
|
|
|
670
711
|
if (!parser) return joinSources(file);
|
|
671
712
|
return parser.parse(file, { extname: parseExtName });
|
|
672
713
|
}
|
|
673
|
-
async run(files, { parsers, mode = "sequential", extension
|
|
674
|
-
await
|
|
714
|
+
async run(files, { parsers, mode = "sequential", extension } = {}) {
|
|
715
|
+
await this.events.emit("start", files);
|
|
675
716
|
const total = files.length;
|
|
676
717
|
let processed = 0;
|
|
677
718
|
const processOne = async (file) => {
|
|
@@ -681,7 +722,7 @@ var FileProcessor = class {
|
|
|
681
722
|
});
|
|
682
723
|
const currentProcessed = ++processed;
|
|
683
724
|
const percentage = currentProcessed / total * 100;
|
|
684
|
-
await
|
|
725
|
+
await this.events.emit("update", {
|
|
685
726
|
file,
|
|
686
727
|
source,
|
|
687
728
|
processed: currentProcessed,
|
|
@@ -691,56 +732,13 @@ var FileProcessor = class {
|
|
|
691
732
|
};
|
|
692
733
|
if (mode === "sequential") for (const file of files) await processOne(file);
|
|
693
734
|
else await Promise.all(files.map((file) => this.#limit(() => processOne(file))));
|
|
694
|
-
await
|
|
735
|
+
await this.events.emit("end", files);
|
|
695
736
|
return files;
|
|
696
737
|
}
|
|
697
738
|
};
|
|
698
739
|
//#endregion
|
|
699
|
-
//#region src/createStorage.ts
|
|
700
|
-
/**
|
|
701
|
-
* Factory for implementing custom storage backends that control where generated files are written.
|
|
702
|
-
*
|
|
703
|
-
* Takes a builder function `(options: TOptions) => Storage` and returns a factory `(options?: TOptions) => Storage`.
|
|
704
|
-
* Kubb provides filesystem and in-memory implementations out of the box.
|
|
705
|
-
*
|
|
706
|
-
* @note Call the returned factory with optional options to instantiate the storage adapter.
|
|
707
|
-
*
|
|
708
|
-
* @example
|
|
709
|
-
* ```ts
|
|
710
|
-
* import { createStorage } from '@kubb/core'
|
|
711
|
-
*
|
|
712
|
-
* export const memoryStorage = createStorage(() => {
|
|
713
|
-
* const store = new Map<string, string>()
|
|
714
|
-
* return {
|
|
715
|
-
* name: 'memory',
|
|
716
|
-
* async hasItem(key) { return store.has(key) },
|
|
717
|
-
* async getItem(key) { return store.get(key) ?? null },
|
|
718
|
-
* async setItem(key, value) { store.set(key, value) },
|
|
719
|
-
* async removeItem(key) { store.delete(key) },
|
|
720
|
-
* async getKeys(base) {
|
|
721
|
-
* const keys = [...store.keys()]
|
|
722
|
-
* return base ? keys.filter((k) => k.startsWith(base)) : keys
|
|
723
|
-
* },
|
|
724
|
-
* async clear(base) { if (!base) store.clear() },
|
|
725
|
-
* }
|
|
726
|
-
* })
|
|
727
|
-
*
|
|
728
|
-
* // Instantiate:
|
|
729
|
-
* const storage = memoryStorage()
|
|
730
|
-
* ```
|
|
731
|
-
*/
|
|
732
|
-
function createStorage(build) {
|
|
733
|
-
return (options) => build(options ?? {});
|
|
734
|
-
}
|
|
735
|
-
//#endregion
|
|
736
740
|
//#region src/storages/fsStorage.ts
|
|
737
741
|
/**
|
|
738
|
-
* Detects the filesystem error used to indicate that a path does not exist.
|
|
739
|
-
*/
|
|
740
|
-
function isMissingPathError(error) {
|
|
741
|
-
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
742
|
-
}
|
|
743
|
-
/**
|
|
744
742
|
* Built-in filesystem storage driver.
|
|
745
743
|
*
|
|
746
744
|
* This is the default storage when no `storage` option is configured in the root config.
|
|
@@ -771,17 +769,15 @@ const fsStorage = createStorage(() => ({
|
|
|
771
769
|
try {
|
|
772
770
|
await (0, node_fs_promises.access)((0, node_path.resolve)(key));
|
|
773
771
|
return true;
|
|
774
|
-
} catch (
|
|
775
|
-
|
|
776
|
-
throw new Error(`Failed to access storage item "${key}"`, { cause: error });
|
|
772
|
+
} catch (_error) {
|
|
773
|
+
return false;
|
|
777
774
|
}
|
|
778
775
|
},
|
|
779
776
|
async getItem(key) {
|
|
780
777
|
try {
|
|
781
778
|
return await (0, node_fs_promises.readFile)((0, node_path.resolve)(key), "utf8");
|
|
782
|
-
} catch (
|
|
783
|
-
|
|
784
|
-
throw new Error(`Failed to read storage item "${key}"`, { cause: error });
|
|
779
|
+
} catch (_error) {
|
|
780
|
+
return null;
|
|
785
781
|
}
|
|
786
782
|
},
|
|
787
783
|
async setItem(key, value) {
|
|
@@ -797,9 +793,8 @@ const fsStorage = createStorage(() => ({
|
|
|
797
793
|
let entries;
|
|
798
794
|
try {
|
|
799
795
|
entries = await (0, node_fs_promises.readdir)(dir, { withFileTypes: true });
|
|
800
|
-
} catch (
|
|
801
|
-
|
|
802
|
-
throw new Error(`Failed to list storage keys under "${resolvedBase}"`, { cause: error });
|
|
796
|
+
} catch (_error) {
|
|
797
|
+
return;
|
|
803
798
|
}
|
|
804
799
|
for (const entry of entries) {
|
|
805
800
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
@@ -816,37 +811,69 @@ const fsStorage = createStorage(() => ({
|
|
|
816
811
|
}
|
|
817
812
|
}));
|
|
818
813
|
//#endregion
|
|
819
|
-
//#region
|
|
820
|
-
var version = "5.0.0-beta.1";
|
|
821
|
-
//#endregion
|
|
822
|
-
//#region src/utils/diagnostics.ts
|
|
814
|
+
//#region src/createKubb.ts
|
|
823
815
|
/**
|
|
824
|
-
*
|
|
816
|
+
* Builds a `Storage` view scoped to the file paths produced by the current build.
|
|
825
817
|
*
|
|
826
|
-
*
|
|
827
|
-
*
|
|
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.
|
|
828
822
|
*/
|
|
829
|
-
function
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
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
|
+
}))();
|
|
842
852
|
}
|
|
843
|
-
//#endregion
|
|
844
|
-
//#region src/createKubb.ts
|
|
845
853
|
async function setup(userConfig, options = {}) {
|
|
846
854
|
const hooks = options.hooks ?? new AsyncEventEmitter();
|
|
847
|
-
const
|
|
855
|
+
const config = {
|
|
856
|
+
...userConfig,
|
|
857
|
+
root: userConfig.root || process.cwd(),
|
|
858
|
+
parsers: userConfig.parsers ?? [],
|
|
859
|
+
adapter: userConfig.adapter,
|
|
860
|
+
output: {
|
|
861
|
+
format: false,
|
|
862
|
+
lint: false,
|
|
863
|
+
extension: require_PluginDriver.DEFAULT_EXTENSION,
|
|
864
|
+
defaultBanner: require_PluginDriver.DEFAULT_BANNER,
|
|
865
|
+
...userConfig.output
|
|
866
|
+
},
|
|
867
|
+
storage: userConfig.storage ?? fsStorage(),
|
|
868
|
+
devtools: userConfig.devtools ? {
|
|
869
|
+
studioUrl: require_PluginDriver.DEFAULT_STUDIO_URL,
|
|
870
|
+
...typeof userConfig.devtools === "boolean" ? {} : userConfig.devtools
|
|
871
|
+
} : void 0,
|
|
872
|
+
plugins: userConfig.plugins ?? []
|
|
873
|
+
};
|
|
874
|
+
const driver = new require_PluginDriver.PluginDriver(config, { hooks });
|
|
875
|
+
const storage = createSourcesView(config.storage);
|
|
848
876
|
const diagnosticInfo = getDiagnosticInfo();
|
|
849
|
-
if (Array.isArray(userConfig.input)) await hooks.emit("kubb:warn", { message: "This feature is still under development — use with caution" });
|
|
850
877
|
await hooks.emit("kubb:debug", {
|
|
851
878
|
date: /* @__PURE__ */ new Date(),
|
|
852
879
|
logs: [
|
|
@@ -856,7 +883,7 @@ async function setup(userConfig, options = {}) {
|
|
|
856
883
|
` • Output: ${userConfig.output?.path || "not specified"}`,
|
|
857
884
|
` • Plugins: ${userConfig.plugins?.length || 0}`,
|
|
858
885
|
"Output Settings:",
|
|
859
|
-
` • Storage: ${
|
|
886
|
+
` • Storage: ${config.storage.name}`,
|
|
860
887
|
` • Formatter: ${userConfig.output?.format || "none"}`,
|
|
861
888
|
` • Linter: ${userConfig.output?.lint || "none"}`,
|
|
862
889
|
"Environment:",
|
|
@@ -877,73 +904,56 @@ async function setup(userConfig, options = {}) {
|
|
|
877
904
|
throw new Error(`Cannot read file/URL defined in \`input.path\` or set with \`kubb generate PATH\` in the CLI of your Kubb config ${userConfig.input.path}`, { cause: error });
|
|
878
905
|
}
|
|
879
906
|
}
|
|
880
|
-
if (!userConfig.adapter) throw new Error("Adapter should be defined");
|
|
881
|
-
const config = {
|
|
882
|
-
...userConfig,
|
|
883
|
-
root: userConfig.root || process.cwd(),
|
|
884
|
-
parsers: userConfig.parsers ?? [],
|
|
885
|
-
adapter: userConfig.adapter,
|
|
886
|
-
output: {
|
|
887
|
-
format: false,
|
|
888
|
-
lint: false,
|
|
889
|
-
write: true,
|
|
890
|
-
extension: require_PluginDriver.DEFAULT_EXTENSION,
|
|
891
|
-
defaultBanner: require_PluginDriver.DEFAULT_BANNER,
|
|
892
|
-
...userConfig.output
|
|
893
|
-
},
|
|
894
|
-
devtools: userConfig.devtools ? {
|
|
895
|
-
studioUrl: require_PluginDriver.DEFAULT_STUDIO_URL,
|
|
896
|
-
...typeof userConfig.devtools === "boolean" ? {} : userConfig.devtools
|
|
897
|
-
} : void 0,
|
|
898
|
-
plugins: userConfig.plugins
|
|
899
|
-
};
|
|
900
|
-
const storage = config.output.write === false ? null : config.storage ?? fsStorage();
|
|
901
907
|
if (config.output.clean) {
|
|
902
908
|
await hooks.emit("kubb:debug", {
|
|
903
909
|
date: /* @__PURE__ */ new Date(),
|
|
904
910
|
logs: ["Cleaning output directories", ` • Output: ${config.output.path}`]
|
|
905
911
|
});
|
|
906
|
-
await storage
|
|
912
|
+
await config.storage.clear((0, node_path.resolve)(config.root, config.output.path));
|
|
907
913
|
}
|
|
908
|
-
const driver = new require_PluginDriver.PluginDriver(config, { hooks });
|
|
909
914
|
function registerMiddlewareHook(event, middlewareHooks) {
|
|
910
915
|
const handler = middlewareHooks[event];
|
|
911
916
|
if (handler) hooks.on(event, handler);
|
|
912
917
|
}
|
|
913
918
|
for (const middleware of config.middleware ?? []) for (const event of Object.keys(middleware.hooks)) registerMiddlewareHook(event, middleware.hooks);
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
}
|
|
919
|
+
if (config.adapter) {
|
|
920
|
+
const source = inputToAdapterSource(config);
|
|
921
|
+
await hooks.emit("kubb:debug", {
|
|
922
|
+
date: /* @__PURE__ */ new Date(),
|
|
923
|
+
logs: [`Running adapter: ${config.adapter.name}`]
|
|
924
|
+
});
|
|
925
|
+
driver.adapter = config.adapter;
|
|
926
|
+
driver.inputNode = await config.adapter.parse(source);
|
|
927
|
+
await hooks.emit("kubb:debug", {
|
|
928
|
+
date: /* @__PURE__ */ new Date(),
|
|
929
|
+
logs: [
|
|
930
|
+
`✓ Adapter '${config.adapter.name}' resolved InputNode`,
|
|
931
|
+
` • Schemas: ${driver.inputNode.schemas.length}`,
|
|
932
|
+
` • Operations: ${driver.inputNode.operations.length}`
|
|
933
|
+
]
|
|
934
|
+
});
|
|
935
|
+
}
|
|
931
936
|
return {
|
|
932
937
|
config,
|
|
933
938
|
hooks,
|
|
934
939
|
driver,
|
|
935
|
-
sources,
|
|
936
940
|
storage
|
|
937
941
|
};
|
|
938
942
|
}
|
|
939
943
|
/**
|
|
940
944
|
* Walks the AST and dispatches nodes to a plugin's direct AST hooks
|
|
941
945
|
* (`schema`, `operation`, `operations`).
|
|
946
|
+
*
|
|
947
|
+
* When `include` contains only operation-scoped filters (`tag`, `operationId`, `path`,
|
|
948
|
+
* `method`, `contentType`) and no `schemaName` filter, the function pre-computes the set
|
|
949
|
+
* of top-level schema names transitively reachable from the included operations and skips
|
|
950
|
+
* schemas that fall outside that set. This ensures that component schemas referenced
|
|
951
|
+
* exclusively by excluded operations are not generated.
|
|
942
952
|
*/
|
|
943
953
|
async function runPluginAstHooks(plugin, context) {
|
|
944
954
|
const { adapter, inputNode, resolver, driver } = context;
|
|
945
955
|
const { exclude, include, override } = plugin.options;
|
|
946
|
-
if (!adapter || !inputNode) throw new Error(`[${plugin.name}] No adapter found. Add an OAS adapter (e.g.
|
|
956
|
+
if (!adapter || !inputNode) throw new Error(`[${plugin.name}] No adapter found. Add an OAS adapter (e.g. adapterOas()) before this plugin in your Kubb config.`);
|
|
947
957
|
function resolveRenderer(gen) {
|
|
948
958
|
return gen.renderer === null ? void 0 : gen.renderer ?? plugin.renderer ?? context.config.renderer;
|
|
949
959
|
}
|
|
@@ -953,10 +963,27 @@ async function runPluginAstHooks(plugin, context) {
|
|
|
953
963
|
...context,
|
|
954
964
|
resolver: driver.getResolver(plugin.name)
|
|
955
965
|
};
|
|
966
|
+
const operationFilterTypes = new Set([
|
|
967
|
+
"tag",
|
|
968
|
+
"operationId",
|
|
969
|
+
"path",
|
|
970
|
+
"method",
|
|
971
|
+
"contentType"
|
|
972
|
+
]);
|
|
973
|
+
const hasOperationBasedIncludes = include?.some(({ type }) => operationFilterTypes.has(type)) ?? false;
|
|
974
|
+
const hasSchemaNameIncludes = include?.some(({ type }) => type === "schemaName") ?? false;
|
|
975
|
+
let allowedSchemaNames;
|
|
976
|
+
if (hasOperationBasedIncludes && !hasSchemaNameIncludes) allowedSchemaNames = (0, _kubb_ast.collectUsedSchemaNames)(inputNode.operations.filter((op) => resolver.resolveOptions(op, {
|
|
977
|
+
options: plugin.options,
|
|
978
|
+
exclude,
|
|
979
|
+
include,
|
|
980
|
+
override
|
|
981
|
+
}) !== null), inputNode.schemas);
|
|
956
982
|
await (0, _kubb_ast.walk)(inputNode, {
|
|
957
983
|
depth: "shallow",
|
|
958
984
|
async schema(node) {
|
|
959
985
|
const transformedNode = plugin.transformer ? (0, _kubb_ast.transform)(node, plugin.transformer) : node;
|
|
986
|
+
if (allowedSchemaNames !== void 0 && transformedNode.name && !allowedSchemaNames.has(transformedNode.name)) return;
|
|
960
987
|
const options = resolver.resolveOptions(transformedNode, {
|
|
961
988
|
options: plugin.options,
|
|
962
989
|
exclude,
|
|
@@ -1009,10 +1036,49 @@ async function runPluginAstHooks(plugin, context) {
|
|
|
1009
1036
|
}
|
|
1010
1037
|
}
|
|
1011
1038
|
async function safeBuild(setupResult) {
|
|
1012
|
-
const { driver, hooks,
|
|
1039
|
+
const { driver, hooks, storage } = setupResult;
|
|
1013
1040
|
const failedPlugins = /* @__PURE__ */ new Set();
|
|
1014
1041
|
const pluginTimings = /* @__PURE__ */ new Map();
|
|
1015
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
|
+
}
|
|
1016
1082
|
try {
|
|
1017
1083
|
await driver.emitSetupHooks();
|
|
1018
1084
|
if (driver.adapter && driver.inputNode) await hooks.emit("kubb:build:start", {
|
|
@@ -1048,6 +1114,7 @@ async function safeBuild(setupResult) {
|
|
|
1048
1114
|
},
|
|
1049
1115
|
upsertFile: (...files) => driver.fileManager.upsert(...files)
|
|
1050
1116
|
});
|
|
1117
|
+
await flushPendingFiles();
|
|
1051
1118
|
await hooks.emit("kubb:debug", {
|
|
1052
1119
|
date: /* @__PURE__ */ new Date(),
|
|
1053
1120
|
logs: [`✓ Plugin started successfully (${formatMs(duration)})`]
|
|
@@ -1067,6 +1134,7 @@ async function safeBuild(setupResult) {
|
|
|
1067
1134
|
},
|
|
1068
1135
|
upsertFile: (...files) => driver.fileManager.upsert(...files)
|
|
1069
1136
|
});
|
|
1137
|
+
await flushPendingFiles();
|
|
1070
1138
|
await hooks.emit("kubb:debug", {
|
|
1071
1139
|
date: errorTimestamp,
|
|
1072
1140
|
logs: [
|
|
@@ -1090,42 +1158,8 @@ async function safeBuild(setupResult) {
|
|
|
1090
1158
|
},
|
|
1091
1159
|
upsertFile: (...files) => driver.fileManager.upsert(...files)
|
|
1092
1160
|
});
|
|
1161
|
+
await flushPendingFiles();
|
|
1093
1162
|
const files = driver.fileManager.files;
|
|
1094
|
-
const parsersMap = /* @__PURE__ */ new Map();
|
|
1095
|
-
for (const parser of config.parsers) if (parser.extNames) for (const extname of parser.extNames) parsersMap.set(extname, parser);
|
|
1096
|
-
const fileProcessor = new FileProcessor();
|
|
1097
|
-
await hooks.emit("kubb:debug", {
|
|
1098
|
-
date: /* @__PURE__ */ new Date(),
|
|
1099
|
-
logs: [`Writing ${files.length} files...`]
|
|
1100
|
-
});
|
|
1101
|
-
await fileProcessor.run(files, {
|
|
1102
|
-
parsers: parsersMap,
|
|
1103
|
-
extension: config.output.extension,
|
|
1104
|
-
onStart: async (processingFiles) => {
|
|
1105
|
-
await hooks.emit("kubb:files:processing:start", { files: processingFiles });
|
|
1106
|
-
},
|
|
1107
|
-
onUpdate: async ({ file, source, processed, total, percentage }) => {
|
|
1108
|
-
await hooks.emit("kubb:file:processing:update", {
|
|
1109
|
-
file,
|
|
1110
|
-
source,
|
|
1111
|
-
processed,
|
|
1112
|
-
total,
|
|
1113
|
-
percentage,
|
|
1114
|
-
config
|
|
1115
|
-
});
|
|
1116
|
-
if (source) {
|
|
1117
|
-
await storage?.setItem(file.path, source);
|
|
1118
|
-
sources.set(file.path, source);
|
|
1119
|
-
}
|
|
1120
|
-
},
|
|
1121
|
-
onEnd: async (processedFiles) => {
|
|
1122
|
-
await hooks.emit("kubb:files:processing:end", { files: processedFiles });
|
|
1123
|
-
await hooks.emit("kubb:debug", {
|
|
1124
|
-
date: /* @__PURE__ */ new Date(),
|
|
1125
|
-
logs: [`✓ File write process completed for ${processedFiles.length} files`]
|
|
1126
|
-
});
|
|
1127
|
-
}
|
|
1128
|
-
});
|
|
1129
1163
|
await hooks.emit("kubb:build:end", {
|
|
1130
1164
|
files,
|
|
1131
1165
|
config,
|
|
@@ -1136,7 +1170,7 @@ async function safeBuild(setupResult) {
|
|
|
1136
1170
|
files,
|
|
1137
1171
|
driver,
|
|
1138
1172
|
pluginTimings,
|
|
1139
|
-
|
|
1173
|
+
storage
|
|
1140
1174
|
};
|
|
1141
1175
|
} catch (error) {
|
|
1142
1176
|
return {
|
|
@@ -1145,14 +1179,14 @@ async function safeBuild(setupResult) {
|
|
|
1145
1179
|
driver,
|
|
1146
1180
|
pluginTimings,
|
|
1147
1181
|
error,
|
|
1148
|
-
|
|
1182
|
+
storage
|
|
1149
1183
|
};
|
|
1150
1184
|
} finally {
|
|
1151
1185
|
driver.dispose();
|
|
1152
1186
|
}
|
|
1153
1187
|
}
|
|
1154
1188
|
async function build(setupResult) {
|
|
1155
|
-
const { files, driver, failedPlugins, pluginTimings, error,
|
|
1189
|
+
const { files, driver, failedPlugins, pluginTimings, error, storage } = await safeBuild(setupResult);
|
|
1156
1190
|
if (error) throw error;
|
|
1157
1191
|
if (failedPlugins.size > 0) {
|
|
1158
1192
|
const errors = [...failedPlugins].map(({ error }) => error);
|
|
@@ -1164,32 +1198,48 @@ async function build(setupResult) {
|
|
|
1164
1198
|
driver,
|
|
1165
1199
|
pluginTimings,
|
|
1166
1200
|
error: void 0,
|
|
1167
|
-
|
|
1201
|
+
storage
|
|
1168
1202
|
};
|
|
1169
1203
|
}
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1204
|
+
/**
|
|
1205
|
+
* Returns a snapshot of the current runtime environment.
|
|
1206
|
+
*
|
|
1207
|
+
* Useful for attaching context to debug logs and error reports so that
|
|
1208
|
+
* issues can be reproduced without manual information gathering.
|
|
1209
|
+
*/
|
|
1210
|
+
function getDiagnosticInfo() {
|
|
1211
|
+
return {
|
|
1212
|
+
nodeVersion: node_process.version,
|
|
1213
|
+
KubbVersion: version,
|
|
1214
|
+
platform: process.platform,
|
|
1215
|
+
arch: process.arch,
|
|
1216
|
+
cwd: process.cwd()
|
|
1174
1217
|
};
|
|
1175
|
-
|
|
1218
|
+
}
|
|
1219
|
+
function isInputPath(config) {
|
|
1220
|
+
return typeof config?.input === "object" && config.input !== null && "path" in config.input;
|
|
1221
|
+
}
|
|
1222
|
+
function inputToAdapterSource(config) {
|
|
1223
|
+
const input = config.input;
|
|
1224
|
+
if (!input) throw new Error("[kubb] input is required when using an adapter. Provide input.path or input.data in your config.");
|
|
1225
|
+
if ("data" in input) return {
|
|
1176
1226
|
type: "data",
|
|
1177
|
-
data:
|
|
1227
|
+
data: input.data
|
|
1178
1228
|
};
|
|
1179
|
-
if (new URLPath(
|
|
1229
|
+
if (new URLPath(input.path).isURL) return {
|
|
1180
1230
|
type: "path",
|
|
1181
|
-
path:
|
|
1231
|
+
path: input.path
|
|
1182
1232
|
};
|
|
1183
1233
|
return {
|
|
1184
1234
|
type: "path",
|
|
1185
|
-
path: (0, node_path.resolve)(config.root,
|
|
1235
|
+
path: (0, node_path.resolve)(config.root, input.path)
|
|
1186
1236
|
};
|
|
1187
1237
|
}
|
|
1188
1238
|
/**
|
|
1189
1239
|
* Creates a Kubb instance bound to a single config entry.
|
|
1190
1240
|
*
|
|
1191
1241
|
* Accepts a user-facing config shape and resolves it to a full {@link Config} during
|
|
1192
|
-
* `setup()`. The instance then holds shared state (`hooks`, `
|
|
1242
|
+
* `setup()`. The instance then holds shared state (`hooks`, `storage`, `driver`, `config`)
|
|
1193
1243
|
* across the `setup → build` lifecycle. Attach event listeners to `kubb.hooks` before
|
|
1194
1244
|
* calling `setup()` or `build()`.
|
|
1195
1245
|
*
|
|
@@ -1211,14 +1261,17 @@ function createKubb(userConfig, options = {}) {
|
|
|
1211
1261
|
get hooks() {
|
|
1212
1262
|
return hooks;
|
|
1213
1263
|
},
|
|
1214
|
-
get
|
|
1215
|
-
|
|
1264
|
+
get storage() {
|
|
1265
|
+
if (!setupResult) throw new Error("[kubb] setup() must be called before accessing storage");
|
|
1266
|
+
return setupResult.storage;
|
|
1216
1267
|
},
|
|
1217
1268
|
get driver() {
|
|
1218
|
-
|
|
1269
|
+
if (!setupResult) throw new Error("[kubb] setup() must be called before accessing driver");
|
|
1270
|
+
return setupResult.driver;
|
|
1219
1271
|
},
|
|
1220
1272
|
get config() {
|
|
1221
|
-
|
|
1273
|
+
if (!setupResult) throw new Error("[kubb] setup() must be called before accessing config");
|
|
1274
|
+
return setupResult.config;
|
|
1222
1275
|
},
|
|
1223
1276
|
async setup() {
|
|
1224
1277
|
setupResult = await setup(userConfig, { hooks });
|
|
@@ -1282,7 +1335,11 @@ function defineGenerator(generator) {
|
|
|
1282
1335
|
/**
|
|
1283
1336
|
* Wraps a logger definition into a typed {@link Logger}.
|
|
1284
1337
|
*
|
|
1285
|
-
*
|
|
1338
|
+
* The optional second type parameter `TInstallReturn` allows loggers to return
|
|
1339
|
+
* a value from `install` — for example, a sink factory that the caller can
|
|
1340
|
+
* forward to hook execution.
|
|
1341
|
+
*
|
|
1342
|
+
* @example Basic logger
|
|
1286
1343
|
* ```ts
|
|
1287
1344
|
* export const myLogger = defineLogger({
|
|
1288
1345
|
* name: 'my-logger',
|
|
@@ -1292,6 +1349,17 @@ function defineGenerator(generator) {
|
|
|
1292
1349
|
* },
|
|
1293
1350
|
* })
|
|
1294
1351
|
* ```
|
|
1352
|
+
*
|
|
1353
|
+
* @example Logger that returns a hook sink factory
|
|
1354
|
+
* ```ts
|
|
1355
|
+
* export const myLogger = defineLogger<LoggerOptions, HookSinkFactory>({
|
|
1356
|
+
* name: 'my-logger',
|
|
1357
|
+
* install(context, options) {
|
|
1358
|
+
* // … register event handlers …
|
|
1359
|
+
* return (commandWithArgs) => ({ onStdout: console.log })
|
|
1360
|
+
* },
|
|
1361
|
+
* })
|
|
1362
|
+
* ```
|
|
1295
1363
|
*/
|
|
1296
1364
|
function defineLogger(logger) {
|
|
1297
1365
|
return logger;
|
|
@@ -1362,34 +1430,6 @@ function defineParser(parser) {
|
|
|
1362
1430
|
return parser;
|
|
1363
1431
|
}
|
|
1364
1432
|
//#endregion
|
|
1365
|
-
//#region src/definePlugin.ts
|
|
1366
|
-
/**
|
|
1367
|
-
* Wraps a factory function and returns a typed `Plugin` with lifecycle handlers grouped under `hooks`.
|
|
1368
|
-
*
|
|
1369
|
-
* Handlers live in a single `hooks` object (inspired by Astro integrations).
|
|
1370
|
-
* All lifecycle events from `KubbHooks` are available for subscription.
|
|
1371
|
-
*
|
|
1372
|
-
* @note For real plugins, use a `PluginFactoryOptions` type parameter to get type-safe context in `kubb:plugin:setup`.
|
|
1373
|
-
* Plugin names should follow the convention `plugin-<feature>` (e.g., `plugin-react-query`, `plugin-zod`).
|
|
1374
|
-
*
|
|
1375
|
-
* @example
|
|
1376
|
-
* ```ts
|
|
1377
|
-
* import { definePlugin } from '@kubb/core'
|
|
1378
|
-
*
|
|
1379
|
-
* export const pluginTs = definePlugin((options: { prefix?: string } = {}) => ({
|
|
1380
|
-
* name: 'plugin-ts',
|
|
1381
|
-
* hooks: {
|
|
1382
|
-
* 'kubb:plugin:setup'(ctx) {
|
|
1383
|
-
* ctx.setResolver(resolverTs)
|
|
1384
|
-
* },
|
|
1385
|
-
* },
|
|
1386
|
-
* }))
|
|
1387
|
-
* ```
|
|
1388
|
-
*/
|
|
1389
|
-
function definePlugin(factory) {
|
|
1390
|
-
return (options) => factory(options ?? {});
|
|
1391
|
-
}
|
|
1392
|
-
//#endregion
|
|
1393
1433
|
//#region src/storages/memoryStorage.ts
|
|
1394
1434
|
/**
|
|
1395
1435
|
* In-memory storage driver. Useful for testing and dry-run scenarios where
|
|
@@ -1459,7 +1499,7 @@ exports.defineGenerator = defineGenerator;
|
|
|
1459
1499
|
exports.defineLogger = defineLogger;
|
|
1460
1500
|
exports.defineMiddleware = defineMiddleware;
|
|
1461
1501
|
exports.defineParser = defineParser;
|
|
1462
|
-
exports.definePlugin = definePlugin;
|
|
1502
|
+
exports.definePlugin = require_PluginDriver.definePlugin;
|
|
1463
1503
|
exports.defineResolver = require_PluginDriver.defineResolver;
|
|
1464
1504
|
exports.fsStorage = fsStorage;
|
|
1465
1505
|
exports.isInputPath = isInputPath;
|