@kubb/cli 5.0.0-beta.84 → 5.0.0-beta.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{Telemetry-ugO-B77y.js → Telemetry-Cuzoes9Y.js} +6 -2
- package/dist/Telemetry-Cuzoes9Y.js.map +1 -0
- package/dist/{Telemetry-jtbchpQE.cjs → Telemetry-CwQYBgsg.cjs} +11 -1
- package/dist/Telemetry-CwQYBgsg.cjs.map +1 -0
- package/dist/{generate-DDgZnlMs.js → generate-C1bIl1nH.js} +34 -24
- package/dist/generate-C1bIl1nH.js.map +1 -0
- package/dist/{generate-Diob_zqj.cjs → generate-Cgmty90l.cjs} +34 -23
- package/dist/generate-Cgmty90l.cjs.map +1 -0
- package/dist/index.cjs +28 -192
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +29 -193
- package/dist/index.js.map +1 -1
- package/dist/{init-uOQx7jSE.cjs → init-DqgB69HY.cjs} +9 -10
- package/dist/init-DqgB69HY.cjs.map +1 -0
- package/dist/{init-Cn3jZVkf.js → init-EnhDxlBB.js} +10 -10
- package/dist/init-EnhDxlBB.js.map +1 -0
- package/dist/{mcp-n-IOoFZL.js → mcp-5DDTiwIA.js} +6 -6
- package/dist/mcp-5DDTiwIA.js.map +1 -0
- package/dist/{mcp-BxhOXHGD.cjs → mcp-DYmjmXQb.cjs} +5 -6
- package/dist/mcp-DYmjmXQb.cjs.map +1 -0
- package/dist/{package-BBBOfxZz.cjs → package-B57sF1X0.cjs} +2 -2
- package/dist/package-B57sF1X0.cjs.map +1 -0
- package/dist/package-CQbxcw7I.js +6 -0
- package/dist/package-CQbxcw7I.js.map +1 -0
- package/dist/{run-DXEMoDFa.cjs → run-3qq_Q4Tg.cjs} +4 -4
- package/dist/run-3qq_Q4Tg.cjs.map +1 -0
- package/dist/{run-Bz6ZUrhp.cjs → run-B9FN0sHW.cjs} +2 -2
- package/dist/run-B9FN0sHW.cjs.map +1 -0
- package/dist/{run-CPBFfbI7.js → run-BFhNcn8b.js} +4 -10
- package/dist/run-BFhNcn8b.js.map +1 -0
- package/dist/{run-D8TRnpBB.js → run-CCsw-Y-v.js} +226 -268
- package/dist/run-CCsw-Y-v.js.map +1 -0
- package/dist/{run-BBLhhWZu.js → run-D0Gs_UzJ.js} +2 -2
- package/dist/run-D0Gs_UzJ.js.map +1 -0
- package/dist/{run-ChSqYuc1.cjs → run-DT9pRBLX.cjs} +228 -269
- package/dist/run-DT9pRBLX.cjs.map +1 -0
- package/dist/{run-DYkciQ4u.cjs → run-DYzUPE7Z.cjs} +4 -10
- package/dist/run-DYzUPE7Z.cjs.map +1 -0
- package/dist/{run-44Zxh8Ec.js → run-yMRylOST.js} +3 -3
- package/dist/run-yMRylOST.js.map +1 -0
- package/dist/{tools-D0UogMU3.js → tools-B23ltmWP.js} +3 -3
- package/dist/tools-B23ltmWP.js.map +1 -0
- package/dist/{tools-CZT9wSA6.cjs → tools-CeIABV0T.cjs} +3 -3
- package/dist/tools-CeIABV0T.cjs.map +1 -0
- package/dist/{validate-CYIieoc4.cjs → validate-BTVjxR4L.cjs} +8 -9
- package/dist/validate-BTVjxR4L.cjs.map +1 -0
- package/dist/{validate-BoG8ZZgE.js → validate-CZFmahWd.js} +9 -9
- package/dist/validate-CZFmahWd.js.map +1 -0
- package/package.json +8 -7
- package/dist/Telemetry-jtbchpQE.cjs.map +0 -1
- package/dist/Telemetry-ugO-B77y.js.map +0 -1
- package/dist/defineCommand-Bo3yZTWI.cjs +0 -36
- package/dist/defineCommand-Bo3yZTWI.cjs.map +0 -1
- package/dist/defineCommand-DMEeqliP.js +0 -31
- package/dist/defineCommand-DMEeqliP.js.map +0 -1
- package/dist/generate-DDgZnlMs.js.map +0 -1
- package/dist/generate-Diob_zqj.cjs.map +0 -1
- package/dist/init-Cn3jZVkf.js.map +0 -1
- package/dist/init-uOQx7jSE.cjs.map +0 -1
- package/dist/mcp-BxhOXHGD.cjs.map +0 -1
- package/dist/mcp-n-IOoFZL.js.map +0 -1
- package/dist/package-BBBOfxZz.cjs.map +0 -1
- package/dist/package-DKwwXnAz.js +0 -6
- package/dist/package-DKwwXnAz.js.map +0 -1
- package/dist/run-44Zxh8Ec.js.map +0 -1
- package/dist/run-BBLhhWZu.js.map +0 -1
- package/dist/run-Bz6ZUrhp.cjs.map +0 -1
- package/dist/run-CPBFfbI7.js.map +0 -1
- package/dist/run-ChSqYuc1.cjs.map +0 -1
- package/dist/run-D8TRnpBB.js.map +0 -1
- package/dist/run-DXEMoDFa.cjs.map +0 -1
- package/dist/run-DYkciQ4u.cjs.map +0 -1
- package/dist/tools-CZT9wSA6.cjs.map +0 -1
- package/dist/tools-D0UogMU3.js.map +0 -1
- package/dist/validate-BoG8ZZgE.js.map +0 -1
- package/dist/validate-CYIieoc4.cjs.map +0 -1
|
@@ -1,126 +1,17 @@
|
|
|
1
1
|
import "./rolldown-runtime-C0LytTxp.js";
|
|
2
|
+
import { a as WATCHER_IGNORED_PATHS, i as UPDATE_CHECK_TIMEOUT_MS, n as KUBB_NPM_PACKAGE_URL, o as canUseTTY, t as Telemetry } from "./Telemetry-Cuzoes9Y.js";
|
|
2
3
|
import { n as toCause, r as toError } from "./errors-Dc_d7BfX.js";
|
|
3
|
-
import {
|
|
4
|
-
import { i as linters, n as detectTool, r as formatters } from "./tools-
|
|
5
|
-
import { t as version } from "./package-DKwwXnAz.js";
|
|
4
|
+
import { t as version } from "./package-CQbxcw7I.js";
|
|
5
|
+
import { i as linters, n as detectTool, r as formatters } from "./tools-B23ltmWP.js";
|
|
6
6
|
import { styleText } from "node:util";
|
|
7
|
-
import
|
|
8
|
-
import { hash } from "node:crypto";
|
|
7
|
+
import process$1 from "node:process";
|
|
9
8
|
import { existsSync } from "node:fs";
|
|
10
9
|
import path, { basename, dirname, relative, resolve } from "node:path";
|
|
11
|
-
import process$1 from "node:process";
|
|
12
10
|
import * as clack from "@clack/prompts";
|
|
13
|
-
import { Diagnostics, cliReporter, createKubb, logLevel } from "@kubb/core";
|
|
11
|
+
import { AsyncEventEmitter, Diagnostics, cliReporter, createKubb, logLevel } from "@kubb/core";
|
|
14
12
|
import { createJiti } from "jiti";
|
|
15
13
|
import { NonZeroExitError, x } from "tinyexec";
|
|
16
14
|
import { loadConfig } from "unconfig";
|
|
17
|
-
//#region ../../internals/utils/src/asyncEventEmitter.ts
|
|
18
|
-
/**
|
|
19
|
-
* Typed `EventEmitter` that awaits all async listeners before resolving.
|
|
20
|
-
* Wraps Node's `EventEmitter` with full TypeScript event-map inference.
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* ```ts
|
|
24
|
-
* const emitter = new AsyncEventEmitter<{ build: [name: string] }>()
|
|
25
|
-
* emitter.on('build', async (name) => { console.log(name) })
|
|
26
|
-
* await emitter.emit('build', 'petstore') // all listeners awaited
|
|
27
|
-
* ```
|
|
28
|
-
*/
|
|
29
|
-
var AsyncEventEmitter = class {
|
|
30
|
-
/**
|
|
31
|
-
* Maximum number of listeners per event before Node emits a memory-leak warning.
|
|
32
|
-
* @default 10
|
|
33
|
-
*/
|
|
34
|
-
constructor(maxListener = 10) {
|
|
35
|
-
this.#emitter.setMaxListeners(maxListener);
|
|
36
|
-
}
|
|
37
|
-
#emitter = new EventEmitter();
|
|
38
|
-
/**
|
|
39
|
-
* Emits `eventName` and awaits all registered listeners sequentially.
|
|
40
|
-
* Throws if any listener rejects, wrapping the cause with the event name and serialized arguments.
|
|
41
|
-
*
|
|
42
|
-
* @example
|
|
43
|
-
* ```ts
|
|
44
|
-
* await emitter.emit('build', 'petstore')
|
|
45
|
-
* ```
|
|
46
|
-
*/
|
|
47
|
-
emit(eventName, ...eventArgs) {
|
|
48
|
-
const listeners = this.#emitter.listeners(eventName);
|
|
49
|
-
if (listeners.length === 0) return;
|
|
50
|
-
return this.#emitAll(eventName, listeners, eventArgs);
|
|
51
|
-
}
|
|
52
|
-
async #emitAll(eventName, listeners, eventArgs) {
|
|
53
|
-
for (const listener of listeners) try {
|
|
54
|
-
await listener(...eventArgs);
|
|
55
|
-
} catch (err) {
|
|
56
|
-
let serializedArgs;
|
|
57
|
-
try {
|
|
58
|
-
serializedArgs = JSON.stringify(eventArgs);
|
|
59
|
-
} catch {
|
|
60
|
-
serializedArgs = String(eventArgs);
|
|
61
|
-
}
|
|
62
|
-
throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: toError(err) });
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Registers a persistent listener for `eventName`.
|
|
67
|
-
*
|
|
68
|
-
* @example
|
|
69
|
-
* ```ts
|
|
70
|
-
* emitter.on('build', async (name) => { console.log(name) })
|
|
71
|
-
* ```
|
|
72
|
-
*/
|
|
73
|
-
on(eventName, handler) {
|
|
74
|
-
this.#emitter.on(eventName, handler);
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Removes a previously registered listener.
|
|
78
|
-
*
|
|
79
|
-
* @example
|
|
80
|
-
* ```ts
|
|
81
|
-
* emitter.off('build', handler)
|
|
82
|
-
* ```
|
|
83
|
-
*/
|
|
84
|
-
off(eventName, handler) {
|
|
85
|
-
this.#emitter.off(eventName, handler);
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Returns the number of listeners registered for `eventName`.
|
|
89
|
-
*
|
|
90
|
-
* @example
|
|
91
|
-
* ```ts
|
|
92
|
-
* emitter.on('build', handler)
|
|
93
|
-
* emitter.listenerCount('build') // 1
|
|
94
|
-
* ```
|
|
95
|
-
*/
|
|
96
|
-
listenerCount(eventName) {
|
|
97
|
-
return this.#emitter.listenerCount(eventName);
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Raises or lowers the per-event listener ceiling before Node warns about a memory leak.
|
|
101
|
-
* Set this above the expected listener count when many listeners attach by design.
|
|
102
|
-
*
|
|
103
|
-
* @example
|
|
104
|
-
* ```ts
|
|
105
|
-
* emitter.setMaxListeners(40)
|
|
106
|
-
* ```
|
|
107
|
-
*/
|
|
108
|
-
setMaxListeners(max) {
|
|
109
|
-
this.#emitter.setMaxListeners(max);
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Removes all listeners from every event channel.
|
|
113
|
-
*
|
|
114
|
-
* @example
|
|
115
|
-
* ```ts
|
|
116
|
-
* emitter.removeAll()
|
|
117
|
-
* ```
|
|
118
|
-
*/
|
|
119
|
-
removeAll() {
|
|
120
|
-
this.#emitter.removeAllListeners();
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
//#endregion
|
|
124
15
|
//#region ../../internals/utils/src/time.ts
|
|
125
16
|
/**
|
|
126
17
|
* Calculates elapsed time in milliseconds from a high-resolution `process.hrtime` start time.
|
|
@@ -265,6 +156,43 @@ function formatMsWithColor(ms) {
|
|
|
265
156
|
return styleText("red", formatted);
|
|
266
157
|
}
|
|
267
158
|
//#endregion
|
|
159
|
+
//#region ../../internals/utils/src/promise.ts
|
|
160
|
+
/**
|
|
161
|
+
* Wraps `run` so invocations never overlap: a trigger that lands while a run is in flight
|
|
162
|
+
* marks it dirty and runs once more after it finishes, no matter how many triggers arrived.
|
|
163
|
+
* Useful for event-driven reruns (a file watcher, a queue drain) where bursts should
|
|
164
|
+
* coalesce into a single trailing run.
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```ts
|
|
168
|
+
* const rebuild = createSerialRunner({
|
|
169
|
+
* run: () => build(),
|
|
170
|
+
* onError: (error) => log.error(error.message),
|
|
171
|
+
* })
|
|
172
|
+
* watcher.on('change', () => void rebuild())
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
function createSerialRunner({ run, onError }) {
|
|
176
|
+
let running = false;
|
|
177
|
+
let dirty = false;
|
|
178
|
+
return async () => {
|
|
179
|
+
if (running) {
|
|
180
|
+
dirty = true;
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
running = true;
|
|
184
|
+
do {
|
|
185
|
+
dirty = false;
|
|
186
|
+
try {
|
|
187
|
+
await run();
|
|
188
|
+
} catch (error) {
|
|
189
|
+
onError(toError(error));
|
|
190
|
+
}
|
|
191
|
+
} while (dirty);
|
|
192
|
+
running = false;
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
//#endregion
|
|
268
196
|
//#region src/loggers/defineLogger.ts
|
|
269
197
|
/**
|
|
270
198
|
* Type-safe helper for authoring a {@link Logger}.
|
|
@@ -373,20 +301,18 @@ const clackLogger = defineLogger({
|
|
|
373
301
|
clack.log.warn(text);
|
|
374
302
|
});
|
|
375
303
|
context.on("kubb:error", ({ error }) => {
|
|
376
|
-
const caused = toCause(error);
|
|
377
304
|
const text = [styleText("red", "✗"), error.message].join(" ");
|
|
378
305
|
if (state.isSpinning) {
|
|
379
306
|
stopSpinner(getMessage(text));
|
|
380
307
|
return;
|
|
381
308
|
}
|
|
382
309
|
clack.log.error(getMessage(text));
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
for (const frame of frames) clack.log.message(getMessage(styleText("dim", frame
|
|
386
|
-
if (
|
|
387
|
-
clack.log.message(styleText("dim",
|
|
388
|
-
const
|
|
389
|
-
for (const frame of frames) clack.log.message(getMessage(` ${styleText("dim", frame.trim())}`));
|
|
310
|
+
const frames = logLevel$5 >= logLevel.verbose ? formatErrorFrames(error) : null;
|
|
311
|
+
if (frames) {
|
|
312
|
+
for (const frame of frames.frames) clack.log.message(getMessage(styleText("dim", frame)));
|
|
313
|
+
if (frames.cause) {
|
|
314
|
+
clack.log.message(styleText("dim", frames.cause.header));
|
|
315
|
+
for (const frame of frames.cause.frames) clack.log.message(getMessage(` ${styleText("dim", frame)}`));
|
|
390
316
|
}
|
|
391
317
|
}
|
|
392
318
|
});
|
|
@@ -586,16 +512,14 @@ const plainLogger = defineLogger({
|
|
|
586
512
|
console.log(text);
|
|
587
513
|
});
|
|
588
514
|
context.on("kubb:error", ({ error }) => {
|
|
589
|
-
const caused = toCause(error);
|
|
590
515
|
const text = getMessage(["✗", error.message].join(" "));
|
|
591
516
|
console.log(text);
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
for (const frame of frames) console.log(getMessage(frame
|
|
595
|
-
if (
|
|
596
|
-
console.log(
|
|
597
|
-
const
|
|
598
|
-
for (const frame of frames) console.log(getMessage(` ${frame.trim()}`));
|
|
517
|
+
const frames = logLevel$4 >= logLevel.verbose ? formatErrorFrames(error) : null;
|
|
518
|
+
if (frames) {
|
|
519
|
+
for (const frame of frames.frames) console.log(getMessage(frame));
|
|
520
|
+
if (frames.cause) {
|
|
521
|
+
console.log(frames.cause.header);
|
|
522
|
+
for (const frame of frames.cause.frames) console.log(getMessage(` ${frame}`));
|
|
599
523
|
}
|
|
600
524
|
}
|
|
601
525
|
});
|
|
@@ -682,6 +606,22 @@ function formatMessage(message, logLevel$3) {
|
|
|
682
606
|
return message;
|
|
683
607
|
}
|
|
684
608
|
/**
|
|
609
|
+
* First stack frames for verbose error output, including an optional `cause` chain.
|
|
610
|
+
*/
|
|
611
|
+
function formatErrorFrames(error) {
|
|
612
|
+
if (!error.stack) return null;
|
|
613
|
+
const frames = error.stack.split("\n").slice(1, 4).map((frame) => frame.trim());
|
|
614
|
+
const caused = toCause(error);
|
|
615
|
+
if (!caused?.stack) return { frames };
|
|
616
|
+
return {
|
|
617
|
+
frames,
|
|
618
|
+
cause: {
|
|
619
|
+
header: `└─ caused by ${caused.message}`,
|
|
620
|
+
frames: caused.stack.split("\n").slice(1, 4).map((frame) => frame.trim())
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
685
625
|
* Build the progress summary line shown by the clack logger.
|
|
686
626
|
* Returns null when there is nothing to display.
|
|
687
627
|
*/
|
|
@@ -742,9 +682,6 @@ function createHookTimer() {
|
|
|
742
682
|
if (!hrStart) return;
|
|
743
683
|
starts.delete(id);
|
|
744
684
|
return getElapsedMs(hrStart);
|
|
745
|
-
},
|
|
746
|
-
clear() {
|
|
747
|
-
starts.clear();
|
|
748
685
|
}
|
|
749
686
|
};
|
|
750
687
|
}
|
|
@@ -757,14 +694,6 @@ function createHookTimer() {
|
|
|
757
694
|
function formatCommandWithArgs(command, args) {
|
|
758
695
|
return args?.length ? `${command} ${args.join(" ")}` : command;
|
|
759
696
|
}
|
|
760
|
-
function detectLogger() {
|
|
761
|
-
if (canUseTTY()) return "clack";
|
|
762
|
-
return "plain";
|
|
763
|
-
}
|
|
764
|
-
const logMapper = {
|
|
765
|
-
clack: clackLogger,
|
|
766
|
-
plain: plainLogger
|
|
767
|
-
};
|
|
768
697
|
/**
|
|
769
698
|
* Bridges a {@link Reporter} onto the run's event emitter: calls `report` with each config's
|
|
770
699
|
* {@link GenerationResult} on `kubb:generation:end`. The reporter never touches the emitter.
|
|
@@ -798,10 +727,7 @@ async function setupReporters(context, { logLevel, reporters }) {
|
|
|
798
727
|
for (const reporter of reporters) {
|
|
799
728
|
if (reporter.name === "cli") {
|
|
800
729
|
if (hasJson) continue;
|
|
801
|
-
|
|
802
|
-
const logger = logMapper[type];
|
|
803
|
-
if (!logger) throw new Error(`Unknown adapter type: ${type}`);
|
|
804
|
-
await logger.install(context, { logLevel });
|
|
730
|
+
await (canUseTTY() ? clackLogger : plainLogger).install(context, { logLevel });
|
|
805
731
|
}
|
|
806
732
|
installReporter(context, reporter, ctx);
|
|
807
733
|
}
|
|
@@ -912,6 +838,34 @@ async function getConfigs({ configPath, input, watch, logLevel }) {
|
|
|
912
838
|
}))
|
|
913
839
|
};
|
|
914
840
|
}
|
|
841
|
+
let hookSequence = 0;
|
|
842
|
+
/**
|
|
843
|
+
* Returns a process-unique id that correlates a hook's `kubb:hook:start` and `kubb:hook:end`
|
|
844
|
+
* events, which loggers use to key their per-hook state.
|
|
845
|
+
*/
|
|
846
|
+
function createHookId() {
|
|
847
|
+
hookSequence += 1;
|
|
848
|
+
return `hook-${hookSequence}`;
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* Returns `true` when `latest` is a newer semver version than `current`. Compares each numeric
|
|
852
|
+
* part, so `5.10.0` beats `5.9.0` where a plain string comparison would not. Prerelease
|
|
853
|
+
* suffixes are ignored, and a malformed version never reports an update.
|
|
854
|
+
*
|
|
855
|
+
* @example Double-digit minor
|
|
856
|
+
* `isNewerVersion('5.9.0', '5.10.0') // true`
|
|
857
|
+
*
|
|
858
|
+
* @example String comparison would get this wrong the other way
|
|
859
|
+
* `isNewerVersion('5.10.0', '5.9.0') // false`
|
|
860
|
+
*/
|
|
861
|
+
function isNewerVersion(current, latest) {
|
|
862
|
+
const release = (value) => value.split("-")[0] ?? "";
|
|
863
|
+
const isNumeric = (value) => /^\d+(\.\d+)*$/.test(value);
|
|
864
|
+
const currentRelease = release(current);
|
|
865
|
+
const latestRelease = release(latest);
|
|
866
|
+
if (!isNumeric(currentRelease) || !isNumeric(latestRelease)) return false;
|
|
867
|
+
return currentRelease.localeCompare(latestRelease, void 0, { numeric: true }) < 0;
|
|
868
|
+
}
|
|
915
869
|
/**
|
|
916
870
|
* Tokenizes a shell command string, respecting single and double quotes.
|
|
917
871
|
*
|
|
@@ -925,44 +879,48 @@ function tokenize(command) {
|
|
|
925
879
|
return (command.match(/[^\s"']+|"([^"]*)"|'([^']*)'/g) ?? []).map((token) => token.replace(/^["']|["']$/g, ""));
|
|
926
880
|
}
|
|
927
881
|
/**
|
|
928
|
-
* Runs the `done` hooks defined in a Kubb config in sequence
|
|
882
|
+
* Runs the `done` hooks defined in a Kubb config in sequence and returns each hook's outcome,
|
|
883
|
+
* so the caller can turn failures into diagnostics.
|
|
929
884
|
*/
|
|
930
885
|
async function executeHooks({ configHooks, hooks }) {
|
|
931
886
|
const commands = Array.isArray(configHooks.done) ? configHooks.done : [configHooks.done].filter(Boolean);
|
|
887
|
+
const results = [];
|
|
932
888
|
for (const command of commands) {
|
|
933
889
|
const [cmd, ...args] = tokenize(command);
|
|
934
890
|
if (!cmd) continue;
|
|
935
|
-
const hookId =
|
|
891
|
+
const hookId = createHookId();
|
|
936
892
|
const commandWithArgs = [cmd, ...args].join(" ");
|
|
937
893
|
await hooks.emit("kubb:hook:start", {
|
|
938
894
|
id: hookId,
|
|
939
895
|
command: cmd,
|
|
940
896
|
args
|
|
941
897
|
});
|
|
942
|
-
await runHook({
|
|
898
|
+
results.push(await runHook({
|
|
943
899
|
id: hookId,
|
|
944
900
|
command: cmd,
|
|
945
901
|
args,
|
|
946
902
|
commandWithArgs,
|
|
947
903
|
hooks
|
|
948
|
-
});
|
|
904
|
+
}));
|
|
949
905
|
}
|
|
906
|
+
return results;
|
|
950
907
|
}
|
|
951
908
|
/**
|
|
952
|
-
* Spawns a hook command and
|
|
953
|
-
* A non-zero exit
|
|
909
|
+
* Spawns a hook command and returns its outcome, mirroring it through `kubb:hook:end` for the
|
|
910
|
+
* loggers. A non-zero exit returns `success: false` rather than throwing, so the caller can turn
|
|
954
911
|
* it into a diagnostic. Other spawn errors do the same. Output is streamed through `kubb:hook:line`
|
|
955
912
|
* only while a listener is attached.
|
|
956
913
|
*/
|
|
957
914
|
async function runHook({ id, command, args, commandWithArgs, hooks }) {
|
|
958
|
-
const emitEnd = (
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
915
|
+
const emitEnd = async (result) => {
|
|
916
|
+
await hooks.emit("kubb:hook:end", {
|
|
917
|
+
command,
|
|
918
|
+
args,
|
|
919
|
+
id,
|
|
920
|
+
...result
|
|
921
|
+
});
|
|
922
|
+
return result;
|
|
923
|
+
};
|
|
966
924
|
const stream = hooks.listenerCount("kubb:hook:line") > 0;
|
|
967
925
|
try {
|
|
968
926
|
const proc = x(command, [...args ?? []], {
|
|
@@ -975,15 +933,20 @@ async function runHook({ id, command, args, commandWithArgs, hooks }) {
|
|
|
975
933
|
});
|
|
976
934
|
await proc;
|
|
977
935
|
await hooks.emit("kubb:success", { message: `${styleText("dim", commandWithArgs)} successfully executed` });
|
|
978
|
-
|
|
936
|
+
return emitEnd({
|
|
937
|
+
success: true,
|
|
938
|
+
error: null
|
|
939
|
+
});
|
|
979
940
|
} catch (err) {
|
|
980
|
-
if (!(err instanceof NonZeroExitError)) {
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
}
|
|
941
|
+
if (!(err instanceof NonZeroExitError)) return emitEnd({
|
|
942
|
+
success: false,
|
|
943
|
+
error: toError(err)
|
|
944
|
+
});
|
|
984
945
|
const stderr = err.output?.stderr ?? "";
|
|
985
946
|
const stdout = err.output?.stdout ?? "";
|
|
986
|
-
|
|
947
|
+
return emitEnd({
|
|
948
|
+
success: false,
|
|
949
|
+
error: /* @__PURE__ */ new Error(`Hook execute failed: ${commandWithArgs}`),
|
|
987
950
|
stdout,
|
|
988
951
|
stderr
|
|
989
952
|
});
|
|
@@ -991,7 +954,9 @@ async function runHook({ id, command, args, commandWithArgs, hooks }) {
|
|
|
991
954
|
}
|
|
992
955
|
/**
|
|
993
956
|
* Starts a file watcher on the given paths and calls `cb` on any change.
|
|
994
|
-
* Ignores `.git` and `node_modules` directories.
|
|
957
|
+
* Ignores `.git` and `node_modules` directories. Event bursts (an editor save emits several)
|
|
958
|
+
* are debounced into one build, and builds never overlap: changes during a build queue exactly
|
|
959
|
+
* one rebuild.
|
|
995
960
|
*/
|
|
996
961
|
async function startWatcher(path, cb, log = {
|
|
997
962
|
info: console.log,
|
|
@@ -1000,7 +965,8 @@ async function startWatcher(path, cb, log = {
|
|
|
1000
965
|
const { watch } = await import("chokidar");
|
|
1001
966
|
const watcher = watch(path, {
|
|
1002
967
|
ignorePermissionErrors: true,
|
|
1003
|
-
ignored: WATCHER_IGNORED_PATHS
|
|
968
|
+
ignored: WATCHER_IGNORED_PATHS,
|
|
969
|
+
ignoreInitial: true
|
|
1004
970
|
});
|
|
1005
971
|
process$1.once("SIGINT", () => {
|
|
1006
972
|
watcher.close();
|
|
@@ -1008,36 +974,28 @@ async function startWatcher(path, cb, log = {
|
|
|
1008
974
|
process$1.once("SIGTERM", () => {
|
|
1009
975
|
watcher.close();
|
|
1010
976
|
});
|
|
1011
|
-
|
|
977
|
+
const runBuild = createSerialRunner({
|
|
978
|
+
run: () => cb(path),
|
|
979
|
+
onError: () => log.error(styleText("red", "Watcher failed"))
|
|
980
|
+
});
|
|
981
|
+
let debounceTimer = null;
|
|
982
|
+
watcher.on("all", (type, file) => {
|
|
1012
983
|
log.info(styleText("yellow", styleText("bold", `Change detected: ${type} ${file}`)));
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
}
|
|
984
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
985
|
+
debounceTimer = setTimeout(() => {
|
|
986
|
+
debounceTimer = null;
|
|
987
|
+
runBuild();
|
|
988
|
+
}, 100);
|
|
1018
989
|
});
|
|
1019
990
|
}
|
|
1020
991
|
//#endregion
|
|
1021
992
|
//#region src/runners/generate/run.ts
|
|
1022
993
|
/**
|
|
1023
|
-
*
|
|
1024
|
-
* so
|
|
994
|
+
* Runs one formatter or linter pass over the output directory. Returns the failure instead of
|
|
995
|
+
* throwing, so the caller can turn it into a coded diagnostic. Failures never render here:
|
|
996
|
+
* the caller emits them through `Diagnostics.emit`, like every other diagnostic.
|
|
1025
997
|
*/
|
|
1026
|
-
function
|
|
1027
|
-
return new Promise((resolve, reject) => {
|
|
1028
|
-
const handler = (ctx) => {
|
|
1029
|
-
if (ctx.id !== hookId) return;
|
|
1030
|
-
hooks.off("kubb:hook:end", handler);
|
|
1031
|
-
if (!ctx.success) {
|
|
1032
|
-
reject(ctx.error ?? new Error(fallbackErrorMessage));
|
|
1033
|
-
return;
|
|
1034
|
-
}
|
|
1035
|
-
Promise.resolve(onSuccess()).then(resolve).catch(reject);
|
|
1036
|
-
};
|
|
1037
|
-
hooks.on("kubb:hook:end", handler);
|
|
1038
|
-
});
|
|
1039
|
-
}
|
|
1040
|
-
async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefix, noToolMessage, configName, outputPath, logLevel: logLevel$1, hooks, onStart, onEnd }) {
|
|
998
|
+
async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefix, noToolMessage, outputPath, logLevel: logLevel$1, hooks, onStart, onEnd }) {
|
|
1041
999
|
await onStart();
|
|
1042
1000
|
let resolvedTool = toolValue;
|
|
1043
1001
|
if (resolvedTool === "auto") {
|
|
@@ -1048,38 +1006,38 @@ async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefi
|
|
|
1048
1006
|
await hooks.emit("kubb:info", { message: `Auto-detected ${toolLabel}: ${styleText("dim", resolvedTool)}` });
|
|
1049
1007
|
}
|
|
1050
1008
|
}
|
|
1051
|
-
let toolError;
|
|
1009
|
+
let toolError = null;
|
|
1052
1010
|
if (resolvedTool && resolvedTool !== "auto" && resolvedTool in toolMap && existsSync(outputPath)) {
|
|
1053
1011
|
const toolConfig = toolMap[resolvedTool];
|
|
1054
|
-
const hookId = hash("sha256", [configName, resolvedTool].filter(Boolean).join("-"), "hex");
|
|
1055
1012
|
const successMessage = [
|
|
1056
1013
|
`${successPrefix} with ${styleText("dim", resolvedTool)}`,
|
|
1057
1014
|
logLevel$1 >= logLevel.info ? `on ${styleText("dim", outputPath)}` : void 0,
|
|
1058
1015
|
"successfully"
|
|
1059
1016
|
].filter(Boolean).join(" ");
|
|
1060
1017
|
try {
|
|
1018
|
+
const hookId = createHookId();
|
|
1061
1019
|
const hookArgs = toolConfig.args(outputPath);
|
|
1062
1020
|
const commandWithArgs = [toolConfig.command, ...hookArgs].join(" ");
|
|
1063
|
-
const hookEndPromise = waitForHookEnd(hooks, hookId, () => hooks.emit("kubb:success", { message: successMessage }), toolConfig.errorMessage);
|
|
1064
1021
|
await hooks.emit("kubb:hook:start", {
|
|
1065
1022
|
id: hookId,
|
|
1066
1023
|
command: toolConfig.command,
|
|
1067
1024
|
args: hookArgs
|
|
1068
1025
|
});
|
|
1069
|
-
runHook({
|
|
1026
|
+
const result = await runHook({
|
|
1070
1027
|
id: hookId,
|
|
1071
1028
|
command: toolConfig.command,
|
|
1072
1029
|
args: hookArgs,
|
|
1073
1030
|
commandWithArgs,
|
|
1074
1031
|
hooks
|
|
1075
|
-
})
|
|
1076
|
-
await
|
|
1032
|
+
});
|
|
1033
|
+
if (result.success) await hooks.emit("kubb:success", { message: successMessage });
|
|
1034
|
+
else toolError = result.error ?? new Error(toolConfig.errorMessage);
|
|
1077
1035
|
} catch (caughtError) {
|
|
1078
1036
|
toolError = toError(caughtError);
|
|
1079
1037
|
}
|
|
1080
1038
|
}
|
|
1081
1039
|
await onEnd();
|
|
1082
|
-
|
|
1040
|
+
return toolError;
|
|
1083
1041
|
}
|
|
1084
1042
|
async function generate(options) {
|
|
1085
1043
|
const { input, hooks, logLevel } = options;
|
|
@@ -1090,8 +1048,7 @@ async function generate(options) {
|
|
|
1090
1048
|
input: inputPath ? {
|
|
1091
1049
|
...options.config.input,
|
|
1092
1050
|
path: inputPath
|
|
1093
|
-
} : options.config.input
|
|
1094
|
-
...options.config.output
|
|
1051
|
+
} : options.config.input
|
|
1095
1052
|
};
|
|
1096
1053
|
const kubb = createKubb(config, { hooks });
|
|
1097
1054
|
await hooks.emit("kubb:generation:start", { config });
|
|
@@ -1138,67 +1095,60 @@ async function generate(options) {
|
|
|
1138
1095
|
}
|
|
1139
1096
|
const outputPath = path.resolve(config.root, config.output.path);
|
|
1140
1097
|
const outputDiagnostics = [];
|
|
1141
|
-
const
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
"
|
|
1160
|
-
"biome",
|
|
1161
|
-
"eslint"
|
|
1162
|
-
]),
|
|
1163
|
-
toolMap: linters,
|
|
1164
|
-
toolLabel: "linter",
|
|
1165
|
-
successPrefix: "Linting",
|
|
1166
|
-
noToolMessage: "No linter found (oxlint, biome, or eslint). Skipping linting.",
|
|
1167
|
-
onStart: () => hooks.emit("kubb:lint:start"),
|
|
1168
|
-
onEnd: () => hooks.emit("kubb:lint:end")
|
|
1169
|
-
}].filter(Boolean);
|
|
1170
|
-
for (const { code, ...pass } of toolPasses) try {
|
|
1171
|
-
await runToolPass({
|
|
1172
|
-
...pass,
|
|
1173
|
-
configName: config.name,
|
|
1098
|
+
const reportOutputFailure = async (code, label, error) => {
|
|
1099
|
+
const diagnostic = outputDiagnostic(code, label, error);
|
|
1100
|
+
outputDiagnostics.push(diagnostic);
|
|
1101
|
+
await Diagnostics.emit(hooks, diagnostic);
|
|
1102
|
+
};
|
|
1103
|
+
if (config.output.format) {
|
|
1104
|
+
const error = await runToolPass({
|
|
1105
|
+
toolValue: config.output.format,
|
|
1106
|
+
detect: () => detectTool([
|
|
1107
|
+
"oxfmt",
|
|
1108
|
+
"biome",
|
|
1109
|
+
"prettier"
|
|
1110
|
+
]),
|
|
1111
|
+
toolMap: formatters,
|
|
1112
|
+
toolLabel: "formatter",
|
|
1113
|
+
successPrefix: "Formatting",
|
|
1114
|
+
noToolMessage: "No formatter found (oxfmt, biome, or prettier). Skipping formatting.",
|
|
1115
|
+
onStart: () => hooks.emit("kubb:format:start"),
|
|
1116
|
+
onEnd: () => hooks.emit("kubb:format:end"),
|
|
1174
1117
|
outputPath,
|
|
1175
1118
|
logLevel,
|
|
1176
1119
|
hooks
|
|
1177
1120
|
});
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
await
|
|
1121
|
+
if (error) await reportOutputFailure(Diagnostics.code.formatFailed, "formatter", error);
|
|
1122
|
+
}
|
|
1123
|
+
if (config.output.lint) {
|
|
1124
|
+
const error = await runToolPass({
|
|
1125
|
+
toolValue: config.output.lint,
|
|
1126
|
+
detect: () => detectTool([
|
|
1127
|
+
"oxlint",
|
|
1128
|
+
"biome",
|
|
1129
|
+
"eslint"
|
|
1130
|
+
]),
|
|
1131
|
+
toolMap: linters,
|
|
1132
|
+
toolLabel: "linter",
|
|
1133
|
+
successPrefix: "Linting",
|
|
1134
|
+
noToolMessage: "No linter found (oxlint, biome, or eslint). Skipping linting.",
|
|
1135
|
+
onStart: () => hooks.emit("kubb:lint:start"),
|
|
1136
|
+
onEnd: () => hooks.emit("kubb:lint:end"),
|
|
1137
|
+
outputPath,
|
|
1138
|
+
logLevel,
|
|
1139
|
+
hooks
|
|
1140
|
+
});
|
|
1141
|
+
if (error) await reportOutputFailure(Diagnostics.code.lintFailed, "linter", error);
|
|
1182
1142
|
}
|
|
1183
1143
|
if (config.hooks) {
|
|
1184
1144
|
await hooks.emit("kubb:hooks:start");
|
|
1185
|
-
const
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
};
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
await
|
|
1192
|
-
configHooks: config.hooks,
|
|
1193
|
-
hooks
|
|
1194
|
-
});
|
|
1195
|
-
} finally {
|
|
1196
|
-
hooks.off("kubb:hook:end", onHookEnd);
|
|
1197
|
-
}
|
|
1198
|
-
for (const error of hookFailures) {
|
|
1199
|
-
const diagnostic = outputDiagnostic(Diagnostics.code.hookFailed, "Post-generate hook", error);
|
|
1200
|
-
outputDiagnostics.push(diagnostic);
|
|
1201
|
-
await Diagnostics.emit(hooks, diagnostic);
|
|
1145
|
+
const hookResults = await executeHooks({
|
|
1146
|
+
configHooks: config.hooks,
|
|
1147
|
+
hooks
|
|
1148
|
+
});
|
|
1149
|
+
for (const result of hookResults) {
|
|
1150
|
+
if (result.success) continue;
|
|
1151
|
+
await reportOutputFailure(Diagnostics.code.hookFailed, "Post-generate hook", result.error ?? /* @__PURE__ */ new Error("Post-generate hook failed"));
|
|
1202
1152
|
}
|
|
1203
1153
|
await hooks.emit("kubb:hooks:end");
|
|
1204
1154
|
}
|
|
@@ -1235,8 +1185,8 @@ function outputDiagnostic(code, label, caughtError) {
|
|
|
1235
1185
|
}
|
|
1236
1186
|
async function checkForUpdate(hooks) {
|
|
1237
1187
|
try {
|
|
1238
|
-
const data = await (await fetch(KUBB_NPM_PACKAGE_URL)).json();
|
|
1239
|
-
if (data.version && version
|
|
1188
|
+
const data = await (await fetch(KUBB_NPM_PACKAGE_URL, { signal: AbortSignal.timeout(UPDATE_CHECK_TIMEOUT_MS) })).json();
|
|
1189
|
+
if (data.version && isNewerVersion(version, data.version)) await Diagnostics.emit(hooks, Diagnostics.update({
|
|
1240
1190
|
currentVersion: version,
|
|
1241
1191
|
latestVersion: data.version
|
|
1242
1192
|
}));
|
|
@@ -1287,19 +1237,27 @@ async function run({ input, configPath, logLevel: logLevelKey, watch, reporters:
|
|
|
1287
1237
|
info: relativeConfigPath
|
|
1288
1238
|
});
|
|
1289
1239
|
let anyFailed = false;
|
|
1290
|
-
for (const config of configs) if (config.input && "path" in config.input && watch)
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1240
|
+
for (const config of configs) if (config.input && "path" in config.input && watch) {
|
|
1241
|
+
const watchedPaths = [input || config.input.path];
|
|
1242
|
+
const build = async (paths) => {
|
|
1243
|
+
await generate({
|
|
1244
|
+
input,
|
|
1245
|
+
config,
|
|
1246
|
+
logLevel: logLevel$2,
|
|
1247
|
+
hooks
|
|
1248
|
+
});
|
|
1249
|
+
clack.log.step(styleText("yellow", `Watching for changes in ${paths.join(" and ")}`));
|
|
1250
|
+
};
|
|
1251
|
+
try {
|
|
1252
|
+
await build(watchedPaths);
|
|
1253
|
+
} catch (buildError) {
|
|
1254
|
+
await hooks.emit("kubb:error", { error: toError(buildError) });
|
|
1255
|
+
}
|
|
1256
|
+
await startWatcher(watchedPaths, build, {
|
|
1257
|
+
info: (msg) => clack.log.info(msg),
|
|
1258
|
+
error: (msg) => clack.log.error(msg)
|
|
1296
1259
|
});
|
|
1297
|
-
|
|
1298
|
-
}, {
|
|
1299
|
-
info: (msg) => clack.log.info(msg),
|
|
1300
|
-
error: (msg) => clack.log.error(msg)
|
|
1301
|
-
});
|
|
1302
|
-
else try {
|
|
1260
|
+
} else try {
|
|
1303
1261
|
if (!await generate({
|
|
1304
1262
|
input,
|
|
1305
1263
|
config,
|
|
@@ -1320,4 +1278,4 @@ async function run({ input, configPath, logLevel: logLevelKey, watch, reporters:
|
|
|
1320
1278
|
//#endregion
|
|
1321
1279
|
export { run };
|
|
1322
1280
|
|
|
1323
|
-
//# sourceMappingURL=run-
|
|
1281
|
+
//# sourceMappingURL=run-CCsw-Y-v.js.map
|