@kubb/core 5.0.0-alpha.33 → 5.0.0-alpha.35
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/{PluginDriver-BBi_41VF.d.ts → PluginDriver-D8lWvtUg.d.ts} +743 -375
- package/dist/hooks.d.ts +1 -1
- package/dist/index.cjs +1203 -932
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +22 -141
- package/dist/index.js +1220 -942
- package/dist/index.js.map +1 -1
- package/package.json +4 -5
- package/src/FileManager.ts +1 -1
- package/src/FileProcessor.ts +1 -1
- package/src/Kubb.ts +145 -38
- package/src/PluginDriver.ts +318 -40
- package/src/constants.ts +1 -1
- package/src/{build.ts → createKubb.ts} +180 -122
- package/src/createPlugin.ts +1 -0
- package/src/createRenderer.ts +57 -0
- package/src/defineGenerator.ts +57 -84
- package/src/defineLogger.ts +2 -2
- package/src/defineParser.ts +3 -2
- package/src/definePlugin.ts +95 -0
- package/src/defineResolver.ts +1 -1
- package/src/devtools.ts +1 -1
- package/src/index.ts +5 -6
- package/src/renderNode.ts +35 -0
- package/src/types.ts +275 -209
- package/src/utils/TreeNode.ts +1 -1
- package/src/utils/getBarrelFiles.ts +3 -3
- package/src/utils/getFunctionParams.ts +14 -7
- package/src/utils/isInputPath.ts +2 -2
- package/src/utils/packageJSON.ts +2 -3
- package/src/defineConfig.ts +0 -51
- package/src/definePresets.ts +0 -16
- package/src/renderNode.tsx +0 -28
- package/src/utils/getConfigs.ts +0 -16
- package/src/utils/getPreset.ts +0 -78
package/dist/index.cjs
CHANGED
|
@@ -1,23 +1,17 @@
|
|
|
1
|
-
Object.
|
|
2
|
-
__esModule: { value: true },
|
|
3
|
-
[Symbol.toStringTag]: { value: "Module" }
|
|
4
|
-
});
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
5
2
|
const require_chunk = require("./chunk-ByKO4r7w.cjs");
|
|
6
3
|
let node_events = require("node:events");
|
|
7
4
|
let node_fs = require("node:fs");
|
|
8
5
|
let node_fs_promises = require("node:fs/promises");
|
|
9
6
|
let node_path = require("node:path");
|
|
10
|
-
node_path = require_chunk.__toESM(node_path);
|
|
7
|
+
node_path = require_chunk.__toESM(node_path, 1);
|
|
11
8
|
let _kubb_ast = require("@kubb/ast");
|
|
9
|
+
_kubb_ast = require_chunk.__toESM(_kubb_ast, 1);
|
|
12
10
|
let node_perf_hooks = require("node:perf_hooks");
|
|
13
11
|
let fflate = require("fflate");
|
|
14
12
|
let tinyexec = require("tinyexec");
|
|
15
|
-
let _kubb_renderer_jsx = require("@kubb/renderer-jsx");
|
|
16
|
-
let _kubb_renderer_jsx_jsx_runtime = require("@kubb/renderer-jsx/jsx-runtime");
|
|
17
13
|
let node_process = require("node:process");
|
|
18
14
|
let remeda = require("remeda");
|
|
19
|
-
let empathic_package = require("empathic/package");
|
|
20
|
-
empathic_package = require_chunk.__toESM(empathic_package);
|
|
21
15
|
let semver = require("semver");
|
|
22
16
|
//#region ../../internals/utils/src/errors.ts
|
|
23
17
|
/**
|
|
@@ -135,6 +129,18 @@ var AsyncEventEmitter = class {
|
|
|
135
129
|
this.#emitter.off(eventName, handler);
|
|
136
130
|
}
|
|
137
131
|
/**
|
|
132
|
+
* Returns the number of listeners registered for `eventName`.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```ts
|
|
136
|
+
* emitter.on('build', handler)
|
|
137
|
+
* emitter.listenerCount('build') // 1
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
listenerCount(eventName) {
|
|
141
|
+
return this.#emitter.listenerCount(eventName);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
138
144
|
* Removes all listeners from every event channel.
|
|
139
145
|
*
|
|
140
146
|
* @example
|
|
@@ -240,6 +246,26 @@ function formatMs(ms) {
|
|
|
240
246
|
//#endregion
|
|
241
247
|
//#region ../../internals/utils/src/fs.ts
|
|
242
248
|
/**
|
|
249
|
+
* Walks up the directory tree from `cwd` (defaults to `process.cwd()`) and
|
|
250
|
+
* returns the absolute path of the nearest `package.json`, or `null` when none
|
|
251
|
+
* is found before reaching the filesystem root.
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```ts
|
|
255
|
+
* const pkgPath = findPackageJSON('/home/user/project/src') // '/home/user/project/package.json'
|
|
256
|
+
* ```
|
|
257
|
+
*/
|
|
258
|
+
function findPackageJSON(cwd) {
|
|
259
|
+
let dir = cwd ? (0, node_path.resolve)(cwd) : process.cwd();
|
|
260
|
+
while (true) {
|
|
261
|
+
const pkgPath = (0, node_path.join)(dir, "package.json");
|
|
262
|
+
if ((0, node_fs.existsSync)(pkgPath)) return pkgPath;
|
|
263
|
+
const parent = (0, node_path.dirname)(dir);
|
|
264
|
+
if (parent === dir) return null;
|
|
265
|
+
dir = parent;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
243
269
|
* Converts all backslashes to forward slashes.
|
|
244
270
|
* Extended-length Windows paths (`\\?\...`) are left unchanged.
|
|
245
271
|
*/
|
|
@@ -728,6 +754,26 @@ const formatters = {
|
|
|
728
754
|
}
|
|
729
755
|
};
|
|
730
756
|
//#endregion
|
|
757
|
+
//#region src/createAdapter.ts
|
|
758
|
+
/**
|
|
759
|
+
* Creates an adapter factory. Call the returned function with optional options to get the adapter instance.
|
|
760
|
+
*
|
|
761
|
+
* @example
|
|
762
|
+
* export const myAdapter = createAdapter<MyAdapter>((options) => {
|
|
763
|
+
* return {
|
|
764
|
+
* name: 'my-adapter',
|
|
765
|
+
* options,
|
|
766
|
+
* async parse(source) { ... },
|
|
767
|
+
* }
|
|
768
|
+
* })
|
|
769
|
+
*
|
|
770
|
+
* // instantiate
|
|
771
|
+
* const adapter = myAdapter({ validate: true })
|
|
772
|
+
*/
|
|
773
|
+
function createAdapter(build) {
|
|
774
|
+
return (options) => build(options ?? {});
|
|
775
|
+
}
|
|
776
|
+
//#endregion
|
|
731
777
|
//#region ../../node_modules/.pnpm/yocto-queue@1.2.2/node_modules/yocto-queue/index.js
|
|
732
778
|
var Node = class {
|
|
733
779
|
value;
|
|
@@ -898,214 +944,612 @@ var FileProcessor = class {
|
|
|
898
944
|
}
|
|
899
945
|
};
|
|
900
946
|
//#endregion
|
|
901
|
-
//#region src/
|
|
947
|
+
//#region src/definePlugin.ts
|
|
902
948
|
/**
|
|
903
|
-
*
|
|
904
|
-
*
|
|
905
|
-
* The JSON representation is deflate-compressed with {@link deflateSync} before
|
|
906
|
-
* base64url encoding, which typically reduces payload size by 70–80 % and
|
|
907
|
-
* keeps URLs well within browser and server path-length limits.
|
|
949
|
+
* Returns `true` when `plugin` is a hook-style plugin created with `definePlugin`.
|
|
908
950
|
*
|
|
909
|
-
*
|
|
910
|
-
|
|
911
|
-
function encodeAst(input) {
|
|
912
|
-
const compressed = (0, fflate.deflateSync)(new TextEncoder().encode(JSON.stringify(input)));
|
|
913
|
-
return Buffer.from(compressed).toString("base64url");
|
|
914
|
-
}
|
|
915
|
-
/**
|
|
916
|
-
* Constructs the Kubb Studio URL for the given `InputNode`.
|
|
917
|
-
* When `options.ast` is `true`, navigates to the AST inspector (`/ast`).
|
|
918
|
-
* The `input` is encoded and attached as the `?root=` query parameter so Studio
|
|
919
|
-
* can decode and render it without a round-trip to any server.
|
|
951
|
+
* Used by `PluginDriver` to distinguish hook-style plugins from legacy `createPlugin` plugins
|
|
952
|
+
* so it can normalize them and register their handlers on the `AsyncEventEmitter`.
|
|
920
953
|
*/
|
|
921
|
-
function
|
|
922
|
-
return
|
|
954
|
+
function isHookStylePlugin(plugin) {
|
|
955
|
+
return typeof plugin === "object" && plugin !== null && "hooks" in plugin;
|
|
923
956
|
}
|
|
924
957
|
/**
|
|
925
|
-
*
|
|
958
|
+
* Creates a plugin factory using the new hook-style (`hooks:`) API.
|
|
926
959
|
*
|
|
927
|
-
*
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
const url = getStudioUrl(input, studioUrl, options);
|
|
931
|
-
const cmd = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
|
|
932
|
-
const args = process.platform === "win32" ? [
|
|
933
|
-
"/c",
|
|
934
|
-
"start",
|
|
935
|
-
"",
|
|
936
|
-
url
|
|
937
|
-
] : [url];
|
|
938
|
-
try {
|
|
939
|
-
await (0, tinyexec.x)(cmd, args);
|
|
940
|
-
} catch {
|
|
941
|
-
console.log(`\n ${url}\n`);
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
//#endregion
|
|
945
|
-
//#region src/FileManager.ts
|
|
946
|
-
function mergeFile(a, b) {
|
|
947
|
-
return {
|
|
948
|
-
...a,
|
|
949
|
-
sources: [...a.sources || [], ...b.sources || []],
|
|
950
|
-
imports: [...a.imports || [], ...b.imports || []],
|
|
951
|
-
exports: [...a.exports || [], ...b.exports || []]
|
|
952
|
-
};
|
|
953
|
-
}
|
|
954
|
-
/**
|
|
955
|
-
* In-memory file store for generated files.
|
|
960
|
+
* The returned factory is called with optional options and produces a `HookStylePlugin`
|
|
961
|
+
* that coexists with plugins created via the legacy `createPlugin` API in the same
|
|
962
|
+
* `kubb.config.ts`.
|
|
956
963
|
*
|
|
957
|
-
*
|
|
958
|
-
*
|
|
964
|
+
* Lifecycle handlers are registered on the `PluginDriver`'s `AsyncEventEmitter`, enabling
|
|
965
|
+
* both the plugin's own handlers and external tooling (CLI, devtools) to observe every event.
|
|
959
966
|
*
|
|
960
967
|
* @example
|
|
961
968
|
* ```ts
|
|
962
|
-
*
|
|
963
|
-
*
|
|
964
|
-
*
|
|
965
|
-
*
|
|
966
|
-
*
|
|
969
|
+
* // With PluginFactoryOptions (recommended for real plugins)
|
|
970
|
+
* export const pluginTs = definePlugin<PluginTs>((options) => ({
|
|
971
|
+
* name: 'plugin-ts',
|
|
972
|
+
* hooks: {
|
|
973
|
+
* 'kubb:plugin:setup'(ctx) {
|
|
974
|
+
* ctx.setResolver(resolverTs) // typed as Partial<ResolverTs>
|
|
975
|
+
* },
|
|
976
|
+
* },
|
|
977
|
+
* }))
|
|
967
978
|
* ```
|
|
968
979
|
*/
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
/**
|
|
973
|
-
* Adds one or more files. Files with the same path are merged — sources, imports,
|
|
974
|
-
* and exports from all calls with the same path are concatenated together.
|
|
975
|
-
*/
|
|
976
|
-
add(...files) {
|
|
977
|
-
const resolvedFiles = [];
|
|
978
|
-
const mergedFiles = /* @__PURE__ */ new Map();
|
|
979
|
-
files.forEach((file) => {
|
|
980
|
-
const existing = mergedFiles.get(file.path);
|
|
981
|
-
if (existing) mergedFiles.set(file.path, mergeFile(existing, file));
|
|
982
|
-
else mergedFiles.set(file.path, file);
|
|
983
|
-
});
|
|
984
|
-
for (const file of mergedFiles.values()) {
|
|
985
|
-
const resolvedFile = (0, _kubb_ast.createFile)(file);
|
|
986
|
-
this.#cache.set(resolvedFile.path, resolvedFile);
|
|
987
|
-
this.#filesCache = null;
|
|
988
|
-
resolvedFiles.push(resolvedFile);
|
|
989
|
-
}
|
|
990
|
-
return resolvedFiles;
|
|
991
|
-
}
|
|
992
|
-
/**
|
|
993
|
-
* Adds or merges one or more files.
|
|
994
|
-
* If a file with the same path already exists, its sources/imports/exports are merged together.
|
|
995
|
-
*/
|
|
996
|
-
upsert(...files) {
|
|
997
|
-
const resolvedFiles = [];
|
|
998
|
-
const mergedFiles = /* @__PURE__ */ new Map();
|
|
999
|
-
files.forEach((file) => {
|
|
1000
|
-
const existing = mergedFiles.get(file.path);
|
|
1001
|
-
if (existing) mergedFiles.set(file.path, mergeFile(existing, file));
|
|
1002
|
-
else mergedFiles.set(file.path, file);
|
|
1003
|
-
});
|
|
1004
|
-
for (const file of mergedFiles.values()) {
|
|
1005
|
-
const existing = this.#cache.get(file.path);
|
|
1006
|
-
const resolvedFile = (0, _kubb_ast.createFile)(existing ? mergeFile(existing, file) : file);
|
|
1007
|
-
this.#cache.set(resolvedFile.path, resolvedFile);
|
|
1008
|
-
this.#filesCache = null;
|
|
1009
|
-
resolvedFiles.push(resolvedFile);
|
|
1010
|
-
}
|
|
1011
|
-
return resolvedFiles;
|
|
1012
|
-
}
|
|
1013
|
-
getByPath(path) {
|
|
1014
|
-
return this.#cache.get(path) ?? null;
|
|
1015
|
-
}
|
|
1016
|
-
deleteByPath(path) {
|
|
1017
|
-
this.#cache.delete(path);
|
|
1018
|
-
this.#filesCache = null;
|
|
1019
|
-
}
|
|
1020
|
-
clear() {
|
|
1021
|
-
this.#cache.clear();
|
|
1022
|
-
this.#filesCache = null;
|
|
1023
|
-
}
|
|
1024
|
-
/**
|
|
1025
|
-
* All stored files, sorted by path length (shorter paths first).
|
|
1026
|
-
* Barrel/index files (e.g. index.ts) are sorted last within each length bucket.
|
|
1027
|
-
*/
|
|
1028
|
-
get files() {
|
|
1029
|
-
if (this.#filesCache) return this.#filesCache;
|
|
1030
|
-
const keys = [...this.#cache.keys()].sort((a, b) => {
|
|
1031
|
-
if (a.length !== b.length) return a.length - b.length;
|
|
1032
|
-
const aIsIndex = trimExtName$1(a).endsWith("index");
|
|
1033
|
-
if (aIsIndex !== trimExtName$1(b).endsWith("index")) return aIsIndex ? 1 : -1;
|
|
1034
|
-
return 0;
|
|
1035
|
-
});
|
|
1036
|
-
const files = [];
|
|
1037
|
-
for (const key of keys) {
|
|
1038
|
-
const file = this.#cache.get(key);
|
|
1039
|
-
if (file) files.push(file);
|
|
1040
|
-
}
|
|
1041
|
-
this.#filesCache = files;
|
|
1042
|
-
return files;
|
|
1043
|
-
}
|
|
1044
|
-
};
|
|
980
|
+
function definePlugin(factory) {
|
|
981
|
+
return (options) => factory(options ?? {});
|
|
982
|
+
}
|
|
1045
983
|
//#endregion
|
|
1046
|
-
//#region src/
|
|
984
|
+
//#region src/defineResolver.ts
|
|
1047
985
|
/**
|
|
1048
|
-
*
|
|
1049
|
-
*
|
|
1050
|
-
* - Each function receives the accumulated state from the previous call.
|
|
1051
|
-
* - Skips functions that return a falsy value (acts as a no-op for that step).
|
|
1052
|
-
* - Returns an array of all individual results.
|
|
1053
|
-
* @deprecated
|
|
986
|
+
* Checks if an operation matches a pattern for a given filter type (`tag`, `operationId`, `path`, `method`).
|
|
1054
987
|
*/
|
|
1055
|
-
function
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
return
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
}
|
|
988
|
+
function matchesOperationPattern(node, type, pattern) {
|
|
989
|
+
switch (type) {
|
|
990
|
+
case "tag": return node.tags.some((tag) => !!tag.match(pattern));
|
|
991
|
+
case "operationId": return !!node.operationId.match(pattern);
|
|
992
|
+
case "path": return !!node.path.match(pattern);
|
|
993
|
+
case "method": return !!node.method.toLowerCase().match(pattern);
|
|
994
|
+
case "contentType": return !!node.requestBody?.contentType?.match(pattern);
|
|
995
|
+
default: return false;
|
|
996
|
+
}
|
|
1064
997
|
}
|
|
1065
998
|
/**
|
|
1066
|
-
*
|
|
999
|
+
* Checks if a schema matches a pattern for a given filter type (`schemaName`).
|
|
1067
1000
|
*
|
|
1068
|
-
*
|
|
1069
|
-
* - Subsequent functions are skipped once a match is found.
|
|
1070
|
-
* @deprecated
|
|
1001
|
+
* Returns `null` when the filter type doesn't apply to schemas.
|
|
1071
1002
|
*/
|
|
1072
|
-
function
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
});
|
|
1078
|
-
return promise;
|
|
1003
|
+
function matchesSchemaPattern(node, type, pattern) {
|
|
1004
|
+
switch (type) {
|
|
1005
|
+
case "schemaName": return node.name ? !!node.name.match(pattern) : false;
|
|
1006
|
+
default: return null;
|
|
1007
|
+
}
|
|
1079
1008
|
}
|
|
1080
1009
|
/**
|
|
1081
|
-
*
|
|
1010
|
+
* Default name resolver used by `defineResolver`.
|
|
1082
1011
|
*
|
|
1083
|
-
* -
|
|
1084
|
-
* -
|
|
1085
|
-
*
|
|
1012
|
+
* - `camelCase` for `function` and `file` types.
|
|
1013
|
+
* - `PascalCase` for `type`.
|
|
1014
|
+
* - `camelCase` for everything else.
|
|
1086
1015
|
*/
|
|
1087
|
-
function
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1016
|
+
function defaultResolver(name, type) {
|
|
1017
|
+
let resolvedName = camelCase(name);
|
|
1018
|
+
if (type === "file" || type === "function") resolvedName = camelCase(name, { isFile: type === "file" });
|
|
1019
|
+
if (type === "type") resolvedName = pascalCase(name);
|
|
1020
|
+
return resolvedName;
|
|
1091
1021
|
}
|
|
1092
|
-
//#endregion
|
|
1093
|
-
//#region src/PluginDriver.ts
|
|
1094
1022
|
/**
|
|
1095
|
-
*
|
|
1023
|
+
* Default option resolver — applies include/exclude filters and merges matching override options.
|
|
1096
1024
|
*
|
|
1097
|
-
*
|
|
1025
|
+
* Returns `null` when the node is filtered out by an `exclude` rule or not matched by any `include` rule.
|
|
1026
|
+
*
|
|
1027
|
+
* @example Include/exclude filtering
|
|
1098
1028
|
* ```ts
|
|
1099
|
-
*
|
|
1100
|
-
*
|
|
1029
|
+
* const options = defaultResolveOptions(operationNode, {
|
|
1030
|
+
* options: { output: 'types' },
|
|
1031
|
+
* exclude: [{ type: 'tag', pattern: 'internal' }],
|
|
1032
|
+
* })
|
|
1033
|
+
* // → null when node has tag 'internal'
|
|
1101
1034
|
* ```
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
|
|
1035
|
+
*
|
|
1036
|
+
* @example Override merging
|
|
1037
|
+
* ```ts
|
|
1038
|
+
* const options = defaultResolveOptions(operationNode, {
|
|
1039
|
+
* options: { enumType: 'asConst' },
|
|
1040
|
+
* override: [{ type: 'operationId', pattern: 'listPets', options: { enumType: 'enum' } }],
|
|
1041
|
+
* })
|
|
1042
|
+
* // → { enumType: 'enum' } when operationId matches
|
|
1043
|
+
* ```
|
|
1044
|
+
*/
|
|
1045
|
+
function defaultResolveOptions(node, { options, exclude = [], include, override = [] }) {
|
|
1046
|
+
if ((0, _kubb_ast.isOperationNode)(node)) {
|
|
1047
|
+
if (exclude.some(({ type, pattern }) => matchesOperationPattern(node, type, pattern))) return null;
|
|
1048
|
+
if (include && !include.some(({ type, pattern }) => matchesOperationPattern(node, type, pattern))) return null;
|
|
1049
|
+
const overrideOptions = override.find(({ type, pattern }) => matchesOperationPattern(node, type, pattern))?.options;
|
|
1050
|
+
return {
|
|
1051
|
+
...options,
|
|
1052
|
+
...overrideOptions
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
if ((0, _kubb_ast.isSchemaNode)(node)) {
|
|
1056
|
+
if (exclude.some(({ type, pattern }) => matchesSchemaPattern(node, type, pattern) === true)) return null;
|
|
1057
|
+
if (include) {
|
|
1058
|
+
const applicable = include.map(({ type, pattern }) => matchesSchemaPattern(node, type, pattern)).filter((r) => r !== null);
|
|
1059
|
+
if (applicable.length > 0 && !applicable.includes(true)) return null;
|
|
1060
|
+
}
|
|
1061
|
+
const overrideOptions = override.find(({ type, pattern }) => matchesSchemaPattern(node, type, pattern) === true)?.options;
|
|
1062
|
+
return {
|
|
1063
|
+
...options,
|
|
1064
|
+
...overrideOptions
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
return options;
|
|
1068
|
+
}
|
|
1069
|
+
/**
|
|
1070
|
+
* Default path resolver used by `defineResolver`.
|
|
1071
|
+
*
|
|
1072
|
+
* - Returns the output directory in `single` mode.
|
|
1073
|
+
* - Resolves into a tag- or path-based subdirectory when `group` and a `tag`/`path` value are provided.
|
|
1074
|
+
* - Falls back to a flat `output/baseName` path otherwise.
|
|
1075
|
+
*
|
|
1076
|
+
* A custom `group.name` function overrides the default subdirectory naming.
|
|
1077
|
+
* For `tag` groups the default is `${camelCase(tag)}Controller`.
|
|
1078
|
+
* For `path` groups the default is the first path segment after `/`.
|
|
1079
|
+
*
|
|
1080
|
+
* @example Flat output
|
|
1081
|
+
* ```ts
|
|
1082
|
+
* defaultResolvePath({ baseName: 'petTypes.ts' }, { root: '/src', output: { path: 'types' } })
|
|
1083
|
+
* // → '/src/types/petTypes.ts'
|
|
1084
|
+
* ```
|
|
1085
|
+
*
|
|
1086
|
+
* @example Tag-based grouping
|
|
1087
|
+
* ```ts
|
|
1088
|
+
* defaultResolvePath(
|
|
1089
|
+
* { baseName: 'petTypes.ts', tag: 'pets' },
|
|
1090
|
+
* { root: '/src', output: { path: 'types' }, group: { type: 'tag' } },
|
|
1091
|
+
* )
|
|
1092
|
+
* // → '/src/types/petsController/petTypes.ts'
|
|
1093
|
+
* ```
|
|
1094
|
+
*
|
|
1095
|
+
* @example Path-based grouping
|
|
1096
|
+
* ```ts
|
|
1097
|
+
* defaultResolvePath(
|
|
1098
|
+
* { baseName: 'petTypes.ts', path: '/pets/list' },
|
|
1099
|
+
* { root: '/src', output: { path: 'types' }, group: { type: 'path' } },
|
|
1100
|
+
* )
|
|
1101
|
+
* // → '/src/types/pets/petTypes.ts'
|
|
1102
|
+
* ```
|
|
1103
|
+
*
|
|
1104
|
+
* @example Single-file mode
|
|
1105
|
+
* ```ts
|
|
1106
|
+
* defaultResolvePath(
|
|
1107
|
+
* { baseName: 'petTypes.ts', pathMode: 'single' },
|
|
1108
|
+
* { root: '/src', output: { path: 'types' } },
|
|
1109
|
+
* )
|
|
1110
|
+
* // → '/src/types'
|
|
1111
|
+
* ```
|
|
1112
|
+
*/
|
|
1113
|
+
function defaultResolvePath({ baseName, pathMode, tag, path: groupPath }, { root, output, group }) {
|
|
1114
|
+
if ((pathMode ?? getMode(node_path.default.resolve(root, output.path))) === "single") return node_path.default.resolve(root, output.path);
|
|
1115
|
+
if (group && (groupPath || tag)) return node_path.default.resolve(root, output.path, group.name({ group: group.type === "path" ? groupPath : tag }), baseName);
|
|
1116
|
+
return node_path.default.resolve(root, output.path, baseName);
|
|
1117
|
+
}
|
|
1118
|
+
/**
|
|
1119
|
+
* Default file resolver used by `defineResolver`.
|
|
1120
|
+
*
|
|
1121
|
+
* Resolves a `FileNode` by combining name resolution (`resolver.default`) with
|
|
1122
|
+
* path resolution (`resolver.resolvePath`). The resolved file always has empty
|
|
1123
|
+
* `sources`, `imports`, and `exports` arrays — consumers populate those separately.
|
|
1124
|
+
*
|
|
1125
|
+
* In `single` mode the name is omitted and the file sits directly in the output directory.
|
|
1126
|
+
*
|
|
1127
|
+
* @example Resolve a schema file
|
|
1128
|
+
* ```ts
|
|
1129
|
+
* const file = defaultResolveFile.call(resolver,
|
|
1130
|
+
* { name: 'pet', extname: '.ts' },
|
|
1131
|
+
* { root: '/src', output: { path: 'types' } },
|
|
1132
|
+
* )
|
|
1133
|
+
* // → { baseName: 'pet.ts', path: '/src/types/pet.ts', sources: [], ... }
|
|
1134
|
+
* ```
|
|
1135
|
+
*
|
|
1136
|
+
* @example Resolve an operation file with tag grouping
|
|
1137
|
+
* ```ts
|
|
1138
|
+
* const file = defaultResolveFile.call(resolver,
|
|
1139
|
+
* { name: 'listPets', extname: '.ts', tag: 'pets' },
|
|
1140
|
+
* { root: '/src', output: { path: 'types' }, group: { type: 'tag' } },
|
|
1141
|
+
* )
|
|
1142
|
+
* // → { baseName: 'listPets.ts', path: '/src/types/petsController/listPets.ts', ... }
|
|
1143
|
+
* ```
|
|
1144
|
+
*/
|
|
1145
|
+
function defaultResolveFile({ name, extname, tag, path: groupPath }, context) {
|
|
1146
|
+
const pathMode = getMode(node_path.default.resolve(context.root, context.output.path));
|
|
1147
|
+
const baseName = `${pathMode === "single" ? "" : this.default(name, "file")}${extname}`;
|
|
1148
|
+
const filePath = this.resolvePath({
|
|
1149
|
+
baseName,
|
|
1150
|
+
pathMode,
|
|
1151
|
+
tag,
|
|
1152
|
+
path: groupPath
|
|
1153
|
+
}, context);
|
|
1154
|
+
return (0, _kubb_ast.createFile)({
|
|
1155
|
+
path: filePath,
|
|
1156
|
+
baseName: node_path.default.basename(filePath),
|
|
1157
|
+
meta: { pluginName: this.pluginName },
|
|
1158
|
+
sources: [],
|
|
1159
|
+
imports: [],
|
|
1160
|
+
exports: []
|
|
1161
|
+
});
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Generates the default "Generated by Kubb" banner from config and optional node metadata.
|
|
1165
|
+
*/
|
|
1166
|
+
function buildDefaultBanner({ title, description, version, config }) {
|
|
1167
|
+
try {
|
|
1168
|
+
let source = "";
|
|
1169
|
+
if (Array.isArray(config.input)) {
|
|
1170
|
+
const first = config.input[0];
|
|
1171
|
+
if (first && "path" in first) source = node_path.default.basename(first.path);
|
|
1172
|
+
} else if ("path" in config.input) source = node_path.default.basename(config.input.path);
|
|
1173
|
+
else if ("data" in config.input) source = "text content";
|
|
1174
|
+
let banner = "/**\n* Generated by Kubb (https://kubb.dev/).\n* Do not edit manually.\n";
|
|
1175
|
+
if (config.output.defaultBanner === "simple") {
|
|
1176
|
+
banner += "*/\n";
|
|
1177
|
+
return banner;
|
|
1178
|
+
}
|
|
1179
|
+
if (source) banner += `* Source: ${source}\n`;
|
|
1180
|
+
if (title) banner += `* Title: ${title}\n`;
|
|
1181
|
+
if (description) {
|
|
1182
|
+
const formattedDescription = description.replace(/\n/gm, "\n* ");
|
|
1183
|
+
banner += `* Description: ${formattedDescription}\n`;
|
|
1184
|
+
}
|
|
1185
|
+
if (version) banner += `* OpenAPI spec version: ${version}\n`;
|
|
1186
|
+
banner += "*/\n";
|
|
1187
|
+
return banner;
|
|
1188
|
+
} catch (_error) {
|
|
1189
|
+
return "/**\n* Generated by Kubb (https://kubb.dev/).\n* Do not edit manually.\n*/";
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
/**
|
|
1193
|
+
* Default banner resolver — returns the banner string for a generated file.
|
|
1194
|
+
*
|
|
1195
|
+
* A user-supplied `output.banner` overrides the default Kubb "Generated by Kubb" notice.
|
|
1196
|
+
* When no `output.banner` is set, the Kubb notice is used (including `title` and `version`
|
|
1197
|
+
* from the OAS spec when a `node` is provided).
|
|
1198
|
+
*
|
|
1199
|
+
* - When `output.banner` is a function and `node` is provided, returns `output.banner(node)`.
|
|
1200
|
+
* - When `output.banner` is a function and `node` is absent, falls back to the Kubb notice.
|
|
1201
|
+
* - When `output.banner` is a string, returns it directly.
|
|
1202
|
+
* - When `config.output.defaultBanner` is `false`, returns `undefined`.
|
|
1203
|
+
* - Otherwise returns the Kubb "Generated by Kubb" notice.
|
|
1204
|
+
*
|
|
1205
|
+
* @example String banner overrides default
|
|
1206
|
+
* ```ts
|
|
1207
|
+
* defaultResolveBanner(undefined, { output: { banner: '// my banner' }, config })
|
|
1208
|
+
* // → '// my banner'
|
|
1209
|
+
* ```
|
|
1210
|
+
*
|
|
1211
|
+
* @example Function banner with node
|
|
1212
|
+
* ```ts
|
|
1213
|
+
* defaultResolveBanner(inputNode, { output: { banner: (node) => `// v${node.version}` }, config })
|
|
1214
|
+
* // → '// v3.0.0'
|
|
1215
|
+
* ```
|
|
1216
|
+
*
|
|
1217
|
+
* @example No user banner — Kubb notice with OAS metadata
|
|
1218
|
+
* ```ts
|
|
1219
|
+
* defaultResolveBanner(inputNode, { config })
|
|
1220
|
+
* // → '/** Generated by Kubb ... Title: Pet Store ... *\/'
|
|
1221
|
+
* ```
|
|
1222
|
+
*
|
|
1223
|
+
* @example Disabled default banner
|
|
1224
|
+
* ```ts
|
|
1225
|
+
* defaultResolveBanner(undefined, { config: { output: { defaultBanner: false }, ...config } })
|
|
1226
|
+
* // → undefined
|
|
1227
|
+
* ```
|
|
1228
|
+
*/
|
|
1229
|
+
function defaultResolveBanner(node, { output, config }) {
|
|
1230
|
+
if (typeof output?.banner === "function") return output.banner(node);
|
|
1231
|
+
if (typeof output?.banner === "string") return output.banner;
|
|
1232
|
+
if (config.output.defaultBanner === false) return;
|
|
1233
|
+
return buildDefaultBanner({
|
|
1234
|
+
title: node?.meta?.title,
|
|
1235
|
+
version: node?.meta?.version,
|
|
1236
|
+
config
|
|
1237
|
+
});
|
|
1238
|
+
}
|
|
1239
|
+
/**
|
|
1240
|
+
* Default footer resolver — returns the footer string for a generated file.
|
|
1241
|
+
*
|
|
1242
|
+
* - When `output.footer` is a function and `node` is provided, calls it with the node.
|
|
1243
|
+
* - When `output.footer` is a function and `node` is absent, returns `undefined`.
|
|
1244
|
+
* - When `output.footer` is a string, returns it directly.
|
|
1245
|
+
* - Otherwise returns `undefined`.
|
|
1246
|
+
*
|
|
1247
|
+
* @example String footer
|
|
1248
|
+
* ```ts
|
|
1249
|
+
* defaultResolveFooter(undefined, { output: { footer: '// end of file' }, config })
|
|
1250
|
+
* // → '// end of file'
|
|
1251
|
+
* ```
|
|
1252
|
+
*
|
|
1253
|
+
* @example Function footer with node
|
|
1254
|
+
* ```ts
|
|
1255
|
+
* defaultResolveFooter(inputNode, { output: { footer: (node) => `// ${node.title}` }, config })
|
|
1256
|
+
* // → '// Pet Store'
|
|
1257
|
+
* ```
|
|
1258
|
+
*/
|
|
1259
|
+
function defaultResolveFooter(node, { output }) {
|
|
1260
|
+
if (typeof output?.footer === "function") return node ? output.footer(node) : void 0;
|
|
1261
|
+
if (typeof output?.footer === "string") return output.footer;
|
|
1262
|
+
}
|
|
1263
|
+
/**
|
|
1264
|
+
* Defines a resolver for a plugin, injecting built-in defaults for name casing,
|
|
1265
|
+
* include/exclude/override filtering, path resolution, and file construction.
|
|
1266
|
+
*
|
|
1267
|
+
* All four defaults can be overridden by providing them in the builder function:
|
|
1268
|
+
* - `default` — name casing strategy (camelCase / PascalCase)
|
|
1269
|
+
* - `resolveOptions` — include/exclude/override filtering
|
|
1270
|
+
* - `resolvePath` — output path computation
|
|
1271
|
+
* - `resolveFile` — full `FileNode` construction
|
|
1272
|
+
*
|
|
1273
|
+
* Methods in the builder have access to `this` (the full resolver object), so they
|
|
1274
|
+
* can call other resolver methods without circular imports.
|
|
1275
|
+
*
|
|
1276
|
+
* @example Basic resolver with naming helpers
|
|
1277
|
+
* ```ts
|
|
1278
|
+
* export const resolver = defineResolver<PluginTs>(() => ({
|
|
1279
|
+
* name: 'default',
|
|
1280
|
+
* resolveName(node) {
|
|
1281
|
+
* return this.default(node.name, 'function')
|
|
1282
|
+
* },
|
|
1283
|
+
* resolveTypedName(node) {
|
|
1284
|
+
* return this.default(node.name, 'type')
|
|
1285
|
+
* },
|
|
1286
|
+
* }))
|
|
1287
|
+
* ```
|
|
1288
|
+
*
|
|
1289
|
+
* @example Override resolvePath for a custom output structure
|
|
1290
|
+
* ```ts
|
|
1291
|
+
* export const resolver = defineResolver<PluginTs>(() => ({
|
|
1292
|
+
* name: 'custom',
|
|
1293
|
+
* resolvePath({ baseName }, { root, output }) {
|
|
1294
|
+
* return path.resolve(root, output.path, 'generated', baseName)
|
|
1295
|
+
* },
|
|
1296
|
+
* }))
|
|
1297
|
+
* ```
|
|
1298
|
+
*
|
|
1299
|
+
* @example Use this.default inside a helper
|
|
1300
|
+
* ```ts
|
|
1301
|
+
* export const resolver = defineResolver<PluginTs>(() => ({
|
|
1302
|
+
* name: 'default',
|
|
1303
|
+
* resolveParamName(node, param) {
|
|
1304
|
+
* return this.default(`${node.operationId} ${param.in} ${param.name}`, 'type')
|
|
1305
|
+
* },
|
|
1306
|
+
* }))
|
|
1307
|
+
* ```
|
|
1308
|
+
*/
|
|
1309
|
+
function defineResolver(build) {
|
|
1310
|
+
return {
|
|
1311
|
+
default: defaultResolver,
|
|
1312
|
+
resolveOptions: defaultResolveOptions,
|
|
1313
|
+
resolvePath: defaultResolvePath,
|
|
1314
|
+
resolveFile: defaultResolveFile,
|
|
1315
|
+
resolveBanner: defaultResolveBanner,
|
|
1316
|
+
resolveFooter: defaultResolveFooter,
|
|
1317
|
+
...build()
|
|
1318
|
+
};
|
|
1319
|
+
}
|
|
1320
|
+
//#endregion
|
|
1321
|
+
//#region src/devtools.ts
|
|
1322
|
+
/**
|
|
1323
|
+
* Encodes an `InputNode` as a compressed, URL-safe string.
|
|
1324
|
+
*
|
|
1325
|
+
* The JSON representation is deflate-compressed with {@link deflateSync} before
|
|
1326
|
+
* base64url encoding, which typically reduces payload size by 70–80 % and
|
|
1327
|
+
* keeps URLs well within browser and server path-length limits.
|
|
1328
|
+
*
|
|
1329
|
+
* Use {@link decodeAst} to reverse.
|
|
1330
|
+
*/
|
|
1331
|
+
function encodeAst(input) {
|
|
1332
|
+
const compressed = (0, fflate.deflateSync)(new TextEncoder().encode(JSON.stringify(input)));
|
|
1333
|
+
return Buffer.from(compressed).toString("base64url");
|
|
1334
|
+
}
|
|
1335
|
+
/**
|
|
1336
|
+
* Constructs the Kubb Studio URL for the given `InputNode`.
|
|
1337
|
+
* When `options.ast` is `true`, navigates to the AST inspector (`/ast`).
|
|
1338
|
+
* The `input` is encoded and attached as the `?root=` query parameter so Studio
|
|
1339
|
+
* can decode and render it without a round-trip to any server.
|
|
1340
|
+
*/
|
|
1341
|
+
function getStudioUrl(input, studioUrl, options = {}) {
|
|
1342
|
+
return `${studioUrl.replace(/\/$/, "")}${options.ast ? "/ast" : ""}?root=${encodeAst(input)}`;
|
|
1343
|
+
}
|
|
1344
|
+
/**
|
|
1345
|
+
* Opens the Kubb Studio URL for the given `InputNode` in the default browser —
|
|
1346
|
+
*
|
|
1347
|
+
* Falls back to printing the URL if the browser cannot be launched.
|
|
1348
|
+
*/
|
|
1349
|
+
async function openInStudio(input, studioUrl, options = {}) {
|
|
1350
|
+
const url = getStudioUrl(input, studioUrl, options);
|
|
1351
|
+
const cmd = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
|
|
1352
|
+
const args = process.platform === "win32" ? [
|
|
1353
|
+
"/c",
|
|
1354
|
+
"start",
|
|
1355
|
+
"",
|
|
1356
|
+
url
|
|
1357
|
+
] : [url];
|
|
1358
|
+
try {
|
|
1359
|
+
await (0, tinyexec.x)(cmd, args);
|
|
1360
|
+
} catch {
|
|
1361
|
+
console.log(`\n ${url}\n`);
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
//#endregion
|
|
1365
|
+
//#region src/FileManager.ts
|
|
1366
|
+
function mergeFile(a, b) {
|
|
1367
|
+
return {
|
|
1368
|
+
...a,
|
|
1369
|
+
sources: [...a.sources || [], ...b.sources || []],
|
|
1370
|
+
imports: [...a.imports || [], ...b.imports || []],
|
|
1371
|
+
exports: [...a.exports || [], ...b.exports || []]
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1374
|
+
/**
|
|
1375
|
+
* In-memory file store for generated files.
|
|
1376
|
+
*
|
|
1377
|
+
* Files with the same `path` are merged — sources, imports, and exports are concatenated.
|
|
1378
|
+
* The `files` getter returns all stored files sorted by path length (shortest first).
|
|
1379
|
+
*
|
|
1380
|
+
* @example
|
|
1381
|
+
* ```ts
|
|
1382
|
+
* import { FileManager } from '@kubb/core'
|
|
1383
|
+
*
|
|
1384
|
+
* const manager = new FileManager()
|
|
1385
|
+
* manager.upsert(myFile)
|
|
1386
|
+
* console.log(manager.files) // all stored files
|
|
1387
|
+
* ```
|
|
1388
|
+
*/
|
|
1389
|
+
var FileManager = class {
|
|
1390
|
+
#cache = /* @__PURE__ */ new Map();
|
|
1391
|
+
#filesCache = null;
|
|
1392
|
+
/**
|
|
1393
|
+
* Adds one or more files. Files with the same path are merged — sources, imports,
|
|
1394
|
+
* and exports from all calls with the same path are concatenated together.
|
|
1395
|
+
*/
|
|
1396
|
+
add(...files) {
|
|
1397
|
+
const resolvedFiles = [];
|
|
1398
|
+
const mergedFiles = /* @__PURE__ */ new Map();
|
|
1399
|
+
files.forEach((file) => {
|
|
1400
|
+
const existing = mergedFiles.get(file.path);
|
|
1401
|
+
if (existing) mergedFiles.set(file.path, mergeFile(existing, file));
|
|
1402
|
+
else mergedFiles.set(file.path, file);
|
|
1403
|
+
});
|
|
1404
|
+
for (const file of mergedFiles.values()) {
|
|
1405
|
+
const resolvedFile = (0, _kubb_ast.createFile)(file);
|
|
1406
|
+
this.#cache.set(resolvedFile.path, resolvedFile);
|
|
1407
|
+
this.#filesCache = null;
|
|
1408
|
+
resolvedFiles.push(resolvedFile);
|
|
1409
|
+
}
|
|
1410
|
+
return resolvedFiles;
|
|
1411
|
+
}
|
|
1412
|
+
/**
|
|
1413
|
+
* Adds or merges one or more files.
|
|
1414
|
+
* If a file with the same path already exists, its sources/imports/exports are merged together.
|
|
1415
|
+
*/
|
|
1416
|
+
upsert(...files) {
|
|
1417
|
+
const resolvedFiles = [];
|
|
1418
|
+
const mergedFiles = /* @__PURE__ */ new Map();
|
|
1419
|
+
files.forEach((file) => {
|
|
1420
|
+
const existing = mergedFiles.get(file.path);
|
|
1421
|
+
if (existing) mergedFiles.set(file.path, mergeFile(existing, file));
|
|
1422
|
+
else mergedFiles.set(file.path, file);
|
|
1423
|
+
});
|
|
1424
|
+
for (const file of mergedFiles.values()) {
|
|
1425
|
+
const existing = this.#cache.get(file.path);
|
|
1426
|
+
const resolvedFile = (0, _kubb_ast.createFile)(existing ? mergeFile(existing, file) : file);
|
|
1427
|
+
this.#cache.set(resolvedFile.path, resolvedFile);
|
|
1428
|
+
this.#filesCache = null;
|
|
1429
|
+
resolvedFiles.push(resolvedFile);
|
|
1430
|
+
}
|
|
1431
|
+
return resolvedFiles;
|
|
1432
|
+
}
|
|
1433
|
+
getByPath(path) {
|
|
1434
|
+
return this.#cache.get(path) ?? null;
|
|
1435
|
+
}
|
|
1436
|
+
deleteByPath(path) {
|
|
1437
|
+
this.#cache.delete(path);
|
|
1438
|
+
this.#filesCache = null;
|
|
1439
|
+
}
|
|
1440
|
+
clear() {
|
|
1441
|
+
this.#cache.clear();
|
|
1442
|
+
this.#filesCache = null;
|
|
1443
|
+
}
|
|
1444
|
+
/**
|
|
1445
|
+
* All stored files, sorted by path length (shorter paths first).
|
|
1446
|
+
* Barrel/index files (e.g. index.ts) are sorted last within each length bucket.
|
|
1447
|
+
*/
|
|
1448
|
+
get files() {
|
|
1449
|
+
if (this.#filesCache) return this.#filesCache;
|
|
1450
|
+
const keys = [...this.#cache.keys()].sort((a, b) => {
|
|
1451
|
+
if (a.length !== b.length) return a.length - b.length;
|
|
1452
|
+
const aIsIndex = trimExtName$1(a).endsWith("index");
|
|
1453
|
+
if (aIsIndex !== trimExtName$1(b).endsWith("index")) return aIsIndex ? 1 : -1;
|
|
1454
|
+
return 0;
|
|
1455
|
+
});
|
|
1456
|
+
const files = [];
|
|
1457
|
+
for (const key of keys) {
|
|
1458
|
+
const file = this.#cache.get(key);
|
|
1459
|
+
if (file) files.push(file);
|
|
1460
|
+
}
|
|
1461
|
+
this.#filesCache = files;
|
|
1462
|
+
return files;
|
|
1463
|
+
}
|
|
1464
|
+
};
|
|
1465
|
+
//#endregion
|
|
1466
|
+
//#region src/renderNode.ts
|
|
1467
|
+
/**
|
|
1468
|
+
* Handles the return value of a plugin AST hook or generator method.
|
|
1469
|
+
*
|
|
1470
|
+
* - Renderer output → rendered via the provided `rendererFactory` (e.g. JSX), files stored in `driver.fileManager`
|
|
1471
|
+
* - `Array<FileNode>` → added directly into `driver.fileManager`
|
|
1472
|
+
* - `void` / `null` / `undefined` → no-op (plugin handled it via `this.upsertFile`)
|
|
1473
|
+
*
|
|
1474
|
+
* Pass a `rendererFactory` (e.g. `jsxRenderer` from `@kubb/renderer-jsx`) when the result
|
|
1475
|
+
* may be a renderer element. Generators that only return `Array<FileNode>` do not need one.
|
|
1476
|
+
*/
|
|
1477
|
+
async function applyHookResult(result, driver, rendererFactory) {
|
|
1478
|
+
if (!result) return;
|
|
1479
|
+
if (Array.isArray(result)) {
|
|
1480
|
+
driver.fileManager.upsert(...result);
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
if (!rendererFactory) return;
|
|
1484
|
+
const renderer = rendererFactory();
|
|
1485
|
+
await renderer.render(result);
|
|
1486
|
+
driver.fileManager.upsert(...renderer.files);
|
|
1487
|
+
renderer.unmount();
|
|
1488
|
+
}
|
|
1489
|
+
//#endregion
|
|
1490
|
+
//#region src/utils/executeStrategies.ts
|
|
1491
|
+
/**
|
|
1492
|
+
* Runs promise functions in sequence, threading each result into the next call.
|
|
1493
|
+
*
|
|
1494
|
+
* - Each function receives the accumulated state from the previous call.
|
|
1495
|
+
* - Skips functions that return a falsy value (acts as a no-op for that step).
|
|
1496
|
+
* - Returns an array of all individual results.
|
|
1497
|
+
* @deprecated
|
|
1498
|
+
*/
|
|
1499
|
+
function hookSeq(promises) {
|
|
1500
|
+
return promises.filter(Boolean).reduce((promise, func) => {
|
|
1501
|
+
if (typeof func !== "function") throw new Error("HookSeq needs a function that returns a promise `() => Promise<unknown>`");
|
|
1502
|
+
return promise.then((state) => {
|
|
1503
|
+
const calledFunc = func(state);
|
|
1504
|
+
if (calledFunc) return calledFunc.then(Array.prototype.concat.bind(state));
|
|
1505
|
+
return state;
|
|
1506
|
+
});
|
|
1507
|
+
}, Promise.resolve([]));
|
|
1508
|
+
}
|
|
1509
|
+
/**
|
|
1510
|
+
* Runs promise functions in sequence and returns the first non-null result.
|
|
1511
|
+
*
|
|
1512
|
+
* - Stops as soon as `nullCheck` passes for a result (default: `!== null`).
|
|
1513
|
+
* - Subsequent functions are skipped once a match is found.
|
|
1514
|
+
* @deprecated
|
|
1515
|
+
*/
|
|
1516
|
+
function hookFirst(promises, nullCheck = (state) => state !== null) {
|
|
1517
|
+
let promise = Promise.resolve(null);
|
|
1518
|
+
for (const func of promises.filter(Boolean)) promise = promise.then((state) => {
|
|
1519
|
+
if (nullCheck(state)) return state;
|
|
1520
|
+
return func(state);
|
|
1521
|
+
});
|
|
1522
|
+
return promise;
|
|
1523
|
+
}
|
|
1524
|
+
/**
|
|
1525
|
+
* Runs promise functions concurrently and returns all settled results.
|
|
1526
|
+
*
|
|
1527
|
+
* - Limits simultaneous executions to `concurrency` (default: unlimited).
|
|
1528
|
+
* - Uses `Promise.allSettled` so individual failures do not cancel other tasks.
|
|
1529
|
+
* @deprecated
|
|
1530
|
+
*/
|
|
1531
|
+
function hookParallel(promises, concurrency = Number.POSITIVE_INFINITY) {
|
|
1532
|
+
const limit = pLimit(concurrency);
|
|
1533
|
+
const tasks = promises.filter(Boolean).map((promise) => limit(() => promise()));
|
|
1534
|
+
return Promise.allSettled(tasks);
|
|
1535
|
+
}
|
|
1536
|
+
//#endregion
|
|
1537
|
+
//#region src/PluginDriver.ts
|
|
1538
|
+
/**
|
|
1539
|
+
* Returns `'single'` when `fileOrFolder` has a file extension, `'split'` otherwise.
|
|
1540
|
+
*
|
|
1541
|
+
* @example
|
|
1542
|
+
* ```ts
|
|
1543
|
+
* getMode('src/gen/types.ts') // 'single'
|
|
1544
|
+
* getMode('src/gen/types') // 'split'
|
|
1545
|
+
* ```
|
|
1546
|
+
*/
|
|
1547
|
+
function getMode(fileOrFolder) {
|
|
1548
|
+
if (!fileOrFolder) return "split";
|
|
1549
|
+
return (0, node_path.extname)(fileOrFolder) ? "single" : "split";
|
|
1550
|
+
}
|
|
1551
|
+
const hookFirstNullCheck = (state) => !!state?.result;
|
|
1552
|
+
var PluginDriver = class {
|
|
1109
1553
|
config;
|
|
1110
1554
|
options;
|
|
1111
1555
|
/**
|
|
@@ -1122,25 +1566,259 @@ var PluginDriver = class {
|
|
|
1122
1566
|
*/
|
|
1123
1567
|
fileManager = new FileManager();
|
|
1124
1568
|
plugins = /* @__PURE__ */ new Map();
|
|
1569
|
+
/**
|
|
1570
|
+
* Tracks which plugins have generators registered via `addGenerator()` (event-based path).
|
|
1571
|
+
* Used by the build loop to decide whether to emit generator events for a given plugin.
|
|
1572
|
+
*/
|
|
1573
|
+
#pluginsWithEventGenerators = /* @__PURE__ */ new Set();
|
|
1574
|
+
#resolvers = /* @__PURE__ */ new Map();
|
|
1575
|
+
#defaultResolvers = /* @__PURE__ */ new Map();
|
|
1576
|
+
#hookListeners = /* @__PURE__ */ new Map();
|
|
1125
1577
|
constructor(config, options) {
|
|
1126
1578
|
this.config = config;
|
|
1127
|
-
this.options =
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1579
|
+
this.options = {
|
|
1580
|
+
...options,
|
|
1581
|
+
hooks: options.hooks
|
|
1582
|
+
};
|
|
1583
|
+
config.plugins.map((rawPlugin) => {
|
|
1584
|
+
if (isHookStylePlugin(rawPlugin)) return this.#normalizeHookStylePlugin(rawPlugin);
|
|
1585
|
+
return {
|
|
1586
|
+
...rawPlugin,
|
|
1587
|
+
buildStart: rawPlugin.buildStart ?? (() => {}),
|
|
1588
|
+
buildEnd: rawPlugin.buildEnd ?? (() => {})
|
|
1589
|
+
};
|
|
1590
|
+
}).filter((plugin) => {
|
|
1132
1591
|
if (typeof plugin.apply === "function") return plugin.apply(config);
|
|
1133
1592
|
return true;
|
|
1134
1593
|
}).sort((a, b) => {
|
|
1135
|
-
if (b.
|
|
1136
|
-
if (
|
|
1594
|
+
if (b.dependencies?.includes(a.name)) return -1;
|
|
1595
|
+
if (a.dependencies?.includes(b.name)) return 1;
|
|
1137
1596
|
return 0;
|
|
1138
1597
|
}).forEach((plugin) => {
|
|
1139
1598
|
this.plugins.set(plugin.name, plugin);
|
|
1140
1599
|
});
|
|
1141
1600
|
}
|
|
1142
|
-
get
|
|
1143
|
-
|
|
1601
|
+
get hooks() {
|
|
1602
|
+
if (!this.options.hooks) throw new Error("hooks are not defined");
|
|
1603
|
+
return this.options.hooks;
|
|
1604
|
+
}
|
|
1605
|
+
/**
|
|
1606
|
+
* Creates a `Plugin`-compatible object from a hook-style plugin and registers
|
|
1607
|
+
* its lifecycle handlers on the `AsyncEventEmitter`.
|
|
1608
|
+
*
|
|
1609
|
+
* The normalized plugin has an empty `buildStart` — generators registered via
|
|
1610
|
+
* `addGenerator()` in `kubb:plugin:setup` are stored on `normalizedPlugin.generators`
|
|
1611
|
+
* and used by `runPluginAstHooks` during the build.
|
|
1612
|
+
*/
|
|
1613
|
+
#normalizeHookStylePlugin(hookPlugin) {
|
|
1614
|
+
const generators = [];
|
|
1615
|
+
const driver = this;
|
|
1616
|
+
const normalizedPlugin = {
|
|
1617
|
+
name: hookPlugin.name,
|
|
1618
|
+
dependencies: hookPlugin.dependencies,
|
|
1619
|
+
options: {
|
|
1620
|
+
output: { path: "." },
|
|
1621
|
+
exclude: [],
|
|
1622
|
+
override: []
|
|
1623
|
+
},
|
|
1624
|
+
generators,
|
|
1625
|
+
inject: () => void 0,
|
|
1626
|
+
resolveName(name, type) {
|
|
1627
|
+
return driver.getResolver(hookPlugin.name).default(name, type);
|
|
1628
|
+
},
|
|
1629
|
+
resolvePath(baseName, pathMode, resolveOptions) {
|
|
1630
|
+
const resolver = driver.getResolver(hookPlugin.name);
|
|
1631
|
+
const opts = normalizedPlugin.options;
|
|
1632
|
+
const group = resolveOptions?.group;
|
|
1633
|
+
return resolver.resolvePath({
|
|
1634
|
+
baseName,
|
|
1635
|
+
pathMode,
|
|
1636
|
+
tag: group?.tag,
|
|
1637
|
+
path: group?.path
|
|
1638
|
+
}, {
|
|
1639
|
+
root: (0, node_path.resolve)(driver.config.root, driver.config.output.path),
|
|
1640
|
+
output: opts.output,
|
|
1641
|
+
group: opts.group
|
|
1642
|
+
});
|
|
1643
|
+
},
|
|
1644
|
+
buildStart() {},
|
|
1645
|
+
buildEnd() {}
|
|
1646
|
+
};
|
|
1647
|
+
this.registerPluginHooks(hookPlugin, normalizedPlugin);
|
|
1648
|
+
return normalizedPlugin;
|
|
1649
|
+
}
|
|
1650
|
+
/**
|
|
1651
|
+
* Registers a hook-style plugin's lifecycle handlers on the shared `AsyncEventEmitter`.
|
|
1652
|
+
*
|
|
1653
|
+
* For `kubb:plugin:setup`, the registered listener wraps the globally emitted context with a
|
|
1654
|
+
* plugin-specific one so that `addGenerator`, `setResolver`, `setTransformer`, and
|
|
1655
|
+
* `setRenderer` all target the correct `normalizedPlugin` entry in the plugins map.
|
|
1656
|
+
*
|
|
1657
|
+
* All other hooks are iterated and registered directly as pass-through listeners.
|
|
1658
|
+
* Any event key present in the global `KubbHooks` interface can be subscribed to.
|
|
1659
|
+
*
|
|
1660
|
+
* External tooling can subscribe to any of these events via `hooks.on(...)` to observe
|
|
1661
|
+
* the plugin lifecycle without modifying plugin behavior.
|
|
1662
|
+
*/
|
|
1663
|
+
registerPluginHooks(hookPlugin, normalizedPlugin) {
|
|
1664
|
+
const { hooks } = hookPlugin;
|
|
1665
|
+
if (hooks["kubb:plugin:setup"]) {
|
|
1666
|
+
const setupHandler = (globalCtx) => {
|
|
1667
|
+
const pluginCtx = {
|
|
1668
|
+
...globalCtx,
|
|
1669
|
+
options: hookPlugin.options ?? {},
|
|
1670
|
+
addGenerator: (gen) => {
|
|
1671
|
+
this.registerGenerator(normalizedPlugin.name, gen);
|
|
1672
|
+
},
|
|
1673
|
+
setResolver: (resolver) => {
|
|
1674
|
+
this.setPluginResolver(normalizedPlugin.name, resolver);
|
|
1675
|
+
},
|
|
1676
|
+
setTransformer: (visitor) => {
|
|
1677
|
+
normalizedPlugin.transformer = visitor;
|
|
1678
|
+
},
|
|
1679
|
+
setRenderer: (renderer) => {
|
|
1680
|
+
normalizedPlugin.renderer = renderer;
|
|
1681
|
+
},
|
|
1682
|
+
setOptions: (opts) => {
|
|
1683
|
+
normalizedPlugin.options = {
|
|
1684
|
+
...normalizedPlugin.options,
|
|
1685
|
+
...opts
|
|
1686
|
+
};
|
|
1687
|
+
},
|
|
1688
|
+
injectFile: (file) => {
|
|
1689
|
+
const fileNode = (0, _kubb_ast.createFile)({
|
|
1690
|
+
baseName: file.baseName,
|
|
1691
|
+
path: file.path,
|
|
1692
|
+
sources: file.sources ?? [],
|
|
1693
|
+
imports: [],
|
|
1694
|
+
exports: []
|
|
1695
|
+
});
|
|
1696
|
+
this.fileManager.add(fileNode);
|
|
1697
|
+
}
|
|
1698
|
+
};
|
|
1699
|
+
return hooks["kubb:plugin:setup"](pluginCtx);
|
|
1700
|
+
};
|
|
1701
|
+
this.hooks.on("kubb:plugin:setup", setupHandler);
|
|
1702
|
+
this.#trackHookListener("kubb:plugin:setup", setupHandler);
|
|
1703
|
+
}
|
|
1704
|
+
for (const [event, handler] of Object.entries(hooks)) {
|
|
1705
|
+
if (event === "kubb:plugin:setup" || !handler) continue;
|
|
1706
|
+
this.hooks.on(event, handler);
|
|
1707
|
+
this.#trackHookListener(event, handler);
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
/**
|
|
1711
|
+
* Emits the `kubb:plugin:setup` event so that all registered hook-style plugin listeners
|
|
1712
|
+
* can configure generators, resolvers, transformers and renderers before `buildStart` runs.
|
|
1713
|
+
*
|
|
1714
|
+
* Call this once from `safeBuild` before the plugin execution loop begins.
|
|
1715
|
+
*/
|
|
1716
|
+
async emitSetupHooks() {
|
|
1717
|
+
await this.hooks.emit("kubb:plugin:setup", {
|
|
1718
|
+
config: this.config,
|
|
1719
|
+
addGenerator: () => {},
|
|
1720
|
+
setResolver: () => {},
|
|
1721
|
+
setTransformer: () => {},
|
|
1722
|
+
setRenderer: () => {},
|
|
1723
|
+
setOptions: () => {},
|
|
1724
|
+
injectFile: () => {},
|
|
1725
|
+
updateConfig: () => {},
|
|
1726
|
+
options: {}
|
|
1727
|
+
});
|
|
1728
|
+
}
|
|
1729
|
+
/**
|
|
1730
|
+
* Registers a generator for the given plugin on the shared event emitter.
|
|
1731
|
+
*
|
|
1732
|
+
* The generator's `schema`, `operation`, and `operations` methods are registered as
|
|
1733
|
+
* listeners on `kubb:generate:schema`, `kubb:generate:operation`, and `kubb:generate:operations`
|
|
1734
|
+
* respectively. Each listener is scoped to the owning plugin via a `ctx.plugin.name` check
|
|
1735
|
+
* so that generators from different plugins do not cross-fire.
|
|
1736
|
+
*
|
|
1737
|
+
* The renderer resolution chain is: `generator.renderer → plugin.renderer → config.renderer`.
|
|
1738
|
+
* Set `generator.renderer = null` to explicitly opt out of rendering even when the plugin
|
|
1739
|
+
* declares a renderer.
|
|
1740
|
+
*
|
|
1741
|
+
* Call this method inside `addGenerator()` (in `kubb:plugin:setup`) to wire up a generator.
|
|
1742
|
+
*/
|
|
1743
|
+
registerGenerator(pluginName, gen) {
|
|
1744
|
+
const resolveRenderer = () => {
|
|
1745
|
+
const plugin = this.plugins.get(pluginName);
|
|
1746
|
+
return gen.renderer === null ? void 0 : gen.renderer ?? plugin?.renderer ?? this.config.renderer;
|
|
1747
|
+
};
|
|
1748
|
+
if (gen.schema) {
|
|
1749
|
+
const schemaHandler = async (node, ctx) => {
|
|
1750
|
+
if (ctx.plugin.name !== pluginName) return;
|
|
1751
|
+
await applyHookResult(await gen.schema(node, ctx), this, resolveRenderer());
|
|
1752
|
+
};
|
|
1753
|
+
this.hooks.on("kubb:generate:schema", schemaHandler);
|
|
1754
|
+
this.#trackHookListener("kubb:generate:schema", schemaHandler);
|
|
1755
|
+
}
|
|
1756
|
+
if (gen.operation) {
|
|
1757
|
+
const operationHandler = async (node, ctx) => {
|
|
1758
|
+
if (ctx.plugin.name !== pluginName) return;
|
|
1759
|
+
await applyHookResult(await gen.operation(node, ctx), this, resolveRenderer());
|
|
1760
|
+
};
|
|
1761
|
+
this.hooks.on("kubb:generate:operation", operationHandler);
|
|
1762
|
+
this.#trackHookListener("kubb:generate:operation", operationHandler);
|
|
1763
|
+
}
|
|
1764
|
+
if (gen.operations) {
|
|
1765
|
+
const operationsHandler = async (nodes, ctx) => {
|
|
1766
|
+
if (ctx.plugin.name !== pluginName) return;
|
|
1767
|
+
await applyHookResult(await gen.operations(nodes, ctx), this, resolveRenderer());
|
|
1768
|
+
};
|
|
1769
|
+
this.hooks.on("kubb:generate:operations", operationsHandler);
|
|
1770
|
+
this.#trackHookListener("kubb:generate:operations", operationsHandler);
|
|
1771
|
+
}
|
|
1772
|
+
this.#pluginsWithEventGenerators.add(pluginName);
|
|
1773
|
+
}
|
|
1774
|
+
/**
|
|
1775
|
+
* Returns `true` when at least one generator was registered for the given plugin
|
|
1776
|
+
* via `addGenerator()` in `kubb:plugin:setup` (event-based path).
|
|
1777
|
+
*
|
|
1778
|
+
* Used by the build loop to decide whether to walk the AST and emit generator events
|
|
1779
|
+
* for a plugin that has no static `plugin.generators`.
|
|
1780
|
+
*/
|
|
1781
|
+
hasRegisteredGenerators(pluginName) {
|
|
1782
|
+
return this.#pluginsWithEventGenerators.has(pluginName);
|
|
1783
|
+
}
|
|
1784
|
+
dispose() {
|
|
1785
|
+
for (const [event, handlers] of this.#hookListeners) for (const handler of handlers) this.hooks.off(event, handler);
|
|
1786
|
+
this.#hookListeners.clear();
|
|
1787
|
+
this.#pluginsWithEventGenerators.clear();
|
|
1788
|
+
}
|
|
1789
|
+
#trackHookListener(event, handler) {
|
|
1790
|
+
let handlers = this.#hookListeners.get(event);
|
|
1791
|
+
if (!handlers) {
|
|
1792
|
+
handlers = /* @__PURE__ */ new Set();
|
|
1793
|
+
this.#hookListeners.set(event, handlers);
|
|
1794
|
+
}
|
|
1795
|
+
handlers.add(handler);
|
|
1796
|
+
}
|
|
1797
|
+
#createDefaultResolver(pluginName) {
|
|
1798
|
+
const existingResolver = this.#defaultResolvers.get(pluginName);
|
|
1799
|
+
if (existingResolver) return existingResolver;
|
|
1800
|
+
const resolver = defineResolver(() => ({
|
|
1801
|
+
name: "default",
|
|
1802
|
+
pluginName
|
|
1803
|
+
}));
|
|
1804
|
+
this.#defaultResolvers.set(pluginName, resolver);
|
|
1805
|
+
return resolver;
|
|
1806
|
+
}
|
|
1807
|
+
setPluginResolver(pluginName, partial) {
|
|
1808
|
+
const merged = {
|
|
1809
|
+
...this.#createDefaultResolver(pluginName),
|
|
1810
|
+
...partial
|
|
1811
|
+
};
|
|
1812
|
+
this.#resolvers.set(pluginName, merged);
|
|
1813
|
+
const plugin = this.plugins.get(pluginName);
|
|
1814
|
+
if (plugin) plugin.resolver = merged;
|
|
1815
|
+
}
|
|
1816
|
+
getResolver(pluginName) {
|
|
1817
|
+
const dynamicResolver = this.#resolvers.get(pluginName);
|
|
1818
|
+
if (dynamicResolver) return dynamicResolver;
|
|
1819
|
+
const pluginResolver = this.plugins.get(pluginName)?.resolver;
|
|
1820
|
+
if (pluginResolver) return pluginResolver;
|
|
1821
|
+
return this.#createDefaultResolver(pluginName);
|
|
1144
1822
|
}
|
|
1145
1823
|
getContext(plugin) {
|
|
1146
1824
|
const driver = this;
|
|
@@ -1152,7 +1830,7 @@ var PluginDriver = class {
|
|
|
1152
1830
|
getMode(output) {
|
|
1153
1831
|
return getMode((0, node_path.resolve)(driver.config.root, driver.config.output.path, output.path));
|
|
1154
1832
|
},
|
|
1155
|
-
|
|
1833
|
+
hooks: driver.hooks,
|
|
1156
1834
|
plugin,
|
|
1157
1835
|
getPlugin: driver.getPlugin.bind(driver),
|
|
1158
1836
|
requirePlugin: driver.requirePlugin.bind(driver),
|
|
@@ -1170,19 +1848,19 @@ var PluginDriver = class {
|
|
|
1170
1848
|
return driver.adapter;
|
|
1171
1849
|
},
|
|
1172
1850
|
get resolver() {
|
|
1173
|
-
return plugin.
|
|
1851
|
+
return driver.getResolver(plugin.name);
|
|
1174
1852
|
},
|
|
1175
1853
|
get transformer() {
|
|
1176
1854
|
return plugin.transformer;
|
|
1177
1855
|
},
|
|
1178
1856
|
warn(message) {
|
|
1179
|
-
driver.
|
|
1857
|
+
driver.hooks.emit("kubb:warn", message);
|
|
1180
1858
|
},
|
|
1181
1859
|
error(error) {
|
|
1182
|
-
driver.
|
|
1860
|
+
driver.hooks.emit("kubb:error", typeof error === "string" ? new Error(error) : error);
|
|
1183
1861
|
},
|
|
1184
1862
|
info(message) {
|
|
1185
|
-
driver.
|
|
1863
|
+
driver.hooks.emit("kubb:info", message);
|
|
1186
1864
|
},
|
|
1187
1865
|
openInStudio(options) {
|
|
1188
1866
|
if (!driver.config.devtools || driver.#studioIsOpen) return;
|
|
@@ -1193,10 +1871,13 @@ var PluginDriver = class {
|
|
|
1193
1871
|
return openInStudio(driver.inputNode, studioUrl, options);
|
|
1194
1872
|
}
|
|
1195
1873
|
};
|
|
1196
|
-
|
|
1874
|
+
let mergedExtras = {};
|
|
1197
1875
|
for (const p of this.plugins.values()) if (typeof p.inject === "function") {
|
|
1198
1876
|
const result = p.inject.call(baseContext);
|
|
1199
|
-
if (result !== null && typeof result === "object")
|
|
1877
|
+
if (result !== null && typeof result === "object") mergedExtras = {
|
|
1878
|
+
...mergedExtras,
|
|
1879
|
+
...result
|
|
1880
|
+
};
|
|
1200
1881
|
}
|
|
1201
1882
|
return {
|
|
1202
1883
|
...baseContext,
|
|
@@ -1272,7 +1953,7 @@ var PluginDriver = class {
|
|
|
1272
1953
|
async hookForPlugin({ pluginName, hookName, parameters }) {
|
|
1273
1954
|
const plugin = this.plugins.get(pluginName);
|
|
1274
1955
|
if (!plugin) return [null];
|
|
1275
|
-
this.
|
|
1956
|
+
this.hooks.emit("kubb:plugins:hook:progress:start", {
|
|
1276
1957
|
hookName,
|
|
1277
1958
|
plugins: [plugin]
|
|
1278
1959
|
});
|
|
@@ -1282,7 +1963,7 @@ var PluginDriver = class {
|
|
|
1282
1963
|
parameters,
|
|
1283
1964
|
plugin
|
|
1284
1965
|
});
|
|
1285
|
-
this.
|
|
1966
|
+
this.hooks.emit("kubb:plugins:hook:progress:end", { hookName });
|
|
1286
1967
|
return [result];
|
|
1287
1968
|
}
|
|
1288
1969
|
/**
|
|
@@ -1305,7 +1986,7 @@ var PluginDriver = class {
|
|
|
1305
1986
|
async hookFirst({ hookName, parameters, skipped }) {
|
|
1306
1987
|
const plugins = [];
|
|
1307
1988
|
for (const plugin of this.plugins.values()) if (hookName in plugin && (skipped ? !skipped.has(plugin) : true)) plugins.push(plugin);
|
|
1308
|
-
this.
|
|
1989
|
+
this.hooks.emit("kubb:plugins:hook:progress:start", {
|
|
1309
1990
|
hookName,
|
|
1310
1991
|
plugins
|
|
1311
1992
|
});
|
|
@@ -1323,7 +2004,7 @@ var PluginDriver = class {
|
|
|
1323
2004
|
});
|
|
1324
2005
|
};
|
|
1325
2006
|
}), hookFirstNullCheck);
|
|
1326
|
-
this.
|
|
2007
|
+
this.hooks.emit("kubb:plugins:hook:progress:end", { hookName });
|
|
1327
2008
|
return result;
|
|
1328
2009
|
}
|
|
1329
2010
|
/**
|
|
@@ -1348,12 +2029,12 @@ var PluginDriver = class {
|
|
|
1348
2029
|
return parseResult;
|
|
1349
2030
|
}
|
|
1350
2031
|
/**
|
|
1351
|
-
* Runs all plugins in parallel based on `this.plugin` order and `
|
|
2032
|
+
* Runs all plugins in parallel based on `this.plugin` order and `dependencies` settings.
|
|
1352
2033
|
*/
|
|
1353
2034
|
async hookParallel({ hookName, parameters }) {
|
|
1354
2035
|
const plugins = [];
|
|
1355
2036
|
for (const plugin of this.plugins.values()) if (hookName in plugin) plugins.push(plugin);
|
|
1356
|
-
this.
|
|
2037
|
+
this.hooks.emit("kubb:plugins:hook:progress:start", {
|
|
1357
2038
|
hookName,
|
|
1358
2039
|
plugins
|
|
1359
2040
|
});
|
|
@@ -1374,7 +2055,7 @@ var PluginDriver = class {
|
|
|
1374
2055
|
const plugin = plugins[index];
|
|
1375
2056
|
if (plugin) {
|
|
1376
2057
|
const startTime = pluginStartTimes.get(plugin) ?? node_perf_hooks.performance.now();
|
|
1377
|
-
this.
|
|
2058
|
+
this.hooks.emit("kubb:error", result.reason, {
|
|
1378
2059
|
plugin,
|
|
1379
2060
|
hookName,
|
|
1380
2061
|
strategy: "hookParallel",
|
|
@@ -1384,19 +2065,19 @@ var PluginDriver = class {
|
|
|
1384
2065
|
}
|
|
1385
2066
|
}
|
|
1386
2067
|
});
|
|
1387
|
-
this.
|
|
2068
|
+
this.hooks.emit("kubb:plugins:hook:progress:end", { hookName });
|
|
1388
2069
|
return results.reduce((acc, result) => {
|
|
1389
2070
|
if (result.status === "fulfilled") acc.push(result.value);
|
|
1390
2071
|
return acc;
|
|
1391
2072
|
}, []);
|
|
1392
2073
|
}
|
|
1393
2074
|
/**
|
|
1394
|
-
*
|
|
2075
|
+
* Execute a lifecycle hook sequentially for all plugins that implement it.
|
|
1395
2076
|
*/
|
|
1396
2077
|
async hookSeq({ hookName, parameters }) {
|
|
1397
2078
|
const plugins = [];
|
|
1398
2079
|
for (const plugin of this.plugins.values()) if (hookName in plugin) plugins.push(plugin);
|
|
1399
|
-
this.
|
|
2080
|
+
this.hooks.emit("kubb:plugins:hook:progress:start", {
|
|
1400
2081
|
hookName,
|
|
1401
2082
|
plugins
|
|
1402
2083
|
});
|
|
@@ -1408,7 +2089,7 @@ var PluginDriver = class {
|
|
|
1408
2089
|
plugin
|
|
1409
2090
|
});
|
|
1410
2091
|
}));
|
|
1411
|
-
this.
|
|
2092
|
+
this.hooks.emit("kubb:plugins:hook:progress:end", { hookName });
|
|
1412
2093
|
}
|
|
1413
2094
|
getPlugin(pluginName) {
|
|
1414
2095
|
return this.plugins.get(pluginName);
|
|
@@ -1419,13 +2100,10 @@ var PluginDriver = class {
|
|
|
1419
2100
|
return plugin;
|
|
1420
2101
|
}
|
|
1421
2102
|
/**
|
|
1422
|
-
*
|
|
1423
|
-
* @param hookName Name of the plugin hook. Must be either in `PluginHooks` or `OutputPluginValueHooks`.
|
|
1424
|
-
* @param args Arguments passed to the plugin hook.
|
|
1425
|
-
* @param plugin The actual pluginObject to run.
|
|
2103
|
+
* Emit hook-processing completion metadata after a plugin hook resolves.
|
|
1426
2104
|
*/
|
|
1427
2105
|
#emitProcessingEnd({ startTime, output, strategy, hookName, plugin, parameters }) {
|
|
1428
|
-
this.
|
|
2106
|
+
this.hooks.emit("kubb:plugins:hook:processing:end", {
|
|
1429
2107
|
duration: Math.round(node_perf_hooks.performance.now() - startTime),
|
|
1430
2108
|
parameters,
|
|
1431
2109
|
output,
|
|
@@ -1437,7 +2115,7 @@ var PluginDriver = class {
|
|
|
1437
2115
|
#execute({ strategy, hookName, parameters, plugin }) {
|
|
1438
2116
|
const hook = plugin[hookName];
|
|
1439
2117
|
if (!hook) return null;
|
|
1440
|
-
this.
|
|
2118
|
+
this.hooks.emit("kubb:plugins:hook:processing:start", {
|
|
1441
2119
|
strategy,
|
|
1442
2120
|
hookName,
|
|
1443
2121
|
parameters,
|
|
@@ -1457,7 +2135,7 @@ var PluginDriver = class {
|
|
|
1457
2135
|
});
|
|
1458
2136
|
return output;
|
|
1459
2137
|
} catch (error) {
|
|
1460
|
-
this.
|
|
2138
|
+
this.hooks.emit("kubb:error", error, {
|
|
1461
2139
|
plugin,
|
|
1462
2140
|
hookName,
|
|
1463
2141
|
strategy,
|
|
@@ -1468,15 +2146,12 @@ var PluginDriver = class {
|
|
|
1468
2146
|
})();
|
|
1469
2147
|
}
|
|
1470
2148
|
/**
|
|
1471
|
-
*
|
|
1472
|
-
* @param hookName Name of the plugin hook. Must be in `PluginHooks`.
|
|
1473
|
-
* @param args Arguments passed to the plugin hook.
|
|
1474
|
-
* @param plugin The actual plugin
|
|
2149
|
+
* Execute a plugin lifecycle hook synchronously and return its output.
|
|
1475
2150
|
*/
|
|
1476
2151
|
#executeSync({ strategy, hookName, parameters, plugin }) {
|
|
1477
2152
|
const hook = plugin[hookName];
|
|
1478
2153
|
if (!hook) return null;
|
|
1479
|
-
this.
|
|
2154
|
+
this.hooks.emit("kubb:plugins:hook:processing:start", {
|
|
1480
2155
|
strategy,
|
|
1481
2156
|
hookName,
|
|
1482
2157
|
parameters,
|
|
@@ -1495,7 +2170,7 @@ var PluginDriver = class {
|
|
|
1495
2170
|
});
|
|
1496
2171
|
return output;
|
|
1497
2172
|
} catch (error) {
|
|
1498
|
-
this.
|
|
2173
|
+
this.hooks.emit("kubb:error", error, {
|
|
1499
2174
|
plugin,
|
|
1500
2175
|
hookName,
|
|
1501
2176
|
strategy,
|
|
@@ -1506,26 +2181,6 @@ var PluginDriver = class {
|
|
|
1506
2181
|
}
|
|
1507
2182
|
};
|
|
1508
2183
|
//#endregion
|
|
1509
|
-
//#region src/renderNode.tsx
|
|
1510
|
-
/**
|
|
1511
|
-
* Handles the return value of a plugin AST hook or generator method.
|
|
1512
|
-
*
|
|
1513
|
-
* - React element → rendered via renderer-jsx, files stored in `driver.fileManager`
|
|
1514
|
-
* - `Array<FileNode>` → upserted directly into `driver.fileManager`
|
|
1515
|
-
* - `void` / `null` / `undefined` → no-op (plugin handled it via `this.upsertFile`)
|
|
1516
|
-
*/
|
|
1517
|
-
async function applyHookResult(result, driver) {
|
|
1518
|
-
if (!result) return;
|
|
1519
|
-
if (Array.isArray(result)) {
|
|
1520
|
-
driver.fileManager.upsert(...result);
|
|
1521
|
-
return;
|
|
1522
|
-
}
|
|
1523
|
-
const renderer = (0, _kubb_renderer_jsx.createRenderer)();
|
|
1524
|
-
await renderer.render(/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: result }));
|
|
1525
|
-
driver.fileManager.upsert(...renderer.files);
|
|
1526
|
-
renderer.unmount();
|
|
1527
|
-
}
|
|
1528
|
-
//#endregion
|
|
1529
2184
|
//#region src/createStorage.ts
|
|
1530
2185
|
/**
|
|
1531
2186
|
* Creates a storage factory. Call the returned function with optional options to get the storage instance.
|
|
@@ -1623,7 +2278,7 @@ const fsStorage = createStorage(() => ({
|
|
|
1623
2278
|
}));
|
|
1624
2279
|
//#endregion
|
|
1625
2280
|
//#region package.json
|
|
1626
|
-
var version = "5.0.0-alpha.
|
|
2281
|
+
var version = "5.0.0-alpha.35";
|
|
1627
2282
|
//#endregion
|
|
1628
2283
|
//#region src/utils/diagnostics.ts
|
|
1629
2284
|
/**
|
|
@@ -1884,24 +2539,14 @@ function isInputPath(config) {
|
|
|
1884
2539
|
return typeof config?.input === "object" && config.input !== null && "path" in config.input;
|
|
1885
2540
|
}
|
|
1886
2541
|
//#endregion
|
|
1887
|
-
//#region src/
|
|
1888
|
-
/**
|
|
1889
|
-
* Initializes all Kubb infrastructure for a build without executing any plugins.
|
|
1890
|
-
*
|
|
1891
|
-
* - Validates the input path (when applicable).
|
|
1892
|
-
* - Applies config defaults (`root`, `output.*`, `devtools`).
|
|
1893
|
-
* - Runs the adapter (if configured) to produce the universal `InputNode`.
|
|
1894
|
-
* When no adapter is supplied and `@kubb/adapter-oas` is installed as an
|
|
1895
|
-
*
|
|
1896
|
-
* Pass the returned {@link SetupResult} directly to {@link safeBuild} or {@link build}
|
|
1897
|
-
* via the `overrides` argument to reuse the same infrastructure across multiple runs.
|
|
1898
|
-
*/
|
|
2542
|
+
//#region src/createKubb.ts
|
|
1899
2543
|
async function setup(options) {
|
|
1900
|
-
const { config: userConfig
|
|
2544
|
+
const { config: userConfig } = options;
|
|
2545
|
+
const hooks = options.hooks ?? new AsyncEventEmitter();
|
|
1901
2546
|
const sources = /* @__PURE__ */ new Map();
|
|
1902
2547
|
const diagnosticInfo = getDiagnosticInfo();
|
|
1903
|
-
if (Array.isArray(userConfig.input)) await
|
|
1904
|
-
await
|
|
2548
|
+
if (Array.isArray(userConfig.input)) await hooks.emit("kubb:warn", "This feature is still under development — use with caution");
|
|
2549
|
+
await hooks.emit("kubb:debug", {
|
|
1905
2550
|
date: /* @__PURE__ */ new Date(),
|
|
1906
2551
|
logs: [
|
|
1907
2552
|
"Configuration:",
|
|
@@ -1920,7 +2565,7 @@ async function setup(options) {
|
|
|
1920
2565
|
try {
|
|
1921
2566
|
if (isInputPath(userConfig) && !new URLPath(userConfig.input.path).isURL) {
|
|
1922
2567
|
await exists(userConfig.input.path);
|
|
1923
|
-
await
|
|
2568
|
+
await hooks.emit("kubb:debug", {
|
|
1924
2569
|
date: /* @__PURE__ */ new Date(),
|
|
1925
2570
|
logs: [`✓ Input file validated: ${userConfig.input.path}`]
|
|
1926
2571
|
});
|
|
@@ -1933,8 +2578,8 @@ async function setup(options) {
|
|
|
1933
2578
|
}
|
|
1934
2579
|
if (!userConfig.adapter) throw new Error("Adapter should be defined");
|
|
1935
2580
|
const config = {
|
|
1936
|
-
root: userConfig.root || process.cwd(),
|
|
1937
2581
|
...userConfig,
|
|
2582
|
+
root: userConfig.root || process.cwd(),
|
|
1938
2583
|
parsers: userConfig.parsers ?? [],
|
|
1939
2584
|
adapter: userConfig.adapter,
|
|
1940
2585
|
output: {
|
|
@@ -1952,26 +2597,26 @@ async function setup(options) {
|
|
|
1952
2597
|
};
|
|
1953
2598
|
const storage = config.output.write === false ? null : config.output.storage ?? fsStorage();
|
|
1954
2599
|
if (config.output.clean) {
|
|
1955
|
-
await
|
|
2600
|
+
await hooks.emit("kubb:debug", {
|
|
1956
2601
|
date: /* @__PURE__ */ new Date(),
|
|
1957
2602
|
logs: ["Cleaning output directories", ` • Output: ${config.output.path}`]
|
|
1958
2603
|
});
|
|
1959
2604
|
await storage?.clear((0, node_path.resolve)(config.root, config.output.path));
|
|
1960
2605
|
}
|
|
1961
2606
|
const driver = new PluginDriver(config, {
|
|
1962
|
-
|
|
2607
|
+
hooks,
|
|
1963
2608
|
concurrency: 15
|
|
1964
2609
|
});
|
|
1965
2610
|
const adapter = config.adapter;
|
|
1966
2611
|
if (!adapter) throw new Error("No adapter configured. Please provide an adapter in your kubb.config.ts.");
|
|
1967
2612
|
const source = inputToAdapterSource(config);
|
|
1968
|
-
await
|
|
2613
|
+
await hooks.emit("kubb:debug", {
|
|
1969
2614
|
date: /* @__PURE__ */ new Date(),
|
|
1970
2615
|
logs: [`Running adapter: ${adapter.name}`]
|
|
1971
2616
|
});
|
|
1972
2617
|
driver.adapter = adapter;
|
|
1973
2618
|
driver.inputNode = await adapter.parse(source);
|
|
1974
|
-
await
|
|
2619
|
+
await hooks.emit("kubb:debug", {
|
|
1975
2620
|
date: /* @__PURE__ */ new Date(),
|
|
1976
2621
|
logs: [
|
|
1977
2622
|
`✓ Adapter '${adapter.name}' resolved InputNode`,
|
|
@@ -1981,53 +2626,32 @@ async function setup(options) {
|
|
|
1981
2626
|
});
|
|
1982
2627
|
return {
|
|
1983
2628
|
config,
|
|
1984
|
-
|
|
2629
|
+
hooks,
|
|
1985
2630
|
driver,
|
|
1986
2631
|
sources,
|
|
1987
2632
|
storage
|
|
1988
2633
|
};
|
|
1989
2634
|
}
|
|
1990
2635
|
/**
|
|
1991
|
-
* Runs a full Kubb build and throws on any error or plugin failure.
|
|
1992
|
-
*
|
|
1993
|
-
* Internally delegates to {@link safeBuild} and rethrows collected errors.
|
|
1994
|
-
* Pass an existing {@link SetupResult} via `overrides` to skip the setup phase.
|
|
1995
|
-
*/
|
|
1996
|
-
async function build(options, overrides) {
|
|
1997
|
-
const { files, driver, failedPlugins, pluginTimings, error, sources } = await safeBuild(options, overrides);
|
|
1998
|
-
if (error) throw error;
|
|
1999
|
-
if (failedPlugins.size > 0) {
|
|
2000
|
-
const errors = [...failedPlugins].map(({ error }) => error);
|
|
2001
|
-
throw new BuildError(`Build Error with ${failedPlugins.size} failed plugins`, { errors });
|
|
2002
|
-
}
|
|
2003
|
-
return {
|
|
2004
|
-
failedPlugins,
|
|
2005
|
-
files,
|
|
2006
|
-
driver,
|
|
2007
|
-
pluginTimings,
|
|
2008
|
-
error: void 0,
|
|
2009
|
-
sources
|
|
2010
|
-
};
|
|
2011
|
-
}
|
|
2012
|
-
/**
|
|
2013
2636
|
* Walks the AST and dispatches nodes to a plugin's direct AST hooks
|
|
2014
2637
|
* (`schema`, `operation`, `operations`).
|
|
2015
|
-
*
|
|
2016
|
-
* - Each hook accepts a single handler **or an array** — all entries are called in sequence.
|
|
2017
|
-
* - Nodes that are excluded by `exclude`/`include` plugin options are skipped automatically.
|
|
2018
|
-
* - Return values are handled via `applyHookResult`: React elements are rendered,
|
|
2019
|
-
* `FileNode[]` are written via upsert, and `void` is a no-op (manual handling).
|
|
2020
|
-
* - Barrel files are generated automatically when `output.barrelType` is set.
|
|
2021
2638
|
*/
|
|
2022
2639
|
async function runPluginAstHooks(plugin, context) {
|
|
2023
2640
|
const { adapter, inputNode, resolver, driver } = context;
|
|
2024
2641
|
const { exclude, include, override } = plugin.options;
|
|
2025
2642
|
if (!adapter || !inputNode) throw new Error(`[${plugin.name}] No adapter found. Add an OAS adapter (e.g. pluginOas()) before this plugin in your Kubb config.`);
|
|
2643
|
+
function resolveRenderer(gen) {
|
|
2644
|
+
return gen.renderer === null ? void 0 : gen.renderer ?? plugin.renderer ?? context.config.renderer;
|
|
2645
|
+
}
|
|
2646
|
+
const generators = plugin.generators ?? [];
|
|
2026
2647
|
const collectedOperations = [];
|
|
2648
|
+
const generatorContext = {
|
|
2649
|
+
...context,
|
|
2650
|
+
resolver: driver.getResolver(plugin.name)
|
|
2651
|
+
};
|
|
2027
2652
|
await (0, _kubb_ast.walk)(inputNode, {
|
|
2028
2653
|
depth: "shallow",
|
|
2029
2654
|
async schema(node) {
|
|
2030
|
-
if (!plugin.schema) return;
|
|
2031
2655
|
const transformedNode = plugin.transformer ? (0, _kubb_ast.transform)(node, plugin.transformer) : node;
|
|
2032
2656
|
const options = resolver.resolveOptions(transformedNode, {
|
|
2033
2657
|
options: plugin.options,
|
|
@@ -2036,7 +2660,15 @@ async function runPluginAstHooks(plugin, context) {
|
|
|
2036
2660
|
override
|
|
2037
2661
|
});
|
|
2038
2662
|
if (options === null) return;
|
|
2039
|
-
|
|
2663
|
+
const ctx = {
|
|
2664
|
+
...generatorContext,
|
|
2665
|
+
options
|
|
2666
|
+
};
|
|
2667
|
+
for (const gen of generators) {
|
|
2668
|
+
if (!gen.schema) continue;
|
|
2669
|
+
await applyHookResult(await gen.schema(transformedNode, ctx), driver, resolveRenderer(gen));
|
|
2670
|
+
}
|
|
2671
|
+
await driver.hooks.emit("kubb:generate:schema", transformedNode, ctx);
|
|
2040
2672
|
},
|
|
2041
2673
|
async operation(node) {
|
|
2042
2674
|
const transformedNode = plugin.transformer ? (0, _kubb_ast.transform)(node, plugin.transformer) : node;
|
|
@@ -2048,28 +2680,43 @@ async function runPluginAstHooks(plugin, context) {
|
|
|
2048
2680
|
});
|
|
2049
2681
|
if (options !== null) {
|
|
2050
2682
|
collectedOperations.push(transformedNode);
|
|
2051
|
-
|
|
2683
|
+
const ctx = {
|
|
2684
|
+
...generatorContext,
|
|
2685
|
+
options
|
|
2686
|
+
};
|
|
2687
|
+
for (const gen of generators) {
|
|
2688
|
+
if (!gen.operation) continue;
|
|
2689
|
+
await applyHookResult(await gen.operation(transformedNode, ctx), driver, resolveRenderer(gen));
|
|
2690
|
+
}
|
|
2691
|
+
await driver.hooks.emit("kubb:generate:operation", transformedNode, ctx);
|
|
2052
2692
|
}
|
|
2053
2693
|
}
|
|
2054
2694
|
});
|
|
2055
|
-
if (
|
|
2695
|
+
if (collectedOperations.length > 0) {
|
|
2696
|
+
const ctx = {
|
|
2697
|
+
...generatorContext,
|
|
2698
|
+
options: plugin.options
|
|
2699
|
+
};
|
|
2700
|
+
for (const gen of generators) {
|
|
2701
|
+
if (!gen.operations) continue;
|
|
2702
|
+
await applyHookResult(await gen.operations(collectedOperations, ctx), driver, resolveRenderer(gen));
|
|
2703
|
+
}
|
|
2704
|
+
await driver.hooks.emit("kubb:generate:operations", collectedOperations, ctx);
|
|
2705
|
+
}
|
|
2056
2706
|
}
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
*
|
|
2060
|
-
* - Installs each plugin in order, recording failures in `failedPlugins`.
|
|
2061
|
-
* - Generates the root barrel file when `output.barrelType` is set.
|
|
2062
|
-
* - Writes all files through the driver's FileManager and FileProcessor.
|
|
2063
|
-
*
|
|
2064
|
-
* Returns a {@link BuildOutput} even on failure — inspect `error` and
|
|
2065
|
-
* `failedPlugins` to determine whether the build succeeded.
|
|
2066
|
-
*/
|
|
2067
|
-
async function safeBuild(options, overrides) {
|
|
2068
|
-
const { driver, events, sources, storage } = overrides ? overrides : await setup(options);
|
|
2707
|
+
async function safeBuild(setupResult) {
|
|
2708
|
+
const { driver, hooks, sources, storage } = setupResult;
|
|
2069
2709
|
const failedPlugins = /* @__PURE__ */ new Set();
|
|
2070
2710
|
const pluginTimings = /* @__PURE__ */ new Map();
|
|
2071
2711
|
const config = driver.config;
|
|
2072
2712
|
try {
|
|
2713
|
+
await driver.emitSetupHooks();
|
|
2714
|
+
if (driver.adapter && driver.inputNode) await hooks.emit("kubb:build:start", {
|
|
2715
|
+
config,
|
|
2716
|
+
adapter: driver.adapter,
|
|
2717
|
+
inputNode: driver.inputNode,
|
|
2718
|
+
getPlugin: (name) => driver.getPlugin(name)
|
|
2719
|
+
});
|
|
2073
2720
|
for (const plugin of driver.plugins.values()) {
|
|
2074
2721
|
const context = driver.getContext(plugin);
|
|
2075
2722
|
const hrStart = process.hrtime();
|
|
@@ -2077,13 +2724,13 @@ async function safeBuild(options, overrides) {
|
|
|
2077
2724
|
const root = (0, node_path.resolve)(config.root, config.output.path);
|
|
2078
2725
|
try {
|
|
2079
2726
|
const timestamp = /* @__PURE__ */ new Date();
|
|
2080
|
-
await
|
|
2081
|
-
await
|
|
2727
|
+
await hooks.emit("kubb:plugin:start", plugin);
|
|
2728
|
+
await hooks.emit("kubb:debug", {
|
|
2082
2729
|
date: timestamp,
|
|
2083
2730
|
logs: ["Starting plugin...", ` • Plugin Name: ${plugin.name}`]
|
|
2084
2731
|
});
|
|
2085
2732
|
await plugin.buildStart.call(context);
|
|
2086
|
-
if (plugin.
|
|
2733
|
+
if (plugin.generators?.length || driver.hasRegisteredGenerators(plugin.name)) await runPluginAstHooks(plugin, context);
|
|
2087
2734
|
if (output) {
|
|
2088
2735
|
const barrelFiles = await getBarrelFiles(driver.fileManager.files, {
|
|
2089
2736
|
type: output.barrelType ?? "named",
|
|
@@ -2095,11 +2742,11 @@ async function safeBuild(options, overrides) {
|
|
|
2095
2742
|
}
|
|
2096
2743
|
const duration = getElapsedMs(hrStart);
|
|
2097
2744
|
pluginTimings.set(plugin.name, duration);
|
|
2098
|
-
await
|
|
2745
|
+
await hooks.emit("kubb:plugin:end", plugin, {
|
|
2099
2746
|
duration,
|
|
2100
2747
|
success: true
|
|
2101
2748
|
});
|
|
2102
|
-
await
|
|
2749
|
+
await hooks.emit("kubb:debug", {
|
|
2103
2750
|
date: /* @__PURE__ */ new Date(),
|
|
2104
2751
|
logs: [`✓ Plugin started successfully (${formatMs(duration)})`]
|
|
2105
2752
|
});
|
|
@@ -2107,12 +2754,12 @@ async function safeBuild(options, overrides) {
|
|
|
2107
2754
|
const error = caughtError;
|
|
2108
2755
|
const errorTimestamp = /* @__PURE__ */ new Date();
|
|
2109
2756
|
const duration = getElapsedMs(hrStart);
|
|
2110
|
-
await
|
|
2757
|
+
await hooks.emit("kubb:plugin:end", plugin, {
|
|
2111
2758
|
duration,
|
|
2112
2759
|
success: false,
|
|
2113
2760
|
error
|
|
2114
2761
|
});
|
|
2115
|
-
await
|
|
2762
|
+
await hooks.emit("kubb:debug", {
|
|
2116
2763
|
date: errorTimestamp,
|
|
2117
2764
|
logs: [
|
|
2118
2765
|
"✗ Plugin start failed",
|
|
@@ -2131,7 +2778,7 @@ async function safeBuild(options, overrides) {
|
|
|
2131
2778
|
if (config.output.barrelType) {
|
|
2132
2779
|
const rootPath = (0, node_path.resolve)((0, node_path.resolve)(config.root), config.output.path, BARREL_FILENAME);
|
|
2133
2780
|
const rootDir = (0, node_path.dirname)(rootPath);
|
|
2134
|
-
await
|
|
2781
|
+
await hooks.emit("kubb:debug", {
|
|
2135
2782
|
date: /* @__PURE__ */ new Date(),
|
|
2136
2783
|
logs: [
|
|
2137
2784
|
"Generating barrel file",
|
|
@@ -2142,7 +2789,7 @@ async function safeBuild(options, overrides) {
|
|
|
2142
2789
|
const barrelFiles = driver.fileManager.files.filter((file) => {
|
|
2143
2790
|
return file.sources.some((source) => source.isIndexable);
|
|
2144
2791
|
});
|
|
2145
|
-
await
|
|
2792
|
+
await hooks.emit("kubb:debug", {
|
|
2146
2793
|
date: /* @__PURE__ */ new Date(),
|
|
2147
2794
|
logs: [`Found ${barrelFiles.length} indexable files for barrel export`]
|
|
2148
2795
|
});
|
|
@@ -2162,7 +2809,7 @@ async function safeBuild(options, overrides) {
|
|
|
2162
2809
|
meta: {}
|
|
2163
2810
|
});
|
|
2164
2811
|
driver.fileManager.upsert(rootFile);
|
|
2165
|
-
await
|
|
2812
|
+
await hooks.emit("kubb:debug", {
|
|
2166
2813
|
date: /* @__PURE__ */ new Date(),
|
|
2167
2814
|
logs: [`✓ Generated barrel file (${rootFile.exports?.length || 0} exports)`]
|
|
2168
2815
|
});
|
|
@@ -2171,7 +2818,7 @@ async function safeBuild(options, overrides) {
|
|
|
2171
2818
|
const parsersMap = /* @__PURE__ */ new Map();
|
|
2172
2819
|
for (const parser of config.parsers) if (parser.extNames) for (const extname of parser.extNames) parsersMap.set(extname, parser);
|
|
2173
2820
|
const fileProcessor = new FileProcessor();
|
|
2174
|
-
await
|
|
2821
|
+
await hooks.emit("kubb:debug", {
|
|
2175
2822
|
date: /* @__PURE__ */ new Date(),
|
|
2176
2823
|
logs: [`Writing ${files.length} files...`]
|
|
2177
2824
|
});
|
|
@@ -2179,591 +2826,272 @@ async function safeBuild(options, overrides) {
|
|
|
2179
2826
|
parsers: parsersMap,
|
|
2180
2827
|
extension: config.output.extension,
|
|
2181
2828
|
onStart: async (processingFiles) => {
|
|
2182
|
-
await
|
|
2829
|
+
await hooks.emit("kubb:files:processing:start", processingFiles);
|
|
2183
2830
|
},
|
|
2184
2831
|
onUpdate: async ({ file, source, processed, total, percentage }) => {
|
|
2185
|
-
await
|
|
2832
|
+
await hooks.emit("kubb:file:processing:update", {
|
|
2186
2833
|
file,
|
|
2187
2834
|
source,
|
|
2188
2835
|
processed,
|
|
2189
|
-
total,
|
|
2190
|
-
percentage,
|
|
2191
|
-
config
|
|
2192
|
-
});
|
|
2193
|
-
if (source) {
|
|
2194
|
-
await storage?.setItem(file.path, source);
|
|
2195
|
-
sources.set(file.path, source);
|
|
2196
|
-
}
|
|
2197
|
-
},
|
|
2198
|
-
onEnd: async (processedFiles) => {
|
|
2199
|
-
await
|
|
2200
|
-
await
|
|
2201
|
-
date: /* @__PURE__ */ new Date(),
|
|
2202
|
-
logs: [`✓ File write process completed for ${processedFiles.length} files`]
|
|
2203
|
-
});
|
|
2204
|
-
}
|
|
2205
|
-
});
|
|
2206
|
-
for (const plugin of driver.plugins.values()) if (plugin.buildEnd) {
|
|
2207
|
-
const context = driver.getContext(plugin);
|
|
2208
|
-
await plugin.buildEnd.call(context);
|
|
2209
|
-
}
|
|
2210
|
-
return {
|
|
2211
|
-
failedPlugins,
|
|
2212
|
-
files,
|
|
2213
|
-
driver,
|
|
2214
|
-
pluginTimings,
|
|
2215
|
-
sources
|
|
2216
|
-
};
|
|
2217
|
-
} catch (error) {
|
|
2218
|
-
return {
|
|
2219
|
-
failedPlugins,
|
|
2220
|
-
files: [],
|
|
2221
|
-
driver,
|
|
2222
|
-
pluginTimings,
|
|
2223
|
-
error,
|
|
2224
|
-
sources
|
|
2225
|
-
};
|
|
2226
|
-
}
|
|
2227
|
-
}
|
|
2228
|
-
function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, driver }) {
|
|
2229
|
-
const pluginNameMap = /* @__PURE__ */ new Map();
|
|
2230
|
-
for (const plugin of driver.plugins.values()) pluginNameMap.set(plugin.name, plugin);
|
|
2231
|
-
return barrelFiles.flatMap((file) => {
|
|
2232
|
-
const containsOnlyTypes = file.sources?.every((source) => source.isTypeOnly);
|
|
2233
|
-
return (file.sources ?? []).flatMap((source) => {
|
|
2234
|
-
if (!file.path || !source.isIndexable) return [];
|
|
2235
|
-
const meta = file.meta;
|
|
2236
|
-
const pluginOptions = (meta?.pluginName ? pluginNameMap.get(meta.pluginName) : void 0)?.options;
|
|
2237
|
-
if (!pluginOptions || pluginOptions.output?.barrelType === false) return [];
|
|
2238
|
-
const exportName = config.output.barrelType === "all" ? void 0 : source.name ? [source.name] : void 0;
|
|
2239
|
-
if (exportName?.some((n) => existingExports.has(n))) return [];
|
|
2240
|
-
return [(0, _kubb_ast.createExport)({
|
|
2241
|
-
name: exportName,
|
|
2242
|
-
path: getRelativePath(rootDir, file.path),
|
|
2243
|
-
isTypeOnly: config.output.barrelType === "all" ? containsOnlyTypes : source.isTypeOnly
|
|
2244
|
-
})];
|
|
2245
|
-
});
|
|
2246
|
-
});
|
|
2247
|
-
}
|
|
2248
|
-
/**
|
|
2249
|
-
* Maps the resolved `Config['input']` shape into an `AdapterSource` that
|
|
2250
|
-
* the adapter's `parse()` can consume.
|
|
2251
|
-
*/
|
|
2252
|
-
function inputToAdapterSource(config) {
|
|
2253
|
-
if (Array.isArray(config.input)) return {
|
|
2254
|
-
type: "paths",
|
|
2255
|
-
paths: config.input.map((i) => new URLPath(i.path).isURL ? i.path : (0, node_path.resolve)(config.root, i.path))
|
|
2256
|
-
};
|
|
2257
|
-
if ("data" in config.input) return {
|
|
2258
|
-
type: "data",
|
|
2259
|
-
data: config.input.data
|
|
2260
|
-
};
|
|
2261
|
-
if (new URLPath(config.input.path).isURL) return {
|
|
2262
|
-
type: "path",
|
|
2263
|
-
path: config.input.path
|
|
2264
|
-
};
|
|
2265
|
-
return {
|
|
2266
|
-
type: "path",
|
|
2267
|
-
path: (0, node_path.resolve)(config.root, config.input.path)
|
|
2268
|
-
};
|
|
2269
|
-
}
|
|
2270
|
-
//#endregion
|
|
2271
|
-
//#region src/createAdapter.ts
|
|
2272
|
-
/**
|
|
2273
|
-
* Creates an adapter factory. Call the returned function with optional options to get the adapter instance.
|
|
2274
|
-
*
|
|
2275
|
-
* @example
|
|
2276
|
-
* export const myAdapter = createAdapter<MyAdapter>((options) => {
|
|
2277
|
-
* return {
|
|
2278
|
-
* name: 'my-adapter',
|
|
2279
|
-
* options,
|
|
2280
|
-
* async parse(source) { ... },
|
|
2281
|
-
* }
|
|
2282
|
-
* })
|
|
2283
|
-
*
|
|
2284
|
-
* // instantiate
|
|
2285
|
-
* const adapter = myAdapter({ validate: true })
|
|
2286
|
-
*/
|
|
2287
|
-
function createAdapter(build) {
|
|
2288
|
-
return (options) => build(options ?? {});
|
|
2289
|
-
}
|
|
2290
|
-
//#endregion
|
|
2291
|
-
//#region src/createPlugin.ts
|
|
2292
|
-
/**
|
|
2293
|
-
* Creates a plugin factory. Call the returned function with optional options to get the plugin instance.
|
|
2294
|
-
*
|
|
2295
|
-
* @example
|
|
2296
|
-
* ```ts
|
|
2297
|
-
* export const myPlugin = createPlugin<MyPlugin>((options) => {
|
|
2298
|
-
* return {
|
|
2299
|
-
* name: 'my-plugin',
|
|
2300
|
-
* get options() { return options },
|
|
2301
|
-
* resolvePath(baseName) { ... },
|
|
2302
|
-
* resolveName(name, type) { ... },
|
|
2303
|
-
* }
|
|
2304
|
-
* })
|
|
2305
|
-
*
|
|
2306
|
-
* // instantiate
|
|
2307
|
-
* const plugin = myPlugin({ output: { path: 'src/gen' } })
|
|
2308
|
-
* ```
|
|
2309
|
-
*/
|
|
2310
|
-
function createPlugin(build) {
|
|
2311
|
-
return (options) => build(options ?? {});
|
|
2312
|
-
}
|
|
2313
|
-
//#endregion
|
|
2314
|
-
//#region src/defineConfig.ts
|
|
2315
|
-
function defineConfig(config) {
|
|
2316
|
-
return config;
|
|
2317
|
-
}
|
|
2318
|
-
//#endregion
|
|
2319
|
-
//#region src/defineGenerator.ts
|
|
2320
|
-
/**
|
|
2321
|
-
* Defines a generator. Returns the object as-is with correct `this` typings.
|
|
2322
|
-
* No type discrimination (`type: 'react' | 'core'`) needed — `applyHookResult`
|
|
2323
|
-
* handles React elements and `File[]` uniformly.
|
|
2324
|
-
*/
|
|
2325
|
-
function defineGenerator(generator) {
|
|
2326
|
-
return generator;
|
|
2327
|
-
}
|
|
2328
|
-
/**
|
|
2329
|
-
* Merges an array of generators into a single generator.
|
|
2330
|
-
*
|
|
2331
|
-
* The merged generator's `schema`, `operation`, and `operations` methods run
|
|
2332
|
-
* the corresponding method from each input generator in sequence, applying each
|
|
2333
|
-
* result via `applyHookResult`. This eliminates the need to write the loop
|
|
2334
|
-
* manually in each plugin.
|
|
2335
|
-
*
|
|
2336
|
-
* @param generators - Array of generators to merge into a single generator.
|
|
2337
|
-
*
|
|
2338
|
-
* @example
|
|
2339
|
-
* ```ts
|
|
2340
|
-
* const merged = mergeGenerators(generators)
|
|
2341
|
-
*
|
|
2342
|
-
* return {
|
|
2343
|
-
* name: pluginName,
|
|
2344
|
-
* schema: merged.schema,
|
|
2345
|
-
* operation: merged.operation,
|
|
2346
|
-
* operations: merged.operations,
|
|
2347
|
-
* }
|
|
2348
|
-
* ```
|
|
2349
|
-
*/
|
|
2350
|
-
function mergeGenerators(generators) {
|
|
2351
|
-
return {
|
|
2352
|
-
name: generators.length > 0 ? generators.map((g) => g.name).join("+") : "merged",
|
|
2353
|
-
async schema(node, options) {
|
|
2354
|
-
for (const gen of generators) {
|
|
2355
|
-
if (!gen.schema) continue;
|
|
2356
|
-
await applyHookResult(await gen.schema.call(this, node, options), this.driver);
|
|
2357
|
-
}
|
|
2358
|
-
},
|
|
2359
|
-
async operation(node, options) {
|
|
2360
|
-
for (const gen of generators) {
|
|
2361
|
-
if (!gen.operation) continue;
|
|
2362
|
-
await applyHookResult(await gen.operation.call(this, node, options), this.driver);
|
|
2363
|
-
}
|
|
2364
|
-
},
|
|
2365
|
-
async operations(nodes, options) {
|
|
2366
|
-
for (const gen of generators) {
|
|
2367
|
-
if (!gen.operations) continue;
|
|
2368
|
-
await applyHookResult(await gen.operations.call(this, nodes, options), this.driver);
|
|
2836
|
+
total,
|
|
2837
|
+
percentage,
|
|
2838
|
+
config
|
|
2839
|
+
});
|
|
2840
|
+
if (source) {
|
|
2841
|
+
await storage?.setItem(file.path, source);
|
|
2842
|
+
sources.set(file.path, source);
|
|
2843
|
+
}
|
|
2844
|
+
},
|
|
2845
|
+
onEnd: async (processedFiles) => {
|
|
2846
|
+
await hooks.emit("kubb:files:processing:end", processedFiles);
|
|
2847
|
+
await hooks.emit("kubb:debug", {
|
|
2848
|
+
date: /* @__PURE__ */ new Date(),
|
|
2849
|
+
logs: [`✓ File write process completed for ${processedFiles.length} files`]
|
|
2850
|
+
});
|
|
2369
2851
|
}
|
|
2852
|
+
});
|
|
2853
|
+
for (const plugin of driver.plugins.values()) if (plugin.buildEnd) {
|
|
2854
|
+
const context = driver.getContext(plugin);
|
|
2855
|
+
await plugin.buildEnd.call(context);
|
|
2370
2856
|
}
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
* Wraps a logger definition into a typed {@link Logger}.
|
|
2377
|
-
*
|
|
2378
|
-
* @example
|
|
2379
|
-
* export const myLogger = defineLogger({
|
|
2380
|
-
* name: 'my-logger',
|
|
2381
|
-
* install(context, options) {
|
|
2382
|
-
* context.on('info', (message) => console.log('ℹ', message))
|
|
2383
|
-
* context.on('error', (error) => console.error('✗', error.message))
|
|
2384
|
-
* },
|
|
2385
|
-
* })
|
|
2386
|
-
*/
|
|
2387
|
-
function defineLogger(logger) {
|
|
2388
|
-
return logger;
|
|
2389
|
-
}
|
|
2390
|
-
//#endregion
|
|
2391
|
-
//#region src/defineParser.ts
|
|
2392
|
-
/**
|
|
2393
|
-
* Defines a parser with type safety.
|
|
2394
|
-
*
|
|
2395
|
-
* Use this function to create parsers that transform generated files to strings
|
|
2396
|
-
* based on their extension.
|
|
2397
|
-
*
|
|
2398
|
-
* @example
|
|
2399
|
-
* ```ts
|
|
2400
|
-
* import { defineParser } from '@kubb/core'
|
|
2401
|
-
*
|
|
2402
|
-
* export const jsonParser = defineParser({
|
|
2403
|
-
* name: 'json',
|
|
2404
|
-
* extNames: ['.json'],
|
|
2405
|
-
* parse(file) {
|
|
2406
|
-
* const { extractStringsFromNodes } = await import('@kubb/ast')
|
|
2407
|
-
* return file.sources.map((s) => extractStringsFromNodes(s.nodes ?? [])).join('\n')
|
|
2408
|
-
* },
|
|
2409
|
-
* })
|
|
2410
|
-
* ```
|
|
2411
|
-
*/
|
|
2412
|
-
function defineParser(parser) {
|
|
2413
|
-
return parser;
|
|
2414
|
-
}
|
|
2415
|
-
//#endregion
|
|
2416
|
-
//#region src/definePresets.ts
|
|
2417
|
-
/**
|
|
2418
|
-
* Creates a typed presets registry object — a named collection of {@link Preset} entries.
|
|
2419
|
-
*
|
|
2420
|
-
* @example
|
|
2421
|
-
* import { definePreset, definePresets } from '@kubb/core'
|
|
2422
|
-
* import { resolverTsLegacy } from '@kubb/plugin-ts'
|
|
2423
|
-
*
|
|
2424
|
-
* export const myPresets = definePresets({
|
|
2425
|
-
* kubbV4: definePreset('kubbV4', { resolvers: [resolverTsLegacy] }),
|
|
2426
|
-
* })
|
|
2427
|
-
*/
|
|
2428
|
-
function definePresets(presets) {
|
|
2429
|
-
return presets;
|
|
2430
|
-
}
|
|
2431
|
-
//#endregion
|
|
2432
|
-
//#region src/defineResolver.ts
|
|
2433
|
-
/**
|
|
2434
|
-
* Checks if an operation matches a pattern for a given filter type (`tag`, `operationId`, `path`, `method`).
|
|
2435
|
-
*/
|
|
2436
|
-
function matchesOperationPattern(node, type, pattern) {
|
|
2437
|
-
switch (type) {
|
|
2438
|
-
case "tag": return node.tags.some((tag) => !!tag.match(pattern));
|
|
2439
|
-
case "operationId": return !!node.operationId.match(pattern);
|
|
2440
|
-
case "path": return !!node.path.match(pattern);
|
|
2441
|
-
case "method": return !!node.method.toLowerCase().match(pattern);
|
|
2442
|
-
case "contentType": return !!node.requestBody?.contentType?.match(pattern);
|
|
2443
|
-
default: return false;
|
|
2444
|
-
}
|
|
2445
|
-
}
|
|
2446
|
-
/**
|
|
2447
|
-
* Checks if a schema matches a pattern for a given filter type (`schemaName`).
|
|
2448
|
-
*
|
|
2449
|
-
* Returns `null` when the filter type doesn't apply to schemas.
|
|
2450
|
-
*/
|
|
2451
|
-
function matchesSchemaPattern(node, type, pattern) {
|
|
2452
|
-
switch (type) {
|
|
2453
|
-
case "schemaName": return node.name ? !!node.name.match(pattern) : false;
|
|
2454
|
-
default: return null;
|
|
2455
|
-
}
|
|
2456
|
-
}
|
|
2457
|
-
/**
|
|
2458
|
-
* Default name resolver used by `defineResolver`.
|
|
2459
|
-
*
|
|
2460
|
-
* - `camelCase` for `function` and `file` types.
|
|
2461
|
-
* - `PascalCase` for `type`.
|
|
2462
|
-
* - `camelCase` for everything else.
|
|
2463
|
-
*/
|
|
2464
|
-
function defaultResolver(name, type) {
|
|
2465
|
-
let resolvedName = camelCase(name);
|
|
2466
|
-
if (type === "file" || type === "function") resolvedName = camelCase(name, { isFile: type === "file" });
|
|
2467
|
-
if (type === "type") resolvedName = pascalCase(name);
|
|
2468
|
-
return resolvedName;
|
|
2469
|
-
}
|
|
2470
|
-
/**
|
|
2471
|
-
* Default option resolver — applies include/exclude filters and merges matching override options.
|
|
2472
|
-
*
|
|
2473
|
-
* Returns `null` when the node is filtered out by an `exclude` rule or not matched by any `include` rule.
|
|
2474
|
-
*
|
|
2475
|
-
* @example Include/exclude filtering
|
|
2476
|
-
* ```ts
|
|
2477
|
-
* const options = defaultResolveOptions(operationNode, {
|
|
2478
|
-
* options: { output: 'types' },
|
|
2479
|
-
* exclude: [{ type: 'tag', pattern: 'internal' }],
|
|
2480
|
-
* })
|
|
2481
|
-
* // → null when node has tag 'internal'
|
|
2482
|
-
* ```
|
|
2483
|
-
*
|
|
2484
|
-
* @example Override merging
|
|
2485
|
-
* ```ts
|
|
2486
|
-
* const options = defaultResolveOptions(operationNode, {
|
|
2487
|
-
* options: { enumType: 'asConst' },
|
|
2488
|
-
* override: [{ type: 'operationId', pattern: 'listPets', options: { enumType: 'enum' } }],
|
|
2489
|
-
* })
|
|
2490
|
-
* // → { enumType: 'enum' } when operationId matches
|
|
2491
|
-
* ```
|
|
2492
|
-
*/
|
|
2493
|
-
function defaultResolveOptions(node, { options, exclude = [], include, override = [] }) {
|
|
2494
|
-
if ((0, _kubb_ast.isOperationNode)(node)) {
|
|
2495
|
-
if (exclude.some(({ type, pattern }) => matchesOperationPattern(node, type, pattern))) return null;
|
|
2496
|
-
if (include && !include.some(({ type, pattern }) => matchesOperationPattern(node, type, pattern))) return null;
|
|
2497
|
-
const overrideOptions = override.find(({ type, pattern }) => matchesOperationPattern(node, type, pattern))?.options;
|
|
2857
|
+
await hooks.emit("kubb:build:end", {
|
|
2858
|
+
files,
|
|
2859
|
+
config,
|
|
2860
|
+
outputDir: (0, node_path.resolve)(config.root, config.output.path)
|
|
2861
|
+
});
|
|
2498
2862
|
return {
|
|
2499
|
-
|
|
2500
|
-
|
|
2863
|
+
failedPlugins,
|
|
2864
|
+
files,
|
|
2865
|
+
driver,
|
|
2866
|
+
pluginTimings,
|
|
2867
|
+
sources
|
|
2501
2868
|
};
|
|
2502
|
-
}
|
|
2503
|
-
if ((0, _kubb_ast.isSchemaNode)(node)) {
|
|
2504
|
-
if (exclude.some(({ type, pattern }) => matchesSchemaPattern(node, type, pattern) === true)) return null;
|
|
2505
|
-
if (include) {
|
|
2506
|
-
const applicable = include.map(({ type, pattern }) => matchesSchemaPattern(node, type, pattern)).filter((r) => r !== null);
|
|
2507
|
-
if (applicable.length > 0 && !applicable.includes(true)) return null;
|
|
2508
|
-
}
|
|
2509
|
-
const overrideOptions = override.find(({ type, pattern }) => matchesSchemaPattern(node, type, pattern) === true)?.options;
|
|
2869
|
+
} catch (error) {
|
|
2510
2870
|
return {
|
|
2511
|
-
|
|
2512
|
-
|
|
2871
|
+
failedPlugins,
|
|
2872
|
+
files: [],
|
|
2873
|
+
driver,
|
|
2874
|
+
pluginTimings,
|
|
2875
|
+
error,
|
|
2876
|
+
sources
|
|
2513
2877
|
};
|
|
2878
|
+
} finally {
|
|
2879
|
+
driver.dispose();
|
|
2514
2880
|
}
|
|
2515
|
-
return options;
|
|
2516
2881
|
}
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
if (
|
|
2563
|
-
|
|
2564
|
-
|
|
2882
|
+
async function build(setupResult) {
|
|
2883
|
+
const { files, driver, failedPlugins, pluginTimings, error, sources } = await safeBuild(setupResult);
|
|
2884
|
+
if (error) throw error;
|
|
2885
|
+
if (failedPlugins.size > 0) {
|
|
2886
|
+
const errors = [...failedPlugins].map(({ error }) => error);
|
|
2887
|
+
throw new BuildError(`Build Error with ${failedPlugins.size} failed plugins`, { errors });
|
|
2888
|
+
}
|
|
2889
|
+
return {
|
|
2890
|
+
failedPlugins,
|
|
2891
|
+
files,
|
|
2892
|
+
driver,
|
|
2893
|
+
pluginTimings,
|
|
2894
|
+
error: void 0,
|
|
2895
|
+
sources
|
|
2896
|
+
};
|
|
2897
|
+
}
|
|
2898
|
+
function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, driver }) {
|
|
2899
|
+
const pluginNameMap = /* @__PURE__ */ new Map();
|
|
2900
|
+
for (const plugin of driver.plugins.values()) pluginNameMap.set(plugin.name, plugin);
|
|
2901
|
+
return barrelFiles.flatMap((file) => {
|
|
2902
|
+
const containsOnlyTypes = file.sources?.every((source) => source.isTypeOnly);
|
|
2903
|
+
return (file.sources ?? []).flatMap((source) => {
|
|
2904
|
+
if (!file.path || !source.isIndexable) return [];
|
|
2905
|
+
const meta = file.meta;
|
|
2906
|
+
const pluginOptions = (meta?.pluginName ? pluginNameMap.get(meta.pluginName) : void 0)?.options;
|
|
2907
|
+
if (!pluginOptions || pluginOptions.output?.barrelType === false) return [];
|
|
2908
|
+
const exportName = config.output.barrelType === "all" ? void 0 : source.name ? [source.name] : void 0;
|
|
2909
|
+
if (exportName?.some((n) => existingExports.has(n))) return [];
|
|
2910
|
+
return [(0, _kubb_ast.createExport)({
|
|
2911
|
+
name: exportName,
|
|
2912
|
+
path: getRelativePath(rootDir, file.path),
|
|
2913
|
+
isTypeOnly: config.output.barrelType === "all" ? containsOnlyTypes : source.isTypeOnly
|
|
2914
|
+
})];
|
|
2915
|
+
});
|
|
2916
|
+
});
|
|
2917
|
+
}
|
|
2918
|
+
function inputToAdapterSource(config) {
|
|
2919
|
+
if (Array.isArray(config.input)) return {
|
|
2920
|
+
type: "paths",
|
|
2921
|
+
paths: config.input.map((i) => new URLPath(i.path).isURL ? i.path : (0, node_path.resolve)(config.root, i.path))
|
|
2922
|
+
};
|
|
2923
|
+
if ("data" in config.input) return {
|
|
2924
|
+
type: "data",
|
|
2925
|
+
data: config.input.data
|
|
2926
|
+
};
|
|
2927
|
+
if (new URLPath(config.input.path).isURL) return {
|
|
2928
|
+
type: "path",
|
|
2929
|
+
path: config.input.path
|
|
2930
|
+
};
|
|
2931
|
+
return {
|
|
2932
|
+
type: "path",
|
|
2933
|
+
path: (0, node_path.resolve)(config.root, config.input.path)
|
|
2934
|
+
};
|
|
2565
2935
|
}
|
|
2566
2936
|
/**
|
|
2567
|
-
*
|
|
2568
|
-
*
|
|
2569
|
-
* Resolves a `FileNode` by combining name resolution (`resolver.default`) with
|
|
2570
|
-
* path resolution (`resolver.resolvePath`). The resolved file always has empty
|
|
2571
|
-
* `sources`, `imports`, and `exports` arrays — consumers populate those separately.
|
|
2937
|
+
* Creates a Kubb instance bound to a single config entry.
|
|
2572
2938
|
*
|
|
2573
|
-
*
|
|
2939
|
+
* The instance holds shared state (`hooks`, `sources`, `driver`, `config`) across the
|
|
2940
|
+
* `setup → build` lifecycle. Attach event listeners to `kubb.hooks` before
|
|
2941
|
+
* calling `setup()` or `build()`.
|
|
2574
2942
|
*
|
|
2575
|
-
* @example
|
|
2943
|
+
* @example
|
|
2576
2944
|
* ```ts
|
|
2577
|
-
* const
|
|
2578
|
-
* { name: 'pet', extname: '.ts' },
|
|
2579
|
-
* { root: '/src', output: { path: 'types' } },
|
|
2580
|
-
* )
|
|
2581
|
-
* // → { baseName: 'pet.ts', path: '/src/types/pet.ts', sources: [], ... }
|
|
2582
|
-
* ```
|
|
2945
|
+
* const kubb = createKubb({ config })
|
|
2583
2946
|
*
|
|
2584
|
-
*
|
|
2585
|
-
*
|
|
2586
|
-
*
|
|
2587
|
-
*
|
|
2588
|
-
*
|
|
2589
|
-
* )
|
|
2590
|
-
* // → { baseName: 'listPets.ts', path: '/src/types/petsController/listPets.ts', ... }
|
|
2947
|
+
* kubb.hooks.on('kubb:plugin:end', (plugin, { duration }) => {
|
|
2948
|
+
* console.log(`${plugin.name} completed in ${duration}ms`)
|
|
2949
|
+
* })
|
|
2950
|
+
*
|
|
2951
|
+
* const { files, failedPlugins } = await kubb.safeBuild()
|
|
2591
2952
|
* ```
|
|
2592
2953
|
*/
|
|
2593
|
-
function
|
|
2594
|
-
const
|
|
2595
|
-
|
|
2596
|
-
const
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
let banner = "/**\n* Generated by Kubb (https://kubb.dev/).\n* Do not edit manually.\n";
|
|
2623
|
-
if (config.output.defaultBanner === "simple") {
|
|
2624
|
-
banner += "*/\n";
|
|
2625
|
-
return banner;
|
|
2626
|
-
}
|
|
2627
|
-
if (source) banner += `* Source: ${source}\n`;
|
|
2628
|
-
if (title) banner += `* Title: ${title}\n`;
|
|
2629
|
-
if (description) {
|
|
2630
|
-
const formattedDescription = description.replace(/\n/gm, "\n* ");
|
|
2631
|
-
banner += `* Description: ${formattedDescription}\n`;
|
|
2954
|
+
function createKubb(options) {
|
|
2955
|
+
const hooks = options.hooks ?? new AsyncEventEmitter();
|
|
2956
|
+
let setupResult;
|
|
2957
|
+
const instance = {
|
|
2958
|
+
get hooks() {
|
|
2959
|
+
return hooks;
|
|
2960
|
+
},
|
|
2961
|
+
get sources() {
|
|
2962
|
+
return setupResult?.sources ?? /* @__PURE__ */ new Map();
|
|
2963
|
+
},
|
|
2964
|
+
get driver() {
|
|
2965
|
+
return setupResult?.driver;
|
|
2966
|
+
},
|
|
2967
|
+
get config() {
|
|
2968
|
+
return setupResult?.config;
|
|
2969
|
+
},
|
|
2970
|
+
async setup() {
|
|
2971
|
+
setupResult = await setup({
|
|
2972
|
+
config: options.config,
|
|
2973
|
+
hooks
|
|
2974
|
+
});
|
|
2975
|
+
},
|
|
2976
|
+
async build() {
|
|
2977
|
+
if (!setupResult) await instance.setup();
|
|
2978
|
+
return build(setupResult);
|
|
2979
|
+
},
|
|
2980
|
+
async safeBuild() {
|
|
2981
|
+
if (!setupResult) await instance.setup();
|
|
2982
|
+
return safeBuild(setupResult);
|
|
2632
2983
|
}
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
return banner;
|
|
2636
|
-
} catch (_error) {
|
|
2637
|
-
return "/**\n* Generated by Kubb (https://kubb.dev/).\n* Do not edit manually.\n*/";
|
|
2638
|
-
}
|
|
2984
|
+
};
|
|
2985
|
+
return instance;
|
|
2639
2986
|
}
|
|
2987
|
+
//#endregion
|
|
2988
|
+
//#region src/createPlugin.ts
|
|
2640
2989
|
/**
|
|
2641
|
-
*
|
|
2642
|
-
*
|
|
2643
|
-
* A user-supplied `output.banner` overrides the default Kubb "Generated by Kubb" notice.
|
|
2644
|
-
* When no `output.banner` is set, the Kubb notice is used (including `title` and `version`
|
|
2645
|
-
* from the OAS spec when a `node` is provided).
|
|
2646
|
-
*
|
|
2647
|
-
* - When `output.banner` is a function and `node` is provided, returns `output.banner(node)`.
|
|
2648
|
-
* - When `output.banner` is a function and `node` is absent, falls back to the Kubb notice.
|
|
2649
|
-
* - When `output.banner` is a string, returns it directly.
|
|
2650
|
-
* - When `config.output.defaultBanner` is `false`, returns `undefined`.
|
|
2651
|
-
* - Otherwise returns the Kubb "Generated by Kubb" notice.
|
|
2652
|
-
*
|
|
2653
|
-
* @example String banner overrides default
|
|
2654
|
-
* ```ts
|
|
2655
|
-
* defaultResolveBanner(undefined, { output: { banner: '// my banner' }, config })
|
|
2656
|
-
* // → '// my banner'
|
|
2657
|
-
* ```
|
|
2658
|
-
*
|
|
2659
|
-
* @example Function banner with node
|
|
2660
|
-
* ```ts
|
|
2661
|
-
* defaultResolveBanner(inputNode, { output: { banner: (node) => `// v${node.version}` }, config })
|
|
2662
|
-
* // → '// v3.0.0'
|
|
2663
|
-
* ```
|
|
2990
|
+
* Creates a plugin factory. Call the returned function with optional options to get the plugin instance.
|
|
2664
2991
|
*
|
|
2665
|
-
* @example
|
|
2992
|
+
* @example
|
|
2666
2993
|
* ```ts
|
|
2667
|
-
*
|
|
2668
|
-
*
|
|
2669
|
-
*
|
|
2994
|
+
* export const myPlugin = createPlugin<MyPlugin>((options) => {
|
|
2995
|
+
* return {
|
|
2996
|
+
* name: 'my-plugin',
|
|
2997
|
+
* get options() { return options },
|
|
2998
|
+
* resolvePath(baseName) { ... },
|
|
2999
|
+
* resolveName(name, type) { ... },
|
|
3000
|
+
* }
|
|
3001
|
+
* })
|
|
2670
3002
|
*
|
|
2671
|
-
*
|
|
2672
|
-
*
|
|
2673
|
-
* defaultResolveBanner(undefined, { config: { output: { defaultBanner: false }, ...config } })
|
|
2674
|
-
* // → undefined
|
|
3003
|
+
* // instantiate
|
|
3004
|
+
* const plugin = myPlugin({ output: { path: 'src/gen' } })
|
|
2675
3005
|
* ```
|
|
3006
|
+
* @deprecated use definePlugin instead
|
|
2676
3007
|
*/
|
|
2677
|
-
function
|
|
2678
|
-
|
|
2679
|
-
if (typeof output?.banner === "string") return output.banner;
|
|
2680
|
-
if (config.output.defaultBanner === false) return;
|
|
2681
|
-
return buildDefaultBanner({
|
|
2682
|
-
title: node?.meta?.title,
|
|
2683
|
-
version: node?.meta?.version,
|
|
2684
|
-
config
|
|
2685
|
-
});
|
|
3008
|
+
function createPlugin(build) {
|
|
3009
|
+
return (options) => build(options ?? {});
|
|
2686
3010
|
}
|
|
3011
|
+
//#endregion
|
|
3012
|
+
//#region src/createRenderer.ts
|
|
2687
3013
|
/**
|
|
2688
|
-
*
|
|
3014
|
+
* Creates a renderer factory for use in generator definitions.
|
|
2689
3015
|
*
|
|
2690
|
-
*
|
|
2691
|
-
*
|
|
2692
|
-
*
|
|
2693
|
-
* - Otherwise returns `undefined`.
|
|
3016
|
+
* Wrap your renderer factory function with this helper to register it as the
|
|
3017
|
+
* renderer for a generator. Core will call this factory once per render cycle
|
|
3018
|
+
* to obtain a fresh renderer instance.
|
|
2694
3019
|
*
|
|
2695
|
-
* @example
|
|
3020
|
+
* @example
|
|
2696
3021
|
* ```ts
|
|
2697
|
-
*
|
|
2698
|
-
*
|
|
2699
|
-
*
|
|
3022
|
+
* // packages/renderer-jsx/src/index.ts
|
|
3023
|
+
* export const jsxRenderer = createRenderer(() => {
|
|
3024
|
+
* const runtime = new Runtime()
|
|
3025
|
+
* return {
|
|
3026
|
+
* async render(element) { await runtime.render(element) },
|
|
3027
|
+
* get files() { return runtime.nodes },
|
|
3028
|
+
* unmount(error) { runtime.unmount(error) },
|
|
3029
|
+
* }
|
|
3030
|
+
* })
|
|
2700
3031
|
*
|
|
2701
|
-
*
|
|
2702
|
-
*
|
|
2703
|
-
*
|
|
2704
|
-
*
|
|
3032
|
+
* // packages/plugin-zod/src/generators/zodGenerator.tsx
|
|
3033
|
+
* import { jsxRenderer } from '@kubb/renderer-jsx'
|
|
3034
|
+
* export const zodGenerator = defineGenerator<PluginZod>({
|
|
3035
|
+
* name: 'zod',
|
|
3036
|
+
* renderer: jsxRenderer,
|
|
3037
|
+
* schema(node, options) { return <File ...>...</File> },
|
|
3038
|
+
* })
|
|
2705
3039
|
* ```
|
|
2706
3040
|
*/
|
|
2707
|
-
function
|
|
2708
|
-
|
|
2709
|
-
|
|
3041
|
+
function createRenderer(factory) {
|
|
3042
|
+
return factory;
|
|
3043
|
+
}
|
|
3044
|
+
//#endregion
|
|
3045
|
+
//#region src/defineGenerator.ts
|
|
3046
|
+
/**
|
|
3047
|
+
* Defines a generator. Returns the object as-is with correct `this` typings.
|
|
3048
|
+
* `applyHookResult` handles renderer elements and `File[]` uniformly using
|
|
3049
|
+
* the generator's declared `renderer` factory.
|
|
3050
|
+
*/
|
|
3051
|
+
function defineGenerator(generator) {
|
|
3052
|
+
return generator;
|
|
2710
3053
|
}
|
|
3054
|
+
//#endregion
|
|
3055
|
+
//#region src/defineLogger.ts
|
|
2711
3056
|
/**
|
|
2712
|
-
*
|
|
2713
|
-
* include/exclude/override filtering, path resolution, and file construction.
|
|
2714
|
-
*
|
|
2715
|
-
* All four defaults can be overridden by providing them in the builder function:
|
|
2716
|
-
* - `default` — name casing strategy (camelCase / PascalCase)
|
|
2717
|
-
* - `resolveOptions` — include/exclude/override filtering
|
|
2718
|
-
* - `resolvePath` — output path computation
|
|
2719
|
-
* - `resolveFile` — full `FileNode` construction
|
|
2720
|
-
*
|
|
2721
|
-
* Methods in the builder have access to `this` (the full resolver object), so they
|
|
2722
|
-
* can call other resolver methods without circular imports.
|
|
3057
|
+
* Wraps a logger definition into a typed {@link Logger}.
|
|
2723
3058
|
*
|
|
2724
|
-
* @example
|
|
2725
|
-
*
|
|
2726
|
-
*
|
|
2727
|
-
*
|
|
2728
|
-
*
|
|
2729
|
-
*
|
|
2730
|
-
* },
|
|
2731
|
-
* resolveTypedName(node) {
|
|
2732
|
-
* return this.default(node.name, 'type')
|
|
3059
|
+
* @example
|
|
3060
|
+
* export const myLogger = defineLogger({
|
|
3061
|
+
* name: 'my-logger',
|
|
3062
|
+
* install(context, options) {
|
|
3063
|
+
* context.on('kubb:info', (message) => console.log('ℹ', message))
|
|
3064
|
+
* context.on('kubb:error', (error) => console.error('✗', error.message))
|
|
2733
3065
|
* },
|
|
2734
|
-
* })
|
|
2735
|
-
|
|
3066
|
+
* })
|
|
3067
|
+
*/
|
|
3068
|
+
function defineLogger(logger) {
|
|
3069
|
+
return logger;
|
|
3070
|
+
}
|
|
3071
|
+
//#endregion
|
|
3072
|
+
//#region src/defineParser.ts
|
|
3073
|
+
/**
|
|
3074
|
+
* Defines a parser with type safety.
|
|
2736
3075
|
*
|
|
2737
|
-
*
|
|
2738
|
-
*
|
|
2739
|
-
* export const resolver = defineResolver<PluginTs>(() => ({
|
|
2740
|
-
* name: 'custom',
|
|
2741
|
-
* resolvePath({ baseName }, { root, output }) {
|
|
2742
|
-
* return path.resolve(root, output.path, 'generated', baseName)
|
|
2743
|
-
* },
|
|
2744
|
-
* }))
|
|
2745
|
-
* ```
|
|
3076
|
+
* Use this function to create parsers that transform generated files to strings
|
|
3077
|
+
* based on their extension.
|
|
2746
3078
|
*
|
|
2747
|
-
* @example
|
|
3079
|
+
* @example
|
|
2748
3080
|
* ```ts
|
|
2749
|
-
*
|
|
2750
|
-
*
|
|
2751
|
-
*
|
|
2752
|
-
*
|
|
3081
|
+
* import { defineParser } from '@kubb/core'
|
|
3082
|
+
*
|
|
3083
|
+
* export const jsonParser = defineParser({
|
|
3084
|
+
* name: 'json',
|
|
3085
|
+
* extNames: ['.json'],
|
|
3086
|
+
* parse(file) {
|
|
3087
|
+
* const { extractStringsFromNodes } = await import('@kubb/ast')
|
|
3088
|
+
* return file.sources.map((s) => extractStringsFromNodes(s.nodes ?? [])).join('\n')
|
|
2753
3089
|
* },
|
|
2754
|
-
* })
|
|
3090
|
+
* })
|
|
2755
3091
|
* ```
|
|
2756
3092
|
*/
|
|
2757
|
-
function
|
|
2758
|
-
return
|
|
2759
|
-
default: defaultResolver,
|
|
2760
|
-
resolveOptions: defaultResolveOptions,
|
|
2761
|
-
resolvePath: defaultResolvePath,
|
|
2762
|
-
resolveFile: defaultResolveFile,
|
|
2763
|
-
resolveBanner: defaultResolveBanner,
|
|
2764
|
-
resolveFooter: defaultResolveFooter,
|
|
2765
|
-
...build()
|
|
2766
|
-
};
|
|
3093
|
+
function defineParser(parser) {
|
|
3094
|
+
return parser;
|
|
2767
3095
|
}
|
|
2768
3096
|
//#endregion
|
|
2769
3097
|
//#region src/storages/memoryStorage.ts
|
|
@@ -2853,22 +3181,6 @@ async function detectFormatter() {
|
|
|
2853
3181
|
return null;
|
|
2854
3182
|
}
|
|
2855
3183
|
//#endregion
|
|
2856
|
-
//#region src/utils/getConfigs.ts
|
|
2857
|
-
/**
|
|
2858
|
-
* Resolves a {@link ConfigInput} into a normalized array of {@link Config} objects.
|
|
2859
|
-
*
|
|
2860
|
-
* - Awaits the config when it is a `Promise`.
|
|
2861
|
-
* - Calls the factory function with `args` when the config is a function.
|
|
2862
|
-
* - Wraps a single config object in an array for uniform downstream handling.
|
|
2863
|
-
*/
|
|
2864
|
-
async function getConfigs(config, args) {
|
|
2865
|
-
const resolved = await (typeof config === "function" ? config(args) : config);
|
|
2866
|
-
return (Array.isArray(resolved) ? resolved : [resolved]).map((item) => ({
|
|
2867
|
-
plugins: [],
|
|
2868
|
-
...item
|
|
2869
|
-
}));
|
|
2870
|
-
}
|
|
2871
|
-
//#endregion
|
|
2872
3184
|
//#region src/utils/getFunctionParams.ts
|
|
2873
3185
|
function order(items) {
|
|
2874
3186
|
return (0, remeda.sortBy)(items.filter(Boolean), ([_key, item]) => {
|
|
@@ -2987,47 +3299,6 @@ var FunctionParams = class FunctionParams {
|
|
|
2987
3299
|
}
|
|
2988
3300
|
};
|
|
2989
3301
|
//#endregion
|
|
2990
|
-
//#region src/utils/getPreset.ts
|
|
2991
|
-
/**
|
|
2992
|
-
* Returns a copy of `defaults` where each function in `userOverrides` is wrapped
|
|
2993
|
-
* so a `null`/`undefined` return falls back to the original. Non-function values
|
|
2994
|
-
* are assigned directly. All calls use the merged object as `this`.
|
|
2995
|
-
*/
|
|
2996
|
-
function withFallback(defaults, userOverrides) {
|
|
2997
|
-
const merged = { ...defaults };
|
|
2998
|
-
for (const key of Object.keys(userOverrides)) {
|
|
2999
|
-
const userVal = userOverrides[key];
|
|
3000
|
-
const defaultVal = defaults[key];
|
|
3001
|
-
if (typeof userVal === "function" && typeof defaultVal === "function") merged[key] = (...args) => userVal.apply(merged, args) ?? defaultVal.apply(merged, args);
|
|
3002
|
-
else if (userVal !== void 0) merged[key] = userVal;
|
|
3003
|
-
}
|
|
3004
|
-
return merged;
|
|
3005
|
-
}
|
|
3006
|
-
/**
|
|
3007
|
-
* Resolves a named preset into a resolver, transformer, and generators.
|
|
3008
|
-
*
|
|
3009
|
-
* - Selects the preset resolver; wraps it with user overrides using null/undefined fallback.
|
|
3010
|
-
* - Composes the preset's transformers into a single visitor; wraps it with the user transformer using null/undefined fallback.
|
|
3011
|
-
* - Combines preset generators with user-supplied generators; falls back to the `default` preset's generators when neither provides any.
|
|
3012
|
-
*/
|
|
3013
|
-
function getPreset(params) {
|
|
3014
|
-
const { preset: presetName, presets, resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = params;
|
|
3015
|
-
const preset = presets[presetName];
|
|
3016
|
-
const presetResolver = preset?.resolver ?? presets["default"].resolver;
|
|
3017
|
-
const resolver = userResolver ? withFallback(presetResolver, userResolver) : presetResolver;
|
|
3018
|
-
const presetTransformers = preset?.transformers ?? [];
|
|
3019
|
-
const presetTransformer = presetTransformers.length > 0 ? (0, _kubb_ast.composeTransformers)(...presetTransformers) : void 0;
|
|
3020
|
-
const transformer = presetTransformer && userTransformer ? withFallback(presetTransformer, userTransformer) : userTransformer ?? presetTransformer;
|
|
3021
|
-
const presetGenerators = preset?.generators ?? [];
|
|
3022
|
-
const defaultGenerators = presets["default"]?.generators ?? [];
|
|
3023
|
-
return {
|
|
3024
|
-
resolver,
|
|
3025
|
-
transformer,
|
|
3026
|
-
generators: presetGenerators.length > 0 || userGenerators.length > 0 ? [...presetGenerators, ...userGenerators] : defaultGenerators,
|
|
3027
|
-
preset
|
|
3028
|
-
};
|
|
3029
|
-
}
|
|
3030
|
-
//#endregion
|
|
3031
3302
|
//#region src/utils/linters.ts
|
|
3032
3303
|
/**
|
|
3033
3304
|
* Returns `true` when the given linter is installed and callable.
|
|
@@ -3069,7 +3340,7 @@ async function detectLinter() {
|
|
|
3069
3340
|
//#endregion
|
|
3070
3341
|
//#region src/utils/packageJSON.ts
|
|
3071
3342
|
function getPackageJSONSync(cwd) {
|
|
3072
|
-
const pkgPath =
|
|
3343
|
+
const pkgPath = findPackageJSON(cwd);
|
|
3073
3344
|
if (!pkgPath) return null;
|
|
3074
3345
|
return JSON.parse(readSync(pkgPath));
|
|
3075
3346
|
}
|
|
@@ -3114,7 +3385,12 @@ exports.AsyncEventEmitter = AsyncEventEmitter;
|
|
|
3114
3385
|
exports.FunctionParams = FunctionParams;
|
|
3115
3386
|
exports.PluginDriver = PluginDriver;
|
|
3116
3387
|
exports.URLPath = URLPath;
|
|
3117
|
-
exports
|
|
3388
|
+
Object.defineProperty(exports, "ast", {
|
|
3389
|
+
enumerable: true,
|
|
3390
|
+
get: function() {
|
|
3391
|
+
return _kubb_ast;
|
|
3392
|
+
}
|
|
3393
|
+
});
|
|
3118
3394
|
exports.buildDefaultBanner = buildDefaultBanner;
|
|
3119
3395
|
Object.defineProperty(exports, "composeTransformers", {
|
|
3120
3396
|
enumerable: true,
|
|
@@ -3124,19 +3400,19 @@ Object.defineProperty(exports, "composeTransformers", {
|
|
|
3124
3400
|
});
|
|
3125
3401
|
exports.createAdapter = createAdapter;
|
|
3126
3402
|
exports.createFunctionParams = createFunctionParams;
|
|
3403
|
+
exports.createKubb = createKubb;
|
|
3127
3404
|
exports.createPlugin = createPlugin;
|
|
3405
|
+
exports.createRenderer = createRenderer;
|
|
3128
3406
|
exports.createStorage = createStorage;
|
|
3129
|
-
exports.default = build;
|
|
3130
3407
|
exports.defaultResolveBanner = defaultResolveBanner;
|
|
3131
3408
|
exports.defaultResolveFile = defaultResolveFile;
|
|
3132
3409
|
exports.defaultResolveFooter = defaultResolveFooter;
|
|
3133
3410
|
exports.defaultResolveOptions = defaultResolveOptions;
|
|
3134
3411
|
exports.defaultResolvePath = defaultResolvePath;
|
|
3135
|
-
exports.defineConfig = defineConfig;
|
|
3136
3412
|
exports.defineGenerator = defineGenerator;
|
|
3137
3413
|
exports.defineLogger = defineLogger;
|
|
3138
3414
|
exports.defineParser = defineParser;
|
|
3139
|
-
exports.
|
|
3415
|
+
exports.definePlugin = definePlugin;
|
|
3140
3416
|
Object.defineProperty(exports, "definePrinter", {
|
|
3141
3417
|
enumerable: true,
|
|
3142
3418
|
get: function() {
|
|
@@ -3149,17 +3425,12 @@ exports.detectLinter = detectLinter;
|
|
|
3149
3425
|
exports.formatters = formatters;
|
|
3150
3426
|
exports.fsStorage = fsStorage;
|
|
3151
3427
|
exports.getBarrelFiles = getBarrelFiles;
|
|
3152
|
-
exports.getConfigs = getConfigs;
|
|
3153
3428
|
exports.getFunctionParams = getFunctionParams;
|
|
3154
3429
|
exports.getMode = getMode;
|
|
3155
|
-
exports.getPreset = getPreset;
|
|
3156
3430
|
exports.isInputPath = isInputPath;
|
|
3157
3431
|
exports.linters = linters;
|
|
3158
3432
|
exports.logLevel = logLevel;
|
|
3159
3433
|
exports.memoryStorage = memoryStorage;
|
|
3160
|
-
exports.mergeGenerators = mergeGenerators;
|
|
3161
|
-
exports.safeBuild = safeBuild;
|
|
3162
3434
|
exports.satisfiesDependency = satisfiesDependency;
|
|
3163
|
-
exports.setup = setup;
|
|
3164
3435
|
|
|
3165
3436
|
//# sourceMappingURL=index.cjs.map
|