@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.
Files changed (106) hide show
  1. package/dist/{Telemetry-Dw5s6abr.js → Telemetry-cHHOzBW8.js} +3 -3
  2. package/dist/{Telemetry-Dw5s6abr.js.map → Telemetry-cHHOzBW8.js.map} +1 -1
  3. package/dist/{agent-3JmkMghp.js → agent-w0Hlq4mG.js} +2 -2
  4. package/dist/{agent-3JmkMghp.js.map → agent-w0Hlq4mG.js.map} +1 -1
  5. package/dist/background-C64cE-Ua.js +252 -0
  6. package/dist/background-C64cE-Ua.js.map +1 -0
  7. package/dist/background-CqXG88yo.js +2 -0
  8. package/dist/background-DTWZnKnJ.cjs +171 -0
  9. package/dist/background-DTWZnKnJ.cjs.map +1 -0
  10. package/dist/{connect-DBZyr4h7.js → connect-9Oc4cfYT.js} +3 -3
  11. package/dist/{connect-DBZyr4h7.js.map → connect-9Oc4cfYT.js.map} +1 -1
  12. package/dist/{connect-Y7JuBX1H.cjs → connect-aB9I7Wqg.cjs} +2 -2
  13. package/dist/{connect-Y7JuBX1H.cjs.map → connect-aB9I7Wqg.cjs.map} +1 -1
  14. package/dist/{errors-C8yNfV7w.js → errors-BQJzaUwP.js} +2 -2
  15. package/dist/{errors-C8yNfV7w.js.map → errors-BQJzaUwP.js.map} +1 -1
  16. package/dist/{generate-gkR67D5j.js → generate-BOMX7IVh.js} +3 -3
  17. package/dist/{generate-gkR67D5j.js.map → generate-BOMX7IVh.js.map} +1 -1
  18. package/dist/{generate-B_ZwRbtX.cjs → generate-CTBkaj_g.cjs} +2 -2
  19. package/dist/{generate-B_ZwRbtX.cjs.map → generate-CTBkaj_g.cjs.map} +1 -1
  20. package/dist/index.cjs +7 -7
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.js +9 -9
  23. package/dist/{init-u4wOU4d-.js → init-CLoakc-0.js} +4 -4
  24. package/dist/{init-u4wOU4d-.js.map → init-CLoakc-0.js.map} +1 -1
  25. package/dist/{init-DQsM8Jeh.cjs → init-DBHdf5aF.cjs} +3 -3
  26. package/dist/{init-DQsM8Jeh.cjs.map → init-DBHdf5aF.cjs.map} +1 -1
  27. package/dist/{login-D2SQw9L6.js → login-DSlP3N0Y.js} +3 -3
  28. package/dist/{login-D2SQw9L6.js.map → login-DSlP3N0Y.js.map} +1 -1
  29. package/dist/{login-Al8VCMpf.cjs → login-d2Qe4fhd.cjs} +2 -2
  30. package/dist/{login-Al8VCMpf.cjs.map → login-d2Qe4fhd.cjs.map} +1 -1
  31. package/dist/{logout-C-oRSK2O.js → logout-C4B9lPtr.js} +5 -3
  32. package/dist/logout-C4B9lPtr.js.map +1 -0
  33. package/dist/{logout-Cpgcdn_S.cjs → logout-D3GiSg15.cjs} +4 -2
  34. package/dist/logout-D3GiSg15.cjs.map +1 -0
  35. package/dist/{output-D-9bGS7y.cjs → output-9qUFmWFq.cjs} +2 -2
  36. package/dist/{output-D-9bGS7y.cjs.map → output-9qUFmWFq.cjs.map} +1 -1
  37. package/dist/{output-C_Gk4p-8.js → output-Dkoh9Ig6.js} +34 -34
  38. package/dist/{output-C_Gk4p-8.js.map → output-Dkoh9Ig6.js.map} +1 -1
  39. package/dist/package-9W_72uNT.js +6 -0
  40. package/dist/package-9W_72uNT.js.map +1 -0
  41. package/dist/{package-BxuyTfkU.cjs → package-C0HirQFL.cjs} +2 -2
  42. package/dist/package-C0HirQFL.cjs.map +1 -0
  43. package/dist/{rolldown-runtime-C0LytTxp.js → rolldown-runtime-CRm0XQPb.js} +1 -0
  44. package/dist/{run-CLyppKBR.cjs → run-BFn3tpiE.cjs} +2 -2
  45. package/dist/{run-CLyppKBR.cjs.map → run-BFn3tpiE.cjs.map} +1 -1
  46. package/dist/{run-BEZhsX-8.js → run-BH26mNIp.js} +3 -3
  47. package/dist/{run-BEZhsX-8.js.map → run-BH26mNIp.js.map} +1 -1
  48. package/dist/{run-Bidc3n3b.cjs → run-BhRWMu9D.cjs} +2 -2
  49. package/dist/{run-Bidc3n3b.cjs.map → run-BhRWMu9D.cjs.map} +1 -1
  50. package/dist/{run-BLTczbSI.cjs → run-Blvb9Xpo.cjs} +110 -149
  51. package/dist/run-Blvb9Xpo.cjs.map +1 -0
  52. package/dist/{run-BC3zN9tC.js → run-BtgXGBEQ.js} +105 -156
  53. package/dist/run-BtgXGBEQ.js.map +1 -0
  54. package/dist/{run-B7BsVX4x.js → run-DH4iFBCV.js} +5 -5
  55. package/dist/{run-B7BsVX4x.js.map → run-DH4iFBCV.js.map} +1 -1
  56. package/dist/{run-gsDH8AwX.cjs → run-DZIUhVsF.cjs} +2 -2
  57. package/dist/{run-gsDH8AwX.cjs.map → run-DZIUhVsF.cjs.map} +1 -1
  58. package/dist/{run-DHcqvmeS.js → run-DeQhQ9nw.js} +5 -5
  59. package/dist/{run-DHcqvmeS.js.map → run-DeQhQ9nw.js.map} +1 -1
  60. package/dist/{run-EasxFwoD.cjs → run-_9aC9inz.cjs} +4 -4
  61. package/dist/{run-EasxFwoD.cjs.map → run-_9aC9inz.cjs.map} +1 -1
  62. package/dist/{run-TIhvORof.js → run-rjPx8C8b.js} +7 -7
  63. package/dist/{run-TIhvORof.js.map → run-rjPx8C8b.js.map} +1 -1
  64. package/dist/{snapshot-DC2sw8Ob.cjs → snapshot-BOJa_d8W.cjs} +4 -4
  65. package/dist/{snapshot-DC2sw8Ob.cjs.map → snapshot-BOJa_d8W.cjs.map} +1 -1
  66. package/dist/{snapshot-C8XPUNhI.js → snapshot-QwAF-jtn.js} +6 -6
  67. package/dist/{snapshot-C8XPUNhI.js.map → snapshot-QwAF-jtn.js.map} +1 -1
  68. package/dist/start-BJlQdJA_.js +12 -0
  69. package/dist/start-BJlQdJA_.js.map +1 -0
  70. package/dist/start-CNwAkbvJ.cjs +12 -0
  71. package/dist/start-CNwAkbvJ.cjs.map +1 -0
  72. package/dist/status-DGqYtJjk.cjs +17 -0
  73. package/dist/status-DGqYtJjk.cjs.map +1 -0
  74. package/dist/status-Djgd7LoZ.js +17 -0
  75. package/dist/status-Djgd7LoZ.js.map +1 -0
  76. package/dist/stop-CFRhvsL_.cjs +11 -0
  77. package/dist/stop-CFRhvsL_.cjs.map +1 -0
  78. package/dist/stop-CKaFhKLQ.js +11 -0
  79. package/dist/stop-CKaFhKLQ.js.map +1 -0
  80. package/dist/{studio-klqRlnCg.js → studio-BHVkTqrV.js} +27 -13
  81. package/dist/studio-BHVkTqrV.js.map +1 -0
  82. package/dist/{studio-B-67uJDX.cjs → studio-C42UMY7Y.cjs} +26 -12
  83. package/dist/studio-C42UMY7Y.cjs.map +1 -0
  84. package/dist/studioWorker.d.ts +1 -0
  85. package/dist/studioWorker.js +62 -0
  86. package/dist/studioWorker.js.map +1 -0
  87. package/dist/{utils-TpILNAy7.js → utils-BYY3_cyq.js} +486 -486
  88. package/dist/utils-BYY3_cyq.js.map +1 -0
  89. package/dist/{utils-DqUNntyL.cjs → utils-Dcw3l4Wz.cjs} +9 -3
  90. package/dist/utils-Dcw3l4Wz.cjs.map +1 -0
  91. package/package.json +8 -8
  92. package/dist/logout-C-oRSK2O.js.map +0 -1
  93. package/dist/logout-Cpgcdn_S.cjs.map +0 -1
  94. package/dist/package-BxuyTfkU.cjs.map +0 -1
  95. package/dist/package-CyBxmd4k.js +0 -6
  96. package/dist/package-CyBxmd4k.js.map +0 -1
  97. package/dist/run-BC3zN9tC.js.map +0 -1
  98. package/dist/run-BLTczbSI.cjs.map +0 -1
  99. package/dist/status-Bim0sApA.js +0 -11
  100. package/dist/status-Bim0sApA.js.map +0 -1
  101. package/dist/status-CtP3npFS.cjs +0 -11
  102. package/dist/status-CtP3npFS.cjs.map +0 -1
  103. package/dist/studio-B-67uJDX.cjs.map +0 -1
  104. package/dist/studio-klqRlnCg.js.map +0 -1
  105. package/dist/utils-DqUNntyL.cjs.map +0 -1
  106. package/dist/utils-TpILNAy7.js.map +0 -1
