@kubb/cli 5.4.0 → 5.4.2
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-Dw5s6abr.js → Telemetry-cHHOzBW8.js} +3 -3
- package/dist/{Telemetry-Dw5s6abr.js.map → Telemetry-cHHOzBW8.js.map} +1 -1
- package/dist/{agent-3JmkMghp.js → agent-w0Hlq4mG.js} +2 -2
- package/dist/{agent-3JmkMghp.js.map → agent-w0Hlq4mG.js.map} +1 -1
- package/dist/background-C64cE-Ua.js +252 -0
- package/dist/background-C64cE-Ua.js.map +1 -0
- package/dist/background-CqXG88yo.js +2 -0
- package/dist/background-DTWZnKnJ.cjs +171 -0
- package/dist/background-DTWZnKnJ.cjs.map +1 -0
- package/dist/{connect-DBZyr4h7.js → connect-9Oc4cfYT.js} +3 -3
- package/dist/{connect-DBZyr4h7.js.map → connect-9Oc4cfYT.js.map} +1 -1
- package/dist/{connect-Y7JuBX1H.cjs → connect-aB9I7Wqg.cjs} +2 -2
- package/dist/{connect-Y7JuBX1H.cjs.map → connect-aB9I7Wqg.cjs.map} +1 -1
- package/dist/{errors-C8yNfV7w.js → errors-BQJzaUwP.js} +2 -2
- package/dist/{errors-C8yNfV7w.js.map → errors-BQJzaUwP.js.map} +1 -1
- package/dist/{generate-gkR67D5j.js → generate-BOMX7IVh.js} +3 -3
- package/dist/{generate-gkR67D5j.js.map → generate-BOMX7IVh.js.map} +1 -1
- package/dist/{generate-B_ZwRbtX.cjs → generate-CTBkaj_g.cjs} +2 -2
- package/dist/{generate-B_ZwRbtX.cjs.map → generate-CTBkaj_g.cjs.map} +1 -1
- package/dist/index.cjs +7 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +9 -9
- package/dist/{init-u4wOU4d-.js → init-CLoakc-0.js} +4 -4
- package/dist/{init-u4wOU4d-.js.map → init-CLoakc-0.js.map} +1 -1
- package/dist/{init-DQsM8Jeh.cjs → init-DBHdf5aF.cjs} +3 -3
- package/dist/{init-DQsM8Jeh.cjs.map → init-DBHdf5aF.cjs.map} +1 -1
- package/dist/{login-D2SQw9L6.js → login-DSlP3N0Y.js} +3 -3
- package/dist/{login-D2SQw9L6.js.map → login-DSlP3N0Y.js.map} +1 -1
- package/dist/{login-Al8VCMpf.cjs → login-d2Qe4fhd.cjs} +2 -2
- package/dist/{login-Al8VCMpf.cjs.map → login-d2Qe4fhd.cjs.map} +1 -1
- package/dist/{logout-C-oRSK2O.js → logout-C4B9lPtr.js} +5 -3
- package/dist/logout-C4B9lPtr.js.map +1 -0
- package/dist/{logout-Cpgcdn_S.cjs → logout-D3GiSg15.cjs} +4 -2
- package/dist/logout-D3GiSg15.cjs.map +1 -0
- package/dist/{output-D-9bGS7y.cjs → output-9qUFmWFq.cjs} +2 -2
- package/dist/{output-D-9bGS7y.cjs.map → output-9qUFmWFq.cjs.map} +1 -1
- package/dist/{output-C_Gk4p-8.js → output-Dkoh9Ig6.js} +34 -34
- package/dist/{output-C_Gk4p-8.js.map → output-Dkoh9Ig6.js.map} +1 -1
- package/dist/package-9W_72uNT.js +6 -0
- package/dist/package-9W_72uNT.js.map +1 -0
- package/dist/{package-BxuyTfkU.cjs → package-C0HirQFL.cjs} +2 -2
- package/dist/package-C0HirQFL.cjs.map +1 -0
- package/dist/{rolldown-runtime-C0LytTxp.js → rolldown-runtime-CRm0XQPb.js} +1 -0
- package/dist/{run-CLyppKBR.cjs → run-BFn3tpiE.cjs} +2 -2
- package/dist/{run-CLyppKBR.cjs.map → run-BFn3tpiE.cjs.map} +1 -1
- package/dist/{run-BEZhsX-8.js → run-BH26mNIp.js} +3 -3
- package/dist/{run-BEZhsX-8.js.map → run-BH26mNIp.js.map} +1 -1
- package/dist/{run-Bidc3n3b.cjs → run-BhRWMu9D.cjs} +2 -2
- package/dist/{run-Bidc3n3b.cjs.map → run-BhRWMu9D.cjs.map} +1 -1
- package/dist/{run-BLTczbSI.cjs → run-Blvb9Xpo.cjs} +110 -149
- package/dist/run-Blvb9Xpo.cjs.map +1 -0
- package/dist/{run-BC3zN9tC.js → run-BtgXGBEQ.js} +105 -156
- package/dist/run-BtgXGBEQ.js.map +1 -0
- package/dist/{run-B7BsVX4x.js → run-DH4iFBCV.js} +5 -5
- package/dist/{run-B7BsVX4x.js.map → run-DH4iFBCV.js.map} +1 -1
- package/dist/{run-gsDH8AwX.cjs → run-DZIUhVsF.cjs} +2 -2
- package/dist/{run-gsDH8AwX.cjs.map → run-DZIUhVsF.cjs.map} +1 -1
- package/dist/{run-DHcqvmeS.js → run-DeQhQ9nw.js} +5 -5
- package/dist/{run-DHcqvmeS.js.map → run-DeQhQ9nw.js.map} +1 -1
- package/dist/{run-EasxFwoD.cjs → run-_9aC9inz.cjs} +4 -4
- package/dist/{run-EasxFwoD.cjs.map → run-_9aC9inz.cjs.map} +1 -1
- package/dist/{run-TIhvORof.js → run-rjPx8C8b.js} +7 -7
- package/dist/{run-TIhvORof.js.map → run-rjPx8C8b.js.map} +1 -1
- package/dist/{snapshot-DC2sw8Ob.cjs → snapshot-BOJa_d8W.cjs} +4 -4
- package/dist/{snapshot-DC2sw8Ob.cjs.map → snapshot-BOJa_d8W.cjs.map} +1 -1
- package/dist/{snapshot-C8XPUNhI.js → snapshot-QwAF-jtn.js} +6 -6
- package/dist/{snapshot-C8XPUNhI.js.map → snapshot-QwAF-jtn.js.map} +1 -1
- package/dist/start-BJlQdJA_.js +12 -0
- package/dist/start-BJlQdJA_.js.map +1 -0
- package/dist/start-CNwAkbvJ.cjs +12 -0
- package/dist/start-CNwAkbvJ.cjs.map +1 -0
- package/dist/status-DGqYtJjk.cjs +17 -0
- package/dist/status-DGqYtJjk.cjs.map +1 -0
- package/dist/status-Djgd7LoZ.js +17 -0
- package/dist/status-Djgd7LoZ.js.map +1 -0
- package/dist/stop-CFRhvsL_.cjs +11 -0
- package/dist/stop-CFRhvsL_.cjs.map +1 -0
- package/dist/stop-CKaFhKLQ.js +11 -0
- package/dist/stop-CKaFhKLQ.js.map +1 -0
- package/dist/{studio-klqRlnCg.js → studio-BHVkTqrV.js} +27 -13
- package/dist/studio-BHVkTqrV.js.map +1 -0
- package/dist/{studio-B-67uJDX.cjs → studio-C42UMY7Y.cjs} +26 -12
- package/dist/studio-C42UMY7Y.cjs.map +1 -0
- package/dist/studioWorker.d.ts +1 -0
- package/dist/studioWorker.js +62 -0
- package/dist/studioWorker.js.map +1 -0
- package/dist/{utils-TpILNAy7.js → utils-BYY3_cyq.js} +486 -486
- package/dist/utils-BYY3_cyq.js.map +1 -0
- package/dist/{utils-DqUNntyL.cjs → utils-Dcw3l4Wz.cjs} +9 -3
- package/dist/utils-Dcw3l4Wz.cjs.map +1 -0
- package/package.json +8 -8
- package/dist/logout-C-oRSK2O.js.map +0 -1
- package/dist/logout-Cpgcdn_S.cjs.map +0 -1
- package/dist/package-BxuyTfkU.cjs.map +0 -1
- package/dist/package-CyBxmd4k.js +0 -6
- package/dist/package-CyBxmd4k.js.map +0 -1
- package/dist/run-BC3zN9tC.js.map +0 -1
- package/dist/run-BLTczbSI.cjs.map +0 -1
- package/dist/status-Bim0sApA.js +0 -11
- package/dist/status-Bim0sApA.js.map +0 -1
- package/dist/status-CtP3npFS.cjs +0 -11
- package/dist/status-CtP3npFS.cjs.map +0 -1
- package/dist/studio-B-67uJDX.cjs.map +0 -1
- package/dist/studio-klqRlnCg.js.map +0 -1
- package/dist/utils-DqUNntyL.cjs.map +0 -1
- package/dist/utils-TpILNAy7.js.map +0 -1
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import "./rolldown-runtime-
|
|
2
|
-
import { t as toError } from "./errors-
|
|
3
|
-
import { t as getAgentName } from "./agent-
|
|
4
|
-
import { c as URL_WATCHER_TIMEOUT_MS, l as WATCHER_IGNORED_PATHS, s as URL_WATCHER_INTERVAL_MS } from "./Telemetry-
|
|
5
|
-
import { f as
|
|
1
|
+
import "./rolldown-runtime-CRm0XQPb.js";
|
|
2
|
+
import { t as toError } from "./errors-BQJzaUwP.js";
|
|
3
|
+
import { t as getAgentName } from "./agent-w0Hlq4mG.js";
|
|
4
|
+
import { c as URL_WATCHER_TIMEOUT_MS, l as WATCHER_IGNORED_PATHS, s as URL_WATCHER_INTERVAL_MS } from "./Telemetry-cHHOzBW8.js";
|
|
5
|
+
import { f as canUseTTY, h as getElapsedMs, m as formatMs, p as formatMsWithColor } from "./output-Dkoh9Ig6.js";
|
|
6
6
|
import { styleText } from "node:util";
|
|
7
7
|
import { randomUUID } from "node:crypto";
|
|
8
8
|
import process from "node:process";
|
|
9
9
|
import { spawn } from "node:child_process";
|
|
10
10
|
import { basename, dirname, relative, resolve } from "node:path";
|
|
11
|
-
import { Diagnostics, createCliReporter, logLevel } from "@kubb/core";
|
|
12
11
|
import * as clack from "@clack/prompts";
|
|
13
12
|
import { createJiti } from "jiti";
|
|
13
|
+
import { Diagnostics, createCliReporter, logLevel } from "@kubb/core";
|
|
14
14
|
import { NonZeroExitError, x } from "tinyexec";
|
|
15
15
|
import { loadConfig } from "unconfig";
|
|
16
|
-
import {
|
|
16
|
+
import { isGreaterThan, isValid, truncate } from "verkit";
|
|
17
17
|
//#region ../../internals/utils/src/tools.ts
|
|
18
18
|
/**
|
|
19
19
|
* CLI command descriptors for each supported code formatter.
|
|
@@ -121,184 +121,465 @@ function tokenize(command) {
|
|
|
121
121
|
return (command.match(/[^\s"']+|"([^"]*)"|'([^']*)'/g) ?? []).map((token) => token.replace(/^["']|["']$/g, ""));
|
|
122
122
|
}
|
|
123
123
|
//#endregion
|
|
124
|
-
//#region src/
|
|
124
|
+
//#region ../../internals/shared/src/loader.ts
|
|
125
125
|
/**
|
|
126
|
-
*
|
|
126
|
+
* jiti options for loading Kubb config modules: the automatic JSX runtime pointed at
|
|
127
|
+
* `@kubb/renderer-jsx`, and `moduleCache` off so a re-load re-evaluates the file.
|
|
127
128
|
*/
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
failure: "Formatting failed"
|
|
133
|
-
},
|
|
134
|
-
lint: {
|
|
135
|
-
running: "Linting",
|
|
136
|
-
success: "Linted",
|
|
137
|
-
failure: "Linting failed"
|
|
129
|
+
const JITI_OPTIONS = {
|
|
130
|
+
jsx: {
|
|
131
|
+
runtime: "automatic",
|
|
132
|
+
importSource: "@kubb/renderer-jsx"
|
|
138
133
|
},
|
|
139
|
-
|
|
140
|
-
running: "Running post-generate hooks",
|
|
141
|
-
success: "Post-generate hooks completed",
|
|
142
|
-
failure: "Post-generate hooks failed",
|
|
143
|
-
showHookResults: true
|
|
144
|
-
}
|
|
134
|
+
moduleCache: false
|
|
145
135
|
};
|
|
146
136
|
/**
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
|
|
150
|
-
function trimBlankEdges(lines) {
|
|
151
|
-
const start = lines.findIndex((line) => line.trim());
|
|
152
|
-
if (start === -1) return [];
|
|
153
|
-
return lines.slice(start, lines.findLastIndex((line) => line.trim()) + 1);
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Wires a {@link LoggerWriter} onto the run's hooks. This owns what a run says and in what order:
|
|
157
|
-
* one group per config, a step over the plugin work, a progress bar for the writes, one step per
|
|
158
|
-
* output phase, then the summary and the group's closing result. The writer only decides how each
|
|
159
|
-
* line looks, so every logger reports the same run the same way.
|
|
137
|
+
* Creates a jiti-based loader for Kubb's TypeScript and JavaScript config modules.
|
|
138
|
+
*
|
|
139
|
+
* jiti transpiles TypeScript and the `@kubb/renderer-jsx` JSX runtime on the fly.
|
|
160
140
|
*
|
|
161
141
|
* @example
|
|
162
142
|
* ```ts
|
|
163
|
-
*
|
|
143
|
+
* const config = await createModuleLoader().load('/abs/kubb.config.ts', { default: true })
|
|
164
144
|
* ```
|
|
165
145
|
*/
|
|
166
|
-
function
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
146
|
+
function createModuleLoader() {
|
|
147
|
+
const jiti = createJiti(import.meta.url, JITI_OPTIONS);
|
|
148
|
+
return { load(filePath, options) {
|
|
149
|
+
return options?.default ? jiti.import(filePath, { default: true }) : jiti.import(filePath);
|
|
150
|
+
} };
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* TTY logger for local development, with animated steps and progress bars.
|
|
154
|
+
*/
|
|
155
|
+
const clackLogger = {
|
|
156
|
+
name: "clack",
|
|
157
|
+
install: createLogger({
|
|
158
|
+
group: (title) => clack.intro(title),
|
|
159
|
+
groupEnd: (text) => clack.outro(text),
|
|
160
|
+
step: (text) => clack.log.step(text, { spacing: 0 }),
|
|
161
|
+
info: (text) => clack.log.info(text),
|
|
162
|
+
success: (text) => clack.log.success(text),
|
|
163
|
+
warn: (text) => clack.log.warn(text),
|
|
164
|
+
error: (text) => clack.log.error(text),
|
|
165
|
+
block: (lines) => clack.log.message(lines, { spacing: 0 }),
|
|
166
|
+
raw: (lines) => console.log(styleText("dim", lines.join("\n"))),
|
|
167
|
+
diagnostic: (lines) => clack.log.message(lines, {
|
|
168
|
+
symbol: "",
|
|
169
|
+
secondarySymbol: ""
|
|
170
|
+
}),
|
|
171
|
+
update: (lines, title) => clack.box(lines.join("\n"), title, {
|
|
172
|
+
width: "auto",
|
|
173
|
+
formatBorder: (border) => styleText("yellow", border),
|
|
174
|
+
rounded: true,
|
|
175
|
+
withGuide: false,
|
|
176
|
+
contentAlign: "center",
|
|
177
|
+
titleAlign: "center"
|
|
178
|
+
}),
|
|
179
|
+
spinner() {
|
|
180
|
+
const spinner = clack.spinner();
|
|
181
|
+
return {
|
|
182
|
+
start: (text) => spinner.start(text),
|
|
183
|
+
message: (text) => spinner.message(text),
|
|
184
|
+
clear: () => spinner.clear(),
|
|
185
|
+
stop: (text) => spinner.stop(text),
|
|
186
|
+
error: (text) => spinner.error(text)
|
|
187
|
+
};
|
|
188
|
+
},
|
|
189
|
+
progress(max) {
|
|
190
|
+
const bar = clack.progress({
|
|
191
|
+
style: "block",
|
|
192
|
+
max,
|
|
193
|
+
size: 30
|
|
194
|
+
});
|
|
195
|
+
return {
|
|
196
|
+
start: (text) => bar.start(text),
|
|
197
|
+
advance: (text) => bar.advance(1, text),
|
|
198
|
+
stop: (text) => bar.stop(text)
|
|
219
199
|
};
|
|
220
|
-
startSpinner(running);
|
|
221
|
-
}
|
|
222
|
-
function endPhase() {
|
|
223
|
-
const phase = state.phase;
|
|
224
|
-
state.phase = null;
|
|
225
|
-
if (!phase || silent) return;
|
|
226
|
-
const duration = formatMsWithColor(getElapsedMs(phase.hrStart));
|
|
227
|
-
stopSpinner(phase.failed ? `${phase.failureLabel} after ${duration}` : `${phase.successLabel} in ${duration}`, phase.failed ? "failed" : "success");
|
|
228
|
-
if (phase.lines.length) writer.block(phase.lines);
|
|
229
|
-
writeOutput(phase.output);
|
|
230
|
-
}
|
|
231
|
-
function writeOutput(lines) {
|
|
232
|
-
const output = trimBlankEdges(lines);
|
|
233
|
-
if (output.length) writer.raw(output);
|
|
234
|
-
}
|
|
235
|
-
function closeGroup(status) {
|
|
236
|
-
if (!state.groupOpen) return;
|
|
237
|
-
state.groupOpen = false;
|
|
238
|
-
stopSpinner();
|
|
239
|
-
stopProgress();
|
|
240
|
-
writer.groupEnd(status === "failed" ? styleText("red", "✗ Generation failed") : styleText("green", "✓ Generation succeeded"));
|
|
241
|
-
}
|
|
242
|
-
function reset() {
|
|
243
|
-
stopSpinner();
|
|
244
|
-
stopProgress();
|
|
245
|
-
resetProgressCounters(state);
|
|
246
|
-
state.hooks.clear();
|
|
247
|
-
state.pluginLines = [];
|
|
248
|
-
state.phase = null;
|
|
249
|
-
state.groupOpen = false;
|
|
250
200
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
styleText("yellow", "⚠"),
|
|
285
|
-
message,
|
|
286
|
-
logLevel$2 >= logLevel.info && info ? styleText("dim", info) : void 0
|
|
287
|
-
].filter(Boolean).join(" ")));
|
|
288
|
-
});
|
|
289
|
-
context.hook("kubb:error", ({ error }) => {
|
|
290
|
-
if (state.phase) state.phase.failed = true;
|
|
291
|
-
const line = [styleText("red", "✗"), error.message].join(" ");
|
|
292
|
-
if (state.spinner) stopSpinner(line, "failed");
|
|
293
|
-
else writer.error(text(line));
|
|
294
|
-
const frames = logLevel$2 >= logLevel.verbose ? formatErrorFrames(error) : null;
|
|
295
|
-
if (!frames) return;
|
|
296
|
-
writer.block(frames.frames.map((frame) => text(styleText("dim", frame))));
|
|
297
|
-
if (frames.cause) writer.block([styleText("dim", frames.cause.header), ...frames.cause.frames.map((frame) => text(` ${styleText("dim", frame)}`))]);
|
|
201
|
+
})
|
|
202
|
+
};
|
|
203
|
+
//#endregion
|
|
204
|
+
//#region src/loggers/utils.ts
|
|
205
|
+
/**
|
|
206
|
+
* Display path for a config's input: the string form, or its `path` field when the input is an
|
|
207
|
+
* object. Loggers show it alongside `Generation started`.
|
|
208
|
+
*/
|
|
209
|
+
function getInputPath(config) {
|
|
210
|
+
const { input } = config;
|
|
211
|
+
if (typeof input === "string") return input;
|
|
212
|
+
return typeof input?.path === "string" ? input.path : void 0;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Counts a noun, so a message never reads `1 files`.
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* `pluralize(1, 'config')` returns `'1 config'`
|
|
219
|
+
*/
|
|
220
|
+
function pluralize(count, noun) {
|
|
221
|
+
return `${count} ${count === 1 ? noun : `${noun}s`}`;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Optionally prefix a message with a [HH:MM:SS] timestamp when logLevel >= verbose.
|
|
225
|
+
* Shared across all logger adapters to avoid duplication.
|
|
226
|
+
*/
|
|
227
|
+
function formatMessage(message, logLevel$2) {
|
|
228
|
+
if (logLevel$2 >= logLevel.verbose) {
|
|
229
|
+
const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
|
|
230
|
+
hour12: false,
|
|
231
|
+
hour: "2-digit",
|
|
232
|
+
minute: "2-digit",
|
|
233
|
+
second: "2-digit"
|
|
298
234
|
});
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
235
|
+
return `${styleText("dim", `[${timestamp}]`)} ${message}`;
|
|
236
|
+
}
|
|
237
|
+
return message;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Renders the versions from a `studio:connected` event as one parenthetical. The runtime is listed
|
|
241
|
+
* only when it differs from the host, and Studio's only when it sent one.
|
|
242
|
+
*/
|
|
243
|
+
function formatVersions({ studio, kubb, agent }) {
|
|
244
|
+
return [
|
|
245
|
+
`v${agent}`,
|
|
246
|
+
kubb !== agent ? `runtime v${kubb}` : void 0,
|
|
247
|
+
studio ? `Studio v${studio}` : void 0
|
|
248
|
+
].filter(Boolean).join(", ");
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Extracts the `.cause` of an `Error` as an `Error`, or `undefined` when absent or not an `Error`.
|
|
252
|
+
*/
|
|
253
|
+
function toCause(error) {
|
|
254
|
+
return error.cause instanceof Error ? error.cause : void 0;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* First stack frames for verbose error output, including an optional `cause` chain.
|
|
258
|
+
*/
|
|
259
|
+
function formatErrorFrames(error) {
|
|
260
|
+
if (!error.stack) return null;
|
|
261
|
+
const frames = error.stack.split("\n").slice(1, 4).map((frame) => frame.trim());
|
|
262
|
+
const caused = toCause(error);
|
|
263
|
+
if (!caused?.stack) return { frames };
|
|
264
|
+
return {
|
|
265
|
+
frames,
|
|
266
|
+
cause: {
|
|
267
|
+
header: `└─ caused by ${caused.message}`,
|
|
268
|
+
frames: caused.stack.split("\n").slice(1, 4).map((frame) => frame.trim())
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Build the progress summary line shown by the clack logger.
|
|
274
|
+
* Returns null when there is nothing to display.
|
|
275
|
+
*/
|
|
276
|
+
function buildProgressLine(state) {
|
|
277
|
+
const parts = [];
|
|
278
|
+
const duration = formatMs(getElapsedMs(state.hrStart));
|
|
279
|
+
if (state.totalPlugins > 0) {
|
|
280
|
+
const pluginStr = state.failedPlugins > 0 ? `Plugins ${styleText("green", state.completedPlugins.toString())}/${state.totalPlugins} ${styleText("red", `(${state.failedPlugins} failed)`)}` : `Plugins ${styleText("green", state.completedPlugins.toString())}/${state.totalPlugins}`;
|
|
281
|
+
parts.push(pluginStr);
|
|
282
|
+
}
|
|
283
|
+
if (state.totalFiles > 0) parts.push(`Files ${styleText("green", state.processedFiles.toString())}/${state.totalFiles}`);
|
|
284
|
+
if (parts.length === 0) return null;
|
|
285
|
+
parts.push(`${styleText("green", duration)} elapsed`);
|
|
286
|
+
return parts.join(styleText("dim", " | "));
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Creates the per-run progress counters used by the clack logger.
|
|
290
|
+
*/
|
|
291
|
+
function createProgressCounters() {
|
|
292
|
+
return {
|
|
293
|
+
totalPlugins: 0,
|
|
294
|
+
completedPlugins: 0,
|
|
295
|
+
failedPlugins: 0,
|
|
296
|
+
totalFiles: 0,
|
|
297
|
+
processedFiles: 0,
|
|
298
|
+
hrStart: process.hrtime()
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Resets the progress counters in place at the start/end of a generation run.
|
|
303
|
+
*/
|
|
304
|
+
function resetProgressCounters(state) {
|
|
305
|
+
state.totalPlugins = 0;
|
|
306
|
+
state.completedPlugins = 0;
|
|
307
|
+
state.failedPlugins = 0;
|
|
308
|
+
state.totalFiles = 0;
|
|
309
|
+
state.processedFiles = 0;
|
|
310
|
+
state.hrStart = process.hrtime();
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Records a finished plugin against the progress counters.
|
|
314
|
+
*/
|
|
315
|
+
function recordPluginResult(state, success) {
|
|
316
|
+
if (success) state.completedPlugins++;
|
|
317
|
+
else state.failedPlugins++;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Join a command and its optional args into a single display string.
|
|
321
|
+
*
|
|
322
|
+
* @example With args
|
|
323
|
+
* `formatCommandWithArgs('prettier', ['--write', '.'])` returns `'prettier --write .'`
|
|
324
|
+
*/
|
|
325
|
+
function formatCommandWithArgs(command, args) {
|
|
326
|
+
return args?.length ? `${command} ${args.join(" ")}` : command;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Bridges a {@link Reporter} onto the run's hook emitter: calls `report` with each config's
|
|
330
|
+
* {@link GenerationResult} on `kubb:generation:end`. The reporter never touches the emitter.
|
|
331
|
+
*/
|
|
332
|
+
function installReporter(context, reporter, ctx) {
|
|
333
|
+
const pluginFiles = reporter.needsPluginFiles ? /* @__PURE__ */ new Map() : void 0;
|
|
334
|
+
if (pluginFiles) context.hook("kubb:plugin:end", ({ config, plugin, files }) => {
|
|
335
|
+
const filesByPlugin = pluginFiles.get(config) ?? /* @__PURE__ */ new Map();
|
|
336
|
+
const seen = new Set([...filesByPlugin.values()].flatMap((paths) => [...paths]));
|
|
337
|
+
const added = files.filter((file) => !seen.has(file.path)).map((file) => file.path);
|
|
338
|
+
if (added.length) filesByPlugin.set(plugin.name, /* @__PURE__ */ new Set([...filesByPlugin.get(plugin.name) ?? [], ...added]));
|
|
339
|
+
pluginFiles.set(config, filesByPlugin);
|
|
340
|
+
});
|
|
341
|
+
context.hook("kubb:generation:end", async ({ config, diagnostics = [], filesCreated = 0, status = "success", hrStart = process.hrtime() }) => {
|
|
342
|
+
const files = pluginFiles?.get(config);
|
|
343
|
+
const grouped = files && [...files].map(([plugin, paths]) => ({
|
|
344
|
+
plugin,
|
|
345
|
+
files: [...paths]
|
|
346
|
+
}));
|
|
347
|
+
await reporter.report({
|
|
348
|
+
config,
|
|
349
|
+
diagnostics,
|
|
350
|
+
filesCreated,
|
|
351
|
+
status,
|
|
352
|
+
hrStart,
|
|
353
|
+
pluginFiles: grouped
|
|
354
|
+
}, ctx);
|
|
355
|
+
pluginFiles?.delete(config);
|
|
356
|
+
});
|
|
357
|
+
if (reporter.drain) context.hook("kubb:lifecycle:end", () => reporter.drain?.(ctx));
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Installs the live logger (the TUI view) and the given reporters (the output). The reporters are
|
|
361
|
+
* already selected by the caller (the CLI maps `--reporter` to names via `selectReporters`). This
|
|
362
|
+
* only wires them. Loggers receive hook subprocess output through `kubb:hook:line` and the
|
|
363
|
+
* `stdout`/`stderr` on `kubb:hook:end`, so nothing is returned here.
|
|
364
|
+
*
|
|
365
|
+
* Loggers and reporters are independent, except for `cli`: it both installs the live logger view
|
|
366
|
+
* here and registers a reporter that renders the per-config summary through that logger, so the
|
|
367
|
+
* summary lands inside the group the logger opened. The `json` reporter owns stdout, so the whole
|
|
368
|
+
* `cli` reporter (live logger and summary) is skipped whenever `json` is among the reporters, even
|
|
369
|
+
* if `cli` is also listed.
|
|
370
|
+
*/
|
|
371
|
+
async function setupReporters(context, { logLevel, reporters, logger: forcedLogger }) {
|
|
372
|
+
let cliHandle;
|
|
373
|
+
const hasJson = reporters.some((reporter) => reporter.name === "json");
|
|
374
|
+
const ctx = { logLevel };
|
|
375
|
+
for (const reporter of reporters) {
|
|
376
|
+
if (reporter.name !== "cli") {
|
|
377
|
+
installReporter(context, reporter, ctx);
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
if (hasJson) continue;
|
|
381
|
+
const handle = await (forcedLogger ?? (canUseTTY() && !getAgentName() ? clackLogger : plainLogger)).install(context, { logLevel }) ?? void 0;
|
|
382
|
+
cliHandle = handle;
|
|
383
|
+
installReporter(context, createCliReporter({ render: handle?.renderSummary }), ctx);
|
|
384
|
+
}
|
|
385
|
+
return cliHandle;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Picks the reporters whose `name` matches one of `names`, in the order the names are given.
|
|
389
|
+
* The config carries every available reporter, and the host selects which to activate by name
|
|
390
|
+
* (the CLI maps `--reporter` to this). Duplicate names and names without a matching reporter are
|
|
391
|
+
* skipped.
|
|
392
|
+
*/
|
|
393
|
+
function selectReporters(reporters, names) {
|
|
394
|
+
const seen = /* @__PURE__ */ new Set();
|
|
395
|
+
const selected = [];
|
|
396
|
+
for (const name of names) {
|
|
397
|
+
if (seen.has(name)) continue;
|
|
398
|
+
seen.add(name);
|
|
399
|
+
const reporter = reporters.find((candidate) => candidate.name === name);
|
|
400
|
+
if (reporter) selected.push(reporter);
|
|
401
|
+
}
|
|
402
|
+
return selected;
|
|
403
|
+
}
|
|
404
|
+
//#endregion
|
|
405
|
+
//#region src/loggers/createLogger.ts
|
|
406
|
+
/**
|
|
407
|
+
* The three output phases, in the order the generate runner runs them.
|
|
408
|
+
*/
|
|
409
|
+
const PHASES = {
|
|
410
|
+
format: {
|
|
411
|
+
running: "Formatting",
|
|
412
|
+
success: "Formatted",
|
|
413
|
+
failure: "Formatting failed"
|
|
414
|
+
},
|
|
415
|
+
lint: {
|
|
416
|
+
running: "Linting",
|
|
417
|
+
success: "Linted",
|
|
418
|
+
failure: "Linting failed"
|
|
419
|
+
},
|
|
420
|
+
hooks: {
|
|
421
|
+
running: "Running post-generate hooks",
|
|
422
|
+
success: "Post-generate hooks completed",
|
|
423
|
+
failure: "Post-generate hooks failed",
|
|
424
|
+
showHookResults: true
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
/**
|
|
428
|
+
* Drops the blank lines a subprocess leaves at either end of its output, so its block does not open
|
|
429
|
+
* or close on an empty row.
|
|
430
|
+
*/
|
|
431
|
+
function trimBlankEdges(lines) {
|
|
432
|
+
const start = lines.findIndex((line) => line.trim());
|
|
433
|
+
if (start === -1) return [];
|
|
434
|
+
return lines.slice(start, lines.findLastIndex((line) => line.trim()) + 1);
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Wires a {@link LoggerWriter} onto the run's hooks. This owns what a run says and in what order:
|
|
438
|
+
* one group per config, a step over the plugin work, a progress bar for the writes, one step per
|
|
439
|
+
* output phase, then the summary and the group's closing result. The writer only decides how each
|
|
440
|
+
* line looks, so every logger reports the same run the same way.
|
|
441
|
+
*
|
|
442
|
+
* @example
|
|
443
|
+
* ```ts
|
|
444
|
+
* export const plainLogger = { name: 'plain', install: (context, options) => createLogger(writer)(context, options) }
|
|
445
|
+
* ```
|
|
446
|
+
*/
|
|
447
|
+
function createLogger(writer) {
|
|
448
|
+
return function install(context, options) {
|
|
449
|
+
const logLevel$1 = options?.logLevel ?? logLevel.info;
|
|
450
|
+
const silent = logLevel$1 <= logLevel.silent;
|
|
451
|
+
const state = {
|
|
452
|
+
...createProgressCounters(),
|
|
453
|
+
spinner: null,
|
|
454
|
+
progress: null,
|
|
455
|
+
hooks: /* @__PURE__ */ new Map(),
|
|
456
|
+
/**
|
|
457
|
+
* Plugin results held back while the generation step owns the line.
|
|
458
|
+
*/
|
|
459
|
+
pluginLines: [],
|
|
460
|
+
phase: null,
|
|
461
|
+
groupOpen: false
|
|
462
|
+
};
|
|
463
|
+
function text(message) {
|
|
464
|
+
return formatMessage(message, logLevel$1);
|
|
465
|
+
}
|
|
466
|
+
function startSpinner(message) {
|
|
467
|
+
if (silent) return;
|
|
468
|
+
state.spinner = writer.spinner();
|
|
469
|
+
state.spinner.start(text(message));
|
|
470
|
+
}
|
|
471
|
+
function stopSpinner(message, status = "success") {
|
|
472
|
+
const spinner = state.spinner;
|
|
473
|
+
if (!spinner) return;
|
|
474
|
+
state.spinner = null;
|
|
475
|
+
if (message === void 0) {
|
|
476
|
+
spinner.clear();
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
if (status === "failed") {
|
|
480
|
+
spinner.error(text(message));
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
spinner.stop(text(message));
|
|
484
|
+
}
|
|
485
|
+
function stopProgress(message) {
|
|
486
|
+
const progress = state.progress;
|
|
487
|
+
if (!progress) return;
|
|
488
|
+
state.progress = null;
|
|
489
|
+
progress.stop(message === void 0 ? "" : text(message));
|
|
490
|
+
}
|
|
491
|
+
function startPhase({ running, success, failure, showHookResults = false }) {
|
|
492
|
+
state.phase = {
|
|
493
|
+
successLabel: success,
|
|
494
|
+
failureLabel: failure,
|
|
495
|
+
showHookResults,
|
|
496
|
+
failed: false,
|
|
497
|
+
hrStart: process.hrtime(),
|
|
498
|
+
lines: [],
|
|
499
|
+
output: []
|
|
500
|
+
};
|
|
501
|
+
startSpinner(running);
|
|
502
|
+
}
|
|
503
|
+
function endPhase() {
|
|
504
|
+
const phase = state.phase;
|
|
505
|
+
state.phase = null;
|
|
506
|
+
if (!phase || silent) return;
|
|
507
|
+
const duration = formatMsWithColor(getElapsedMs(phase.hrStart));
|
|
508
|
+
stopSpinner(phase.failed ? `${phase.failureLabel} after ${duration}` : `${phase.successLabel} in ${duration}`, phase.failed ? "failed" : "success");
|
|
509
|
+
if (phase.lines.length) writer.block(phase.lines);
|
|
510
|
+
writeOutput(phase.output);
|
|
511
|
+
}
|
|
512
|
+
function writeOutput(lines) {
|
|
513
|
+
const output = trimBlankEdges(lines);
|
|
514
|
+
if (output.length) writer.raw(output);
|
|
515
|
+
}
|
|
516
|
+
function closeGroup(status) {
|
|
517
|
+
if (!state.groupOpen) return;
|
|
518
|
+
state.groupOpen = false;
|
|
519
|
+
stopSpinner();
|
|
520
|
+
stopProgress();
|
|
521
|
+
writer.groupEnd(status === "failed" ? styleText("red", "✗ Generation failed") : styleText("green", "✓ Generation succeeded"));
|
|
522
|
+
}
|
|
523
|
+
function reset() {
|
|
524
|
+
stopSpinner();
|
|
525
|
+
stopProgress();
|
|
526
|
+
resetProgressCounters(state);
|
|
527
|
+
state.hooks.clear();
|
|
528
|
+
state.pluginLines = [];
|
|
529
|
+
state.phase = null;
|
|
530
|
+
state.groupOpen = false;
|
|
531
|
+
}
|
|
532
|
+
context.hook("kubb:info", ({ message, info }) => {
|
|
533
|
+
if (silent) return;
|
|
534
|
+
const line = text([
|
|
535
|
+
styleText("blue", "ℹ"),
|
|
536
|
+
message,
|
|
537
|
+
info ? styleText("dim", info) : void 0
|
|
538
|
+
].filter(Boolean).join(" "));
|
|
539
|
+
if (state.phase) {
|
|
540
|
+
state.phase.lines.push(line);
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
if (state.spinner) {
|
|
544
|
+
state.spinner.message(line);
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
writer.info(line);
|
|
548
|
+
});
|
|
549
|
+
context.hook("kubb:success", ({ message, info }) => {
|
|
550
|
+
if (silent) return;
|
|
551
|
+
const line = text([
|
|
552
|
+
styleText("green", "✓"),
|
|
553
|
+
message,
|
|
554
|
+
logLevel$1 >= logLevel.info && info ? styleText("dim", info) : void 0
|
|
555
|
+
].filter(Boolean).join(" "));
|
|
556
|
+
if (state.spinner) {
|
|
557
|
+
state.spinner.message(line);
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
writer.success(line);
|
|
561
|
+
});
|
|
562
|
+
context.hook("kubb:warn", ({ message, info }) => {
|
|
563
|
+
if (logLevel$1 < logLevel.warn) return;
|
|
564
|
+
writer.warn(text([
|
|
565
|
+
styleText("yellow", "⚠"),
|
|
566
|
+
message,
|
|
567
|
+
logLevel$1 >= logLevel.info && info ? styleText("dim", info) : void 0
|
|
568
|
+
].filter(Boolean).join(" ")));
|
|
569
|
+
});
|
|
570
|
+
context.hook("kubb:error", ({ error }) => {
|
|
571
|
+
if (state.phase) state.phase.failed = true;
|
|
572
|
+
const line = [styleText("red", "✗"), error.message].join(" ");
|
|
573
|
+
if (state.spinner) stopSpinner(line, "failed");
|
|
574
|
+
else writer.error(text(line));
|
|
575
|
+
const frames = logLevel$1 >= logLevel.verbose ? formatErrorFrames(error) : null;
|
|
576
|
+
if (!frames) return;
|
|
577
|
+
writer.block(frames.frames.map((frame) => text(styleText("dim", frame))));
|
|
578
|
+
if (frames.cause) writer.block([styleText("dim", frames.cause.header), ...frames.cause.frames.map((frame) => text(` ${styleText("dim", frame)}`))]);
|
|
579
|
+
});
|
|
580
|
+
context.hook("kubb:diagnostic", ({ diagnostic }) => {
|
|
581
|
+
if (silent && diagnostic.severity !== "error") return;
|
|
582
|
+
stopSpinner();
|
|
302
583
|
stopProgress();
|
|
303
584
|
if (Diagnostics.isUpdate(diagnostic)) {
|
|
304
585
|
writer.update([`\`v${diagnostic.currentVersion}\` → \`v${diagnostic.latestVersion}\``, "Run `npm install -g @kubb/cli` to update"], "Update available for `Kubb`");
|
|
@@ -324,7 +605,7 @@ function createLogger(writer) {
|
|
|
324
605
|
startSpinner("✓ Ready to receive jobs");
|
|
325
606
|
});
|
|
326
607
|
context.hook("studio:disconnected", ({ reason }) => {
|
|
327
|
-
if (logLevel$
|
|
608
|
+
if (logLevel$1 < logLevel.warn) return;
|
|
328
609
|
stopSpinner();
|
|
329
610
|
writer.warn(text(`⚠ Kubb Studio ended the session (${reason})`));
|
|
330
611
|
});
|
|
@@ -344,7 +625,7 @@ function createLogger(writer) {
|
|
|
344
625
|
writer.info(text(styleText("dim", `Retrying connection to Kubb Studio in ${formatMs(delayMs)}`)));
|
|
345
626
|
});
|
|
346
627
|
context.hook("studio:warn", ({ message, permission }) => {
|
|
347
|
-
if (logLevel$
|
|
628
|
+
if (logLevel$1 < logLevel.warn) return;
|
|
348
629
|
const remedy = permission ? `; pass --${permission.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`)} to allow it` : "";
|
|
349
630
|
writer.warn(text(`⚠ ${message}${remedy}`));
|
|
350
631
|
});
|
|
@@ -441,85 +722,34 @@ function createLogger(writer) {
|
|
|
441
722
|
const active = state.hooks.get(id);
|
|
442
723
|
if (!active) return;
|
|
443
724
|
state.hooks.delete(id);
|
|
444
|
-
const label = styleText("dim", name ?? formatCommandWithArgs(command, args));
|
|
445
|
-
const reason = error?.message ? ` (${error.message})` : "";
|
|
446
|
-
const result = success ? `${styleText("green", "✓")} ${label} in ${formatMsWithColor(getElapsedMs(active.hrStart))}` : `${styleText("red", "✗")} ${label} failed${reason}`;
|
|
447
|
-
const phase = state.phase;
|
|
448
|
-
if (phase) {
|
|
449
|
-
if (phase.showHookResults || !success) phase.lines.push(result);
|
|
450
|
-
phase.output.push(...active.lines);
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
stopSpinner();
|
|
454
|
-
writer.step(text(result));
|
|
455
|
-
writeOutput(active.lines);
|
|
456
|
-
});
|
|
457
|
-
context.hook("kubb:generation:end", () => {
|
|
458
|
-
stopSpinner();
|
|
459
|
-
stopProgress();
|
|
460
|
-
});
|
|
461
|
-
context.hook("kubb:lifecycle:end", () => {
|
|
462
|
-
closeGroup("failed");
|
|
463
|
-
reset();
|
|
464
|
-
});
|
|
465
|
-
return { renderSummary(lines, { status }) {
|
|
466
|
-
if (silent || !state.groupOpen) return;
|
|
467
|
-
closeGroup(status);
|
|
468
|
-
writer.diagnostic([...lines]);
|
|
469
|
-
} };
|
|
470
|
-
};
|
|
471
|
-
}
|
|
472
|
-
/**
|
|
473
|
-
* TTY logger for local development, with animated steps and progress bars.
|
|
474
|
-
*/
|
|
475
|
-
const clackLogger = {
|
|
476
|
-
name: "clack",
|
|
477
|
-
install: createLogger({
|
|
478
|
-
group: (title) => clack.intro(title),
|
|
479
|
-
groupEnd: (text) => clack.outro(text),
|
|
480
|
-
step: (text) => clack.log.step(text, { spacing: 0 }),
|
|
481
|
-
info: (text) => clack.log.info(text),
|
|
482
|
-
success: (text) => clack.log.success(text),
|
|
483
|
-
warn: (text) => clack.log.warn(text),
|
|
484
|
-
error: (text) => clack.log.error(text),
|
|
485
|
-
block: (lines) => clack.log.message(lines, { spacing: 0 }),
|
|
486
|
-
raw: (lines) => console.log(styleText("dim", lines.join("\n"))),
|
|
487
|
-
diagnostic: (lines) => clack.log.message(lines, {
|
|
488
|
-
symbol: "",
|
|
489
|
-
secondarySymbol: ""
|
|
490
|
-
}),
|
|
491
|
-
update: (lines, title) => clack.box(lines.join("\n"), title, {
|
|
492
|
-
width: "auto",
|
|
493
|
-
formatBorder: (border) => styleText("yellow", border),
|
|
494
|
-
rounded: true,
|
|
495
|
-
withGuide: false,
|
|
496
|
-
contentAlign: "center",
|
|
497
|
-
titleAlign: "center"
|
|
498
|
-
}),
|
|
499
|
-
spinner() {
|
|
500
|
-
const spinner = clack.spinner();
|
|
501
|
-
return {
|
|
502
|
-
start: (text) => spinner.start(text),
|
|
503
|
-
message: (text) => spinner.message(text),
|
|
504
|
-
clear: () => spinner.clear(),
|
|
505
|
-
stop: (text) => spinner.stop(text),
|
|
506
|
-
error: (text) => spinner.error(text)
|
|
507
|
-
};
|
|
508
|
-
},
|
|
509
|
-
progress(max) {
|
|
510
|
-
const bar = clack.progress({
|
|
511
|
-
style: "block",
|
|
512
|
-
max,
|
|
513
|
-
size: 30
|
|
514
|
-
});
|
|
515
|
-
return {
|
|
516
|
-
start: (text) => bar.start(text),
|
|
517
|
-
advance: (text) => bar.advance(1, text),
|
|
518
|
-
stop: (text) => bar.stop(text)
|
|
519
|
-
};
|
|
520
|
-
}
|
|
521
|
-
})
|
|
522
|
-
};
|
|
725
|
+
const label = styleText("dim", name ?? formatCommandWithArgs(command, args));
|
|
726
|
+
const reason = error?.message ? ` (${error.message})` : "";
|
|
727
|
+
const result = success ? `${styleText("green", "✓")} ${label} in ${formatMsWithColor(getElapsedMs(active.hrStart))}` : `${styleText("red", "✗")} ${label} failed${reason}`;
|
|
728
|
+
const phase = state.phase;
|
|
729
|
+
if (phase) {
|
|
730
|
+
if (phase.showHookResults || !success) phase.lines.push(result);
|
|
731
|
+
phase.output.push(...active.lines);
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
stopSpinner();
|
|
735
|
+
writer.step(text(result));
|
|
736
|
+
writeOutput(active.lines);
|
|
737
|
+
});
|
|
738
|
+
context.hook("kubb:generation:end", () => {
|
|
739
|
+
stopSpinner();
|
|
740
|
+
stopProgress();
|
|
741
|
+
});
|
|
742
|
+
context.hook("kubb:lifecycle:end", () => {
|
|
743
|
+
closeGroup("failed");
|
|
744
|
+
reset();
|
|
745
|
+
});
|
|
746
|
+
return { renderSummary(lines, { status }) {
|
|
747
|
+
if (silent || !state.groupOpen) return;
|
|
748
|
+
closeGroup(status);
|
|
749
|
+
writer.diagnostic([...lines]);
|
|
750
|
+
} };
|
|
751
|
+
};
|
|
752
|
+
}
|
|
523
753
|
//#endregion
|
|
524
754
|
//#region src/loggers/plainLogger.ts
|
|
525
755
|
/**
|
|
@@ -572,236 +802,6 @@ function createPlainLogger(write) {
|
|
|
572
802
|
*/
|
|
573
803
|
const plainLogger = createPlainLogger((line) => console.log(line));
|
|
574
804
|
//#endregion
|
|
575
|
-
//#region src/loggers/utils.ts
|
|
576
|
-
/**
|
|
577
|
-
* Display path for a config's input: the string form, or its `path` field when the input is an
|
|
578
|
-
* object. Loggers show it alongside `Generation started`.
|
|
579
|
-
*/
|
|
580
|
-
function getInputPath(config) {
|
|
581
|
-
const { input } = config;
|
|
582
|
-
if (typeof input === "string") return input;
|
|
583
|
-
return typeof input?.path === "string" ? input.path : void 0;
|
|
584
|
-
}
|
|
585
|
-
/**
|
|
586
|
-
* Counts a noun, so a message never reads `1 files`.
|
|
587
|
-
*
|
|
588
|
-
* @example
|
|
589
|
-
* `pluralize(1, 'config')` returns `'1 config'`
|
|
590
|
-
*/
|
|
591
|
-
function pluralize(count, noun) {
|
|
592
|
-
return `${count} ${count === 1 ? noun : `${noun}s`}`;
|
|
593
|
-
}
|
|
594
|
-
/**
|
|
595
|
-
* Optionally prefix a message with a [HH:MM:SS] timestamp when logLevel >= verbose.
|
|
596
|
-
* Shared across all logger adapters to avoid duplication.
|
|
597
|
-
*/
|
|
598
|
-
function formatMessage(message, logLevel$1) {
|
|
599
|
-
if (logLevel$1 >= logLevel.verbose) {
|
|
600
|
-
const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
|
|
601
|
-
hour12: false,
|
|
602
|
-
hour: "2-digit",
|
|
603
|
-
minute: "2-digit",
|
|
604
|
-
second: "2-digit"
|
|
605
|
-
});
|
|
606
|
-
return `${styleText("dim", `[${timestamp}]`)} ${message}`;
|
|
607
|
-
}
|
|
608
|
-
return message;
|
|
609
|
-
}
|
|
610
|
-
/**
|
|
611
|
-
* Renders the versions from a `studio:connected` event as one parenthetical. The runtime is listed
|
|
612
|
-
* only when it differs from the host, and Studio's only when it sent one.
|
|
613
|
-
*/
|
|
614
|
-
function formatVersions({ studio, kubb, agent }) {
|
|
615
|
-
return [
|
|
616
|
-
`v${agent}`,
|
|
617
|
-
kubb !== agent ? `runtime v${kubb}` : void 0,
|
|
618
|
-
studio ? `Studio v${studio}` : void 0
|
|
619
|
-
].filter(Boolean).join(", ");
|
|
620
|
-
}
|
|
621
|
-
/**
|
|
622
|
-
* Extracts the `.cause` of an `Error` as an `Error`, or `undefined` when absent or not an `Error`.
|
|
623
|
-
*/
|
|
624
|
-
function toCause(error) {
|
|
625
|
-
return error.cause instanceof Error ? error.cause : void 0;
|
|
626
|
-
}
|
|
627
|
-
/**
|
|
628
|
-
* First stack frames for verbose error output, including an optional `cause` chain.
|
|
629
|
-
*/
|
|
630
|
-
function formatErrorFrames(error) {
|
|
631
|
-
if (!error.stack) return null;
|
|
632
|
-
const frames = error.stack.split("\n").slice(1, 4).map((frame) => frame.trim());
|
|
633
|
-
const caused = toCause(error);
|
|
634
|
-
if (!caused?.stack) return { frames };
|
|
635
|
-
return {
|
|
636
|
-
frames,
|
|
637
|
-
cause: {
|
|
638
|
-
header: `└─ caused by ${caused.message}`,
|
|
639
|
-
frames: caused.stack.split("\n").slice(1, 4).map((frame) => frame.trim())
|
|
640
|
-
}
|
|
641
|
-
};
|
|
642
|
-
}
|
|
643
|
-
/**
|
|
644
|
-
* Build the progress summary line shown by the clack logger.
|
|
645
|
-
* Returns null when there is nothing to display.
|
|
646
|
-
*/
|
|
647
|
-
function buildProgressLine(state) {
|
|
648
|
-
const parts = [];
|
|
649
|
-
const duration = formatMs(getElapsedMs(state.hrStart));
|
|
650
|
-
if (state.totalPlugins > 0) {
|
|
651
|
-
const pluginStr = state.failedPlugins > 0 ? `Plugins ${styleText("green", state.completedPlugins.toString())}/${state.totalPlugins} ${styleText("red", `(${state.failedPlugins} failed)`)}` : `Plugins ${styleText("green", state.completedPlugins.toString())}/${state.totalPlugins}`;
|
|
652
|
-
parts.push(pluginStr);
|
|
653
|
-
}
|
|
654
|
-
if (state.totalFiles > 0) parts.push(`Files ${styleText("green", state.processedFiles.toString())}/${state.totalFiles}`);
|
|
655
|
-
if (parts.length === 0) return null;
|
|
656
|
-
parts.push(`${styleText("green", duration)} elapsed`);
|
|
657
|
-
return parts.join(styleText("dim", " | "));
|
|
658
|
-
}
|
|
659
|
-
/**
|
|
660
|
-
* Creates the per-run progress counters used by the clack logger.
|
|
661
|
-
*/
|
|
662
|
-
function createProgressCounters() {
|
|
663
|
-
return {
|
|
664
|
-
totalPlugins: 0,
|
|
665
|
-
completedPlugins: 0,
|
|
666
|
-
failedPlugins: 0,
|
|
667
|
-
totalFiles: 0,
|
|
668
|
-
processedFiles: 0,
|
|
669
|
-
hrStart: process.hrtime()
|
|
670
|
-
};
|
|
671
|
-
}
|
|
672
|
-
/**
|
|
673
|
-
* Resets the progress counters in place at the start/end of a generation run.
|
|
674
|
-
*/
|
|
675
|
-
function resetProgressCounters(state) {
|
|
676
|
-
state.totalPlugins = 0;
|
|
677
|
-
state.completedPlugins = 0;
|
|
678
|
-
state.failedPlugins = 0;
|
|
679
|
-
state.totalFiles = 0;
|
|
680
|
-
state.processedFiles = 0;
|
|
681
|
-
state.hrStart = process.hrtime();
|
|
682
|
-
}
|
|
683
|
-
/**
|
|
684
|
-
* Records a finished plugin against the progress counters.
|
|
685
|
-
*/
|
|
686
|
-
function recordPluginResult(state, success) {
|
|
687
|
-
if (success) state.completedPlugins++;
|
|
688
|
-
else state.failedPlugins++;
|
|
689
|
-
}
|
|
690
|
-
/**
|
|
691
|
-
* Join a command and its optional args into a single display string.
|
|
692
|
-
*
|
|
693
|
-
* @example With args
|
|
694
|
-
* `formatCommandWithArgs('prettier', ['--write', '.'])` returns `'prettier --write .'`
|
|
695
|
-
*/
|
|
696
|
-
function formatCommandWithArgs(command, args) {
|
|
697
|
-
return args?.length ? `${command} ${args.join(" ")}` : command;
|
|
698
|
-
}
|
|
699
|
-
/**
|
|
700
|
-
* Bridges a {@link Reporter} onto the run's hook emitter: calls `report` with each config's
|
|
701
|
-
* {@link GenerationResult} on `kubb:generation:end`. The reporter never touches the emitter.
|
|
702
|
-
*/
|
|
703
|
-
function installReporter(context, reporter, ctx) {
|
|
704
|
-
const pluginFiles = reporter.needsPluginFiles ? /* @__PURE__ */ new Map() : void 0;
|
|
705
|
-
if (pluginFiles) context.hook("kubb:plugin:end", ({ config, plugin, files }) => {
|
|
706
|
-
const filesByPlugin = pluginFiles.get(config) ?? /* @__PURE__ */ new Map();
|
|
707
|
-
const seen = new Set([...filesByPlugin.values()].flatMap((paths) => [...paths]));
|
|
708
|
-
const added = files.filter((file) => !seen.has(file.path)).map((file) => file.path);
|
|
709
|
-
if (added.length) filesByPlugin.set(plugin.name, /* @__PURE__ */ new Set([...filesByPlugin.get(plugin.name) ?? [], ...added]));
|
|
710
|
-
pluginFiles.set(config, filesByPlugin);
|
|
711
|
-
});
|
|
712
|
-
context.hook("kubb:generation:end", async ({ config, diagnostics = [], filesCreated = 0, status = "success", hrStart = process.hrtime() }) => {
|
|
713
|
-
const files = pluginFiles?.get(config);
|
|
714
|
-
const grouped = files && [...files].map(([plugin, paths]) => ({
|
|
715
|
-
plugin,
|
|
716
|
-
files: [...paths]
|
|
717
|
-
}));
|
|
718
|
-
await reporter.report({
|
|
719
|
-
config,
|
|
720
|
-
diagnostics,
|
|
721
|
-
filesCreated,
|
|
722
|
-
status,
|
|
723
|
-
hrStart,
|
|
724
|
-
pluginFiles: grouped
|
|
725
|
-
}, ctx);
|
|
726
|
-
pluginFiles?.delete(config);
|
|
727
|
-
});
|
|
728
|
-
if (reporter.drain) context.hook("kubb:lifecycle:end", () => reporter.drain?.(ctx));
|
|
729
|
-
}
|
|
730
|
-
/**
|
|
731
|
-
* Installs the live logger (the TUI view) and the given reporters (the output). The reporters are
|
|
732
|
-
* already selected by the caller (the CLI maps `--reporter` to names via `selectReporters`). This
|
|
733
|
-
* only wires them. Loggers receive hook subprocess output through `kubb:hook:line` and the
|
|
734
|
-
* `stdout`/`stderr` on `kubb:hook:end`, so nothing is returned here.
|
|
735
|
-
*
|
|
736
|
-
* Loggers and reporters are independent, except for `cli`: it both installs the live logger view
|
|
737
|
-
* here and registers a reporter that renders the per-config summary through that logger, so the
|
|
738
|
-
* summary lands inside the group the logger opened. The `json` reporter owns stdout, so the whole
|
|
739
|
-
* `cli` reporter (live logger and summary) is skipped whenever `json` is among the reporters, even
|
|
740
|
-
* if `cli` is also listed.
|
|
741
|
-
*/
|
|
742
|
-
async function setupReporters(context, { logLevel, reporters, logger: forcedLogger }) {
|
|
743
|
-
let cliHandle;
|
|
744
|
-
const hasJson = reporters.some((reporter) => reporter.name === "json");
|
|
745
|
-
const ctx = { logLevel };
|
|
746
|
-
for (const reporter of reporters) {
|
|
747
|
-
if (reporter.name !== "cli") {
|
|
748
|
-
installReporter(context, reporter, ctx);
|
|
749
|
-
continue;
|
|
750
|
-
}
|
|
751
|
-
if (hasJson) continue;
|
|
752
|
-
const handle = await (forcedLogger ?? (canUseTTY() && !getAgentName() ? clackLogger : plainLogger)).install(context, { logLevel }) ?? void 0;
|
|
753
|
-
cliHandle = handle;
|
|
754
|
-
installReporter(context, createCliReporter({ render: handle?.renderSummary }), ctx);
|
|
755
|
-
}
|
|
756
|
-
return cliHandle;
|
|
757
|
-
}
|
|
758
|
-
/**
|
|
759
|
-
* Picks the reporters whose `name` matches one of `names`, in the order the names are given.
|
|
760
|
-
* The config carries every available reporter, and the host selects which to activate by name
|
|
761
|
-
* (the CLI maps `--reporter` to this). Duplicate names and names without a matching reporter are
|
|
762
|
-
* skipped.
|
|
763
|
-
*/
|
|
764
|
-
function selectReporters(reporters, names) {
|
|
765
|
-
const seen = /* @__PURE__ */ new Set();
|
|
766
|
-
const selected = [];
|
|
767
|
-
for (const name of names) {
|
|
768
|
-
if (seen.has(name)) continue;
|
|
769
|
-
seen.add(name);
|
|
770
|
-
const reporter = reporters.find((candidate) => candidate.name === name);
|
|
771
|
-
if (reporter) selected.push(reporter);
|
|
772
|
-
}
|
|
773
|
-
return selected;
|
|
774
|
-
}
|
|
775
|
-
//#endregion
|
|
776
|
-
//#region ../../internals/shared/src/loader.ts
|
|
777
|
-
/**
|
|
778
|
-
* jiti options for loading Kubb config modules: the automatic JSX runtime pointed at
|
|
779
|
-
* `@kubb/renderer-jsx`, and `moduleCache` off so a re-load re-evaluates the file.
|
|
780
|
-
*/
|
|
781
|
-
const JITI_OPTIONS = {
|
|
782
|
-
jsx: {
|
|
783
|
-
runtime: "automatic",
|
|
784
|
-
importSource: "@kubb/renderer-jsx"
|
|
785
|
-
},
|
|
786
|
-
moduleCache: false
|
|
787
|
-
};
|
|
788
|
-
/**
|
|
789
|
-
* Creates a jiti-based loader for Kubb's TypeScript and JavaScript config modules.
|
|
790
|
-
*
|
|
791
|
-
* jiti transpiles TypeScript and the `@kubb/renderer-jsx` JSX runtime on the fly.
|
|
792
|
-
*
|
|
793
|
-
* @example
|
|
794
|
-
* ```ts
|
|
795
|
-
* const config = await createModuleLoader().load('/abs/kubb.config.ts', { default: true })
|
|
796
|
-
* ```
|
|
797
|
-
*/
|
|
798
|
-
function createModuleLoader() {
|
|
799
|
-
const jiti = createJiti(import.meta.url, JITI_OPTIONS);
|
|
800
|
-
return { load(filePath, options) {
|
|
801
|
-
return options?.default ? jiti.import(filePath, { default: true }) : jiti.import(filePath);
|
|
802
|
-
} };
|
|
803
|
-
}
|
|
804
|
-
//#endregion
|
|
805
805
|
//#region src/runners/generate/utils.ts
|
|
806
806
|
const loader = createModuleLoader();
|
|
807
807
|
const tsLoader = (configFile) => loader.load(configFile, { default: true });
|
|
@@ -876,7 +876,7 @@ async function getConfigs({ configPath, input, watch, logLevel }) {
|
|
|
876
876
|
*/
|
|
877
877
|
function isNewerVersion(current, latest) {
|
|
878
878
|
if (!isValid(current) || !isValid(latest)) return false;
|
|
879
|
-
return
|
|
879
|
+
return isGreaterThan(truncate(latest, "patch"), truncate(current, "patch"));
|
|
880
880
|
}
|
|
881
881
|
/**
|
|
882
882
|
* Runs the `output.postGenerate` commands of a Kubb config in sequence and returns each command's
|
|
@@ -1104,6 +1104,6 @@ function startUrlWatcher(url, cb, options = {}) {
|
|
|
1104
1104
|
return stop;
|
|
1105
1105
|
}
|
|
1106
1106
|
//#endregion
|
|
1107
|
-
export { runPostGenerate as a,
|
|
1107
|
+
export { linters as _, runPostGenerate as a, createPlainLogger as c, selectReporters as d, setupReporters as f, formatters as g, detectTool as h, runHook as i, plainLogger as l, LINTER_PREFERENCE as m, getConfigs as n, startUrlWatcher as o, FORMATTER_PREFERENCE as p, isNewerVersion as r, startWatcher as s, fetchUrlBody as t, pluralize as u };
|
|
1108
1108
|
|
|
1109
|
-
//# sourceMappingURL=utils-
|
|
1109
|
+
//# sourceMappingURL=utils-BYY3_cyq.js.map
|