@kubb/core 5.0.0-alpha.6 → 5.0.0-alpha.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/PluginDriver-Bc0HQM8V.js +948 -0
- package/dist/PluginDriver-Bc0HQM8V.js.map +1 -0
- package/dist/PluginDriver-Dyl2fwfQ.cjs +1039 -0
- package/dist/PluginDriver-Dyl2fwfQ.cjs.map +1 -0
- package/dist/index.cjs +691 -1798
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +279 -265
- package/dist/index.js +678 -1765
- package/dist/index.js.map +1 -1
- package/dist/mocks.cjs +138 -0
- package/dist/mocks.cjs.map +1 -0
- package/dist/mocks.d.ts +74 -0
- package/dist/mocks.js +133 -0
- package/dist/mocks.js.map +1 -0
- package/dist/types-i0b4_23K.d.ts +1903 -0
- package/package.json +51 -57
- package/src/FileManager.ts +110 -0
- package/src/FileProcessor.ts +86 -0
- package/src/Kubb.ts +205 -130
- package/src/PluginDriver.ts +424 -0
- package/src/constants.ts +20 -47
- package/src/createAdapter.ts +25 -0
- package/src/createKubb.ts +527 -0
- package/src/createRenderer.ts +57 -0
- package/src/createStorage.ts +58 -0
- package/src/defineGenerator.ts +88 -100
- package/src/defineLogger.ts +13 -3
- package/src/defineMiddleware.ts +59 -0
- package/src/defineParser.ts +45 -0
- package/src/definePlugin.ts +78 -7
- package/src/defineResolver.ts +521 -0
- package/src/devtools.ts +14 -14
- package/src/index.ts +13 -17
- package/src/mocks.ts +171 -0
- package/src/renderNode.ts +35 -0
- package/src/storages/fsStorage.ts +40 -11
- package/src/storages/memoryStorage.ts +4 -3
- package/src/types.ts +738 -218
- package/src/utils/diagnostics.ts +4 -1
- package/src/utils/isInputPath.ts +10 -0
- package/src/utils/packageJSON.ts +99 -0
- package/dist/PluginManager-vZodFEMe.d.ts +0 -1056
- package/dist/chunk-ByKO4r7w.cjs +0 -38
- package/dist/hooks.cjs +0 -60
- package/dist/hooks.cjs.map +0 -1
- package/dist/hooks.d.ts +0 -64
- package/dist/hooks.js +0 -56
- package/dist/hooks.js.map +0 -1
- package/src/BarrelManager.ts +0 -74
- package/src/PackageManager.ts +0 -180
- package/src/PluginManager.ts +0 -667
- package/src/PromiseManager.ts +0 -40
- package/src/build.ts +0 -419
- package/src/config.ts +0 -56
- package/src/defineAdapter.ts +0 -22
- package/src/defineStorage.ts +0 -56
- package/src/errors.ts +0 -1
- package/src/hooks/index.ts +0 -4
- package/src/hooks/useKubb.ts +0 -55
- package/src/hooks/useMode.ts +0 -11
- package/src/hooks/usePlugin.ts +0 -11
- package/src/hooks/usePluginManager.ts +0 -11
- package/src/utils/FunctionParams.ts +0 -155
- package/src/utils/TreeNode.ts +0 -215
- package/src/utils/executeStrategies.ts +0 -81
- package/src/utils/formatters.ts +0 -56
- package/src/utils/getBarrelFiles.ts +0 -79
- package/src/utils/getConfigs.ts +0 -30
- package/src/utils/getPlugins.ts +0 -23
- package/src/utils/linters.ts +0 -25
- package/src/utils/resolveOptions.ts +0 -93
package/dist/index.js
CHANGED
|
@@ -1,29 +1,20 @@
|
|
|
1
|
-
import "./chunk--u3MIqq1.js";
|
|
2
|
-
import
|
|
1
|
+
import { t as __name } from "./chunk--u3MIqq1.js";
|
|
2
|
+
import { a as DEFAULT_BANNER, c as logLevel, i as defineResolver, l as camelCase, n as applyHookResult, o as DEFAULT_EXTENSION, r as FileManager, s as DEFAULT_STUDIO_URL, t as PluginDriver } from "./PluginDriver-Bc0HQM8V.js";
|
|
3
3
|
import { EventEmitter } from "node:events";
|
|
4
|
-
import { parseArgs, styleText } from "node:util";
|
|
5
|
-
import { readFileSync } from "node:fs";
|
|
6
4
|
import { access, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
import { typescriptParser } from "@kubb/react-fabric/parsers";
|
|
11
|
-
import { fsPlugin } from "@kubb/react-fabric/plugins";
|
|
12
|
-
import { performance } from "node:perf_hooks";
|
|
13
|
-
import { deflateSync } from "fflate";
|
|
14
|
-
import { x } from "tinyexec";
|
|
5
|
+
import { dirname, join, resolve } from "node:path";
|
|
6
|
+
import * as ast from "@kubb/ast";
|
|
7
|
+
import { extractStringsFromNodes, transform, walk } from "@kubb/ast";
|
|
15
8
|
import { version } from "node:process";
|
|
16
|
-
|
|
17
|
-
import { pathToFileURL } from "node:url";
|
|
18
|
-
import * as pkg from "empathic/package";
|
|
19
|
-
import { coerce, satisfies } from "semver";
|
|
20
|
-
import { sortBy } from "remeda";
|
|
21
|
-
//#region ../../internals/utils/dist/index.js
|
|
22
|
-
/** Thrown when a plugin's configuration or input fails validation. */
|
|
23
|
-
var ValidationPluginError = class extends Error {};
|
|
9
|
+
//#region ../../internals/utils/src/errors.ts
|
|
24
10
|
/**
|
|
25
11
|
* Thrown when one or more errors occur during a Kubb build.
|
|
26
12
|
* Carries the full list of underlying errors on `errors`.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* throw new BuildError('Build failed', { errors: [err1, err2] })
|
|
17
|
+
* ```
|
|
27
18
|
*/
|
|
28
19
|
var BuildError = class extends Error {
|
|
29
20
|
errors;
|
|
@@ -35,19 +26,34 @@ var BuildError = class extends Error {
|
|
|
35
26
|
};
|
|
36
27
|
/**
|
|
37
28
|
* Coerces an unknown thrown value to an `Error` instance.
|
|
38
|
-
*
|
|
39
|
-
*
|
|
29
|
+
* Returns the value as-is when it is already an `Error`; otherwise wraps it with `String(value)`.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* try { ... } catch(err) {
|
|
34
|
+
* throw new BuildError('Build failed', { cause: toError(err), errors: [] })
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
40
37
|
*/
|
|
41
38
|
function toError(value) {
|
|
42
39
|
return value instanceof Error ? value : new Error(String(value));
|
|
43
40
|
}
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region ../../internals/utils/src/asyncEventEmitter.ts
|
|
44
43
|
/**
|
|
45
|
-
*
|
|
44
|
+
* Typed `EventEmitter` that awaits all async listeners before resolving.
|
|
46
45
|
* Wraps Node's `EventEmitter` with full TypeScript event-map inference.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* const emitter = new AsyncEventEmitter<{ build: [name: string] }>()
|
|
50
|
+
* emitter.on('build', async (name) => { console.log(name) })
|
|
51
|
+
* await emitter.emit('build', 'petstore') // all listeners awaited
|
|
52
|
+
* ```
|
|
47
53
|
*/
|
|
48
54
|
var AsyncEventEmitter = class {
|
|
49
55
|
/**
|
|
50
|
-
*
|
|
56
|
+
* Maximum number of listeners per event before Node emits a memory-leak warning.
|
|
51
57
|
* @default 10
|
|
52
58
|
*/
|
|
53
59
|
constructor(maxListener = 10) {
|
|
@@ -55,31 +61,48 @@ var AsyncEventEmitter = class {
|
|
|
55
61
|
}
|
|
56
62
|
#emitter = new EventEmitter();
|
|
57
63
|
/**
|
|
58
|
-
* Emits
|
|
64
|
+
* Emits `eventName` and awaits all registered listeners sequentially.
|
|
59
65
|
* Throws if any listener rejects, wrapping the cause with the event name and serialized arguments.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* await emitter.emit('build', 'petstore')
|
|
70
|
+
* ```
|
|
60
71
|
*/
|
|
61
72
|
async emit(eventName, ...eventArgs) {
|
|
62
73
|
const listeners = this.#emitter.listeners(eventName);
|
|
63
74
|
if (listeners.length === 0) return;
|
|
64
|
-
|
|
75
|
+
for (const listener of listeners) try {
|
|
76
|
+
await listener(...eventArgs);
|
|
77
|
+
} catch (err) {
|
|
78
|
+
let serializedArgs;
|
|
65
79
|
try {
|
|
66
|
-
|
|
67
|
-
} catch
|
|
68
|
-
|
|
69
|
-
try {
|
|
70
|
-
serializedArgs = JSON.stringify(eventArgs);
|
|
71
|
-
} catch {
|
|
72
|
-
serializedArgs = String(eventArgs);
|
|
73
|
-
}
|
|
74
|
-
throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: toError(err) });
|
|
80
|
+
serializedArgs = JSON.stringify(eventArgs);
|
|
81
|
+
} catch {
|
|
82
|
+
serializedArgs = String(eventArgs);
|
|
75
83
|
}
|
|
76
|
-
|
|
84
|
+
throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: toError(err) });
|
|
85
|
+
}
|
|
77
86
|
}
|
|
78
|
-
/**
|
|
87
|
+
/**
|
|
88
|
+
* Registers a persistent listener for `eventName`.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* emitter.on('build', async (name) => { console.log(name) })
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
79
95
|
on(eventName, handler) {
|
|
80
96
|
this.#emitter.on(eventName, handler);
|
|
81
97
|
}
|
|
82
|
-
/**
|
|
98
|
+
/**
|
|
99
|
+
* Registers a one-shot listener that removes itself after the first invocation.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* emitter.onOnce('build', async (name) => { console.log(name) })
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
83
106
|
onOnce(eventName, handler) {
|
|
84
107
|
const wrapper = (...args) => {
|
|
85
108
|
this.off(eventName, wrapper);
|
|
@@ -87,237 +110,53 @@ var AsyncEventEmitter = class {
|
|
|
87
110
|
};
|
|
88
111
|
this.on(eventName, wrapper);
|
|
89
112
|
}
|
|
90
|
-
/**
|
|
113
|
+
/**
|
|
114
|
+
* Removes a previously registered listener.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```ts
|
|
118
|
+
* emitter.off('build', handler)
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
91
121
|
off(eventName, handler) {
|
|
92
122
|
this.#emitter.off(eventName, handler);
|
|
93
123
|
}
|
|
94
|
-
/**
|
|
124
|
+
/**
|
|
125
|
+
* Returns the number of listeners registered for `eventName`.
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```ts
|
|
129
|
+
* emitter.on('build', handler)
|
|
130
|
+
* emitter.listenerCount('build') // 1
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
listenerCount(eventName) {
|
|
134
|
+
return this.#emitter.listenerCount(eventName);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Removes all listeners from every event channel.
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```ts
|
|
141
|
+
* emitter.removeAll()
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
95
144
|
removeAll() {
|
|
96
145
|
this.#emitter.removeAllListeners();
|
|
97
146
|
}
|
|
98
147
|
};
|
|
148
|
+
//#endregion
|
|
149
|
+
//#region ../../internals/utils/src/time.ts
|
|
99
150
|
/**
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* and capitalizes each word according to `pascal`.
|
|
103
|
-
*
|
|
104
|
-
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
|
|
105
|
-
*/
|
|
106
|
-
function toCamelOrPascal(text, pascal) {
|
|
107
|
-
return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
|
|
108
|
-
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
109
|
-
if (i === 0 && !pascal) return word.charAt(0).toLowerCase() + word.slice(1);
|
|
110
|
-
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
111
|
-
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Splits `text` on `.` and applies `transformPart` to each segment.
|
|
115
|
-
* The last segment receives `isLast = true`, all earlier segments receive `false`.
|
|
116
|
-
* Segments are joined with `/` to form a file path.
|
|
117
|
-
*/
|
|
118
|
-
function applyToFileParts(text, transformPart) {
|
|
119
|
-
const parts = text.split(".");
|
|
120
|
-
return parts.map((part, i) => transformPart(part, i === parts.length - 1)).join("/");
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Converts `text` to camelCase.
|
|
124
|
-
* When `isFile` is `true`, dot-separated segments are each cased independently and joined with `/`.
|
|
151
|
+
* Calculates elapsed time in milliseconds from a high-resolution `process.hrtime` start time.
|
|
152
|
+
* Rounds to 2 decimal places for sub-millisecond precision without noise.
|
|
125
153
|
*
|
|
126
154
|
* @example
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
prefix,
|
|
133
|
-
suffix
|
|
134
|
-
} : {}));
|
|
135
|
-
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
136
|
-
}
|
|
137
|
-
/** Returns a `CLIAdapter` with type inference. Pass a different adapter to `createCLI` to swap the CLI engine. */
|
|
138
|
-
function defineCLIAdapter(adapter) {
|
|
139
|
-
return adapter;
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Serializes `CommandDefinition[]` to a plain, JSON-serializable structure.
|
|
143
|
-
* Use to expose CLI capabilities to AI agents or MCP tools.
|
|
144
|
-
*/
|
|
145
|
-
function getCommandSchema(defs) {
|
|
146
|
-
return defs.map(serializeCommand);
|
|
147
|
-
}
|
|
148
|
-
function serializeCommand(def) {
|
|
149
|
-
return {
|
|
150
|
-
name: def.name,
|
|
151
|
-
description: def.description,
|
|
152
|
-
arguments: def.arguments,
|
|
153
|
-
options: serializeOptions(def.options ?? {}),
|
|
154
|
-
subCommands: def.subCommands ? def.subCommands.map(serializeCommand) : []
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
function serializeOptions(options) {
|
|
158
|
-
return Object.entries(options).map(([name, opt]) => {
|
|
159
|
-
return {
|
|
160
|
-
name,
|
|
161
|
-
flags: `${opt.short ? `-${opt.short}, ` : ""}--${name}${opt.type === "string" ? ` <${opt.hint ?? name}>` : ""}`,
|
|
162
|
-
type: opt.type,
|
|
163
|
-
description: opt.description,
|
|
164
|
-
...opt.default !== void 0 ? { default: opt.default } : {},
|
|
165
|
-
...opt.hint ? { hint: opt.hint } : {},
|
|
166
|
-
...opt.enum ? { enum: opt.enum } : {},
|
|
167
|
-
...opt.required ? { required: opt.required } : {}
|
|
168
|
-
};
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
/** Prints formatted help output for a command using its `CommandDefinition`. */
|
|
172
|
-
function renderHelp(def, parentName) {
|
|
173
|
-
const schema = getCommandSchema([def])[0];
|
|
174
|
-
const programName = parentName ? `${parentName} ${schema.name}` : schema.name;
|
|
175
|
-
const argsPart = schema.arguments?.length ? ` ${schema.arguments.join(" ")}` : "";
|
|
176
|
-
const subCmdPart = schema.subCommands.length ? " <command>" : "";
|
|
177
|
-
console.log(`\n${styleText("bold", "Usage:")} ${programName}${argsPart}${subCmdPart} [options]\n`);
|
|
178
|
-
if (schema.description) console.log(` ${schema.description}\n`);
|
|
179
|
-
if (schema.subCommands.length) {
|
|
180
|
-
console.log(styleText("bold", "Commands:"));
|
|
181
|
-
for (const sub of schema.subCommands) console.log(` ${styleText("cyan", sub.name.padEnd(16))}${sub.description}`);
|
|
182
|
-
console.log();
|
|
183
|
-
}
|
|
184
|
-
const options = [...schema.options, {
|
|
185
|
-
name: "help",
|
|
186
|
-
flags: "-h, --help",
|
|
187
|
-
type: "boolean",
|
|
188
|
-
description: "Show help"
|
|
189
|
-
}];
|
|
190
|
-
console.log(styleText("bold", "Options:"));
|
|
191
|
-
for (const opt of options) {
|
|
192
|
-
const flags = styleText("cyan", opt.flags.padEnd(30));
|
|
193
|
-
const defaultPart = opt.default !== void 0 ? styleText("dim", ` (default: ${opt.default})`) : "";
|
|
194
|
-
console.log(` ${flags}${opt.description}${defaultPart}`);
|
|
195
|
-
}
|
|
196
|
-
console.log();
|
|
197
|
-
}
|
|
198
|
-
function buildParseOptions(def) {
|
|
199
|
-
const result = { help: {
|
|
200
|
-
type: "boolean",
|
|
201
|
-
short: "h"
|
|
202
|
-
} };
|
|
203
|
-
for (const [name, opt] of Object.entries(def.options ?? {})) result[name] = {
|
|
204
|
-
type: opt.type,
|
|
205
|
-
...opt.short ? { short: opt.short } : {},
|
|
206
|
-
...opt.default !== void 0 ? { default: opt.default } : {}
|
|
207
|
-
};
|
|
208
|
-
return result;
|
|
209
|
-
}
|
|
210
|
-
async function runCommand(def, argv, parentName) {
|
|
211
|
-
const parseOptions = buildParseOptions(def);
|
|
212
|
-
let parsed;
|
|
213
|
-
try {
|
|
214
|
-
const result = parseArgs({
|
|
215
|
-
args: argv,
|
|
216
|
-
options: parseOptions,
|
|
217
|
-
allowPositionals: true,
|
|
218
|
-
strict: false
|
|
219
|
-
});
|
|
220
|
-
parsed = {
|
|
221
|
-
values: result.values,
|
|
222
|
-
positionals: result.positionals
|
|
223
|
-
};
|
|
224
|
-
} catch {
|
|
225
|
-
renderHelp(def, parentName);
|
|
226
|
-
process.exit(1);
|
|
227
|
-
}
|
|
228
|
-
if (parsed.values["help"]) {
|
|
229
|
-
renderHelp(def, parentName);
|
|
230
|
-
process.exit(0);
|
|
231
|
-
}
|
|
232
|
-
for (const [name, opt] of Object.entries(def.options ?? {})) if (opt.required && parsed.values[name] === void 0) {
|
|
233
|
-
console.error(styleText("red", `Error: --${name} is required`));
|
|
234
|
-
renderHelp(def, parentName);
|
|
235
|
-
process.exit(1);
|
|
236
|
-
}
|
|
237
|
-
if (!def.run) {
|
|
238
|
-
renderHelp(def, parentName);
|
|
239
|
-
process.exit(0);
|
|
240
|
-
}
|
|
241
|
-
try {
|
|
242
|
-
await def.run(parsed);
|
|
243
|
-
} catch (err) {
|
|
244
|
-
console.error(styleText("red", `Error: ${err instanceof Error ? err.message : String(err)}`));
|
|
245
|
-
renderHelp(def, parentName);
|
|
246
|
-
process.exit(1);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
function printRootHelp(programName, version, defs) {
|
|
250
|
-
console.log(`\n${styleText("bold", "Usage:")} ${programName} <command> [options]\n`);
|
|
251
|
-
console.log(` Kubb generation — v${version}\n`);
|
|
252
|
-
console.log(styleText("bold", "Commands:"));
|
|
253
|
-
for (const def of defs) console.log(` ${styleText("cyan", def.name.padEnd(16))}${def.description}`);
|
|
254
|
-
console.log();
|
|
255
|
-
console.log(styleText("bold", "Options:"));
|
|
256
|
-
console.log(` ${styleText("cyan", "-v, --version".padEnd(30))}Show version number`);
|
|
257
|
-
console.log(` ${styleText("cyan", "-h, --help".padEnd(30))}Show help`);
|
|
258
|
-
console.log();
|
|
259
|
-
console.log(`Run ${styleText("cyan", `${programName} <command> --help`)} for command-specific help.\n`);
|
|
260
|
-
}
|
|
261
|
-
defineCLIAdapter({
|
|
262
|
-
renderHelp(def, parentName) {
|
|
263
|
-
renderHelp(def, parentName);
|
|
264
|
-
},
|
|
265
|
-
async run(defs, argv, opts) {
|
|
266
|
-
const { programName, defaultCommandName, version } = opts;
|
|
267
|
-
const args = argv.length >= 2 && argv[0]?.includes("node") ? argv.slice(2) : argv;
|
|
268
|
-
if (args[0] === "--version" || args[0] === "-v") {
|
|
269
|
-
console.log(version);
|
|
270
|
-
process.exit(0);
|
|
271
|
-
}
|
|
272
|
-
if (args[0] === "--help" || args[0] === "-h") {
|
|
273
|
-
printRootHelp(programName, version, defs);
|
|
274
|
-
process.exit(0);
|
|
275
|
-
}
|
|
276
|
-
if (args.length === 0) {
|
|
277
|
-
const defaultDef = defs.find((d) => d.name === defaultCommandName);
|
|
278
|
-
if (defaultDef?.run) await runCommand(defaultDef, [], programName);
|
|
279
|
-
else printRootHelp(programName, version, defs);
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
const [first, ...rest] = args;
|
|
283
|
-
const isKnownSubcommand = defs.some((d) => d.name === first);
|
|
284
|
-
let def;
|
|
285
|
-
let commandArgv;
|
|
286
|
-
let parentName;
|
|
287
|
-
if (isKnownSubcommand) {
|
|
288
|
-
def = defs.find((d) => d.name === first);
|
|
289
|
-
commandArgv = rest;
|
|
290
|
-
parentName = programName;
|
|
291
|
-
} else {
|
|
292
|
-
def = defs.find((d) => d.name === defaultCommandName);
|
|
293
|
-
commandArgv = args;
|
|
294
|
-
parentName = programName;
|
|
295
|
-
}
|
|
296
|
-
if (!def) {
|
|
297
|
-
console.error(`Unknown command: ${first}`);
|
|
298
|
-
printRootHelp(programName, version, defs);
|
|
299
|
-
process.exit(1);
|
|
300
|
-
}
|
|
301
|
-
if (def.subCommands?.length) {
|
|
302
|
-
const [subName, ...subRest] = commandArgv;
|
|
303
|
-
const subDef = def.subCommands.find((s) => s.name === subName);
|
|
304
|
-
if (subName === "--help" || subName === "-h") {
|
|
305
|
-
renderHelp(def, parentName);
|
|
306
|
-
process.exit(0);
|
|
307
|
-
}
|
|
308
|
-
if (!subDef) {
|
|
309
|
-
renderHelp(def, parentName);
|
|
310
|
-
process.exit(subName ? 1 : 0);
|
|
311
|
-
}
|
|
312
|
-
await runCommand(subDef, subRest, `${parentName} ${def.name}`);
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
await runCommand(def, commandArgv, parentName);
|
|
316
|
-
}
|
|
317
|
-
});
|
|
318
|
-
/**
|
|
319
|
-
* Calculates elapsed time in milliseconds from a high-resolution start time.
|
|
320
|
-
* Rounds to 2 decimal places to provide sub-millisecond precision without noise.
|
|
155
|
+
* ```ts
|
|
156
|
+
* const start = process.hrtime()
|
|
157
|
+
* doWork()
|
|
158
|
+
* getElapsedMs(start) // 42.35
|
|
159
|
+
* ```
|
|
321
160
|
*/
|
|
322
161
|
function getElapsedMs(hrStart) {
|
|
323
162
|
const [seconds, nanoseconds] = process.hrtime(hrStart);
|
|
@@ -325,96 +164,62 @@ function getElapsedMs(hrStart) {
|
|
|
325
164
|
return Math.round(ms * 100) / 100;
|
|
326
165
|
}
|
|
327
166
|
/**
|
|
328
|
-
* Converts a millisecond duration into a human-readable string.
|
|
329
|
-
*
|
|
167
|
+
* Converts a millisecond duration into a human-readable string (`ms`, `s`, or `m s`).
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```ts
|
|
171
|
+
* formatMs(250) // '250ms'
|
|
172
|
+
* formatMs(1500) // '1.50s'
|
|
173
|
+
* formatMs(90000) // '1m 30.0s'
|
|
174
|
+
* ```
|
|
330
175
|
*/
|
|
331
176
|
function formatMs(ms) {
|
|
332
177
|
if (ms >= 6e4) return `${Math.floor(ms / 6e4)}m ${(ms % 6e4 / 1e3).toFixed(1)}s`;
|
|
333
178
|
if (ms >= 1e3) return `${(ms / 1e3).toFixed(2)}s`;
|
|
334
179
|
return `${Math.round(ms)}ms`;
|
|
335
180
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
* Falls back to `255` for any channel that cannot be parsed.
|
|
339
|
-
*/
|
|
340
|
-
function parseHex(color) {
|
|
341
|
-
const int = Number.parseInt(color.replace("#", ""), 16);
|
|
342
|
-
return Number.isNaN(int) ? {
|
|
343
|
-
r: 255,
|
|
344
|
-
g: 255,
|
|
345
|
-
b: 255
|
|
346
|
-
} : {
|
|
347
|
-
r: int >> 16 & 255,
|
|
348
|
-
g: int >> 8 & 255,
|
|
349
|
-
b: int & 255
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
/**
|
|
353
|
-
* Returns a function that wraps a string in a 24-bit ANSI true-color escape sequence
|
|
354
|
-
* for the given hex color.
|
|
355
|
-
*/
|
|
356
|
-
function hex(color) {
|
|
357
|
-
const { r, g, b } = parseHex(color);
|
|
358
|
-
return (text) => `\x1b[38;2;${r};${g};${b}m${text}\x1b[0m`;
|
|
359
|
-
}
|
|
360
|
-
hex("#F55A17"), hex("#F5A217"), hex("#F58517"), hex("#B45309"), hex("#FFFFFF"), hex("#adadc6"), hex("#FDA4AF");
|
|
361
|
-
/**
|
|
362
|
-
* Converts all backslashes to forward slashes.
|
|
363
|
-
* Extended-length Windows paths (`\\?\...`) are left unchanged.
|
|
364
|
-
*/
|
|
365
|
-
function toSlash(p) {
|
|
366
|
-
if (p.startsWith("\\\\?\\")) return p;
|
|
367
|
-
return p.replaceAll("\\", "/");
|
|
368
|
-
}
|
|
369
|
-
/**
|
|
370
|
-
* Returns the relative path from `rootDir` to `filePath`, always using
|
|
371
|
-
* forward slashes and prefixed with `./` when not already traversing upward.
|
|
372
|
-
*/
|
|
373
|
-
function getRelativePath(rootDir, filePath) {
|
|
374
|
-
if (!rootDir || !filePath) throw new Error(`Root and file should be filled in when retrieving the relativePath, ${rootDir || ""} ${filePath || ""}`);
|
|
375
|
-
const relativePath = posix.relative(toSlash(rootDir), toSlash(filePath));
|
|
376
|
-
return relativePath.startsWith("../") ? relativePath : `./${relativePath}`;
|
|
377
|
-
}
|
|
181
|
+
//#endregion
|
|
182
|
+
//#region ../../internals/utils/src/fs.ts
|
|
378
183
|
/**
|
|
379
184
|
* Resolves to `true` when the file or directory at `path` exists.
|
|
380
185
|
* Uses `Bun.file().exists()` when running under Bun, `fs.access` otherwise.
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```ts
|
|
189
|
+
* if (await exists('./kubb.config.ts')) {
|
|
190
|
+
* const content = await read('./kubb.config.ts')
|
|
191
|
+
* }
|
|
192
|
+
* ```
|
|
381
193
|
*/
|
|
382
194
|
async function exists(path) {
|
|
383
195
|
if (typeof Bun !== "undefined") return Bun.file(path).exists();
|
|
384
196
|
return access(path).then(() => true, () => false);
|
|
385
197
|
}
|
|
386
198
|
/**
|
|
387
|
-
* Reads the file at `path` as a UTF-8 string.
|
|
388
|
-
* Uses `Bun.file().text()` when running under Bun, `fs.readFile` otherwise.
|
|
389
|
-
*/
|
|
390
|
-
async function read(path) {
|
|
391
|
-
if (typeof Bun !== "undefined") return Bun.file(path).text();
|
|
392
|
-
return readFile(path, { encoding: "utf8" });
|
|
393
|
-
}
|
|
394
|
-
/** Synchronous counterpart of `read`. */
|
|
395
|
-
function readSync(path) {
|
|
396
|
-
return readFileSync(path, { encoding: "utf8" });
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
199
|
* Writes `data` to `path`, trimming leading/trailing whitespace before saving.
|
|
400
|
-
* Skips the write
|
|
401
|
-
* identical to what is already on disk.
|
|
200
|
+
* Skips the write when the trimmed content is empty or identical to what is already on disk.
|
|
402
201
|
* Creates any missing parent directories automatically.
|
|
403
|
-
* When `sanity` is `true`, re-reads the file after writing and throws if the
|
|
404
|
-
*
|
|
202
|
+
* When `sanity` is `true`, re-reads the file after writing and throws if the content does not match.
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```ts
|
|
206
|
+
* await write('./src/Pet.ts', source) // writes and returns trimmed content
|
|
207
|
+
* await write('./src/Pet.ts', source) // null — file unchanged
|
|
208
|
+
* await write('./src/Pet.ts', ' ') // null — empty content skipped
|
|
209
|
+
* ```
|
|
405
210
|
*/
|
|
406
211
|
async function write(path, data, options = {}) {
|
|
407
212
|
const trimmed = data.trim();
|
|
408
|
-
if (trimmed === "") return
|
|
213
|
+
if (trimmed === "") return null;
|
|
409
214
|
const resolved = resolve(path);
|
|
410
215
|
if (typeof Bun !== "undefined") {
|
|
411
216
|
const file = Bun.file(resolved);
|
|
412
|
-
if ((await file.exists() ? await file.text() : null) === trimmed) return
|
|
217
|
+
if ((await file.exists() ? await file.text() : null) === trimmed) return null;
|
|
413
218
|
await Bun.write(resolved, trimmed);
|
|
414
219
|
return trimmed;
|
|
415
220
|
}
|
|
416
221
|
try {
|
|
417
|
-
if (await readFile(resolved, { encoding: "utf-8" }) === trimmed) return
|
|
222
|
+
if (await readFile(resolved, { encoding: "utf-8" }) === trimmed) return null;
|
|
418
223
|
} catch {}
|
|
419
224
|
await mkdir(dirname(resolved), { recursive: true });
|
|
420
225
|
await writeFile(resolved, trimmed, { encoding: "utf-8" });
|
|
@@ -425,124 +230,31 @@ async function write(path, data, options = {}) {
|
|
|
425
230
|
}
|
|
426
231
|
return trimmed;
|
|
427
232
|
}
|
|
428
|
-
/**
|
|
233
|
+
/**
|
|
234
|
+
* Recursively removes `path`. Silently succeeds when `path` does not exist.
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* ```ts
|
|
238
|
+
* await clean('./dist')
|
|
239
|
+
* ```
|
|
240
|
+
*/
|
|
429
241
|
async function clean(path) {
|
|
430
242
|
return rm(path, {
|
|
431
243
|
recursive: true,
|
|
432
244
|
force: true
|
|
433
245
|
});
|
|
434
246
|
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
* Use this when you need to track usage frequency but always emit the original identifier.
|
|
438
|
-
*/
|
|
439
|
-
function setUniqueName(originalName, data) {
|
|
440
|
-
let used = data[originalName] || 0;
|
|
441
|
-
if (used) {
|
|
442
|
-
data[originalName] = ++used;
|
|
443
|
-
return originalName;
|
|
444
|
-
}
|
|
445
|
-
data[originalName] = 1;
|
|
446
|
-
return originalName;
|
|
447
|
-
}
|
|
448
|
-
/**
|
|
449
|
-
* JavaScript and Java reserved words.
|
|
450
|
-
* @link https://github.com/jonschlinkert/reserved/blob/master/index.js
|
|
451
|
-
*/
|
|
452
|
-
const reservedWords = [
|
|
453
|
-
"abstract",
|
|
454
|
-
"arguments",
|
|
455
|
-
"boolean",
|
|
456
|
-
"break",
|
|
457
|
-
"byte",
|
|
458
|
-
"case",
|
|
459
|
-
"catch",
|
|
460
|
-
"char",
|
|
461
|
-
"class",
|
|
462
|
-
"const",
|
|
463
|
-
"continue",
|
|
464
|
-
"debugger",
|
|
465
|
-
"default",
|
|
466
|
-
"delete",
|
|
467
|
-
"do",
|
|
468
|
-
"double",
|
|
469
|
-
"else",
|
|
470
|
-
"enum",
|
|
471
|
-
"eval",
|
|
472
|
-
"export",
|
|
473
|
-
"extends",
|
|
474
|
-
"false",
|
|
475
|
-
"final",
|
|
476
|
-
"finally",
|
|
477
|
-
"float",
|
|
478
|
-
"for",
|
|
479
|
-
"function",
|
|
480
|
-
"goto",
|
|
481
|
-
"if",
|
|
482
|
-
"implements",
|
|
483
|
-
"import",
|
|
484
|
-
"in",
|
|
485
|
-
"instanceof",
|
|
486
|
-
"int",
|
|
487
|
-
"interface",
|
|
488
|
-
"let",
|
|
489
|
-
"long",
|
|
490
|
-
"native",
|
|
491
|
-
"new",
|
|
492
|
-
"null",
|
|
493
|
-
"package",
|
|
494
|
-
"private",
|
|
495
|
-
"protected",
|
|
496
|
-
"public",
|
|
497
|
-
"return",
|
|
498
|
-
"short",
|
|
499
|
-
"static",
|
|
500
|
-
"super",
|
|
501
|
-
"switch",
|
|
502
|
-
"synchronized",
|
|
503
|
-
"this",
|
|
504
|
-
"throw",
|
|
505
|
-
"throws",
|
|
506
|
-
"transient",
|
|
507
|
-
"true",
|
|
508
|
-
"try",
|
|
509
|
-
"typeof",
|
|
510
|
-
"var",
|
|
511
|
-
"void",
|
|
512
|
-
"volatile",
|
|
513
|
-
"while",
|
|
514
|
-
"with",
|
|
515
|
-
"yield",
|
|
516
|
-
"Array",
|
|
517
|
-
"Date",
|
|
518
|
-
"hasOwnProperty",
|
|
519
|
-
"Infinity",
|
|
520
|
-
"isFinite",
|
|
521
|
-
"isNaN",
|
|
522
|
-
"isPrototypeOf",
|
|
523
|
-
"length",
|
|
524
|
-
"Math",
|
|
525
|
-
"name",
|
|
526
|
-
"NaN",
|
|
527
|
-
"Number",
|
|
528
|
-
"Object",
|
|
529
|
-
"prototype",
|
|
530
|
-
"String",
|
|
531
|
-
"toString",
|
|
532
|
-
"undefined",
|
|
533
|
-
"valueOf"
|
|
534
|
-
];
|
|
535
|
-
/**
|
|
536
|
-
* Prefixes a word with `_` when it is a reserved JavaScript/Java identifier
|
|
537
|
-
* or starts with a digit.
|
|
538
|
-
*/
|
|
539
|
-
function transformReservedWord(word) {
|
|
540
|
-
const firstChar = word.charCodeAt(0);
|
|
541
|
-
if (word && (reservedWords.includes(word) || firstChar >= 48 && firstChar <= 57)) return `_${word}`;
|
|
542
|
-
return word;
|
|
543
|
-
}
|
|
247
|
+
//#endregion
|
|
248
|
+
//#region ../../internals/utils/src/reserved.ts
|
|
544
249
|
/**
|
|
545
250
|
* Returns `true` when `name` is a syntactically valid JavaScript variable name.
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```ts
|
|
254
|
+
* isValidVarName('status') // true
|
|
255
|
+
* isValidVarName('class') // false (reserved word)
|
|
256
|
+
* isValidVarName('42foo') // false (starts with digit)
|
|
257
|
+
* ```
|
|
546
258
|
*/
|
|
547
259
|
function isValidVarName(name) {
|
|
548
260
|
try {
|
|
@@ -552,6 +264,8 @@ function isValidVarName(name) {
|
|
|
552
264
|
}
|
|
553
265
|
return true;
|
|
554
266
|
}
|
|
267
|
+
//#endregion
|
|
268
|
+
//#region ../../internals/utils/src/urlPath.ts
|
|
555
269
|
/**
|
|
556
270
|
* Parses and transforms an OpenAPI/Swagger path string into various URL formats.
|
|
557
271
|
*
|
|
@@ -561,18 +275,33 @@ function isValidVarName(name) {
|
|
|
561
275
|
* p.template // '`/pet/${petId}`'
|
|
562
276
|
*/
|
|
563
277
|
var URLPath = class {
|
|
564
|
-
/**
|
|
278
|
+
/**
|
|
279
|
+
* The raw OpenAPI/Swagger path string, e.g. `/pet/{petId}`.
|
|
280
|
+
*/
|
|
565
281
|
path;
|
|
566
282
|
#options;
|
|
567
283
|
constructor(path, options = {}) {
|
|
568
284
|
this.path = path;
|
|
569
285
|
this.#options = options;
|
|
570
286
|
}
|
|
571
|
-
/** Converts the OpenAPI path to Express-style colon syntax, e.g. `/pet/{petId}` → `/pet/:petId`.
|
|
287
|
+
/** Converts the OpenAPI path to Express-style colon syntax, e.g. `/pet/{petId}` → `/pet/:petId`.
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* ```ts
|
|
291
|
+
* new URLPath('/pet/{petId}').URL // '/pet/:petId'
|
|
292
|
+
* ```
|
|
293
|
+
*/
|
|
572
294
|
get URL() {
|
|
573
295
|
return this.toURLPath();
|
|
574
296
|
}
|
|
575
|
-
/** Returns `true` when `path` is a fully-qualified URL (e.g. starts with `https://`).
|
|
297
|
+
/** Returns `true` when `path` is a fully-qualified URL (e.g. starts with `https://`).
|
|
298
|
+
*
|
|
299
|
+
* @example
|
|
300
|
+
* ```ts
|
|
301
|
+
* new URLPath('https://petstore.swagger.io/v2/pet').isURL // true
|
|
302
|
+
* new URLPath('/pet/{petId}').isURL // false
|
|
303
|
+
* ```
|
|
304
|
+
*/
|
|
576
305
|
get isURL() {
|
|
577
306
|
try {
|
|
578
307
|
return !!new URL(this.path).href;
|
|
@@ -590,11 +319,25 @@ var URLPath = class {
|
|
|
590
319
|
get template() {
|
|
591
320
|
return this.toTemplateString();
|
|
592
321
|
}
|
|
593
|
-
/** Returns the path and its extracted params as a structured `URLObject`, or as a stringified expression when `stringify` is set.
|
|
322
|
+
/** Returns the path and its extracted params as a structured `URLObject`, or as a stringified expression when `stringify` is set.
|
|
323
|
+
*
|
|
324
|
+
* @example
|
|
325
|
+
* ```ts
|
|
326
|
+
* new URLPath('/pet/{petId}').object
|
|
327
|
+
* // { url: '/pet/:petId', params: { petId: 'petId' } }
|
|
328
|
+
* ```
|
|
329
|
+
*/
|
|
594
330
|
get object() {
|
|
595
331
|
return this.toObject();
|
|
596
332
|
}
|
|
597
|
-
/** Returns a map of path parameter names, or `undefined` when the path has no parameters.
|
|
333
|
+
/** Returns a map of path parameter names, or `undefined` when the path has no parameters.
|
|
334
|
+
*
|
|
335
|
+
* @example
|
|
336
|
+
* ```ts
|
|
337
|
+
* new URLPath('/pet/{petId}').params // { petId: 'petId' }
|
|
338
|
+
* new URLPath('/pet').params // undefined
|
|
339
|
+
* ```
|
|
340
|
+
*/
|
|
598
341
|
get params() {
|
|
599
342
|
return this.getParams();
|
|
600
343
|
}
|
|
@@ -602,7 +345,9 @@ var URLPath = class {
|
|
|
602
345
|
const param = isValidVarName(raw) ? raw : camelCase(raw);
|
|
603
346
|
return this.#options.casing === "camelcase" ? camelCase(param) : param;
|
|
604
347
|
}
|
|
605
|
-
/**
|
|
348
|
+
/**
|
|
349
|
+
* Iterates over every `{param}` token in `path`, calling `fn` with the raw token and transformed name.
|
|
350
|
+
*/
|
|
606
351
|
#eachParam(fn) {
|
|
607
352
|
for (const match of this.path.matchAll(/\{([^}]+)\}/g)) {
|
|
608
353
|
const raw = match[1];
|
|
@@ -639,6 +384,12 @@ var URLPath = class {
|
|
|
639
384
|
* Extracts all `{param}` segments from the path and returns them as a key-value map.
|
|
640
385
|
* An optional `replacer` transforms each parameter name in both key and value positions.
|
|
641
386
|
* Returns `undefined` when no path parameters are found.
|
|
387
|
+
*
|
|
388
|
+
* @example
|
|
389
|
+
* ```ts
|
|
390
|
+
* new URLPath('/pet/{petId}/tag/{tagId}').getParams()
|
|
391
|
+
* // { petId: 'petId', tagId: 'tagId' }
|
|
392
|
+
* ```
|
|
642
393
|
*/
|
|
643
394
|
getParams(replacer) {
|
|
644
395
|
const params = {};
|
|
@@ -648,130 +399,43 @@ var URLPath = class {
|
|
|
648
399
|
});
|
|
649
400
|
return Object.keys(params).length > 0 ? params : void 0;
|
|
650
401
|
}
|
|
651
|
-
/** Converts the OpenAPI path to Express-style colon syntax
|
|
402
|
+
/** Converts the OpenAPI path to Express-style colon syntax.
|
|
403
|
+
*
|
|
404
|
+
* @example
|
|
405
|
+
* ```ts
|
|
406
|
+
* new URLPath('/pet/{petId}').toURLPath() // '/pet/:petId'
|
|
407
|
+
* ```
|
|
408
|
+
*/
|
|
652
409
|
toURLPath() {
|
|
653
410
|
return this.path.replace(/\{([^}]+)\}/g, ":$1");
|
|
654
411
|
}
|
|
655
412
|
};
|
|
656
413
|
//#endregion
|
|
657
|
-
//#region src/
|
|
658
|
-
function defineConfig(config) {
|
|
659
|
-
return config;
|
|
660
|
-
}
|
|
661
|
-
/**
|
|
662
|
-
* Type guard to check if a given config has an `input.path`.
|
|
663
|
-
*/
|
|
664
|
-
function isInputPath(config) {
|
|
665
|
-
return typeof config?.input === "object" && config.input !== null && "path" in config.input;
|
|
666
|
-
}
|
|
667
|
-
//#endregion
|
|
668
|
-
//#region src/constants.ts
|
|
669
|
-
const DEFAULT_STUDIO_URL = "https://studio.kubb.dev";
|
|
670
|
-
const BARREL_FILENAME = "index.ts";
|
|
671
|
-
const DEFAULT_BANNER = "simple";
|
|
672
|
-
const DEFAULT_EXTENSION = { ".ts": ".ts" };
|
|
673
|
-
const PATH_SEPARATORS = ["/", "\\"];
|
|
674
|
-
const logLevel = {
|
|
675
|
-
silent: Number.NEGATIVE_INFINITY,
|
|
676
|
-
error: 0,
|
|
677
|
-
warn: 1,
|
|
678
|
-
info: 3,
|
|
679
|
-
verbose: 4,
|
|
680
|
-
debug: 5
|
|
681
|
-
};
|
|
682
|
-
const linters = {
|
|
683
|
-
eslint: {
|
|
684
|
-
command: "eslint",
|
|
685
|
-
args: (outputPath) => [outputPath, "--fix"],
|
|
686
|
-
errorMessage: "Eslint not found"
|
|
687
|
-
},
|
|
688
|
-
biome: {
|
|
689
|
-
command: "biome",
|
|
690
|
-
args: (outputPath) => [
|
|
691
|
-
"lint",
|
|
692
|
-
"--fix",
|
|
693
|
-
outputPath
|
|
694
|
-
],
|
|
695
|
-
errorMessage: "Biome not found"
|
|
696
|
-
},
|
|
697
|
-
oxlint: {
|
|
698
|
-
command: "oxlint",
|
|
699
|
-
args: (outputPath) => ["--fix", outputPath],
|
|
700
|
-
errorMessage: "Oxlint not found"
|
|
701
|
-
}
|
|
702
|
-
};
|
|
703
|
-
const formatters = {
|
|
704
|
-
prettier: {
|
|
705
|
-
command: "prettier",
|
|
706
|
-
args: (outputPath) => [
|
|
707
|
-
"--ignore-unknown",
|
|
708
|
-
"--write",
|
|
709
|
-
outputPath
|
|
710
|
-
],
|
|
711
|
-
errorMessage: "Prettier not found"
|
|
712
|
-
},
|
|
713
|
-
biome: {
|
|
714
|
-
command: "biome",
|
|
715
|
-
args: (outputPath) => [
|
|
716
|
-
"format",
|
|
717
|
-
"--write",
|
|
718
|
-
outputPath
|
|
719
|
-
],
|
|
720
|
-
errorMessage: "Biome not found"
|
|
721
|
-
},
|
|
722
|
-
oxfmt: {
|
|
723
|
-
command: "oxfmt",
|
|
724
|
-
args: (outputPath) => [outputPath],
|
|
725
|
-
errorMessage: "Oxfmt not found"
|
|
726
|
-
}
|
|
727
|
-
};
|
|
728
|
-
//#endregion
|
|
729
|
-
//#region src/devtools.ts
|
|
414
|
+
//#region src/createAdapter.ts
|
|
730
415
|
/**
|
|
731
|
-
*
|
|
732
|
-
*
|
|
733
|
-
* The JSON representation is deflate-compressed with {@link deflateSync} before
|
|
734
|
-
* base64url encoding, which typically reduces payload size by 70–80 % and
|
|
735
|
-
* keeps URLs well within browser and server path-length limits.
|
|
416
|
+
* Creates an adapter factory. Call the returned function with optional options to get the adapter instance.
|
|
736
417
|
*
|
|
737
|
-
*
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
*
|
|
745
|
-
* When `options.ast` is `true`, navigates to the AST inspector (`/ast`).
|
|
746
|
-
* The `root` is encoded and attached as the `?root=` query parameter so Studio
|
|
747
|
-
* can decode and render it without a round-trip to any server.
|
|
748
|
-
*/
|
|
749
|
-
function getStudioUrl(root, studioUrl, options = {}) {
|
|
750
|
-
return `${studioUrl.replace(/\/$/, "")}${options.ast ? "/ast" : ""}?root=${encodeAst(root)}`;
|
|
751
|
-
}
|
|
752
|
-
/**
|
|
753
|
-
* Opens the Kubb Studio URL for the given `RootNode` in the default browser —
|
|
418
|
+
* @example
|
|
419
|
+
* export const myAdapter = createAdapter<MyAdapter>((options) => {
|
|
420
|
+
* return {
|
|
421
|
+
* name: 'my-adapter',
|
|
422
|
+
* options,
|
|
423
|
+
* async parse(source) { ... },
|
|
424
|
+
* }
|
|
425
|
+
* })
|
|
754
426
|
*
|
|
755
|
-
*
|
|
427
|
+
* // instantiate
|
|
428
|
+
* const adapter = myAdapter({ validate: true })
|
|
756
429
|
*/
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
const cmd = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
|
|
760
|
-
const args = process.platform === "win32" ? [
|
|
761
|
-
"/c",
|
|
762
|
-
"start",
|
|
763
|
-
"",
|
|
764
|
-
url
|
|
765
|
-
] : [url];
|
|
766
|
-
try {
|
|
767
|
-
await x(cmd, args);
|
|
768
|
-
} catch {
|
|
769
|
-
console.log(`\n ${url}\n`);
|
|
770
|
-
}
|
|
430
|
+
function createAdapter(build) {
|
|
431
|
+
return (options) => build(options ?? {});
|
|
771
432
|
}
|
|
772
433
|
//#endregion
|
|
773
434
|
//#region ../../node_modules/.pnpm/yocto-queue@1.2.2/node_modules/yocto-queue/index.js
|
|
774
|
-
var Node = class {
|
|
435
|
+
var Node$1 = class {
|
|
436
|
+
static {
|
|
437
|
+
__name(this, "Node");
|
|
438
|
+
}
|
|
775
439
|
value;
|
|
776
440
|
next;
|
|
777
441
|
constructor(value) {
|
|
@@ -786,7 +450,7 @@ var Queue = class {
|
|
|
786
450
|
this.clear();
|
|
787
451
|
}
|
|
788
452
|
enqueue(value) {
|
|
789
|
-
const node = new Node(value);
|
|
453
|
+
const node = new Node$1(value);
|
|
790
454
|
if (this.#head) {
|
|
791
455
|
this.#tail.next = node;
|
|
792
456
|
this.#tail = node;
|
|
@@ -897,494 +561,83 @@ function validateConcurrency(concurrency) {
|
|
|
897
561
|
if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) throw new TypeError("Expected `concurrency` to be a number from 1 and up");
|
|
898
562
|
}
|
|
899
563
|
//#endregion
|
|
900
|
-
//#region src/
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
*/
|
|
904
|
-
function hookSeq(promises) {
|
|
905
|
-
return promises.filter(Boolean).reduce((promise, func) => {
|
|
906
|
-
if (typeof func !== "function") throw new Error("HookSeq needs a function that returns a promise `() => Promise<unknown>`");
|
|
907
|
-
return promise.then((state) => {
|
|
908
|
-
const calledFunc = func(state);
|
|
909
|
-
if (calledFunc) return calledFunc.then(Array.prototype.concat.bind(state));
|
|
910
|
-
return state;
|
|
911
|
-
});
|
|
912
|
-
}, Promise.resolve([]));
|
|
913
|
-
}
|
|
914
|
-
/**
|
|
915
|
-
* Chains promises, first non-null result stops and returns
|
|
916
|
-
*/
|
|
917
|
-
function hookFirst(promises, nullCheck = (state) => state !== null) {
|
|
918
|
-
let promise = Promise.resolve(null);
|
|
919
|
-
for (const func of promises.filter(Boolean)) promise = promise.then((state) => {
|
|
920
|
-
if (nullCheck(state)) return state;
|
|
921
|
-
return func(state);
|
|
922
|
-
});
|
|
923
|
-
return promise;
|
|
564
|
+
//#region src/FileProcessor.ts
|
|
565
|
+
function joinSources(file) {
|
|
566
|
+
return file.sources.map((item) => extractStringsFromNodes(item.nodes)).filter(Boolean).join("\n\n");
|
|
924
567
|
}
|
|
925
568
|
/**
|
|
926
|
-
*
|
|
569
|
+
* Converts a single file to a string using the registered parsers.
|
|
570
|
+
* Falls back to joining source values when no matching parser is found.
|
|
571
|
+
*
|
|
572
|
+
* @internal
|
|
927
573
|
*/
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
574
|
+
var FileProcessor = class {
|
|
575
|
+
#limit = pLimit(100);
|
|
576
|
+
async parse(file, { parsers, extension } = {}) {
|
|
577
|
+
const parseExtName = extension?.[file.extname] || void 0;
|
|
578
|
+
if (!parsers || !file.extname) return joinSources(file);
|
|
579
|
+
const parser = parsers.get(file.extname);
|
|
580
|
+
if (!parser) return joinSources(file);
|
|
581
|
+
return parser.parse(file, { extname: parseExtName });
|
|
582
|
+
}
|
|
583
|
+
async run(files, { parsers, mode = "sequential", extension, onStart, onEnd, onUpdate } = {}) {
|
|
584
|
+
await onStart?.(files);
|
|
585
|
+
const total = files.length;
|
|
586
|
+
let processed = 0;
|
|
587
|
+
const processOne = async (file) => {
|
|
588
|
+
const source = await this.parse(file, {
|
|
589
|
+
extension,
|
|
590
|
+
parsers
|
|
591
|
+
});
|
|
592
|
+
const currentProcessed = ++processed;
|
|
593
|
+
const percentage = currentProcessed / total * 100;
|
|
594
|
+
await onUpdate?.({
|
|
595
|
+
file,
|
|
596
|
+
source,
|
|
597
|
+
processed: currentProcessed,
|
|
598
|
+
percentage,
|
|
599
|
+
total
|
|
600
|
+
});
|
|
601
|
+
};
|
|
602
|
+
if (mode === "sequential") for (const file of files) await processOne(file);
|
|
603
|
+
else await Promise.all(files.map((file) => this.#limit(() => processOne(file))));
|
|
604
|
+
await onEnd?.(files);
|
|
605
|
+
return files;
|
|
945
606
|
}
|
|
946
607
|
};
|
|
947
|
-
|
|
948
|
-
|
|
608
|
+
//#endregion
|
|
609
|
+
//#region src/createStorage.ts
|
|
610
|
+
/**
|
|
611
|
+
* Creates a storage factory. Call the returned function with optional options to get the storage instance.
|
|
612
|
+
*
|
|
613
|
+
* @example
|
|
614
|
+
* export const memoryStorage = createStorage(() => {
|
|
615
|
+
* const store = new Map<string, string>()
|
|
616
|
+
* return {
|
|
617
|
+
* name: 'memory',
|
|
618
|
+
* async hasItem(key) { return store.has(key) },
|
|
619
|
+
* async getItem(key) { return store.get(key) ?? null },
|
|
620
|
+
* async setItem(key, value) { store.set(key, value) },
|
|
621
|
+
* async removeItem(key) { store.delete(key) },
|
|
622
|
+
* async getKeys(base) {
|
|
623
|
+
* const keys = [...store.keys()]
|
|
624
|
+
* return base ? keys.filter((k) => k.startsWith(base)) : keys
|
|
625
|
+
* },
|
|
626
|
+
* async clear(base) { if (!base) store.clear() },
|
|
627
|
+
* }
|
|
628
|
+
* })
|
|
629
|
+
*/
|
|
630
|
+
function createStorage(build) {
|
|
631
|
+
return (options) => build(options ?? {});
|
|
949
632
|
}
|
|
950
633
|
//#endregion
|
|
951
|
-
//#region src/
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
634
|
+
//#region src/storages/fsStorage.ts
|
|
635
|
+
/**
|
|
636
|
+
* Detects the filesystem error used to indicate that a path does not exist.
|
|
637
|
+
*/
|
|
638
|
+
function isMissingPathError(error) {
|
|
639
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
955
640
|
}
|
|
956
|
-
var PluginManager = class {
|
|
957
|
-
config;
|
|
958
|
-
options;
|
|
959
|
-
/**
|
|
960
|
-
* The universal `@kubb/ast` `RootNode` produced by the adapter, set by
|
|
961
|
-
* the build pipeline after the adapter's `parse()` resolves.
|
|
962
|
-
*/
|
|
963
|
-
rootNode = void 0;
|
|
964
|
-
adapter = void 0;
|
|
965
|
-
#studioIsOpen = false;
|
|
966
|
-
#plugins = /* @__PURE__ */ new Set();
|
|
967
|
-
#usedPluginNames = {};
|
|
968
|
-
#promiseManager;
|
|
969
|
-
constructor(config, options) {
|
|
970
|
-
this.config = config;
|
|
971
|
-
this.options = options;
|
|
972
|
-
this.#promiseManager = new PromiseManager({ nullCheck: (state) => !!state?.result });
|
|
973
|
-
[...config.plugins || []].forEach((plugin) => {
|
|
974
|
-
const parsedPlugin = this.#parse(plugin);
|
|
975
|
-
this.#plugins.add(parsedPlugin);
|
|
976
|
-
});
|
|
977
|
-
}
|
|
978
|
-
get events() {
|
|
979
|
-
return this.options.events;
|
|
980
|
-
}
|
|
981
|
-
getContext(plugin) {
|
|
982
|
-
const plugins = [...this.#plugins];
|
|
983
|
-
const pluginManager = this;
|
|
984
|
-
const baseContext = {
|
|
985
|
-
fabric: this.options.fabric,
|
|
986
|
-
config: this.config,
|
|
987
|
-
plugin,
|
|
988
|
-
events: this.options.events,
|
|
989
|
-
pluginManager: this,
|
|
990
|
-
mode: getMode(resolve(this.config.root, this.config.output.path)),
|
|
991
|
-
addFile: async (...files) => {
|
|
992
|
-
await this.options.fabric.addFile(...files);
|
|
993
|
-
},
|
|
994
|
-
upsertFile: async (...files) => {
|
|
995
|
-
await this.options.fabric.upsertFile(...files);
|
|
996
|
-
},
|
|
997
|
-
get rootNode() {
|
|
998
|
-
return pluginManager.rootNode;
|
|
999
|
-
},
|
|
1000
|
-
get adapter() {
|
|
1001
|
-
return pluginManager.adapter;
|
|
1002
|
-
},
|
|
1003
|
-
openInStudio(options) {
|
|
1004
|
-
if (!pluginManager.config.devtools || pluginManager.#studioIsOpen) return;
|
|
1005
|
-
if (typeof pluginManager.config.devtools !== "object") throw new Error("Devtools must be an object");
|
|
1006
|
-
if (!pluginManager.rootNode || !pluginManager.adapter) throw new Error("adapter is not defined, make sure you have set the parser in kubb.config.ts");
|
|
1007
|
-
pluginManager.#studioIsOpen = true;
|
|
1008
|
-
const studioUrl = pluginManager.config.devtools?.studioUrl ?? "https://studio.kubb.dev";
|
|
1009
|
-
return openInStudio(pluginManager.rootNode, studioUrl, options);
|
|
1010
|
-
}
|
|
1011
|
-
};
|
|
1012
|
-
const mergedExtras = {};
|
|
1013
|
-
for (const p of plugins) if (typeof p.inject === "function") {
|
|
1014
|
-
const result = p.inject.call(baseContext, baseContext);
|
|
1015
|
-
if (result !== null && typeof result === "object") Object.assign(mergedExtras, result);
|
|
1016
|
-
}
|
|
1017
|
-
return {
|
|
1018
|
-
...baseContext,
|
|
1019
|
-
...mergedExtras
|
|
1020
|
-
};
|
|
1021
|
-
}
|
|
1022
|
-
get plugins() {
|
|
1023
|
-
return this.#getSortedPlugins();
|
|
1024
|
-
}
|
|
1025
|
-
getFile({ name, mode, extname, pluginName, options }) {
|
|
1026
|
-
const resolvedName = mode ? mode === "single" ? "" : this.resolveName({
|
|
1027
|
-
name,
|
|
1028
|
-
pluginName,
|
|
1029
|
-
type: "file"
|
|
1030
|
-
}) : name;
|
|
1031
|
-
const path = this.resolvePath({
|
|
1032
|
-
baseName: `${resolvedName}${extname}`,
|
|
1033
|
-
mode,
|
|
1034
|
-
pluginName,
|
|
1035
|
-
options
|
|
1036
|
-
});
|
|
1037
|
-
if (!path) throw new Error(`Filepath should be defined for resolvedName "${resolvedName}" and pluginName "${pluginName}"`);
|
|
1038
|
-
return {
|
|
1039
|
-
path,
|
|
1040
|
-
baseName: basename(path),
|
|
1041
|
-
meta: { pluginName },
|
|
1042
|
-
sources: [],
|
|
1043
|
-
imports: [],
|
|
1044
|
-
exports: []
|
|
1045
|
-
};
|
|
1046
|
-
}
|
|
1047
|
-
resolvePath = (params) => {
|
|
1048
|
-
const defaultPath = resolve(resolve(this.config.root, this.config.output.path), params.baseName);
|
|
1049
|
-
if (params.pluginName) return this.hookForPluginSync({
|
|
1050
|
-
pluginName: params.pluginName,
|
|
1051
|
-
hookName: "resolvePath",
|
|
1052
|
-
parameters: [
|
|
1053
|
-
params.baseName,
|
|
1054
|
-
params.mode,
|
|
1055
|
-
params.options
|
|
1056
|
-
]
|
|
1057
|
-
})?.at(0) || defaultPath;
|
|
1058
|
-
return this.hookFirstSync({
|
|
1059
|
-
hookName: "resolvePath",
|
|
1060
|
-
parameters: [
|
|
1061
|
-
params.baseName,
|
|
1062
|
-
params.mode,
|
|
1063
|
-
params.options
|
|
1064
|
-
]
|
|
1065
|
-
})?.result || defaultPath;
|
|
1066
|
-
};
|
|
1067
|
-
resolveName = (params) => {
|
|
1068
|
-
if (params.pluginName) {
|
|
1069
|
-
const names = this.hookForPluginSync({
|
|
1070
|
-
pluginName: params.pluginName,
|
|
1071
|
-
hookName: "resolveName",
|
|
1072
|
-
parameters: [params.name.trim(), params.type]
|
|
1073
|
-
});
|
|
1074
|
-
return transformReservedWord([...new Set(names)].at(0) || params.name);
|
|
1075
|
-
}
|
|
1076
|
-
const name = this.hookFirstSync({
|
|
1077
|
-
hookName: "resolveName",
|
|
1078
|
-
parameters: [params.name.trim(), params.type]
|
|
1079
|
-
})?.result;
|
|
1080
|
-
return transformReservedWord(name ?? params.name);
|
|
1081
|
-
};
|
|
1082
|
-
/**
|
|
1083
|
-
* Run a specific hookName for plugin x.
|
|
1084
|
-
*/
|
|
1085
|
-
async hookForPlugin({ pluginName, hookName, parameters }) {
|
|
1086
|
-
const plugins = this.getPluginsByName(hookName, pluginName);
|
|
1087
|
-
this.events.emit("plugins:hook:progress:start", {
|
|
1088
|
-
hookName,
|
|
1089
|
-
plugins
|
|
1090
|
-
});
|
|
1091
|
-
const items = [];
|
|
1092
|
-
for (const plugin of plugins) {
|
|
1093
|
-
const result = await this.#execute({
|
|
1094
|
-
strategy: "hookFirst",
|
|
1095
|
-
hookName,
|
|
1096
|
-
parameters,
|
|
1097
|
-
plugin
|
|
1098
|
-
});
|
|
1099
|
-
if (result !== void 0 && result !== null) items.push(result);
|
|
1100
|
-
}
|
|
1101
|
-
this.events.emit("plugins:hook:progress:end", { hookName });
|
|
1102
|
-
return items;
|
|
1103
|
-
}
|
|
1104
|
-
/**
|
|
1105
|
-
* Run a specific hookName for plugin x.
|
|
1106
|
-
*/
|
|
1107
|
-
hookForPluginSync({ pluginName, hookName, parameters }) {
|
|
1108
|
-
return this.getPluginsByName(hookName, pluginName).map((plugin) => {
|
|
1109
|
-
return this.#executeSync({
|
|
1110
|
-
strategy: "hookFirst",
|
|
1111
|
-
hookName,
|
|
1112
|
-
parameters,
|
|
1113
|
-
plugin
|
|
1114
|
-
});
|
|
1115
|
-
}).filter((x) => x !== null);
|
|
1116
|
-
}
|
|
1117
|
-
/**
|
|
1118
|
-
* Returns the first non-null result.
|
|
1119
|
-
*/
|
|
1120
|
-
async hookFirst({ hookName, parameters, skipped }) {
|
|
1121
|
-
const plugins = this.#getSortedPlugins(hookName).filter((plugin) => {
|
|
1122
|
-
return skipped ? !skipped.has(plugin) : true;
|
|
1123
|
-
});
|
|
1124
|
-
this.events.emit("plugins:hook:progress:start", {
|
|
1125
|
-
hookName,
|
|
1126
|
-
plugins
|
|
1127
|
-
});
|
|
1128
|
-
const promises = plugins.map((plugin) => {
|
|
1129
|
-
return async () => {
|
|
1130
|
-
const value = await this.#execute({
|
|
1131
|
-
strategy: "hookFirst",
|
|
1132
|
-
hookName,
|
|
1133
|
-
parameters,
|
|
1134
|
-
plugin
|
|
1135
|
-
});
|
|
1136
|
-
return Promise.resolve({
|
|
1137
|
-
plugin,
|
|
1138
|
-
result: value
|
|
1139
|
-
});
|
|
1140
|
-
};
|
|
1141
|
-
});
|
|
1142
|
-
const result = await this.#promiseManager.run("first", promises);
|
|
1143
|
-
this.events.emit("plugins:hook:progress:end", { hookName });
|
|
1144
|
-
return result;
|
|
1145
|
-
}
|
|
1146
|
-
/**
|
|
1147
|
-
* Returns the first non-null result.
|
|
1148
|
-
*/
|
|
1149
|
-
hookFirstSync({ hookName, parameters, skipped }) {
|
|
1150
|
-
let parseResult = null;
|
|
1151
|
-
const plugins = this.#getSortedPlugins(hookName).filter((plugin) => {
|
|
1152
|
-
return skipped ? !skipped.has(plugin) : true;
|
|
1153
|
-
});
|
|
1154
|
-
for (const plugin of plugins) {
|
|
1155
|
-
parseResult = {
|
|
1156
|
-
result: this.#executeSync({
|
|
1157
|
-
strategy: "hookFirst",
|
|
1158
|
-
hookName,
|
|
1159
|
-
parameters,
|
|
1160
|
-
plugin
|
|
1161
|
-
}),
|
|
1162
|
-
plugin
|
|
1163
|
-
};
|
|
1164
|
-
if (parseResult?.result != null) break;
|
|
1165
|
-
}
|
|
1166
|
-
return parseResult;
|
|
1167
|
-
}
|
|
1168
|
-
/**
|
|
1169
|
-
* Runs all plugins in parallel based on `this.plugin` order and `pre`/`post` settings.
|
|
1170
|
-
*/
|
|
1171
|
-
async hookParallel({ hookName, parameters }) {
|
|
1172
|
-
const plugins = this.#getSortedPlugins(hookName);
|
|
1173
|
-
this.events.emit("plugins:hook:progress:start", {
|
|
1174
|
-
hookName,
|
|
1175
|
-
plugins
|
|
1176
|
-
});
|
|
1177
|
-
const pluginStartTimes = /* @__PURE__ */ new Map();
|
|
1178
|
-
const promises = plugins.map((plugin) => {
|
|
1179
|
-
return () => {
|
|
1180
|
-
pluginStartTimes.set(plugin, performance.now());
|
|
1181
|
-
return this.#execute({
|
|
1182
|
-
strategy: "hookParallel",
|
|
1183
|
-
hookName,
|
|
1184
|
-
parameters,
|
|
1185
|
-
plugin
|
|
1186
|
-
});
|
|
1187
|
-
};
|
|
1188
|
-
});
|
|
1189
|
-
const results = await this.#promiseManager.run("parallel", promises, { concurrency: this.options.concurrency });
|
|
1190
|
-
results.forEach((result, index) => {
|
|
1191
|
-
if (isPromiseRejectedResult(result)) {
|
|
1192
|
-
const plugin = this.#getSortedPlugins(hookName)[index];
|
|
1193
|
-
if (plugin) {
|
|
1194
|
-
const startTime = pluginStartTimes.get(plugin) ?? performance.now();
|
|
1195
|
-
this.events.emit("error", result.reason, {
|
|
1196
|
-
plugin,
|
|
1197
|
-
hookName,
|
|
1198
|
-
strategy: "hookParallel",
|
|
1199
|
-
duration: Math.round(performance.now() - startTime),
|
|
1200
|
-
parameters
|
|
1201
|
-
});
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
});
|
|
1205
|
-
this.events.emit("plugins:hook:progress:end", { hookName });
|
|
1206
|
-
return results.reduce((acc, result) => {
|
|
1207
|
-
if (result.status === "fulfilled") acc.push(result.value);
|
|
1208
|
-
return acc;
|
|
1209
|
-
}, []);
|
|
1210
|
-
}
|
|
1211
|
-
/**
|
|
1212
|
-
* Chains plugins
|
|
1213
|
-
*/
|
|
1214
|
-
async hookSeq({ hookName, parameters }) {
|
|
1215
|
-
const plugins = this.#getSortedPlugins(hookName);
|
|
1216
|
-
this.events.emit("plugins:hook:progress:start", {
|
|
1217
|
-
hookName,
|
|
1218
|
-
plugins
|
|
1219
|
-
});
|
|
1220
|
-
const promises = plugins.map((plugin) => {
|
|
1221
|
-
return () => this.#execute({
|
|
1222
|
-
strategy: "hookSeq",
|
|
1223
|
-
hookName,
|
|
1224
|
-
parameters,
|
|
1225
|
-
plugin
|
|
1226
|
-
});
|
|
1227
|
-
});
|
|
1228
|
-
await this.#promiseManager.run("seq", promises);
|
|
1229
|
-
this.events.emit("plugins:hook:progress:end", { hookName });
|
|
1230
|
-
}
|
|
1231
|
-
#getSortedPlugins(hookName) {
|
|
1232
|
-
const plugins = [...this.#plugins];
|
|
1233
|
-
if (hookName) return plugins.filter((plugin) => hookName in plugin);
|
|
1234
|
-
return plugins.map((plugin) => {
|
|
1235
|
-
if (plugin.pre) {
|
|
1236
|
-
let missingPlugins = plugin.pre.filter((pluginName) => !plugins.find((pluginToFind) => pluginToFind.name === pluginName));
|
|
1237
|
-
if (missingPlugins.includes("plugin-oas") && this.adapter) missingPlugins = missingPlugins.filter((pluginName) => pluginName !== "plugin-oas");
|
|
1238
|
-
if (missingPlugins.length > 0) throw new ValidationPluginError(`The plugin '${plugin.name}' has a pre set that references missing plugins for '${missingPlugins.join(", ")}'`);
|
|
1239
|
-
}
|
|
1240
|
-
return plugin;
|
|
1241
|
-
}).sort((a, b) => {
|
|
1242
|
-
if (b.pre?.includes(a.name)) return 1;
|
|
1243
|
-
if (b.post?.includes(a.name)) return -1;
|
|
1244
|
-
return 0;
|
|
1245
|
-
});
|
|
1246
|
-
}
|
|
1247
|
-
getPluginByName(pluginName) {
|
|
1248
|
-
return [...this.#plugins].find((item) => item.name === pluginName);
|
|
1249
|
-
}
|
|
1250
|
-
getPluginsByName(hookName, pluginName) {
|
|
1251
|
-
const plugins = [...this.plugins];
|
|
1252
|
-
const pluginByPluginName = plugins.filter((plugin) => hookName in plugin).filter((item) => item.name === pluginName);
|
|
1253
|
-
if (!pluginByPluginName?.length) {
|
|
1254
|
-
const corePlugin = plugins.find((plugin) => plugin.name === "core" && hookName in plugin);
|
|
1255
|
-
return corePlugin ? [corePlugin] : [];
|
|
1256
|
-
}
|
|
1257
|
-
return pluginByPluginName;
|
|
1258
|
-
}
|
|
1259
|
-
/**
|
|
1260
|
-
* Run an async plugin hook and return the result.
|
|
1261
|
-
* @param hookName Name of the plugin hook. Must be either in `PluginHooks` or `OutputPluginValueHooks`.
|
|
1262
|
-
* @param args Arguments passed to the plugin hook.
|
|
1263
|
-
* @param plugin The actual pluginObject to run.
|
|
1264
|
-
*/
|
|
1265
|
-
#emitProcessingEnd({ startTime, output, strategy, hookName, plugin, parameters }) {
|
|
1266
|
-
this.events.emit("plugins:hook:processing:end", {
|
|
1267
|
-
duration: Math.round(performance.now() - startTime),
|
|
1268
|
-
parameters,
|
|
1269
|
-
output,
|
|
1270
|
-
strategy,
|
|
1271
|
-
hookName,
|
|
1272
|
-
plugin
|
|
1273
|
-
});
|
|
1274
|
-
}
|
|
1275
|
-
#execute({ strategy, hookName, parameters, plugin }) {
|
|
1276
|
-
const hook = plugin[hookName];
|
|
1277
|
-
if (!hook) return null;
|
|
1278
|
-
this.events.emit("plugins:hook:processing:start", {
|
|
1279
|
-
strategy,
|
|
1280
|
-
hookName,
|
|
1281
|
-
parameters,
|
|
1282
|
-
plugin
|
|
1283
|
-
});
|
|
1284
|
-
const startTime = performance.now();
|
|
1285
|
-
return (async () => {
|
|
1286
|
-
try {
|
|
1287
|
-
const output = typeof hook === "function" ? await Promise.resolve(hook.apply(this.getContext(plugin), parameters ?? [])) : hook;
|
|
1288
|
-
this.#emitProcessingEnd({
|
|
1289
|
-
startTime,
|
|
1290
|
-
output,
|
|
1291
|
-
strategy,
|
|
1292
|
-
hookName,
|
|
1293
|
-
plugin,
|
|
1294
|
-
parameters
|
|
1295
|
-
});
|
|
1296
|
-
return output;
|
|
1297
|
-
} catch (error) {
|
|
1298
|
-
this.events.emit("error", error, {
|
|
1299
|
-
plugin,
|
|
1300
|
-
hookName,
|
|
1301
|
-
strategy,
|
|
1302
|
-
duration: Math.round(performance.now() - startTime)
|
|
1303
|
-
});
|
|
1304
|
-
return null;
|
|
1305
|
-
}
|
|
1306
|
-
})();
|
|
1307
|
-
}
|
|
1308
|
-
/**
|
|
1309
|
-
* Run a sync plugin hook and return the result.
|
|
1310
|
-
* @param hookName Name of the plugin hook. Must be in `PluginHooks`.
|
|
1311
|
-
* @param args Arguments passed to the plugin hook.
|
|
1312
|
-
* @param plugin The actual plugin
|
|
1313
|
-
*/
|
|
1314
|
-
#executeSync({ strategy, hookName, parameters, plugin }) {
|
|
1315
|
-
const hook = plugin[hookName];
|
|
1316
|
-
if (!hook) return null;
|
|
1317
|
-
this.events.emit("plugins:hook:processing:start", {
|
|
1318
|
-
strategy,
|
|
1319
|
-
hookName,
|
|
1320
|
-
parameters,
|
|
1321
|
-
plugin
|
|
1322
|
-
});
|
|
1323
|
-
const startTime = performance.now();
|
|
1324
|
-
try {
|
|
1325
|
-
const output = typeof hook === "function" ? hook.apply(this.getContext(plugin), parameters) : hook;
|
|
1326
|
-
this.#emitProcessingEnd({
|
|
1327
|
-
startTime,
|
|
1328
|
-
output,
|
|
1329
|
-
strategy,
|
|
1330
|
-
hookName,
|
|
1331
|
-
plugin,
|
|
1332
|
-
parameters
|
|
1333
|
-
});
|
|
1334
|
-
return output;
|
|
1335
|
-
} catch (error) {
|
|
1336
|
-
this.events.emit("error", error, {
|
|
1337
|
-
plugin,
|
|
1338
|
-
hookName,
|
|
1339
|
-
strategy,
|
|
1340
|
-
duration: Math.round(performance.now() - startTime)
|
|
1341
|
-
});
|
|
1342
|
-
return null;
|
|
1343
|
-
}
|
|
1344
|
-
}
|
|
1345
|
-
#parse(plugin) {
|
|
1346
|
-
const usedPluginNames = this.#usedPluginNames;
|
|
1347
|
-
setUniqueName(plugin.name, usedPluginNames);
|
|
1348
|
-
const usageCount = usedPluginNames[plugin.name];
|
|
1349
|
-
if (usageCount && usageCount > 1) throw new ValidationPluginError(`Duplicate plugin "${plugin.name}" detected. Each plugin can only be used once. Use a different configuration instead of adding multiple instances of the same plugin.`);
|
|
1350
|
-
return {
|
|
1351
|
-
install() {},
|
|
1352
|
-
...plugin
|
|
1353
|
-
};
|
|
1354
|
-
}
|
|
1355
|
-
};
|
|
1356
|
-
//#endregion
|
|
1357
|
-
//#region src/defineStorage.ts
|
|
1358
|
-
/**
|
|
1359
|
-
* Wraps a storage builder so the `options` argument is optional, following the
|
|
1360
|
-
* same factory pattern as `definePlugin`, `defineLogger`, and `defineAdapter`.
|
|
1361
|
-
*
|
|
1362
|
-
* The builder receives the resolved options object and must return a
|
|
1363
|
-
* `DefineStorage`-compatible object that includes a `name` string.
|
|
1364
|
-
*
|
|
1365
|
-
* @example
|
|
1366
|
-
* ```ts
|
|
1367
|
-
* import { defineStorage } from '@kubb/core'
|
|
1368
|
-
*
|
|
1369
|
-
* export const memoryStorage = defineStorage((_options) => {
|
|
1370
|
-
* const store = new Map<string, string>()
|
|
1371
|
-
* return {
|
|
1372
|
-
* name: 'memory',
|
|
1373
|
-
* async hasItem(key) { return store.has(key) },
|
|
1374
|
-
* async getItem(key) { return store.get(key) ?? null },
|
|
1375
|
-
* async setItem(key, value) { store.set(key, value) },
|
|
1376
|
-
* async removeItem(key) { store.delete(key) },
|
|
1377
|
-
* async getKeys() { return [...store.keys()] },
|
|
1378
|
-
* async clear() { store.clear() },
|
|
1379
|
-
* }
|
|
1380
|
-
* })
|
|
1381
|
-
* ```
|
|
1382
|
-
*/
|
|
1383
|
-
function defineStorage(build) {
|
|
1384
|
-
return (options) => build(options ?? {});
|
|
1385
|
-
}
|
|
1386
|
-
//#endregion
|
|
1387
|
-
//#region src/storages/fsStorage.ts
|
|
1388
641
|
/**
|
|
1389
642
|
* Built-in filesystem storage driver.
|
|
1390
643
|
*
|
|
@@ -1400,7 +653,8 @@ function defineStorage(build) {
|
|
|
1400
653
|
*
|
|
1401
654
|
* @example
|
|
1402
655
|
* ```ts
|
|
1403
|
-
* import {
|
|
656
|
+
* import { fsStorage } from '@kubb/core'
|
|
657
|
+
* import { defineConfig } from 'kubb'
|
|
1404
658
|
*
|
|
1405
659
|
* export default defineConfig({
|
|
1406
660
|
* input: { path: './petStore.yaml' },
|
|
@@ -1408,21 +662,23 @@ function defineStorage(build) {
|
|
|
1408
662
|
* })
|
|
1409
663
|
* ```
|
|
1410
664
|
*/
|
|
1411
|
-
const fsStorage =
|
|
665
|
+
const fsStorage = createStorage(() => ({
|
|
1412
666
|
name: "fs",
|
|
1413
667
|
async hasItem(key) {
|
|
1414
668
|
try {
|
|
1415
669
|
await access(resolve(key));
|
|
1416
670
|
return true;
|
|
1417
|
-
} catch {
|
|
1418
|
-
return false;
|
|
671
|
+
} catch (error) {
|
|
672
|
+
if (isMissingPathError(error)) return false;
|
|
673
|
+
throw new Error(`Failed to access storage item "${key}"`, { cause: error });
|
|
1419
674
|
}
|
|
1420
675
|
},
|
|
1421
676
|
async getItem(key) {
|
|
1422
677
|
try {
|
|
1423
678
|
return await readFile(resolve(key), "utf8");
|
|
1424
|
-
} catch {
|
|
1425
|
-
return null;
|
|
679
|
+
} catch (error) {
|
|
680
|
+
if (isMissingPathError(error)) return null;
|
|
681
|
+
throw new Error(`Failed to read storage item "${key}"`, { cause: error });
|
|
1426
682
|
}
|
|
1427
683
|
},
|
|
1428
684
|
async setItem(key, value) {
|
|
@@ -1433,12 +689,14 @@ const fsStorage = defineStorage(() => ({
|
|
|
1433
689
|
},
|
|
1434
690
|
async getKeys(base) {
|
|
1435
691
|
const keys = [];
|
|
692
|
+
const resolvedBase = resolve(base ?? process.cwd());
|
|
1436
693
|
async function walk(dir, prefix) {
|
|
1437
694
|
let entries;
|
|
1438
695
|
try {
|
|
1439
696
|
entries = await readdir(dir, { withFileTypes: true });
|
|
1440
|
-
} catch {
|
|
1441
|
-
return;
|
|
697
|
+
} catch (error) {
|
|
698
|
+
if (isMissingPathError(error)) return;
|
|
699
|
+
throw new Error(`Failed to list storage keys under "${resolvedBase}"`, { cause: error });
|
|
1442
700
|
}
|
|
1443
701
|
for (const entry of entries) {
|
|
1444
702
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
@@ -1446,7 +704,7 @@ const fsStorage = defineStorage(() => ({
|
|
|
1446
704
|
else keys.push(rel);
|
|
1447
705
|
}
|
|
1448
706
|
}
|
|
1449
|
-
await walk(
|
|
707
|
+
await walk(resolvedBase, "");
|
|
1450
708
|
return keys;
|
|
1451
709
|
},
|
|
1452
710
|
async clear(base) {
|
|
@@ -1456,11 +714,14 @@ const fsStorage = defineStorage(() => ({
|
|
|
1456
714
|
}));
|
|
1457
715
|
//#endregion
|
|
1458
716
|
//#region package.json
|
|
1459
|
-
var version$1 = "5.0.0-alpha.
|
|
717
|
+
var version$1 = "5.0.0-alpha.60";
|
|
1460
718
|
//#endregion
|
|
1461
719
|
//#region src/utils/diagnostics.ts
|
|
1462
720
|
/**
|
|
1463
|
-
*
|
|
721
|
+
* Returns a snapshot of the current runtime environment.
|
|
722
|
+
*
|
|
723
|
+
* Useful for attaching context to debug logs and error reports so that
|
|
724
|
+
* issues can be reproduced without manual information gathering.
|
|
1464
725
|
*/
|
|
1465
726
|
function getDiagnosticInfo() {
|
|
1466
727
|
return {
|
|
@@ -1472,13 +733,18 @@ function getDiagnosticInfo() {
|
|
|
1472
733
|
};
|
|
1473
734
|
}
|
|
1474
735
|
//#endregion
|
|
1475
|
-
//#region src/
|
|
1476
|
-
|
|
1477
|
-
|
|
736
|
+
//#region src/utils/isInputPath.ts
|
|
737
|
+
function isInputPath(config) {
|
|
738
|
+
return typeof config?.input === "object" && config.input !== null && "path" in config.input;
|
|
739
|
+
}
|
|
740
|
+
//#endregion
|
|
741
|
+
//#region src/createKubb.ts
|
|
742
|
+
async function setup(userConfig, options = {}) {
|
|
743
|
+
const hooks = options.hooks ?? new AsyncEventEmitter();
|
|
1478
744
|
const sources = /* @__PURE__ */ new Map();
|
|
1479
745
|
const diagnosticInfo = getDiagnosticInfo();
|
|
1480
|
-
if (Array.isArray(userConfig.input)) await
|
|
1481
|
-
await
|
|
746
|
+
if (Array.isArray(userConfig.input)) await hooks.emit("kubb:warn", { message: "This feature is still under development — use with caution" });
|
|
747
|
+
await hooks.emit("kubb:debug", {
|
|
1482
748
|
date: /* @__PURE__ */ new Date(),
|
|
1483
749
|
logs: [
|
|
1484
750
|
"Configuration:",
|
|
@@ -1497,7 +763,7 @@ async function setup(options) {
|
|
|
1497
763
|
try {
|
|
1498
764
|
if (isInputPath(userConfig) && !new URLPath(userConfig.input.path).isURL) {
|
|
1499
765
|
await exists(userConfig.input.path);
|
|
1500
|
-
await
|
|
766
|
+
await hooks.emit("kubb:debug", {
|
|
1501
767
|
date: /* @__PURE__ */ new Date(),
|
|
1502
768
|
logs: [`✓ Input file validated: ${userConfig.input.path}`]
|
|
1503
769
|
});
|
|
@@ -1508,12 +774,14 @@ async function setup(options) {
|
|
|
1508
774
|
throw new Error(`Cannot read file/URL defined in \`input.path\` or set with \`kubb generate PATH\` in the CLI of your Kubb config ${userConfig.input.path}`, { cause: error });
|
|
1509
775
|
}
|
|
1510
776
|
}
|
|
1511
|
-
|
|
1512
|
-
|
|
777
|
+
if (!userConfig.adapter) throw new Error("Adapter should be defined");
|
|
778
|
+
const config = {
|
|
1513
779
|
...userConfig,
|
|
780
|
+
root: userConfig.root || process.cwd(),
|
|
781
|
+
parsers: userConfig.parsers ?? [],
|
|
782
|
+
adapter: userConfig.adapter,
|
|
1514
783
|
output: {
|
|
1515
784
|
write: true,
|
|
1516
|
-
barrelType: "named",
|
|
1517
785
|
extension: DEFAULT_EXTENSION,
|
|
1518
786
|
defaultBanner: DEFAULT_BANNER,
|
|
1519
787
|
...userConfig.output
|
|
@@ -1524,139 +792,166 @@ async function setup(options) {
|
|
|
1524
792
|
} : void 0,
|
|
1525
793
|
plugins: userConfig.plugins
|
|
1526
794
|
};
|
|
1527
|
-
const storage =
|
|
1528
|
-
if (
|
|
1529
|
-
await
|
|
1530
|
-
date: /* @__PURE__ */ new Date(),
|
|
1531
|
-
logs: ["Cleaning output directories", ` • Output: ${definedConfig.output.path}`]
|
|
1532
|
-
});
|
|
1533
|
-
await storage?.clear(resolve(definedConfig.root, definedConfig.output.path));
|
|
1534
|
-
}
|
|
1535
|
-
const fabric = createFabric();
|
|
1536
|
-
fabric.use(fsPlugin);
|
|
1537
|
-
fabric.use(typescriptParser);
|
|
1538
|
-
fabric.context.on("files:processing:start", (files) => {
|
|
1539
|
-
events.emit("files:processing:start", files);
|
|
1540
|
-
events.emit("debug", {
|
|
1541
|
-
date: /* @__PURE__ */ new Date(),
|
|
1542
|
-
logs: [`Writing ${files.length} files...`]
|
|
1543
|
-
});
|
|
1544
|
-
});
|
|
1545
|
-
fabric.context.on("file:processing:update", async (params) => {
|
|
1546
|
-
const { file, source } = params;
|
|
1547
|
-
await events.emit("file:processing:update", {
|
|
1548
|
-
...params,
|
|
1549
|
-
config: definedConfig,
|
|
1550
|
-
source
|
|
1551
|
-
});
|
|
1552
|
-
if (source) {
|
|
1553
|
-
const key = relative(resolve(definedConfig.root), file.path);
|
|
1554
|
-
await storage?.setItem(key, source);
|
|
1555
|
-
sources.set(file.path, source);
|
|
1556
|
-
}
|
|
1557
|
-
});
|
|
1558
|
-
fabric.context.on("files:processing:end", async (files) => {
|
|
1559
|
-
await events.emit("files:processing:end", files);
|
|
1560
|
-
await events.emit("debug", {
|
|
795
|
+
const storage = config.output.write === false ? null : config.output.storage ?? fsStorage();
|
|
796
|
+
if (config.output.clean) {
|
|
797
|
+
await hooks.emit("kubb:debug", {
|
|
1561
798
|
date: /* @__PURE__ */ new Date(),
|
|
1562
|
-
logs: [
|
|
799
|
+
logs: ["Cleaning output directories", ` • Output: ${config.output.path}`]
|
|
1563
800
|
});
|
|
801
|
+
await storage?.clear(resolve(config.root, config.output.path));
|
|
802
|
+
}
|
|
803
|
+
const driver = new PluginDriver(config, { hooks });
|
|
804
|
+
for (const middleware of config.middleware ?? []) middleware.install(hooks);
|
|
805
|
+
const adapter = config.adapter;
|
|
806
|
+
if (!adapter) throw new Error("No adapter configured. Please provide an adapter in your kubb.config.ts.");
|
|
807
|
+
const source = inputToAdapterSource(config);
|
|
808
|
+
await hooks.emit("kubb:debug", {
|
|
809
|
+
date: /* @__PURE__ */ new Date(),
|
|
810
|
+
logs: [`Running adapter: ${adapter.name}`]
|
|
1564
811
|
});
|
|
1565
|
-
|
|
812
|
+
driver.adapter = adapter;
|
|
813
|
+
driver.inputNode = await adapter.parse(source);
|
|
814
|
+
await hooks.emit("kubb:debug", {
|
|
1566
815
|
date: /* @__PURE__ */ new Date(),
|
|
1567
816
|
logs: [
|
|
1568
|
-
|
|
1569
|
-
` •
|
|
1570
|
-
` •
|
|
817
|
+
`✓ Adapter '${adapter.name}' resolved InputNode`,
|
|
818
|
+
` • Schemas: ${driver.inputNode.schemas.length}`,
|
|
819
|
+
` • Operations: ${driver.inputNode.operations.length}`
|
|
1571
820
|
]
|
|
1572
821
|
});
|
|
1573
|
-
const pluginManager = new PluginManager(definedConfig, {
|
|
1574
|
-
fabric,
|
|
1575
|
-
events,
|
|
1576
|
-
concurrency: 15
|
|
1577
|
-
});
|
|
1578
|
-
if (definedConfig.adapter) {
|
|
1579
|
-
const source = inputToAdapterSource(definedConfig);
|
|
1580
|
-
await events.emit("debug", {
|
|
1581
|
-
date: /* @__PURE__ */ new Date(),
|
|
1582
|
-
logs: [`Running adapter: ${definedConfig.adapter.name}`]
|
|
1583
|
-
});
|
|
1584
|
-
pluginManager.adapter = definedConfig.adapter;
|
|
1585
|
-
pluginManager.rootNode = await definedConfig.adapter.parse(source);
|
|
1586
|
-
await events.emit("debug", {
|
|
1587
|
-
date: /* @__PURE__ */ new Date(),
|
|
1588
|
-
logs: [
|
|
1589
|
-
`✓ Adapter '${definedConfig.adapter.name}' resolved RootNode`,
|
|
1590
|
-
` • Schemas: ${pluginManager.rootNode.schemas.length}`,
|
|
1591
|
-
` • Operations: ${pluginManager.rootNode.operations.length}`
|
|
1592
|
-
]
|
|
1593
|
-
});
|
|
1594
|
-
}
|
|
1595
822
|
return {
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
sources
|
|
823
|
+
config,
|
|
824
|
+
hooks,
|
|
825
|
+
driver,
|
|
826
|
+
sources,
|
|
827
|
+
storage
|
|
1600
828
|
};
|
|
1601
829
|
}
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
}
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
830
|
+
/**
|
|
831
|
+
* Walks the AST and dispatches nodes to a plugin's direct AST hooks
|
|
832
|
+
* (`schema`, `operation`, `operations`).
|
|
833
|
+
*/
|
|
834
|
+
async function runPluginAstHooks(plugin, context) {
|
|
835
|
+
const { adapter, inputNode, resolver, driver } = context;
|
|
836
|
+
const { exclude, include, override } = plugin.options;
|
|
837
|
+
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.`);
|
|
838
|
+
function resolveRenderer(gen) {
|
|
839
|
+
return gen.renderer === null ? void 0 : gen.renderer ?? plugin.renderer ?? context.config.renderer;
|
|
840
|
+
}
|
|
841
|
+
const generators = plugin.generators ?? [];
|
|
842
|
+
const collectedOperations = [];
|
|
843
|
+
const generatorContext = {
|
|
844
|
+
...context,
|
|
845
|
+
resolver: driver.getResolver(plugin.name)
|
|
1617
846
|
};
|
|
847
|
+
await walk(inputNode, {
|
|
848
|
+
depth: "shallow",
|
|
849
|
+
async schema(node) {
|
|
850
|
+
const transformedNode = plugin.transformer ? transform(node, plugin.transformer) : node;
|
|
851
|
+
const options = resolver.resolveOptions(transformedNode, {
|
|
852
|
+
options: plugin.options,
|
|
853
|
+
exclude,
|
|
854
|
+
include,
|
|
855
|
+
override
|
|
856
|
+
});
|
|
857
|
+
if (options === null) return;
|
|
858
|
+
const ctx = {
|
|
859
|
+
...generatorContext,
|
|
860
|
+
options
|
|
861
|
+
};
|
|
862
|
+
for (const gen of generators) {
|
|
863
|
+
if (!gen.schema) continue;
|
|
864
|
+
await applyHookResult(await gen.schema(transformedNode, ctx), driver, resolveRenderer(gen));
|
|
865
|
+
}
|
|
866
|
+
await driver.hooks.emit("kubb:generate:schema", transformedNode, ctx);
|
|
867
|
+
},
|
|
868
|
+
async operation(node) {
|
|
869
|
+
const transformedNode = plugin.transformer ? transform(node, plugin.transformer) : node;
|
|
870
|
+
const options = resolver.resolveOptions(transformedNode, {
|
|
871
|
+
options: plugin.options,
|
|
872
|
+
exclude,
|
|
873
|
+
include,
|
|
874
|
+
override
|
|
875
|
+
});
|
|
876
|
+
if (options !== null) {
|
|
877
|
+
collectedOperations.push(transformedNode);
|
|
878
|
+
const ctx = {
|
|
879
|
+
...generatorContext,
|
|
880
|
+
options
|
|
881
|
+
};
|
|
882
|
+
for (const gen of generators) {
|
|
883
|
+
if (!gen.operation) continue;
|
|
884
|
+
await applyHookResult(await gen.operation(transformedNode, ctx), driver, resolveRenderer(gen));
|
|
885
|
+
}
|
|
886
|
+
await driver.hooks.emit("kubb:generate:operation", transformedNode, ctx);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
});
|
|
890
|
+
if (collectedOperations.length > 0) {
|
|
891
|
+
const ctx = {
|
|
892
|
+
...generatorContext,
|
|
893
|
+
options: plugin.options
|
|
894
|
+
};
|
|
895
|
+
for (const gen of generators) {
|
|
896
|
+
if (!gen.operations) continue;
|
|
897
|
+
await applyHookResult(await gen.operations(collectedOperations, ctx), driver, resolveRenderer(gen));
|
|
898
|
+
}
|
|
899
|
+
await driver.hooks.emit("kubb:generate:operations", collectedOperations, ctx);
|
|
900
|
+
}
|
|
1618
901
|
}
|
|
1619
|
-
async function safeBuild(
|
|
1620
|
-
const {
|
|
902
|
+
async function safeBuild(setupResult) {
|
|
903
|
+
const { driver, hooks, sources, storage } = setupResult;
|
|
1621
904
|
const failedPlugins = /* @__PURE__ */ new Set();
|
|
1622
905
|
const pluginTimings = /* @__PURE__ */ new Map();
|
|
1623
|
-
const config =
|
|
906
|
+
const config = driver.config;
|
|
1624
907
|
try {
|
|
1625
|
-
|
|
1626
|
-
|
|
908
|
+
await driver.emitSetupHooks();
|
|
909
|
+
if (driver.adapter && driver.inputNode) await hooks.emit("kubb:build:start", {
|
|
910
|
+
config,
|
|
911
|
+
adapter: driver.adapter,
|
|
912
|
+
inputNode: driver.inputNode,
|
|
913
|
+
getPlugin: driver.getPlugin.bind(driver),
|
|
914
|
+
get files() {
|
|
915
|
+
return driver.fileManager.files;
|
|
916
|
+
},
|
|
917
|
+
upsertFile: (...files) => driver.fileManager.upsert(...files)
|
|
918
|
+
});
|
|
919
|
+
for (const plugin of driver.plugins.values()) {
|
|
920
|
+
const context = driver.getContext(plugin);
|
|
1627
921
|
const hrStart = process.hrtime();
|
|
1628
|
-
const installer = plugin.install.bind(context);
|
|
1629
922
|
try {
|
|
1630
923
|
const timestamp = /* @__PURE__ */ new Date();
|
|
1631
|
-
await
|
|
1632
|
-
await
|
|
924
|
+
await hooks.emit("kubb:plugin:start", { plugin });
|
|
925
|
+
await hooks.emit("kubb:debug", {
|
|
1633
926
|
date: timestamp,
|
|
1634
|
-
logs: ["
|
|
927
|
+
logs: ["Starting plugin...", ` • Plugin Name: ${plugin.name}`]
|
|
1635
928
|
});
|
|
1636
|
-
await
|
|
929
|
+
if (plugin.generators?.length || driver.hasRegisteredGenerators(plugin.name)) await runPluginAstHooks(plugin, context);
|
|
1637
930
|
const duration = getElapsedMs(hrStart);
|
|
1638
931
|
pluginTimings.set(plugin.name, duration);
|
|
1639
|
-
await
|
|
932
|
+
await hooks.emit("kubb:plugin:end", {
|
|
933
|
+
plugin,
|
|
1640
934
|
duration,
|
|
1641
935
|
success: true
|
|
1642
936
|
});
|
|
1643
|
-
await
|
|
937
|
+
await hooks.emit("kubb:debug", {
|
|
1644
938
|
date: /* @__PURE__ */ new Date(),
|
|
1645
|
-
logs: [`✓ Plugin
|
|
939
|
+
logs: [`✓ Plugin started successfully (${formatMs(duration)})`]
|
|
1646
940
|
});
|
|
1647
941
|
} catch (caughtError) {
|
|
1648
942
|
const error = caughtError;
|
|
1649
943
|
const errorTimestamp = /* @__PURE__ */ new Date();
|
|
1650
944
|
const duration = getElapsedMs(hrStart);
|
|
1651
|
-
await
|
|
945
|
+
await hooks.emit("kubb:plugin:end", {
|
|
946
|
+
plugin,
|
|
1652
947
|
duration,
|
|
1653
948
|
success: false,
|
|
1654
949
|
error
|
|
1655
950
|
});
|
|
1656
|
-
await
|
|
951
|
+
await hooks.emit("kubb:debug", {
|
|
1657
952
|
date: errorTimestamp,
|
|
1658
953
|
logs: [
|
|
1659
|
-
"✗ Plugin
|
|
954
|
+
"✗ Plugin start failed",
|
|
1660
955
|
` • Plugin Name: ${plugin.name}`,
|
|
1661
956
|
` • Error: ${error.constructor.name} - ${error.message}`,
|
|
1662
957
|
" • Stack Trace:",
|
|
@@ -1669,251 +964,292 @@ async function safeBuild(options, overrides) {
|
|
|
1669
964
|
});
|
|
1670
965
|
}
|
|
1671
966
|
}
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
}
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
967
|
+
await hooks.emit("kubb:plugins:end", {
|
|
968
|
+
config,
|
|
969
|
+
get files() {
|
|
970
|
+
return driver.fileManager.files;
|
|
971
|
+
},
|
|
972
|
+
upsertFile: (...files) => driver.fileManager.upsert(...files)
|
|
973
|
+
});
|
|
974
|
+
const files = driver.fileManager.files;
|
|
975
|
+
const parsersMap = /* @__PURE__ */ new Map();
|
|
976
|
+
for (const parser of config.parsers) if (parser.extNames) for (const extname of parser.extNames) parsersMap.set(extname, parser);
|
|
977
|
+
const fileProcessor = new FileProcessor();
|
|
978
|
+
await hooks.emit("kubb:debug", {
|
|
979
|
+
date: /* @__PURE__ */ new Date(),
|
|
980
|
+
logs: [`Writing ${files.length} files...`]
|
|
981
|
+
});
|
|
982
|
+
await fileProcessor.run(files, {
|
|
983
|
+
parsers: parsersMap,
|
|
984
|
+
extension: config.output.extension,
|
|
985
|
+
onStart: async (processingFiles) => {
|
|
986
|
+
await hooks.emit("kubb:files:processing:start", { files: processingFiles });
|
|
987
|
+
},
|
|
988
|
+
onUpdate: async ({ file, source, processed, total, percentage }) => {
|
|
989
|
+
await hooks.emit("kubb:file:processing:update", {
|
|
990
|
+
file,
|
|
991
|
+
source,
|
|
992
|
+
processed,
|
|
993
|
+
total,
|
|
994
|
+
percentage,
|
|
995
|
+
config
|
|
996
|
+
});
|
|
997
|
+
if (source) {
|
|
998
|
+
await storage?.setItem(file.path, source);
|
|
999
|
+
sources.set(file.path, source);
|
|
1000
|
+
}
|
|
1001
|
+
},
|
|
1002
|
+
onEnd: async (processedFiles) => {
|
|
1003
|
+
await hooks.emit("kubb:files:processing:end", { files: processedFiles });
|
|
1004
|
+
await hooks.emit("kubb:debug", {
|
|
1005
|
+
date: /* @__PURE__ */ new Date(),
|
|
1006
|
+
logs: [`✓ File write process completed for ${processedFiles.length} files`]
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
});
|
|
1010
|
+
await hooks.emit("kubb:build:end", {
|
|
1011
|
+
files,
|
|
1012
|
+
config,
|
|
1013
|
+
outputDir: resolve(config.root, config.output.path)
|
|
1014
|
+
});
|
|
1713
1015
|
return {
|
|
1714
1016
|
failedPlugins,
|
|
1715
|
-
fabric,
|
|
1716
1017
|
files,
|
|
1717
|
-
|
|
1018
|
+
driver,
|
|
1718
1019
|
pluginTimings,
|
|
1719
1020
|
sources
|
|
1720
1021
|
};
|
|
1721
1022
|
} catch (error) {
|
|
1722
1023
|
return {
|
|
1723
1024
|
failedPlugins,
|
|
1724
|
-
fabric,
|
|
1725
1025
|
files: [],
|
|
1726
|
-
|
|
1026
|
+
driver,
|
|
1727
1027
|
pluginTimings,
|
|
1728
1028
|
error,
|
|
1729
1029
|
sources
|
|
1730
1030
|
};
|
|
1031
|
+
} finally {
|
|
1032
|
+
driver.dispose();
|
|
1731
1033
|
}
|
|
1732
1034
|
}
|
|
1733
|
-
function
|
|
1734
|
-
const
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
const
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
isTypeOnly: config.output.barrelType === "all" ? containsOnlyTypes : source.isTypeOnly
|
|
1749
|
-
}];
|
|
1750
|
-
});
|
|
1751
|
-
});
|
|
1035
|
+
async function build(setupResult) {
|
|
1036
|
+
const { files, driver, failedPlugins, pluginTimings, error, sources } = await safeBuild(setupResult);
|
|
1037
|
+
if (error) throw error;
|
|
1038
|
+
if (failedPlugins.size > 0) {
|
|
1039
|
+
const errors = [...failedPlugins].map(({ error }) => error);
|
|
1040
|
+
throw new BuildError(`Build Error with ${failedPlugins.size} failed plugins`, { errors });
|
|
1041
|
+
}
|
|
1042
|
+
return {
|
|
1043
|
+
failedPlugins,
|
|
1044
|
+
files,
|
|
1045
|
+
driver,
|
|
1046
|
+
pluginTimings,
|
|
1047
|
+
error: void 0,
|
|
1048
|
+
sources
|
|
1049
|
+
};
|
|
1752
1050
|
}
|
|
1753
|
-
/**
|
|
1754
|
-
* Maps the resolved `Config['input']` shape into an `AdapterSource` that
|
|
1755
|
-
* the adapter's `parse()` can consume.
|
|
1756
|
-
*/
|
|
1757
1051
|
function inputToAdapterSource(config) {
|
|
1758
1052
|
if (Array.isArray(config.input)) return {
|
|
1759
1053
|
type: "paths",
|
|
1760
|
-
paths: config.input.map((i) => resolve(config.root, i.path))
|
|
1054
|
+
paths: config.input.map((i) => new URLPath(i.path).isURL ? i.path : resolve(config.root, i.path))
|
|
1761
1055
|
};
|
|
1762
1056
|
if ("data" in config.input) return {
|
|
1763
1057
|
type: "data",
|
|
1764
1058
|
data: config.input.data
|
|
1765
1059
|
};
|
|
1060
|
+
if (new URLPath(config.input.path).isURL) return {
|
|
1061
|
+
type: "path",
|
|
1062
|
+
path: config.input.path
|
|
1063
|
+
};
|
|
1766
1064
|
return {
|
|
1767
1065
|
type: "path",
|
|
1768
1066
|
path: resolve(config.root, config.input.path)
|
|
1769
1067
|
};
|
|
1770
1068
|
}
|
|
1771
|
-
//#endregion
|
|
1772
|
-
//#region src/defineAdapter.ts
|
|
1773
1069
|
/**
|
|
1774
|
-
*
|
|
1070
|
+
* Creates a Kubb instance bound to a single config entry.
|
|
1071
|
+
*
|
|
1072
|
+
* Accepts a user-facing config shape and resolves it to a full {@link Config} during
|
|
1073
|
+
* `setup()`. The instance then holds shared state (`hooks`, `sources`, `driver`, `config`)
|
|
1074
|
+
* across the `setup → build` lifecycle. Attach event listeners to `kubb.hooks` before
|
|
1075
|
+
* calling `setup()` or `build()`.
|
|
1775
1076
|
*
|
|
1776
1077
|
* @example
|
|
1777
1078
|
* ```ts
|
|
1778
|
-
*
|
|
1779
|
-
*
|
|
1780
|
-
*
|
|
1781
|
-
*
|
|
1782
|
-
* options: { validate, dateType, ... },
|
|
1783
|
-
* parse(source) { ... },
|
|
1784
|
-
* }
|
|
1079
|
+
* const kubb = createKubb(userConfig)
|
|
1080
|
+
*
|
|
1081
|
+
* kubb.hooks.on('kubb:plugin:end', ({ plugin, duration }) => {
|
|
1082
|
+
* console.log(`${plugin.name} completed in ${duration}ms`)
|
|
1785
1083
|
* })
|
|
1084
|
+
*
|
|
1085
|
+
* const { files, failedPlugins } = await kubb.safeBuild()
|
|
1786
1086
|
* ```
|
|
1787
1087
|
*/
|
|
1788
|
-
function
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
if (generator.type === "react") return {
|
|
1795
|
-
version: "2",
|
|
1796
|
-
Operations() {
|
|
1797
|
-
return null;
|
|
1088
|
+
function createKubb(userConfig, options = {}) {
|
|
1089
|
+
const hooks = options.hooks ?? new AsyncEventEmitter();
|
|
1090
|
+
let setupResult;
|
|
1091
|
+
const instance = {
|
|
1092
|
+
get hooks() {
|
|
1093
|
+
return hooks;
|
|
1798
1094
|
},
|
|
1799
|
-
|
|
1800
|
-
return
|
|
1095
|
+
get sources() {
|
|
1096
|
+
return setupResult?.sources ?? /* @__PURE__ */ new Map();
|
|
1801
1097
|
},
|
|
1802
|
-
|
|
1803
|
-
return
|
|
1098
|
+
get driver() {
|
|
1099
|
+
return setupResult?.driver;
|
|
1804
1100
|
},
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
return {
|
|
1808
|
-
version: "2",
|
|
1809
|
-
async operations() {
|
|
1810
|
-
return [];
|
|
1101
|
+
get config() {
|
|
1102
|
+
return setupResult?.config;
|
|
1811
1103
|
},
|
|
1812
|
-
async
|
|
1813
|
-
|
|
1104
|
+
async setup() {
|
|
1105
|
+
setupResult = await setup(userConfig, { hooks });
|
|
1814
1106
|
},
|
|
1815
|
-
async
|
|
1816
|
-
|
|
1107
|
+
async build() {
|
|
1108
|
+
if (!setupResult) await instance.setup();
|
|
1109
|
+
return build(setupResult);
|
|
1817
1110
|
},
|
|
1818
|
-
|
|
1111
|
+
async safeBuild() {
|
|
1112
|
+
if (!setupResult) await instance.setup();
|
|
1113
|
+
return safeBuild(setupResult);
|
|
1114
|
+
}
|
|
1819
1115
|
};
|
|
1116
|
+
return instance;
|
|
1117
|
+
}
|
|
1118
|
+
//#endregion
|
|
1119
|
+
//#region src/createRenderer.ts
|
|
1120
|
+
/**
|
|
1121
|
+
* Creates a renderer factory for use in generator definitions.
|
|
1122
|
+
*
|
|
1123
|
+
* Wrap your renderer factory function with this helper to register it as the
|
|
1124
|
+
* renderer for a generator. Core will call this factory once per render cycle
|
|
1125
|
+
* to obtain a fresh renderer instance.
|
|
1126
|
+
*
|
|
1127
|
+
* @example
|
|
1128
|
+
* ```ts
|
|
1129
|
+
* // packages/renderer-jsx/src/index.ts
|
|
1130
|
+
* export const jsxRenderer = createRenderer(() => {
|
|
1131
|
+
* const runtime = new Runtime()
|
|
1132
|
+
* return {
|
|
1133
|
+
* async render(element) { await runtime.render(element) },
|
|
1134
|
+
* get files() { return runtime.nodes },
|
|
1135
|
+
* unmount(error) { runtime.unmount(error) },
|
|
1136
|
+
* }
|
|
1137
|
+
* })
|
|
1138
|
+
*
|
|
1139
|
+
* // packages/plugin-zod/src/generators/zodGenerator.tsx
|
|
1140
|
+
* import { jsxRenderer } from '@kubb/renderer-jsx'
|
|
1141
|
+
* export const zodGenerator = defineGenerator<PluginZod>({
|
|
1142
|
+
* name: 'zod',
|
|
1143
|
+
* renderer: jsxRenderer,
|
|
1144
|
+
* schema(node, options) { return <File ...>...</File> },
|
|
1145
|
+
* })
|
|
1146
|
+
* ```
|
|
1147
|
+
*/
|
|
1148
|
+
function createRenderer(factory) {
|
|
1149
|
+
return factory;
|
|
1150
|
+
}
|
|
1151
|
+
//#endregion
|
|
1152
|
+
//#region src/defineGenerator.ts
|
|
1153
|
+
/**
|
|
1154
|
+
* Defines a generator. Returns the object as-is with correct `this` typings.
|
|
1155
|
+
* `applyHookResult` handles renderer elements and `File[]` uniformly using
|
|
1156
|
+
* the generator's declared `renderer` factory.
|
|
1157
|
+
*/
|
|
1158
|
+
function defineGenerator(generator) {
|
|
1159
|
+
return generator;
|
|
1820
1160
|
}
|
|
1821
1161
|
//#endregion
|
|
1822
1162
|
//#region src/defineLogger.ts
|
|
1163
|
+
/**
|
|
1164
|
+
* Wraps a logger definition into a typed {@link Logger}.
|
|
1165
|
+
*
|
|
1166
|
+
* @example
|
|
1167
|
+
* export const myLogger = defineLogger({
|
|
1168
|
+
* name: 'my-logger',
|
|
1169
|
+
* install(context, options) {
|
|
1170
|
+
* context.on('kubb:info', (message) => console.log('ℹ', message))
|
|
1171
|
+
* context.on('kubb:error', (error) => console.error('✗', error.message))
|
|
1172
|
+
* },
|
|
1173
|
+
* })
|
|
1174
|
+
*/
|
|
1823
1175
|
function defineLogger(logger) {
|
|
1824
|
-
return
|
|
1176
|
+
return logger;
|
|
1825
1177
|
}
|
|
1826
1178
|
//#endregion
|
|
1827
|
-
//#region src/
|
|
1179
|
+
//#region src/defineMiddleware.ts
|
|
1828
1180
|
/**
|
|
1829
|
-
*
|
|
1181
|
+
* Identity factory for middleware.
|
|
1182
|
+
* Returns the middleware object unchanged but provides a typed entry-point
|
|
1183
|
+
* to define middleware with proper inference.
|
|
1184
|
+
*
|
|
1185
|
+
* @example
|
|
1186
|
+
* ```ts
|
|
1187
|
+
* export const myMiddleware = defineMiddleware({
|
|
1188
|
+
* name: 'my-middleware',
|
|
1189
|
+
* install(hooks) {
|
|
1190
|
+
* hooks.on('kubb:build:end', ({ files }) => {
|
|
1191
|
+
* console.log(`Build complete with ${files.length} files`)
|
|
1192
|
+
* })
|
|
1193
|
+
* },
|
|
1194
|
+
* })
|
|
1195
|
+
* ```
|
|
1830
1196
|
*/
|
|
1831
|
-
function
|
|
1832
|
-
return
|
|
1197
|
+
function defineMiddleware(middleware) {
|
|
1198
|
+
return middleware;
|
|
1833
1199
|
}
|
|
1834
1200
|
//#endregion
|
|
1835
|
-
//#region src/
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
}
|
|
1888
|
-
async getVersion(dependency) {
|
|
1889
|
-
if (typeof dependency === "string" && PackageManager.#cache[dependency]) return PackageManager.#cache[dependency];
|
|
1890
|
-
const packageJSON = await this.getPackageJSON();
|
|
1891
|
-
if (!packageJSON) return;
|
|
1892
|
-
return this.#match(packageJSON, dependency);
|
|
1893
|
-
}
|
|
1894
|
-
getVersionSync(dependency) {
|
|
1895
|
-
if (typeof dependency === "string" && PackageManager.#cache[dependency]) return PackageManager.#cache[dependency];
|
|
1896
|
-
const packageJSON = this.getPackageJSONSync();
|
|
1897
|
-
if (!packageJSON) return;
|
|
1898
|
-
return this.#match(packageJSON, dependency);
|
|
1899
|
-
}
|
|
1900
|
-
async isValid(dependency, version) {
|
|
1901
|
-
const packageVersion = await this.getVersion(dependency);
|
|
1902
|
-
if (!packageVersion) return false;
|
|
1903
|
-
if (packageVersion === version) return true;
|
|
1904
|
-
const semVer = coerce(packageVersion);
|
|
1905
|
-
if (!semVer) return false;
|
|
1906
|
-
return satisfies(semVer, version);
|
|
1907
|
-
}
|
|
1908
|
-
isValidSync(dependency, version) {
|
|
1909
|
-
const packageVersion = this.getVersionSync(dependency);
|
|
1910
|
-
if (!packageVersion) return false;
|
|
1911
|
-
if (packageVersion === version) return true;
|
|
1912
|
-
const semVer = coerce(packageVersion);
|
|
1913
|
-
if (!semVer) return false;
|
|
1914
|
-
return satisfies(semVer, version);
|
|
1915
|
-
}
|
|
1916
|
-
};
|
|
1201
|
+
//#region src/defineParser.ts
|
|
1202
|
+
/**
|
|
1203
|
+
* Defines a parser with type safety.
|
|
1204
|
+
*
|
|
1205
|
+
* Use this function to create parsers that transform generated files to strings
|
|
1206
|
+
* based on their extension.
|
|
1207
|
+
*
|
|
1208
|
+
* @example
|
|
1209
|
+
* ```ts
|
|
1210
|
+
* import { defineParser } from '@kubb/core'
|
|
1211
|
+
*
|
|
1212
|
+
* export const jsonParser = defineParser({
|
|
1213
|
+
* name: 'json',
|
|
1214
|
+
* extNames: ['.json'],
|
|
1215
|
+
* parse(file) {
|
|
1216
|
+
* const { extractStringsFromNodes } = await import('@kubb/ast')
|
|
1217
|
+
* return file.sources.map((s) => extractStringsFromNodes(s.nodes ?? [])).join('\n')
|
|
1218
|
+
* },
|
|
1219
|
+
* })
|
|
1220
|
+
* ```
|
|
1221
|
+
*/
|
|
1222
|
+
function defineParser(parser) {
|
|
1223
|
+
return parser;
|
|
1224
|
+
}
|
|
1225
|
+
//#endregion
|
|
1226
|
+
//#region src/definePlugin.ts
|
|
1227
|
+
/**
|
|
1228
|
+
* Creates a plugin factory using the hook-style (`hooks:`) API.
|
|
1229
|
+
*
|
|
1230
|
+
* The returned factory is called with optional options and produces a `Plugin`
|
|
1231
|
+
* that coexists with plugins created via the legacy `createPlugin` API in the same
|
|
1232
|
+
* `kubb.config.ts`.
|
|
1233
|
+
*
|
|
1234
|
+
* Lifecycle handlers are registered on the `PluginDriver`'s `AsyncEventEmitter`, enabling
|
|
1235
|
+
* both the plugin's own handlers and external tooling (CLI, devtools) to observe every event.
|
|
1236
|
+
*
|
|
1237
|
+
* @example
|
|
1238
|
+
* ```ts
|
|
1239
|
+
* // With PluginFactoryOptions (recommended for real plugins)
|
|
1240
|
+
* export const pluginTs = definePlugin<PluginTs>((options) => ({
|
|
1241
|
+
* name: 'plugin-ts',
|
|
1242
|
+
* hooks: {
|
|
1243
|
+
* 'kubb:plugin:setup'(ctx) {
|
|
1244
|
+
* ctx.setResolver(resolverTs) // typed as Partial<ResolverTs>
|
|
1245
|
+
* },
|
|
1246
|
+
* },
|
|
1247
|
+
* }))
|
|
1248
|
+
* ```
|
|
1249
|
+
*/
|
|
1250
|
+
function definePlugin(factory) {
|
|
1251
|
+
return (options) => factory(options ?? {});
|
|
1252
|
+
}
|
|
1917
1253
|
//#endregion
|
|
1918
1254
|
//#region src/storages/memoryStorage.ts
|
|
1919
1255
|
/**
|
|
@@ -1925,7 +1261,8 @@ var PackageManager = class PackageManager {
|
|
|
1925
1261
|
*
|
|
1926
1262
|
* @example
|
|
1927
1263
|
* ```ts
|
|
1928
|
-
* import {
|
|
1264
|
+
* import { memoryStorage } from '@kubb/core'
|
|
1265
|
+
* import { defineConfig } from 'kubb'
|
|
1929
1266
|
*
|
|
1930
1267
|
* export default defineConfig({
|
|
1931
1268
|
* input: { path: './petStore.yaml' },
|
|
@@ -1933,7 +1270,7 @@ var PackageManager = class PackageManager {
|
|
|
1933
1270
|
* })
|
|
1934
1271
|
* ```
|
|
1935
1272
|
*/
|
|
1936
|
-
const memoryStorage =
|
|
1273
|
+
const memoryStorage = createStorage(() => {
|
|
1937
1274
|
const store = /* @__PURE__ */ new Map();
|
|
1938
1275
|
return {
|
|
1939
1276
|
name: "memory",
|
|
@@ -1963,430 +1300,6 @@ const memoryStorage = defineStorage(() => {
|
|
|
1963
1300
|
};
|
|
1964
1301
|
});
|
|
1965
1302
|
//#endregion
|
|
1966
|
-
|
|
1967
|
-
/**
|
|
1968
|
-
* @deprecated
|
|
1969
|
-
*/
|
|
1970
|
-
var FunctionParams = class FunctionParams {
|
|
1971
|
-
#items = [];
|
|
1972
|
-
get items() {
|
|
1973
|
-
return this.#items.flat();
|
|
1974
|
-
}
|
|
1975
|
-
add(item) {
|
|
1976
|
-
if (!item) return this;
|
|
1977
|
-
if (Array.isArray(item)) {
|
|
1978
|
-
item.filter((x) => x !== void 0).forEach((it) => {
|
|
1979
|
-
this.#items.push(it);
|
|
1980
|
-
});
|
|
1981
|
-
return this;
|
|
1982
|
-
}
|
|
1983
|
-
this.#items.push(item);
|
|
1984
|
-
return this;
|
|
1985
|
-
}
|
|
1986
|
-
static #orderItems(items) {
|
|
1987
|
-
return sortBy(items.filter(Boolean), [(item) => Array.isArray(item), "desc"], [(item) => !Array.isArray(item) && item.default !== void 0, "asc"], [(item) => Array.isArray(item) || (item.required ?? true), "desc"]);
|
|
1988
|
-
}
|
|
1989
|
-
static #addParams(acc, item) {
|
|
1990
|
-
const { enabled = true, name, type, required = true, ...rest } = item;
|
|
1991
|
-
if (!enabled) return acc;
|
|
1992
|
-
if (!name) {
|
|
1993
|
-
acc.push(`${type}${rest.default ? ` = ${rest.default}` : ""}`);
|
|
1994
|
-
return acc;
|
|
1995
|
-
}
|
|
1996
|
-
const parameterName = name.startsWith("{") ? name : camelCase(name);
|
|
1997
|
-
if (type) if (required) acc.push(`${parameterName}: ${type}${rest.default ? ` = ${rest.default}` : ""}`);
|
|
1998
|
-
else acc.push(`${parameterName}?: ${type}`);
|
|
1999
|
-
else acc.push(`${parameterName}`);
|
|
2000
|
-
return acc;
|
|
2001
|
-
}
|
|
2002
|
-
static toObject(items) {
|
|
2003
|
-
let type = [];
|
|
2004
|
-
let name = [];
|
|
2005
|
-
const enabled = items.every((item) => item.enabled) ? items.at(0)?.enabled : true;
|
|
2006
|
-
const required = items.every((item) => item.required) ?? true;
|
|
2007
|
-
items.forEach((item) => {
|
|
2008
|
-
name = FunctionParams.#addParams(name, {
|
|
2009
|
-
...item,
|
|
2010
|
-
type: void 0
|
|
2011
|
-
});
|
|
2012
|
-
if (items.some((item) => item.type)) type = FunctionParams.#addParams(type, item);
|
|
2013
|
-
});
|
|
2014
|
-
return {
|
|
2015
|
-
name: `{ ${name.join(", ")} }`,
|
|
2016
|
-
type: type.length ? `{ ${type.join("; ")} }` : void 0,
|
|
2017
|
-
enabled,
|
|
2018
|
-
required
|
|
2019
|
-
};
|
|
2020
|
-
}
|
|
2021
|
-
toObject() {
|
|
2022
|
-
const items = FunctionParams.#orderItems(this.#items).flat();
|
|
2023
|
-
return FunctionParams.toObject(items);
|
|
2024
|
-
}
|
|
2025
|
-
static toString(items) {
|
|
2026
|
-
return FunctionParams.#orderItems(items).reduce((acc, item) => {
|
|
2027
|
-
if (Array.isArray(item)) {
|
|
2028
|
-
if (item.length <= 0) return acc;
|
|
2029
|
-
const subItems = FunctionParams.#orderItems(item);
|
|
2030
|
-
const objectItem = FunctionParams.toObject(subItems);
|
|
2031
|
-
return FunctionParams.#addParams(acc, objectItem);
|
|
2032
|
-
}
|
|
2033
|
-
return FunctionParams.#addParams(acc, item);
|
|
2034
|
-
}, []).join(", ");
|
|
2035
|
-
}
|
|
2036
|
-
toString() {
|
|
2037
|
-
const items = FunctionParams.#orderItems(this.#items);
|
|
2038
|
-
return FunctionParams.toString(items);
|
|
2039
|
-
}
|
|
2040
|
-
};
|
|
2041
|
-
//#endregion
|
|
2042
|
-
//#region src/utils/formatters.ts
|
|
2043
|
-
/**
|
|
2044
|
-
* Check if a formatter command is available in the system.
|
|
2045
|
-
*
|
|
2046
|
-
* @param formatter - The formatter to check ('biome', 'prettier', or 'oxfmt')
|
|
2047
|
-
* @returns Promise that resolves to true if the formatter is available, false otherwise
|
|
2048
|
-
*
|
|
2049
|
-
* @remarks
|
|
2050
|
-
* This function checks availability by running `<formatter> --version` command.
|
|
2051
|
-
* All supported formatters (biome, prettier, oxfmt) implement the --version flag.
|
|
2052
|
-
*/
|
|
2053
|
-
async function isFormatterAvailable(formatter) {
|
|
2054
|
-
try {
|
|
2055
|
-
await x(formatter, ["--version"], { nodeOptions: { stdio: "ignore" } });
|
|
2056
|
-
return true;
|
|
2057
|
-
} catch {
|
|
2058
|
-
return false;
|
|
2059
|
-
}
|
|
2060
|
-
}
|
|
2061
|
-
/**
|
|
2062
|
-
* Detect which formatter is available in the system.
|
|
2063
|
-
*
|
|
2064
|
-
* @returns Promise that resolves to the first available formatter or undefined if none are found
|
|
2065
|
-
*
|
|
2066
|
-
* @remarks
|
|
2067
|
-
* Checks in order of preference: biome, oxfmt, prettier.
|
|
2068
|
-
* Uses the `--version` flag to detect if each formatter command is available.
|
|
2069
|
-
* This is a reliable method as all supported formatters implement this flag.
|
|
2070
|
-
*
|
|
2071
|
-
* @example
|
|
2072
|
-
* ```typescript
|
|
2073
|
-
* const formatter = await detectFormatter()
|
|
2074
|
-
* if (formatter) {
|
|
2075
|
-
* console.log(`Using ${formatter} for formatting`)
|
|
2076
|
-
* } else {
|
|
2077
|
-
* console.log('No formatter found')
|
|
2078
|
-
* }
|
|
2079
|
-
* ```
|
|
2080
|
-
*/
|
|
2081
|
-
async function detectFormatter() {
|
|
2082
|
-
for (const formatter of [
|
|
2083
|
-
"biome",
|
|
2084
|
-
"oxfmt",
|
|
2085
|
-
"prettier"
|
|
2086
|
-
]) if (await isFormatterAvailable(formatter)) return formatter;
|
|
2087
|
-
}
|
|
2088
|
-
//#endregion
|
|
2089
|
-
//#region src/utils/TreeNode.ts
|
|
2090
|
-
var TreeNode = class TreeNode {
|
|
2091
|
-
data;
|
|
2092
|
-
parent;
|
|
2093
|
-
children = [];
|
|
2094
|
-
#cachedLeaves = void 0;
|
|
2095
|
-
constructor(data, parent) {
|
|
2096
|
-
this.data = data;
|
|
2097
|
-
this.parent = parent;
|
|
2098
|
-
}
|
|
2099
|
-
addChild(data) {
|
|
2100
|
-
const child = new TreeNode(data, this);
|
|
2101
|
-
if (!this.children) this.children = [];
|
|
2102
|
-
this.children.push(child);
|
|
2103
|
-
return child;
|
|
2104
|
-
}
|
|
2105
|
-
get root() {
|
|
2106
|
-
if (!this.parent) return this;
|
|
2107
|
-
return this.parent.root;
|
|
2108
|
-
}
|
|
2109
|
-
get leaves() {
|
|
2110
|
-
if (!this.children || this.children.length === 0) return [this];
|
|
2111
|
-
if (this.#cachedLeaves) return this.#cachedLeaves;
|
|
2112
|
-
const leaves = [];
|
|
2113
|
-
for (const child of this.children) leaves.push(...child.leaves);
|
|
2114
|
-
this.#cachedLeaves = leaves;
|
|
2115
|
-
return leaves;
|
|
2116
|
-
}
|
|
2117
|
-
forEach(callback) {
|
|
2118
|
-
if (typeof callback !== "function") throw new TypeError("forEach() callback must be a function");
|
|
2119
|
-
callback(this);
|
|
2120
|
-
for (const child of this.children) child.forEach(callback);
|
|
2121
|
-
return this;
|
|
2122
|
-
}
|
|
2123
|
-
findDeep(predicate) {
|
|
2124
|
-
if (typeof predicate !== "function") throw new TypeError("find() predicate must be a function");
|
|
2125
|
-
return this.leaves.find(predicate);
|
|
2126
|
-
}
|
|
2127
|
-
forEachDeep(callback) {
|
|
2128
|
-
if (typeof callback !== "function") throw new TypeError("forEach() callback must be a function");
|
|
2129
|
-
this.leaves.forEach(callback);
|
|
2130
|
-
}
|
|
2131
|
-
filterDeep(callback) {
|
|
2132
|
-
if (typeof callback !== "function") throw new TypeError("filter() callback must be a function");
|
|
2133
|
-
return this.leaves.filter(callback);
|
|
2134
|
-
}
|
|
2135
|
-
mapDeep(callback) {
|
|
2136
|
-
if (typeof callback !== "function") throw new TypeError("map() callback must be a function");
|
|
2137
|
-
return this.leaves.map(callback);
|
|
2138
|
-
}
|
|
2139
|
-
static build(files, root) {
|
|
2140
|
-
try {
|
|
2141
|
-
const filteredTree = buildDirectoryTree(files, root);
|
|
2142
|
-
if (!filteredTree) return null;
|
|
2143
|
-
const treeNode = new TreeNode({
|
|
2144
|
-
name: filteredTree.name,
|
|
2145
|
-
path: filteredTree.path,
|
|
2146
|
-
file: filteredTree.file,
|
|
2147
|
-
type: getMode(filteredTree.path)
|
|
2148
|
-
});
|
|
2149
|
-
const recurse = (node, item) => {
|
|
2150
|
-
const subNode = node.addChild({
|
|
2151
|
-
name: item.name,
|
|
2152
|
-
path: item.path,
|
|
2153
|
-
file: item.file,
|
|
2154
|
-
type: getMode(item.path)
|
|
2155
|
-
});
|
|
2156
|
-
if (item.children?.length) item.children?.forEach((child) => {
|
|
2157
|
-
recurse(subNode, child);
|
|
2158
|
-
});
|
|
2159
|
-
};
|
|
2160
|
-
filteredTree.children?.forEach((child) => {
|
|
2161
|
-
recurse(treeNode, child);
|
|
2162
|
-
});
|
|
2163
|
-
return treeNode;
|
|
2164
|
-
} catch (error) {
|
|
2165
|
-
throw new Error("Something went wrong with creating barrel files with the TreeNode class", { cause: error });
|
|
2166
|
-
}
|
|
2167
|
-
}
|
|
2168
|
-
};
|
|
2169
|
-
const normalizePath = (p) => p.replaceAll("\\", "/");
|
|
2170
|
-
function buildDirectoryTree(files, rootFolder = "") {
|
|
2171
|
-
const normalizedRootFolder = normalizePath(rootFolder);
|
|
2172
|
-
const rootPrefix = normalizedRootFolder.endsWith("/") ? normalizedRootFolder : `${normalizedRootFolder}/`;
|
|
2173
|
-
const filteredFiles = files.filter((file) => {
|
|
2174
|
-
const normalizedFilePath = normalizePath(file.path);
|
|
2175
|
-
return rootFolder ? normalizedFilePath.startsWith(rootPrefix) && !normalizedFilePath.endsWith(".json") : !normalizedFilePath.endsWith(".json");
|
|
2176
|
-
});
|
|
2177
|
-
if (filteredFiles.length === 0) return null;
|
|
2178
|
-
const root = {
|
|
2179
|
-
name: rootFolder || "",
|
|
2180
|
-
path: rootFolder || "",
|
|
2181
|
-
children: []
|
|
2182
|
-
};
|
|
2183
|
-
filteredFiles.forEach((file) => {
|
|
2184
|
-
const parts = file.path.slice(rootFolder.length).split("/").filter(Boolean);
|
|
2185
|
-
let currentLevel = root.children;
|
|
2186
|
-
let currentPath = normalizePath(rootFolder);
|
|
2187
|
-
parts.forEach((part, index) => {
|
|
2188
|
-
currentPath = path.posix.join(currentPath, part);
|
|
2189
|
-
let existingNode = currentLevel.find((node) => node.name === part);
|
|
2190
|
-
if (!existingNode) {
|
|
2191
|
-
if (index === parts.length - 1) existingNode = {
|
|
2192
|
-
name: part,
|
|
2193
|
-
file,
|
|
2194
|
-
path: currentPath
|
|
2195
|
-
};
|
|
2196
|
-
else existingNode = {
|
|
2197
|
-
name: part,
|
|
2198
|
-
path: currentPath,
|
|
2199
|
-
children: []
|
|
2200
|
-
};
|
|
2201
|
-
currentLevel.push(existingNode);
|
|
2202
|
-
}
|
|
2203
|
-
if (!existingNode.file) currentLevel = existingNode.children;
|
|
2204
|
-
});
|
|
2205
|
-
});
|
|
2206
|
-
return root;
|
|
2207
|
-
}
|
|
2208
|
-
//#endregion
|
|
2209
|
-
//#region src/BarrelManager.ts
|
|
2210
|
-
/** biome-ignore-all lint/suspicious/useIterableCallbackReturn: not needed */
|
|
2211
|
-
var BarrelManager = class {
|
|
2212
|
-
getFiles({ files: generatedFiles, root }) {
|
|
2213
|
-
const cachedFiles = /* @__PURE__ */ new Map();
|
|
2214
|
-
TreeNode.build(generatedFiles, root)?.forEach((treeNode) => {
|
|
2215
|
-
if (!treeNode || !treeNode.children || !treeNode.parent?.data.path) return;
|
|
2216
|
-
const barrelFile = {
|
|
2217
|
-
path: join(treeNode.parent?.data.path, "index.ts"),
|
|
2218
|
-
baseName: "index.ts",
|
|
2219
|
-
exports: [],
|
|
2220
|
-
imports: [],
|
|
2221
|
-
sources: []
|
|
2222
|
-
};
|
|
2223
|
-
const previousBarrelFile = cachedFiles.get(barrelFile.path);
|
|
2224
|
-
treeNode.leaves.forEach((item) => {
|
|
2225
|
-
if (!item.data.name) return;
|
|
2226
|
-
(item.data.file?.sources || []).forEach((source) => {
|
|
2227
|
-
if (!item.data.file?.path || !source.isIndexable || !source.name) return;
|
|
2228
|
-
if (previousBarrelFile?.sources.some((item) => item.name === source.name && item.isTypeOnly === source.isTypeOnly)) return;
|
|
2229
|
-
barrelFile.exports.push({
|
|
2230
|
-
name: [source.name],
|
|
2231
|
-
path: getRelativePath(treeNode.parent?.data.path, item.data.path),
|
|
2232
|
-
isTypeOnly: source.isTypeOnly
|
|
2233
|
-
});
|
|
2234
|
-
barrelFile.sources.push({
|
|
2235
|
-
name: source.name,
|
|
2236
|
-
isTypeOnly: source.isTypeOnly,
|
|
2237
|
-
value: "",
|
|
2238
|
-
isExportable: false,
|
|
2239
|
-
isIndexable: false
|
|
2240
|
-
});
|
|
2241
|
-
});
|
|
2242
|
-
});
|
|
2243
|
-
if (previousBarrelFile) {
|
|
2244
|
-
previousBarrelFile.sources.push(...barrelFile.sources);
|
|
2245
|
-
previousBarrelFile.exports?.push(...barrelFile.exports || []);
|
|
2246
|
-
} else cachedFiles.set(barrelFile.path, barrelFile);
|
|
2247
|
-
});
|
|
2248
|
-
return [...cachedFiles.values()];
|
|
2249
|
-
}
|
|
2250
|
-
};
|
|
2251
|
-
//#endregion
|
|
2252
|
-
//#region src/utils/getBarrelFiles.ts
|
|
2253
|
-
function trimExtName(text) {
|
|
2254
|
-
const dotIndex = text.lastIndexOf(".");
|
|
2255
|
-
if (dotIndex > 0 && !text.includes("/", dotIndex)) return text.slice(0, dotIndex);
|
|
2256
|
-
return text;
|
|
2257
|
-
}
|
|
2258
|
-
async function getBarrelFiles(files, { type, meta = {}, root, output }) {
|
|
2259
|
-
if (!type || type === "propagate") return [];
|
|
2260
|
-
const barrelManager = new BarrelManager();
|
|
2261
|
-
const pathToBuildFrom = join(root, output.path);
|
|
2262
|
-
if (trimExtName(pathToBuildFrom).endsWith("index")) return [];
|
|
2263
|
-
const barrelFiles = barrelManager.getFiles({
|
|
2264
|
-
files,
|
|
2265
|
-
root: pathToBuildFrom,
|
|
2266
|
-
meta
|
|
2267
|
-
});
|
|
2268
|
-
if (type === "all") return barrelFiles.map((file) => {
|
|
2269
|
-
return {
|
|
2270
|
-
...file,
|
|
2271
|
-
exports: file.exports?.map((exportItem) => {
|
|
2272
|
-
return {
|
|
2273
|
-
...exportItem,
|
|
2274
|
-
name: void 0
|
|
2275
|
-
};
|
|
2276
|
-
})
|
|
2277
|
-
};
|
|
2278
|
-
});
|
|
2279
|
-
return barrelFiles.map((indexFile) => {
|
|
2280
|
-
return {
|
|
2281
|
-
...indexFile,
|
|
2282
|
-
meta
|
|
2283
|
-
};
|
|
2284
|
-
});
|
|
2285
|
-
}
|
|
2286
|
-
//#endregion
|
|
2287
|
-
//#region src/utils/getPlugins.ts
|
|
2288
|
-
function isJSONPlugins(plugins) {
|
|
2289
|
-
return Array.isArray(plugins) && plugins.some((plugin) => Array.isArray(plugin) && typeof plugin[0] === "string");
|
|
2290
|
-
}
|
|
2291
|
-
function isObjectPlugins(plugins) {
|
|
2292
|
-
return plugins instanceof Object && !Array.isArray(plugins);
|
|
2293
|
-
}
|
|
2294
|
-
function getPlugins(plugins) {
|
|
2295
|
-
if (isObjectPlugins(plugins)) throw new Error("Object plugins are not supported anymore, best to use http://kubb.dev/getting-started/configure#json");
|
|
2296
|
-
if (isJSONPlugins(plugins)) throw new Error("JSON plugins are not supported anymore, best to use http://kubb.dev/getting-started/configure#json");
|
|
2297
|
-
return Promise.resolve(plugins);
|
|
2298
|
-
}
|
|
2299
|
-
//#endregion
|
|
2300
|
-
//#region src/utils/getConfigs.ts
|
|
2301
|
-
/**
|
|
2302
|
-
* Converting UserConfig to Config Array without a change in the object beside the JSON convert.
|
|
2303
|
-
*/
|
|
2304
|
-
async function getConfigs(config, args) {
|
|
2305
|
-
let userConfigs = await (typeof config === "function" ? Promise.resolve(config(args)) : Promise.resolve(config));
|
|
2306
|
-
if (!Array.isArray(userConfigs)) userConfigs = [userConfigs];
|
|
2307
|
-
const results = [];
|
|
2308
|
-
for (const item of userConfigs) {
|
|
2309
|
-
const plugins = item.plugins ? await getPlugins(item.plugins) : void 0;
|
|
2310
|
-
results.push({
|
|
2311
|
-
...item,
|
|
2312
|
-
plugins
|
|
2313
|
-
});
|
|
2314
|
-
}
|
|
2315
|
-
return results;
|
|
2316
|
-
}
|
|
2317
|
-
//#endregion
|
|
2318
|
-
//#region src/utils/linters.ts
|
|
2319
|
-
async function isLinterAvailable(linter) {
|
|
2320
|
-
try {
|
|
2321
|
-
await x(linter, ["--version"], { nodeOptions: { stdio: "ignore" } });
|
|
2322
|
-
return true;
|
|
2323
|
-
} catch {
|
|
2324
|
-
return false;
|
|
2325
|
-
}
|
|
2326
|
-
}
|
|
2327
|
-
async function detectLinter() {
|
|
2328
|
-
for (const linter of [
|
|
2329
|
-
"biome",
|
|
2330
|
-
"oxlint",
|
|
2331
|
-
"eslint"
|
|
2332
|
-
]) if (await isLinterAvailable(linter)) return linter;
|
|
2333
|
-
}
|
|
2334
|
-
//#endregion
|
|
2335
|
-
//#region src/utils/resolveOptions.ts
|
|
2336
|
-
function matchesOperationPattern(node, type, pattern) {
|
|
2337
|
-
switch (type) {
|
|
2338
|
-
case "tag": return node.tags.some((tag) => !!tag.match(pattern));
|
|
2339
|
-
case "operationId": return !!node.operationId.match(pattern);
|
|
2340
|
-
case "path": return !!node.path.match(pattern);
|
|
2341
|
-
case "method": return !!node.method.toLowerCase().match(pattern);
|
|
2342
|
-
default: return false;
|
|
2343
|
-
}
|
|
2344
|
-
}
|
|
2345
|
-
function matchesSchemaPattern(node, type, pattern) {
|
|
2346
|
-
switch (type) {
|
|
2347
|
-
case "schemaName": return node.name ? !!node.name.match(pattern) : false;
|
|
2348
|
-
default: return null;
|
|
2349
|
-
}
|
|
2350
|
-
}
|
|
2351
|
-
/**
|
|
2352
|
-
* Resolves the effective plugin options for a given AST node by applying
|
|
2353
|
-
* `exclude`, `include`, and `override` rules from the plugin configuration.
|
|
2354
|
-
*
|
|
2355
|
-
* Returns `null` when the node is excluded or not matched by `include`.
|
|
2356
|
-
* Returns the merged options (base options merged with any matching `override`) otherwise.
|
|
2357
|
-
*
|
|
2358
|
-
* Supported filter types for `OperationNode`: `tag`, `operationId`, `path`, `method`.
|
|
2359
|
-
* Supported filter types for `SchemaNode`: `schemaName`.
|
|
2360
|
-
*
|
|
2361
|
-
* @example
|
|
2362
|
-
* const resolved = resolveOptions(operationNode, { options, exclude, include, override })
|
|
2363
|
-
* if (!resolved) return // excluded
|
|
2364
|
-
*/
|
|
2365
|
-
function resolveOptions(node, { options, exclude = [], include, override = [] }) {
|
|
2366
|
-
if (isOperationNode(node)) {
|
|
2367
|
-
if (exclude.some(({ type, pattern }) => matchesOperationPattern(node, type, pattern))) return null;
|
|
2368
|
-
if (include && !include.some(({ type, pattern }) => matchesOperationPattern(node, type, pattern))) return null;
|
|
2369
|
-
const overrideOptions = override.find(({ type, pattern }) => matchesOperationPattern(node, type, pattern))?.options;
|
|
2370
|
-
return {
|
|
2371
|
-
...options,
|
|
2372
|
-
...overrideOptions
|
|
2373
|
-
};
|
|
2374
|
-
}
|
|
2375
|
-
if (isSchemaNode(node)) {
|
|
2376
|
-
if (exclude.some(({ type, pattern }) => matchesSchemaPattern(node, type, pattern) === true)) return null;
|
|
2377
|
-
if (include) {
|
|
2378
|
-
const applicable = include.map(({ type, pattern }) => matchesSchemaPattern(node, type, pattern)).filter((r) => r !== null);
|
|
2379
|
-
if (applicable.length > 0 && !applicable.includes(true)) return null;
|
|
2380
|
-
}
|
|
2381
|
-
const overrideOptions = override.find(({ type, pattern }) => matchesSchemaPattern(node, type, pattern) === true)?.options;
|
|
2382
|
-
return {
|
|
2383
|
-
...options,
|
|
2384
|
-
...overrideOptions
|
|
2385
|
-
};
|
|
2386
|
-
}
|
|
2387
|
-
return options;
|
|
2388
|
-
}
|
|
2389
|
-
//#endregion
|
|
2390
|
-
export { AsyncEventEmitter, FunctionParams, PackageManager, PluginManager, PromiseManager, URLPath, build, build as default, defineAdapter, defineConfig, defineGenerator, defineLogger, definePlugin, definePrinter, defineStorage, detectFormatter, detectLinter, formatters, fsStorage, getBarrelFiles, getConfigs, getMode, isInputPath, linters, logLevel, memoryStorage, resolveOptions, safeBuild, setup };
|
|
1303
|
+
export { AsyncEventEmitter, FileManager, FileProcessor, PluginDriver, URLPath, ast, createAdapter, createKubb, createRenderer, createStorage, defineGenerator, defineLogger, defineMiddleware, defineParser, definePlugin, defineResolver, fsStorage, isInputPath, logLevel, memoryStorage };
|
|
2391
1304
|
|
|
2392
1305
|
//# sourceMappingURL=index.js.map
|