@@ -1,19 +1,19 @@
1
- import "./rolldown-runtime-C0LytTxp.js";
2
- import { t as toError } from "./errors-C8yNfV7w.js";
3
- import { t as getAgentName } from "./agent-3JmkMghp.js";
4
- import { c as URL_WATCHER_TIMEOUT_MS, l as WATCHER_IGNORED_PATHS, s as URL_WATCHER_INTERVAL_MS } from "./Telemetry-Dw5s6abr.js";
5
- import { f as formatMsWithColor, h as getElapsedMs, m as formatMs, p as canUseTTY } from "./output-C_Gk4p-8.js";
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 { isGreater, isValid, truncate } from "verkit";
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/loggers/createLogger.ts
124
+ //#region ../../internals/shared/src/loader.ts
125
125
  /**
126
- * The three output phases, in the order the generate runner runs them.
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 PHASES = {
129
- format: {
130
- running: "Formatting",
131
- success: "Formatted",
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
- hooks: {
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
- * Drops the blank lines a subprocess leaves at either end of its output, so its block does not open
148
- * or close on an empty row.
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
- * export const plainLogger = { name: 'plain', install: (context, options) => createLogger(writer)(context, options) }
143
+ * const config = await createModuleLoader().load('/abs/kubb.config.ts', { default: true })
164
144
  * ```
165
145
  */
166
- function createLogger(writer) {
167
- return function install(context, options) {
168
- const logLevel$2 = options?.logLevel ?? logLevel.info;
169
- const silent = logLevel$2 <= logLevel.silent;
170
- const state = {
171
- ...createProgressCounters(),
172
- spinner: null,
173
- progress: null,
174
- hooks: /* @__PURE__ */ new Map(),
175
- /**
176
- * Plugin results held back while the generation step owns the line.
177
- */
178
- pluginLines: [],
179
- phase: null,
180
- groupOpen: false
181
- };
182
- function text(message) {
183
- return formatMessage(message, logLevel$2);
184
- }
185
- function startSpinner(message) {
186
- if (silent) return;
187
- state.spinner = writer.spinner();
188
- state.spinner.start(text(message));
189
- }
190
- function stopSpinner(message, status = "success") {
191
- const spinner = state.spinner;
192
- if (!spinner) return;
193
- state.spinner = null;
194
- if (message === void 0) {
195
- spinner.clear();
196
- return;
197
- }
198
- if (status === "failed") {
199
- spinner.error(text(message));
200
- return;
201
- }
202
- spinner.stop(text(message));
203
- }
204
- function stopProgress(message) {
205
- const progress = state.progress;
206
- if (!progress) return;
207
- state.progress = null;
208
- progress.stop(message === void 0 ? "" : text(message));
209
- }
210
- function startPhase({ running, success, failure, showHookResults = false }) {
211
- state.phase = {
212
- successLabel: success,
213
- failureLabel: failure,
214
- showHookResults,
215
- failed: false,
216
- hrStart: process.hrtime(),
217
- lines: [],
218
- output: []
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
- context.hook("kubb:info", ({ message, info }) => {
252
- if (silent) return;
253
- const line = text([
254
- styleText("blue", "ℹ"),
255
- message,
256
- info ? styleText("dim", info) : void 0
257
- ].filter(Boolean).join(" "));
258
- if (state.phase) {
259
- state.phase.lines.push(line);
260
- return;
261
- }
262
- if (state.spinner) {
263
- state.spinner.message(line);
264
- return;
265
- }
266
- writer.info(line);
267
- });
268
- context.hook("kubb:success", ({ message, info }) => {
269
- if (silent) return;
270
- const line = text([
271
- styleText("green", "✓"),
272
- message,
273
- logLevel$2 >= logLevel.info && info ? styleText("dim", info) : void 0
274
- ].filter(Boolean).join(" "));
275
- if (state.spinner) {
276
- state.spinner.message(line);
277
- return;
278
- }
279
- writer.success(line);
280
- });
281
- context.hook("kubb:warn", ({ message, info }) => {
282
- if (logLevel$2 < logLevel.warn) return;
283
- writer.warn(text([
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
- context.hook("kubb:diagnostic", ({ diagnostic }) => {
300
- if (silent && diagnostic.severity !== "error") return;
301
- stopSpinner();
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$2 < logLevel.warn) return;
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$2 < logLevel.warn) return;
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 isGreater(truncate(latest, "patch"), truncate(current, "patch"));
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, pluralize as c, createPlainLogger as d, FORMATTER_PREFERENCE as f, linters as g, formatters as h, runHook as i, selectReporters as l, detectTool as m, getConfigs as n, startUrlWatcher as o, LINTER_PREFERENCE as p, isNewerVersion as r, startWatcher as s, fetchUrlBody as t, setupReporters as u };
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-TpILNAy7.js.map
1109
+ //# sourceMappingURL=utils-BYY3_cyq.js.map