@kubb/cli 5.0.0-alpha.9 → 5.0.0-beta.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 (135) hide show
  1. package/README.md +4 -2
  2. package/bin/kubb.js +6 -0
  3. package/dist/{agent-BKphjOIF.cjs → agent-0Nk--lcr.cjs} +5 -5
  4. package/dist/agent-0Nk--lcr.cjs.map +1 -0
  5. package/dist/agent-B_pirbeB.cjs +116 -0
  6. package/dist/agent-B_pirbeB.cjs.map +1 -0
  7. package/dist/{agent-5mmp7QzF.js → agent-DKeVuiUC.js} +5 -5
  8. package/dist/agent-DKeVuiUC.js.map +1 -0
  9. package/dist/agent-Ev5hU5hH.js +112 -0
  10. package/dist/agent-Ev5hU5hH.js.map +1 -0
  11. package/dist/{constants-D0XHAHeZ.cjs → constants-CnDXa1R6.cjs} +30 -60
  12. package/dist/constants-CnDXa1R6.cjs.map +1 -0
  13. package/dist/{constants-DJM9zCXm.js → constants-aL3CP_Wq.js} +23 -59
  14. package/dist/constants-aL3CP_Wq.js.map +1 -0
  15. package/dist/define-Bdn8j5VM.cjs +54 -0
  16. package/dist/define-Bdn8j5VM.cjs.map +1 -0
  17. package/dist/define-Ctii4bel.js +43 -0
  18. package/dist/define-Ctii4bel.js.map +1 -0
  19. package/dist/{errors-DBW0N9w4.cjs → errors-CLCjoSg0.cjs} +22 -6
  20. package/dist/errors-CLCjoSg0.cjs.map +1 -0
  21. package/dist/errors-CjPmyZHy.js +43 -0
  22. package/dist/errors-CjPmyZHy.js.map +1 -0
  23. package/dist/{generate-Rly1EXBN.js → generate-B3PZ6Dp-.js} +3 -3
  24. package/dist/generate-B3PZ6Dp-.js.map +1 -0
  25. package/dist/{generate-Cq5RDTBL.cjs → generate-B3jl4ukb.cjs} +559 -265
  26. package/dist/generate-B3jl4ukb.cjs.map +1 -0
  27. package/dist/{generate-DU5zzc54.cjs → generate-DL_7a7Wd.cjs} +3 -3
  28. package/dist/generate-DL_7a7Wd.cjs.map +1 -0
  29. package/dist/{generate-BHNyeQXl.js → generate-Dt_r0ELY.js} +552 -258
  30. package/dist/generate-Dt_r0ELY.js.map +1 -0
  31. package/dist/index.cjs +40 -18
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.js +40 -18
  34. package/dist/index.js.map +1 -1
  35. package/dist/{init-iN7e1XwI.js → init-Bj94Nvt8.js} +4 -4
  36. package/dist/init-Bj94Nvt8.js.map +1 -0
  37. package/dist/{init-BK6inBTR.cjs → init-CZ5Xq2Hd.cjs} +45 -58
  38. package/dist/init-CZ5Xq2Hd.cjs.map +1 -0
  39. package/dist/{init-CN1JFyGX.cjs → init-CyN1oyTF.cjs} +4 -4
  40. package/dist/init-CyN1oyTF.cjs.map +1 -0
  41. package/dist/{init-BQ6zfsnw.js → init-eNRlotJK.js} +41 -54
  42. package/dist/init-eNRlotJK.js.map +1 -0
  43. package/dist/{mcp-eP1S40LZ.js → mcp-BzW703d7.js} +4 -4
  44. package/dist/{mcp-eP1S40LZ.js.map → mcp-BzW703d7.js.map} +1 -1
  45. package/dist/{mcp-CONmm_xT.cjs → mcp-CLcDV4Jm.cjs} +5 -6
  46. package/dist/mcp-CLcDV4Jm.cjs.map +1 -0
  47. package/dist/{mcp-BiGUvbWP.js → mcp-D7EIR9fR.js} +4 -5
  48. package/dist/mcp-D7EIR9fR.js.map +1 -0
  49. package/dist/{mcp-T7Q4nWbT.cjs → mcp-ZY-ONTOp.cjs} +4 -4
  50. package/dist/{mcp-T7Q4nWbT.cjs.map → mcp-ZY-ONTOp.cjs.map} +1 -1
  51. package/dist/{package-BJ6ionm6.cjs → package-D8wlStAg.cjs} +2 -2
  52. package/dist/package-D8wlStAg.cjs.map +1 -0
  53. package/dist/package-Yo-9_m5C.js +6 -0
  54. package/dist/package-Yo-9_m5C.js.map +1 -0
  55. package/dist/{shell-7HPrTCJ5.cjs → shell-475fQKaX.cjs} +8 -3
  56. package/dist/shell-475fQKaX.cjs.map +1 -0
  57. package/dist/{shell-DqqWsHCD.js → shell-DLzN4fRo.js} +8 -3
  58. package/dist/shell-DLzN4fRo.js.map +1 -0
  59. package/dist/{telemetry-DZ7IrLAU.cjs → telemetry-DN95_2pF.cjs} +50 -8
  60. package/dist/telemetry-DN95_2pF.cjs.map +1 -0
  61. package/dist/{telemetry-BF3SMlH6.js → telemetry-LgT_sdPe.js} +48 -6
  62. package/dist/telemetry-LgT_sdPe.js.map +1 -0
  63. package/dist/{validate-DAZdX_0i.js → validate-Dplr99xO.js} +4 -4
  64. package/dist/validate-Dplr99xO.js.map +1 -0
  65. package/dist/{validate-DucFMytl.cjs → validate-_8mBa63G.cjs} +4 -4
  66. package/dist/validate-_8mBa63G.cjs.map +1 -0
  67. package/dist/{validate-BImbbx1t.js → validate-kLJoT_hi.js} +5 -13
  68. package/dist/validate-kLJoT_hi.js.map +1 -0
  69. package/dist/{validate-ujLCYSWU.cjs → validate-yKKzqEZ5.cjs} +6 -14
  70. package/dist/validate-yKKzqEZ5.cjs.map +1 -0
  71. package/package.json +47 -46
  72. package/src/commands/agent/start.ts +20 -4
  73. package/src/commands/generate.ts +35 -6
  74. package/src/commands/init.ts +6 -1
  75. package/src/commands/validate.ts +6 -1
  76. package/src/constants.ts +19 -38
  77. package/src/index.ts +7 -10
  78. package/src/loggers/clackLogger.ts +54 -46
  79. package/src/loggers/fileSystemLogger.ts +15 -16
  80. package/src/loggers/githubActionsLogger.ts +23 -24
  81. package/src/loggers/plainLogger.ts +22 -23
  82. package/src/runners/agent.ts +81 -34
  83. package/src/runners/generate.ts +90 -100
  84. package/src/runners/init.ts +24 -51
  85. package/src/runners/mcp.ts +17 -4
  86. package/src/runners/validate.ts +19 -15
  87. package/src/utils/executeHooks.ts +15 -15
  88. package/src/utils/flags.ts +1 -2
  89. package/src/utils/getConfig.ts +10 -0
  90. package/src/utils/getCosmiConfig.ts +21 -12
  91. package/src/utils/getSummary.ts +1 -1
  92. package/src/utils/runHook.ts +29 -13
  93. package/src/utils/telemetry.ts +16 -3
  94. package/bin/kubb.cjs +0 -18
  95. package/dist/agent-5mmp7QzF.js.map +0 -1
  96. package/dist/agent-BKphjOIF.cjs.map +0 -1
  97. package/dist/agent-BapvKB4r.cjs +0 -92
  98. package/dist/agent-BapvKB4r.cjs.map +0 -1
  99. package/dist/agent-CBrpIMMU.js +0 -88
  100. package/dist/agent-CBrpIMMU.js.map +0 -1
  101. package/dist/constants-D0XHAHeZ.cjs.map +0 -1
  102. package/dist/constants-DJM9zCXm.js.map +0 -1
  103. package/dist/define--M_JMcDC.js +0 -25
  104. package/dist/define--M_JMcDC.js.map +0 -1
  105. package/dist/define-D6Kfm7-Z.cjs +0 -36
  106. package/dist/define-D6Kfm7-Z.cjs.map +0 -1
  107. package/dist/errors-6mF_WKxg.js +0 -27
  108. package/dist/errors-6mF_WKxg.js.map +0 -1
  109. package/dist/errors-DBW0N9w4.cjs.map +0 -1
  110. package/dist/generate-BHNyeQXl.js.map +0 -1
  111. package/dist/generate-Cq5RDTBL.cjs.map +0 -1
  112. package/dist/generate-DU5zzc54.cjs.map +0 -1
  113. package/dist/generate-Rly1EXBN.js.map +0 -1
  114. package/dist/init-BK6inBTR.cjs.map +0 -1
  115. package/dist/init-BQ6zfsnw.js.map +0 -1
  116. package/dist/init-CN1JFyGX.cjs.map +0 -1
  117. package/dist/init-iN7e1XwI.js.map +0 -1
  118. package/dist/jiti-Cd3S0xwr.cjs +0 -16
  119. package/dist/jiti-Cd3S0xwr.cjs.map +0 -1
  120. package/dist/jiti-e08mD2Ph.js +0 -11
  121. package/dist/jiti-e08mD2Ph.js.map +0 -1
  122. package/dist/mcp-BiGUvbWP.js.map +0 -1
  123. package/dist/mcp-CONmm_xT.cjs.map +0 -1
  124. package/dist/package-BJ6ionm6.cjs.map +0 -1
  125. package/dist/package-BKZ0H3Zf.js +0 -6
  126. package/dist/package-BKZ0H3Zf.js.map +0 -1
  127. package/dist/shell-7HPrTCJ5.cjs.map +0 -1
  128. package/dist/shell-DqqWsHCD.js.map +0 -1
  129. package/dist/telemetry-BF3SMlH6.js.map +0 -1
  130. package/dist/telemetry-DZ7IrLAU.cjs.map +0 -1
  131. package/dist/validate-BImbbx1t.js.map +0 -1
  132. package/dist/validate-DAZdX_0i.js.map +0 -1
  133. package/dist/validate-DucFMytl.cjs.map +0 -1
  134. package/dist/validate-ujLCYSWU.cjs.map +0 -1
  135. package/src/utils/jiti.ts +0 -9
@@ -1,30 +1,38 @@
1
1
  import "./chunk--u3MIqq1.js";
2
- import { n as toCause, r as toError } from "./errors-6mF_WKxg.js";
3
- import { a as canUseTTY, i as executeIfOnline, o as isGitHubActions, r as sendTelemetry, t as buildTelemetryEvent } from "./telemetry-BF3SMlH6.js";
4
- import { n as tokenize } from "./shell-DqqWsHCD.js";
5
- import { t as version } from "./package-BKZ0H3Zf.js";
6
- import { a as WATCHER_IGNORED_PATHS, i as SUMMARY_SEPARATOR, t as KUBB_NPM_PACKAGE_URL } from "./constants-DJM9zCXm.js";
2
+ import { n as toCause, r as toError } from "./errors-CjPmyZHy.js";
3
+ import { a as canUseTTY, i as executeIfOnline, o as isGitHubActions, r as sendTelemetry, t as buildTelemetryEvent } from "./telemetry-LgT_sdPe.js";
4
+ import { n as tokenize } from "./shell-DLzN4fRo.js";
5
+ import { t as version } from "./package-Yo-9_m5C.js";
6
+ import { a as SUMMARY_SEPARATOR, n as KUBB_NPM_PACKAGE_URL, o as WATCHER_IGNORED_PATHS } from "./constants-aL3CP_Wq.js";
7
7
  import { styleText } from "node:util";
8
8
  import { EventEmitter } from "node:events";
9
9
  import { createHash } from "node:crypto";
10
- import "node:fs";
10
+ import { spawn } from "node:child_process";
11
+ import { readdirSync } from "node:fs";
11
12
  import { mkdir, readFile, writeFile } from "node:fs/promises";
12
13
  import path, { dirname, relative, resolve } from "node:path";
13
14
  import process$1 from "node:process";
14
15
  import * as clack from "@clack/prompts";
15
- import { defineLogger, detectFormatter, detectLinter, formatters, getConfigs, isInputPath, linters, logLevel, safeBuild, setup } from "@kubb/core";
16
+ import { createKubb, defineLogger, isInputPath, logLevel } from "@kubb/core";
16
17
  import { NonZeroExitError, x } from "tinyexec";
17
18
  import { Writable } from "node:stream";
18
19
  import { cosmiconfig } from "cosmiconfig";
19
- import { createJiti } from "jiti";
20
+ import { unrun } from "unrun";
20
21
  //#region ../../internals/utils/src/asyncEventEmitter.ts
21
22
  /**
22
- * A typed EventEmitter that awaits all async listeners before resolving.
23
+ * Typed `EventEmitter` that awaits all async listeners before resolving.
23
24
  * Wraps Node's `EventEmitter` with full TypeScript event-map inference.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * const emitter = new AsyncEventEmitter<{ build: [name: string] }>()
29
+ * emitter.on('build', async (name) => { console.log(name) })
30
+ * await emitter.emit('build', 'petstore') // all listeners awaited
31
+ * ```
24
32
  */
25
33
  var AsyncEventEmitter = class {
26
34
  /**
27
- * `maxListener` controls the maximum number of listeners per event before Node emits a memory-leak warning.
35
+ * Maximum number of listeners per event before Node emits a memory-leak warning.
28
36
  * @default 10
29
37
  */
30
38
  constructor(maxListener = 10) {
@@ -32,31 +40,48 @@ var AsyncEventEmitter = class {
32
40
  }
33
41
  #emitter = new EventEmitter();
34
42
  /**
35
- * Emits an event and awaits all registered listeners in parallel.
43
+ * Emits `eventName` and awaits all registered listeners sequentially.
36
44
  * Throws if any listener rejects, wrapping the cause with the event name and serialized arguments.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * await emitter.emit('build', 'petstore')
49
+ * ```
37
50
  */
38
51
  async emit(eventName, ...eventArgs) {
39
52
  const listeners = this.#emitter.listeners(eventName);
40
53
  if (listeners.length === 0) return;
41
- await Promise.all(listeners.map(async (listener) => {
54
+ for (const listener of listeners) try {
55
+ await listener(...eventArgs);
56
+ } catch (err) {
57
+ let serializedArgs;
42
58
  try {
43
- return await listener(...eventArgs);
44
- } catch (err) {
45
- let serializedArgs;
46
- try {
47
- serializedArgs = JSON.stringify(eventArgs);
48
- } catch {
49
- serializedArgs = String(eventArgs);
50
- }
51
- throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: toError(err) });
59
+ serializedArgs = JSON.stringify(eventArgs);
60
+ } catch {
61
+ serializedArgs = String(eventArgs);
52
62
  }
53
- }));
63
+ throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: toError(err) });
64
+ }
54
65
  }
55
- /** Registers a persistent listener for the given event. */
66
+ /**
67
+ * Registers a persistent listener for `eventName`.
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * emitter.on('build', async (name) => { console.log(name) })
72
+ * ```
73
+ */
56
74
  on(eventName, handler) {
57
75
  this.#emitter.on(eventName, handler);
58
76
  }
59
- /** Registers a one-shot listener that removes itself after the first invocation. */
77
+ /**
78
+ * Registers a one-shot listener that removes itself after the first invocation.
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * emitter.onOnce('build', async (name) => { console.log(name) })
83
+ * ```
84
+ */
60
85
  onOnce(eventName, handler) {
61
86
  const wrapper = (...args) => {
62
87
  this.off(eventName, wrapper);
@@ -64,11 +89,37 @@ var AsyncEventEmitter = class {
64
89
  };
65
90
  this.on(eventName, wrapper);
66
91
  }
67
- /** Removes a previously registered listener. */
92
+ /**
93
+ * Removes a previously registered listener.
94
+ *
95
+ * @example
96
+ * ```ts
97
+ * emitter.off('build', handler)
98
+ * ```
99
+ */
68
100
  off(eventName, handler) {
69
101
  this.#emitter.off(eventName, handler);
70
102
  }
71
- /** Removes all listeners from every event channel. */
103
+ /**
104
+ * Returns the number of listeners registered for `eventName`.
105
+ *
106
+ * @example
107
+ * ```ts
108
+ * emitter.on('build', handler)
109
+ * emitter.listenerCount('build') // 1
110
+ * ```
111
+ */
112
+ listenerCount(eventName) {
113
+ return this.#emitter.listenerCount(eventName);
114
+ }
115
+ /**
116
+ * Removes all listeners from every event channel.
117
+ *
118
+ * @example
119
+ * ```ts
120
+ * emitter.removeAll()
121
+ * ```
122
+ */
72
123
  removeAll() {
73
124
  this.#emitter.removeAllListeners();
74
125
  }
@@ -76,8 +127,15 @@ var AsyncEventEmitter = class {
76
127
  //#endregion
77
128
  //#region ../../internals/utils/src/time.ts
78
129
  /**
79
- * Calculates elapsed time in milliseconds from a high-resolution start time.
80
- * Rounds to 2 decimal places to provide sub-millisecond precision without noise.
130
+ * Calculates elapsed time in milliseconds from a high-resolution `process.hrtime` start time.
131
+ * Rounds to 2 decimal places for sub-millisecond precision without noise.
132
+ *
133
+ * @example
134
+ * ```ts
135
+ * const start = process.hrtime()
136
+ * doWork()
137
+ * getElapsedMs(start) // 42.35
138
+ * ```
81
139
  */
82
140
  function getElapsedMs(hrStart) {
83
141
  const [seconds, nanoseconds] = process.hrtime(hrStart);
@@ -85,8 +143,14 @@ function getElapsedMs(hrStart) {
85
143
  return Math.round(ms * 100) / 100;
86
144
  }
87
145
  /**
88
- * Converts a millisecond duration into a human-readable string.
89
- * Adjusts units (ms, s, m s) based on the magnitude of the duration.
146
+ * Converts a millisecond duration into a human-readable string (`ms`, `s`, or `m s`).
147
+ *
148
+ * @example
149
+ * ```ts
150
+ * formatMs(250) // '250ms'
151
+ * formatMs(1500) // '1.50s'
152
+ * formatMs(90000) // '1m 30.0s'
153
+ * ```
90
154
  */
91
155
  function formatMs(ms) {
92
156
  if (ms >= 6e4) return `${Math.floor(ms / 6e4)}m ${(ms % 6e4 / 1e3).toFixed(1)}s`;
@@ -94,7 +158,14 @@ function formatMs(ms) {
94
158
  return `${Math.round(ms)}ms`;
95
159
  }
96
160
  /**
97
- * Convenience helper: formats the elapsed time since `hrStart` in one step.
161
+ * Formats the elapsed time since `hrStart` as a human-readable string.
162
+ *
163
+ * @example
164
+ * ```ts
165
+ * const start = process.hrtime()
166
+ * doWork()
167
+ * formatHrtime(start) // '1.50s'
168
+ * ```
98
169
  */
99
170
  function formatHrtime(hrStart) {
100
171
  return formatMs(getElapsedMs(hrStart));
@@ -136,18 +207,46 @@ function gradient(colorStops, text) {
136
207
  return `\x1b[38;2;${Math.round(from.r + (to.r - from.r) * lt)};${Math.round(from.g + (to.g - from.g) * lt)};${Math.round(from.b + (to.b - from.b) * lt)}m${char}\x1b[0m`;
137
208
  }).join("");
138
209
  }
139
- /** ANSI color functions for each part of the Kubb mascot illustration. */
210
+ /**
211
+ * ANSI color functions for each part of the Kubb mascot illustration.
212
+ */
140
213
  const palette = {
214
+ /**
215
+ * Top cap of the skittle.
216
+ */
141
217
  lid: hex("#F55A17"),
218
+ /**
219
+ * Upper wood body.
220
+ */
142
221
  woodTop: hex("#F5A217"),
222
+ /**
223
+ * Middle wood body.
224
+ */
143
225
  woodMid: hex("#F58517"),
226
+ /**
227
+ * Base wood body.
228
+ */
144
229
  woodBase: hex("#B45309"),
230
+ /**
231
+ * Eye whites.
232
+ */
145
233
  eye: hex("#FFFFFF"),
234
+ /**
235
+ * Highlight accent.
236
+ */
146
237
  highlight: hex("#adadc6"),
238
+ /**
239
+ * Cheek blush.
240
+ */
147
241
  blush: hex("#FDA4AF")
148
242
  };
149
243
  /**
150
- * Generates the Kubb mascot welcome banner.
244
+ * Generates the Kubb mascot welcome banner as an ANSI-colored string.
245
+ *
246
+ * @example
247
+ * ```ts
248
+ * console.log(getIntro({ title: 'kubb.config.ts', description: 'generating…', version: '5.0.0', areEyesOpen: true }))
249
+ * ```
151
250
  */
152
251
  function getIntro({ title, description, version, areEyesOpen }) {
153
252
  const kubbVersion = gradient([
@@ -165,7 +264,9 @@ function getIntro({ title, description, version, areEyesOpen }) {
165
264
  ${palette.woodBase("▀▀▀▀▀▀▀▀▀▀▀▀▀")}
166
265
  `;
167
266
  }
168
- /** ANSI color names available for terminal output. */
267
+ /**
268
+ * ANSI color names used by {@link randomCliColor} for deterministic terminal coloring.
269
+ */
169
270
  const randomColors = [
170
271
  "black",
171
272
  "red",
@@ -178,15 +279,27 @@ const randomColors = [
178
279
  "gray"
179
280
  ];
180
281
  /**
181
- * Returns the text wrapped in a deterministic ANSI color derived from the text's SHA-256 hash.
282
+ * Wraps `text` in a deterministic ANSI color derived from the text's SHA-256 hash.
283
+ *
284
+ * @example
285
+ * ```ts
286
+ * randomCliColor('petstore') // '\x1b[33m' + 'petstore' + '\x1b[39m' (always the same color for 'petstore')
287
+ * ```
182
288
  */
183
289
  function randomCliColor(text) {
184
290
  if (!text) return "";
185
291
  return styleText(randomColors[createHash("sha256").update(text).digest().readUInt32BE(0) % randomColors.length] ?? "white", text);
186
292
  }
187
293
  /**
188
- * Formats a millisecond duration with an ANSI color based on thresholds:
189
- * green 500 ms · yellow 1 000 ms · red > 1 000 ms
294
+ * Formats a millisecond duration with a threshold-based ANSI color.
295
+ * `≤ 500 ms` → green · `≤ 1 000 ms` → yellow · `> 1 000 ms` → red.
296
+ *
297
+ * @example
298
+ * ```ts
299
+ * formatMsWithColor(200) // '\x1b[32m200ms\x1b[39m'
300
+ * formatMsWithColor(800) // '\x1b[33m800ms\x1b[39m'
301
+ * formatMsWithColor(1500) // '\x1b[31m1.50s\x1b[39m'
302
+ * ```
190
303
  */
191
304
  function formatMsWithColor(ms) {
192
305
  const formatted = formatMs(ms);
@@ -195,27 +308,96 @@ function formatMsWithColor(ms) {
195
308
  return styleText("red", formatted);
196
309
  }
197
310
  //#endregion
311
+ //#region ../../internals/utils/src/formatters.ts
312
+ /**
313
+ * CLI command descriptors for each supported code formatter.
314
+ *
315
+ * Each entry contains the executable `command`, an `args` factory that maps an
316
+ * output path to the correct argument list, and an `errorMessage` shown when
317
+ * the formatter is not found.
318
+ */
319
+ const formatters = {
320
+ prettier: {
321
+ command: "prettier",
322
+ args: (outputPath) => [
323
+ "--ignore-unknown",
324
+ "--write",
325
+ outputPath
326
+ ],
327
+ errorMessage: "Prettier not found"
328
+ },
329
+ biome: {
330
+ command: "biome",
331
+ args: (outputPath) => [
332
+ "format",
333
+ "--write",
334
+ outputPath
335
+ ],
336
+ errorMessage: "Biome not found"
337
+ },
338
+ oxfmt: {
339
+ command: "oxfmt",
340
+ args: (outputPath) => [outputPath],
341
+ errorMessage: "Oxfmt not found"
342
+ }
343
+ };
344
+ async function isFormatterAvailable(formatter) {
345
+ return new Promise((resolve) => {
346
+ const child = spawn(formatter, ["--version"], { stdio: "ignore" });
347
+ child.on("close", (code) => resolve(code === 0));
348
+ child.on("error", () => resolve(false));
349
+ });
350
+ }
351
+ /**
352
+ * Detects the first available code formatter on the current system.
353
+ *
354
+ * - Checks in preference order: `oxfmt`, `biome`, `prettier`.
355
+ * - Returns `null` when none are found.
356
+ *
357
+ * @example
358
+ * ```ts
359
+ * const formatter = await detectFormatter()
360
+ * if (formatter) {
361
+ * console.log(`Using ${formatter} for formatting`)
362
+ * }
363
+ * ```
364
+ */
365
+ async function detectFormatter() {
366
+ const formatterNames = new Set([
367
+ "oxfmt",
368
+ "biome",
369
+ "prettier"
370
+ ]);
371
+ for (const formatter of formatterNames) if (await isFormatterAvailable(formatter)) return formatter;
372
+ return null;
373
+ }
374
+ //#endregion
198
375
  //#region ../../internals/utils/src/fs.ts
199
376
  /**
200
377
  * Writes `data` to `path`, trimming leading/trailing whitespace before saving.
201
- * Skips the write and returns `undefined` when the trimmed content is empty or
202
- * identical to what is already on disk.
378
+ * Skips the write when the trimmed content is empty or identical to what is already on disk.
203
379
  * Creates any missing parent directories automatically.
204
- * When `sanity` is `true`, re-reads the file after writing and throws if the
205
- * content does not match.
380
+ * When `sanity` is `true`, re-reads the file after writing and throws if the content does not match.
381
+ *
382
+ * @example
383
+ * ```ts
384
+ * await write('./src/Pet.ts', source) // writes and returns trimmed content
385
+ * await write('./src/Pet.ts', source) // null — file unchanged
386
+ * await write('./src/Pet.ts', ' ') // null — empty content skipped
387
+ * ```
206
388
  */
207
389
  async function write(path, data, options = {}) {
208
390
  const trimmed = data.trim();
209
- if (trimmed === "") return void 0;
391
+ if (trimmed === "") return null;
210
392
  const resolved = resolve(path);
211
393
  if (typeof Bun !== "undefined") {
212
394
  const file = Bun.file(resolved);
213
- if ((await file.exists() ? await file.text() : null) === trimmed) return void 0;
395
+ if ((await file.exists() ? await file.text() : null) === trimmed) return null;
214
396
  await Bun.write(resolved, trimmed);
215
397
  return trimmed;
216
398
  }
217
399
  try {
218
- if (await readFile(resolved, { encoding: "utf-8" }) === trimmed) return void 0;
400
+ if (await readFile(resolved, { encoding: "utf-8" }) === trimmed) return null;
219
401
  } catch {}
220
402
  await mkdir(dirname(resolved), { recursive: true });
221
403
  await writeFile(resolved, trimmed, { encoding: "utf-8" });
@@ -227,6 +409,83 @@ async function write(path, data, options = {}) {
227
409
  return trimmed;
228
410
  }
229
411
  //#endregion
412
+ //#region ../../internals/utils/src/linters.ts
413
+ /**
414
+ * Collects all files under `dir` recursively using Node's built-in fs APIs.
415
+ *
416
+ * Passing explicit file paths to oxlint (instead of a directory) bypasses
417
+ * oxlint's `.gitignore`-aware directory traversal, which would otherwise skip
418
+ * files that are listed in `.gitignore` (e.g. generated output directories).
419
+ */
420
+ function findLintableFiles(dir) {
421
+ try {
422
+ return readdirSync(dir, {
423
+ withFileTypes: true,
424
+ recursive: true
425
+ }).filter((d) => d.isFile()).map((d) => `${d.parentPath}/${d.name}`);
426
+ } catch {
427
+ return [];
428
+ }
429
+ }
430
+ /**
431
+ * CLI command descriptors for each supported linter.
432
+ *
433
+ * Each entry contains the executable `command`, an `args` factory that maps an
434
+ * output path to the correct argument list, and an `errorMessage` shown when
435
+ * the linter is not found.
436
+ */
437
+ const linters = {
438
+ eslint: {
439
+ command: "eslint",
440
+ args: (outputPath) => [outputPath, "--fix"],
441
+ errorMessage: "Eslint not found"
442
+ },
443
+ biome: {
444
+ command: "biome",
445
+ args: (outputPath) => [
446
+ "lint",
447
+ "--fix",
448
+ outputPath
449
+ ],
450
+ errorMessage: "Biome not found"
451
+ },
452
+ oxlint: {
453
+ command: "oxlint",
454
+ args: (outputPath) => ["--fix", ...findLintableFiles(outputPath)],
455
+ errorMessage: "Oxlint not found"
456
+ }
457
+ };
458
+ async function isLinterAvailable(linter) {
459
+ return new Promise((resolve) => {
460
+ const child = spawn(linter, ["--version"], { stdio: "ignore" });
461
+ child.on("close", (code) => resolve(code === 0));
462
+ child.on("error", () => resolve(false));
463
+ });
464
+ }
465
+ /**
466
+ * Detects the first available linter on the current system.
467
+ *
468
+ * - Checks in preference order: `oxlint`, `biome`, `eslint`.
469
+ * - Returns `null` when none are found.
470
+ *
471
+ * @example
472
+ * ```ts
473
+ * const linter = await detectLinter()
474
+ * if (linter) {
475
+ * console.log(`Using ${linter} for linting`)
476
+ * }
477
+ * ```
478
+ */
479
+ async function detectLinter() {
480
+ const linterNames = new Set([
481
+ "oxlint",
482
+ "biome",
483
+ "eslint"
484
+ ]);
485
+ for (const linter of linterNames) if (await isLinterAvailable(linter)) return linter;
486
+ return null;
487
+ }
488
+ //#endregion
230
489
  //#region src/utils/getSummary.ts
231
490
  function getSummary({ failedPlugins, filesCreated, status, hrStart, config, pluginTimings }) {
232
491
  const duration = formatHrtime(hrStart);
@@ -237,7 +496,7 @@ function getSummary({ failedPlugins, filesCreated, status, hrStart, config, plug
237
496
  pluginsFailed: status === "failed" ? [...failedPlugins].map(({ plugin }) => randomCliColor(plugin.name)).join(", ") : void 0,
238
497
  filesCreated,
239
498
  time: styleText("green", duration),
240
- output: path.isAbsolute(config.root) ? path.resolve(config.root, config.output.path) : config.root
499
+ output: path.resolve(config.root, config.output.path)
241
500
  };
242
501
  const labels = {
243
502
  plugins: "Plugins:",
@@ -267,23 +526,21 @@ function getSummary({ failedPlugins, filesCreated, status, hrStart, config, plug
267
526
  //#endregion
268
527
  //#region src/utils/runHook.ts
269
528
  /**
270
- * Execute a hook command, emit debug/hook:end events, and forward output to
271
- * an optional HookOutputSink. All three logger adapters share this function
272
- * so the process-spawning logic lives in exactly one place.
529
+ * Executes a hook command, emits debug and completion events, and forwards output to an optional sink.
273
530
  */
274
531
  async function runHook({ id, command, args, commandWithArgs, context, stream = false, sink }) {
275
532
  try {
276
533
  const proc = x(command, [...args ?? []], {
277
- nodeOptions: { detached: true },
534
+ nodeOptions: { detached: process.platform !== "win32" },
278
535
  throwOnError: true
279
536
  });
280
537
  if (stream && sink?.onLine) for await (const line of proc) sink.onLine(line);
281
538
  const result = await proc;
282
- await context.emit("debug", {
539
+ await context.emit("kubb:debug", {
283
540
  date: /* @__PURE__ */ new Date(),
284
541
  logs: [result.stdout.trimEnd()]
285
542
  });
286
- await context.emit("hook:end", {
543
+ await context.emit("kubb:hook:end", {
287
544
  command,
288
545
  args,
289
546
  id,
@@ -292,33 +549,33 @@ async function runHook({ id, command, args, commandWithArgs, context, stream = f
292
549
  });
293
550
  } catch (err) {
294
551
  if (!(err instanceof NonZeroExitError)) {
295
- await context.emit("hook:end", {
552
+ await context.emit("kubb:hook:end", {
296
553
  command,
297
554
  args,
298
555
  id,
299
556
  success: false,
300
557
  error: toError(err)
301
558
  });
302
- await context.emit("error", toError(err));
559
+ await context.emit("kubb:error", { error: toError(err) });
303
560
  return;
304
561
  }
305
562
  const stderr = err.output?.stderr ?? "";
306
563
  const stdout = err.output?.stdout ?? "";
307
- await context.emit("debug", {
564
+ await context.emit("kubb:debug", {
308
565
  date: /* @__PURE__ */ new Date(),
309
566
  logs: [stdout, stderr].filter(Boolean)
310
567
  });
311
568
  if (stderr) sink?.onStderr?.(stderr);
312
569
  if (stdout) sink?.onStdout?.(stdout);
313
570
  const errorMessage = /* @__PURE__ */ new Error(`Hook execute failed: ${commandWithArgs}`);
314
- await context.emit("hook:end", {
571
+ await context.emit("kubb:hook:end", {
315
572
  command,
316
573
  args,
317
574
  id,
318
575
  success: false,
319
576
  error: errorMessage
320
577
  });
321
- await context.emit("error", errorMessage);
578
+ await context.emit("kubb:error", { error: errorMessage });
322
579
  }
323
580
  }
324
581
  //#endregion
@@ -337,8 +594,7 @@ var ClackWritable = class extends Writable {
337
594
  //#endregion
338
595
  //#region src/loggers/clackLogger.ts
339
596
  /**
340
- * Clack adapter for local TTY environments
341
- * Provides a beautiful CLI UI with flat structure inspired by Claude's CLI patterns
597
+ * TTY logger with beautiful UI and progress indicators for local development.
342
598
  */
343
599
  const clackLogger = defineLogger({
344
600
  name: "clack",
@@ -386,7 +642,7 @@ const clackLogger = defineLogger({
386
642
  state.spinner.stop(text);
387
643
  state.isSpinning = false;
388
644
  }
389
- context.on("info", (message, info = "") => {
645
+ context.on("kubb:info", ({ message, info = "" }) => {
390
646
  if (logLevel$8 <= logLevel.silent) return;
391
647
  const text = getMessage([
392
648
  styleText("blue", "ℹ"),
@@ -396,7 +652,7 @@ const clackLogger = defineLogger({
396
652
  if (state.isSpinning) state.spinner.message(text);
397
653
  else clack.log.info(text);
398
654
  });
399
- context.on("success", (message, info = "") => {
655
+ context.on("kubb:success", ({ message, info = "" }) => {
400
656
  if (logLevel$8 <= logLevel.silent) return;
401
657
  const text = getMessage([
402
658
  styleText("blue", "✓"),
@@ -406,7 +662,7 @@ const clackLogger = defineLogger({
406
662
  if (state.isSpinning) stopSpinner(text);
407
663
  else clack.log.success(text);
408
664
  });
409
- context.on("warn", (message, info) => {
665
+ context.on("kubb:warn", ({ message, info }) => {
410
666
  if (logLevel$8 < logLevel.warn) return;
411
667
  const text = getMessage([
412
668
  styleText("yellow", "⚠"),
@@ -415,7 +671,7 @@ const clackLogger = defineLogger({
415
671
  ].filter(Boolean).join(" "));
416
672
  clack.log.warn(text);
417
673
  });
418
- context.on("error", (error) => {
674
+ context.on("kubb:error", ({ error }) => {
419
675
  const caused = toCause(error);
420
676
  const text = [styleText("red", "✗"), error.message].join(" ");
421
677
  if (state.isSpinning) stopSpinner(getMessage(text));
@@ -430,19 +686,24 @@ const clackLogger = defineLogger({
430
686
  }
431
687
  }
432
688
  });
433
- context.on("version:new", (version, latestVersion) => {
689
+ context.on("kubb:version:new", ({ currentVersion, latestVersion }) => {
434
690
  if (logLevel$8 <= logLevel.silent) return;
435
- clack.box(`\`v${version}\` → \`v${latestVersion}\`
691
+ try {
692
+ clack.box(`\`v${currentVersion}\` → \`v${latestVersion}\`
436
693
  Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
437
- width: "auto",
438
- formatBorder: (s) => styleText("yellow", s),
439
- rounded: true,
440
- withGuide: false,
441
- contentAlign: "center",
442
- titleAlign: "center"
443
- });
694
+ width: "auto",
695
+ formatBorder: (s) => styleText("yellow", s),
696
+ rounded: true,
697
+ withGuide: false,
698
+ contentAlign: "center",
699
+ titleAlign: "center"
700
+ });
701
+ } catch {
702
+ console.log(`Update available for Kubb: v${currentVersion} → v${latestVersion}`);
703
+ console.log("Run `npm install -g @kubb/cli` to update");
704
+ }
444
705
  });
445
- context.on("lifecycle:start", async (version) => {
706
+ context.on("kubb:lifecycle:start", async ({ version }) => {
446
707
  console.log(`\n${getIntro({
447
708
  title: "The ultimate toolkit for working with APIs",
448
709
  description: "Ready to start",
@@ -451,24 +712,24 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
451
712
  })}\n`);
452
713
  reset();
453
714
  });
454
- context.on("config:start", () => {
715
+ context.on("kubb:config:start", () => {
455
716
  if (logLevel$8 <= logLevel.silent) return;
456
717
  const text = getMessage("Configuration started");
457
718
  clack.intro(text);
458
719
  startSpinner(getMessage("Configuration loading"));
459
720
  });
460
- context.on("config:end", (_configs) => {
721
+ context.on("kubb:config:end", () => {
461
722
  if (logLevel$8 <= logLevel.silent) return;
462
723
  const text = getMessage("Configuration completed");
463
724
  clack.outro(text);
464
725
  });
465
- context.on("generation:start", (config) => {
726
+ context.on("kubb:generation:start", ({ config }) => {
466
727
  reset();
467
728
  state.totalPlugins = config.plugins?.length ?? 0;
468
729
  const text = getMessage(["Generation started", config.name ? `for ${styleText("dim", config.name)}` : void 0].filter(Boolean).join(" "));
469
730
  clack.intro(text);
470
731
  });
471
- context.on("plugin:start", (plugin) => {
732
+ context.on("kubb:plugin:start", ({ plugin }) => {
472
733
  if (logLevel$8 <= logLevel.silent) return;
473
734
  stopSpinner();
474
735
  const progressBar = clack.progress({
@@ -486,7 +747,7 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
486
747
  interval
487
748
  });
488
749
  });
489
- context.on("plugin:end", (plugin, { duration, success }) => {
750
+ context.on("kubb:plugin:end", ({ plugin, duration, success }) => {
490
751
  stopSpinner();
491
752
  const active = state.activeProgress.get(plugin.name);
492
753
  if (!active || logLevel$8 === logLevel.silent) return;
@@ -499,7 +760,7 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
499
760
  state.activeProgress.delete(plugin.name);
500
761
  showProgressStep();
501
762
  });
502
- context.on("files:processing:start", (files) => {
763
+ context.on("kubb:files:processing:start", ({ files }) => {
503
764
  if (logLevel$8 <= logLevel.silent) return;
504
765
  stopSpinner();
505
766
  state.totalFiles = files.length;
@@ -510,11 +771,11 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
510
771
  max: files.length,
511
772
  size: 30
512
773
  });
513
- context.emit("info", text);
774
+ context.emit("kubb:info", { message: text });
514
775
  progressBar.start(getMessage(text));
515
776
  state.activeProgress.set("files", { progressBar });
516
777
  });
517
- context.on("file:processing:update", ({ file, config }) => {
778
+ context.on("kubb:file:processing:update", ({ file, config }) => {
518
779
  if (logLevel$8 <= logLevel.silent) return;
519
780
  stopSpinner();
520
781
  state.processedFiles++;
@@ -523,7 +784,7 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
523
784
  if (!active) return;
524
785
  active.progressBar.advance(void 0, text);
525
786
  });
526
- context.on("files:processing:end", () => {
787
+ context.on("kubb:files:processing:end", () => {
527
788
  if (logLevel$8 <= logLevel.silent) return;
528
789
  stopSpinner();
529
790
  const text = getMessage("Files written successfully");
@@ -533,31 +794,31 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
533
794
  state.activeProgress.delete("files");
534
795
  showProgressStep();
535
796
  });
536
- context.on("generation:end", (config) => {
797
+ context.on("kubb:generation:end", ({ config }) => {
537
798
  const text = getMessage(config.name ? `Generation completed for ${styleText("dim", config.name)}` : "Generation completed");
538
799
  clack.outro(text);
539
800
  });
540
- context.on("format:start", () => {
801
+ context.on("kubb:format:start", () => {
541
802
  if (logLevel$8 <= logLevel.silent) return;
542
803
  const text = getMessage("Format started");
543
804
  clack.intro(text);
544
805
  });
545
- context.on("format:end", () => {
806
+ context.on("kubb:format:end", () => {
546
807
  if (logLevel$8 <= logLevel.silent) return;
547
808
  const text = getMessage("Format completed");
548
809
  clack.outro(text);
549
810
  });
550
- context.on("lint:start", () => {
811
+ context.on("kubb:lint:start", () => {
551
812
  if (logLevel$8 <= logLevel.silent) return;
552
813
  const text = getMessage("Lint started");
553
814
  clack.intro(text);
554
815
  });
555
- context.on("lint:end", () => {
816
+ context.on("kubb:lint:end", () => {
556
817
  if (logLevel$8 <= logLevel.silent) return;
557
818
  const text = getMessage("Lint completed");
558
819
  clack.outro(text);
559
820
  });
560
- context.on("hook:start", async ({ id, command, args }) => {
821
+ context.on("kubb:hook:start", async ({ id, command, args }) => {
561
822
  const commandWithArgs = formatCommandWithArgs(command, args);
562
823
  const text = getMessage(`Hook ${styleText("dim", commandWithArgs)} started`);
563
824
  if (!id) return;
@@ -592,12 +853,12 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
592
853
  }
593
854
  });
594
855
  });
595
- context.on("hook:end", ({ command, args }) => {
856
+ context.on("kubb:hook:end", ({ command, args }) => {
596
857
  if (logLevel$8 <= logLevel.silent) return;
597
858
  const text = getMessage(`Hook ${styleText("dim", formatCommandWithArgs(command, args))} successfully executed`);
598
859
  clack.outro(text);
599
860
  });
600
- context.on("generation:summary", (config, { pluginTimings, failedPlugins, filesCreated, status, hrStart }) => {
861
+ context.on("kubb:generation:summary", ({ config, pluginTimings, failedPlugins, filesCreated, status, hrStart }) => {
601
862
  const summary = getSummary({
602
863
  failedPlugins,
603
864
  filesCreated,
@@ -610,16 +871,20 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
610
871
  summary.unshift("\n");
611
872
  summary.push("\n");
612
873
  const borderColor = status === "success" ? "green" : "red";
613
- clack.box(summary.join("\n"), getMessage(title), {
614
- width: "auto",
615
- formatBorder: (s) => styleText(borderColor, s),
616
- rounded: true,
617
- withGuide: false,
618
- contentAlign: "left",
619
- titleAlign: "center"
620
- });
874
+ try {
875
+ clack.box(summary.join("\n"), getMessage(title), {
876
+ width: "auto",
877
+ formatBorder: (s) => styleText(borderColor, s),
878
+ rounded: true,
879
+ withGuide: false,
880
+ contentAlign: "left",
881
+ titleAlign: "center"
882
+ });
883
+ } catch {
884
+ console.log(summary.join("\n"));
885
+ }
621
886
  });
622
- context.on("lifecycle:end", () => {
887
+ context.on("kubb:lifecycle:end", () => {
623
888
  reset();
624
889
  });
625
890
  }
@@ -627,11 +892,8 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
627
892
  //#endregion
628
893
  //#region src/loggers/fileSystemLogger.ts
629
894
  /**
630
- * FileSystem logger for debug log persistence
631
- * Captures debug and verbose events and writes them to files in .kubb directory
632
- *
633
- * Note: Logs are written on lifecycle:end or process exit. If the process crashes
634
- * before these events, some cached logs may be lost.
895
+ * FileSystem logger that captures debug events and writes them to `.kubb` directory files.
896
+ * Note: Logs write on `lifecycle:end` or process exit. Cached logs may be lost if the process crashes before these events.
635
897
  */
636
898
  const fileSystemLogger = defineLogger({
637
899
  name: "filesystem",
@@ -660,63 +922,66 @@ const fileSystemLogger = defineLogger({
660
922
  files[pathName].push(`[${timestamp}]\n${log.logs.join("\n")}`);
661
923
  }
662
924
  }
663
- await Promise.all(Object.entries(files).map(([fileName, logs]) => write(fileName, logs.join("\n\n"))));
925
+ for (const [fileName, logs] of Object.entries(files)) await write(fileName, logs.join("\n\n"));
664
926
  return Object.keys(files);
665
927
  }
666
- context.on("info", (message, info) => {
928
+ context.on("kubb:info", ({ message, info }) => {
667
929
  state.cachedLogs.add({
668
930
  date: /* @__PURE__ */ new Date(),
669
931
  logs: [`ℹ ${message} ${info}`]
670
932
  });
671
933
  });
672
- context.on("success", (message, info) => {
934
+ context.on("kubb:success", ({ message, info }) => {
673
935
  state.cachedLogs.add({
674
936
  date: /* @__PURE__ */ new Date(),
675
937
  logs: [`✓ ${message} ${info}`]
676
938
  });
677
939
  });
678
- context.on("warn", (message, info) => {
940
+ context.on("kubb:warn", ({ message, info }) => {
679
941
  state.cachedLogs.add({
680
942
  date: /* @__PURE__ */ new Date(),
681
943
  logs: [`⚠ ${message} ${info}`]
682
944
  });
683
945
  });
684
- context.on("error", (error) => {
946
+ context.on("kubb:error", ({ error }) => {
685
947
  state.cachedLogs.add({
686
948
  date: /* @__PURE__ */ new Date(),
687
949
  logs: [`✗ ${error.message}`, error.stack || "unknown stack"]
688
950
  });
689
951
  });
690
- context.on("debug", (message) => {
952
+ context.on("kubb:debug", (message) => {
691
953
  state.cachedLogs.add({
692
954
  date: /* @__PURE__ */ new Date(),
693
955
  logs: message.logs
694
956
  });
695
957
  });
696
- context.on("plugin:start", (plugin) => {
958
+ context.on("kubb:plugin:start", ({ plugin }) => {
697
959
  state.cachedLogs.add({
698
960
  date: /* @__PURE__ */ new Date(),
699
961
  logs: [`Generating ${plugin.name}`]
700
962
  });
701
963
  });
702
- context.on("plugin:end", (plugin, { duration, success }) => {
964
+ context.on("kubb:plugin:end", ({ plugin, duration, success }) => {
703
965
  const durationStr = formatMs(duration);
704
966
  state.cachedLogs.add({
705
967
  date: /* @__PURE__ */ new Date(),
706
968
  logs: [success ? `${plugin.name} completed in ${durationStr}` : `${plugin.name} failed in ${durationStr}`]
707
969
  });
708
970
  });
709
- context.on("files:processing:start", (files) => {
971
+ context.on("kubb:files:processing:start", ({ files }) => {
710
972
  state.cachedLogs.add({
711
973
  date: /* @__PURE__ */ new Date(),
712
974
  logs: [`Start ${files.length} writing:`, ...files.map((file) => file.path)]
713
975
  });
714
976
  });
715
- context.on("generation:end", async (config) => {
977
+ context.on("kubb:generation:end", async ({ config }) => {
716
978
  const writtenFilePaths = await writeLogs(config.name);
717
979
  if (writtenFilePaths.length > 0) {
718
980
  const files = writtenFilePaths.map((f) => relative(process$1.cwd(), f));
719
- await context.emit("info", "Debug files written to:", files.join(", "));
981
+ await context.emit("kubb:info", {
982
+ message: "Debug files written to:",
983
+ info: files.join(", ")
984
+ });
720
985
  }
721
986
  reset();
722
987
  });
@@ -731,8 +996,7 @@ const fileSystemLogger = defineLogger({
731
996
  //#endregion
732
997
  //#region src/loggers/githubActionsLogger.ts
733
998
  /**
734
- * GitHub Actions adapter for CI environments
735
- * Uses Github group annotations for collapsible sections
999
+ * GitHub Actions logger using group annotations for collapsible sections in CI.
736
1000
  */
737
1001
  const githubActionsLogger = defineLogger({
738
1002
  name: "github-actions",
@@ -770,7 +1034,7 @@ const githubActionsLogger = defineLogger({
770
1034
  function closeGroup(_name) {
771
1035
  console.log("::endgroup::");
772
1036
  }
773
- context.on("info", (message, info = "") => {
1037
+ context.on("kubb:info", ({ message, info = "" }) => {
774
1038
  if (logLevel$7 <= logLevel.silent) return;
775
1039
  const text = getMessage([
776
1040
  styleText("blue", "ℹ"),
@@ -779,7 +1043,7 @@ const githubActionsLogger = defineLogger({
779
1043
  ].join(" "));
780
1044
  console.log(text);
781
1045
  });
782
- context.on("success", (message, info = "") => {
1046
+ context.on("kubb:success", ({ message, info = "" }) => {
783
1047
  if (logLevel$7 <= logLevel.silent) return;
784
1048
  const text = getMessage([
785
1049
  styleText("blue", "✓"),
@@ -788,7 +1052,7 @@ const githubActionsLogger = defineLogger({
788
1052
  ].filter(Boolean).join(" "));
789
1053
  console.log(text);
790
1054
  });
791
- context.on("warn", (message, info = "") => {
1055
+ context.on("kubb:warn", ({ message, info = "" }) => {
792
1056
  if (logLevel$7 <= logLevel.silent) return;
793
1057
  const text = getMessage([
794
1058
  styleText("yellow", "⚠"),
@@ -797,7 +1061,7 @@ const githubActionsLogger = defineLogger({
797
1061
  ].filter(Boolean).join(" "));
798
1062
  console.warn(`::warning::${text}`);
799
1063
  });
800
- context.on("error", (error) => {
1064
+ context.on("kubb:error", ({ error }) => {
801
1065
  const caused = toCause(error);
802
1066
  if (logLevel$7 <= logLevel.silent) return;
803
1067
  const message = error.message || String(error);
@@ -812,37 +1076,37 @@ const githubActionsLogger = defineLogger({
812
1076
  }
813
1077
  }
814
1078
  });
815
- context.on("lifecycle:start", (version) => {
1079
+ context.on("kubb:lifecycle:start", ({ version }) => {
816
1080
  console.log(styleText("yellow", `Kubb ${version} 🧩`));
817
1081
  reset();
818
1082
  });
819
- context.on("config:start", () => {
1083
+ context.on("kubb:config:start", () => {
820
1084
  if (logLevel$7 <= logLevel.silent) return;
821
1085
  const text = getMessage("Configuration started");
822
1086
  openGroup("Configuration");
823
1087
  console.log(text);
824
1088
  });
825
- context.on("config:end", (configs) => {
1089
+ context.on("kubb:config:end", ({ configs }) => {
826
1090
  state.currentConfigs = configs;
827
1091
  if (logLevel$7 <= logLevel.silent) return;
828
1092
  const text = getMessage("Configuration completed");
829
1093
  console.log(text);
830
1094
  closeGroup("Configuration");
831
1095
  });
832
- context.on("generation:start", (config) => {
1096
+ context.on("kubb:generation:start", ({ config }) => {
833
1097
  reset();
834
1098
  state.totalPlugins = config.plugins?.length ?? 0;
835
1099
  const text = config.name ? `Generation for ${styleText("bold", config.name)}` : "Generation";
836
1100
  if (state.currentConfigs.length > 1) openGroup(text);
837
1101
  if (state.currentConfigs.length === 1) console.log(getMessage(text));
838
1102
  });
839
- context.on("plugin:start", (plugin) => {
1103
+ context.on("kubb:plugin:start", ({ plugin }) => {
840
1104
  if (logLevel$7 <= logLevel.silent) return;
841
1105
  const text = getMessage(`Generating ${styleText("bold", plugin.name)}`);
842
1106
  if (state.currentConfigs.length === 1) openGroup(`Plugin: ${plugin.name}`);
843
1107
  console.log(text);
844
1108
  });
845
- context.on("plugin:end", (plugin, { duration, success }) => {
1109
+ context.on("kubb:plugin:end", ({ plugin, duration, success }) => {
846
1110
  if (logLevel$7 <= logLevel.silent) return;
847
1111
  if (success) state.completedPlugins++;
848
1112
  else state.failedPlugins++;
@@ -853,7 +1117,7 @@ const githubActionsLogger = defineLogger({
853
1117
  if (state.currentConfigs.length === 1) closeGroup(`Plugin: ${plugin.name}`);
854
1118
  showProgressStep();
855
1119
  });
856
- context.on("files:processing:start", (files) => {
1120
+ context.on("kubb:files:processing:start", ({ files }) => {
857
1121
  if (logLevel$7 <= logLevel.silent) return;
858
1122
  state.totalFiles = files.length;
859
1123
  state.processedFiles = 0;
@@ -861,46 +1125,46 @@ const githubActionsLogger = defineLogger({
861
1125
  const text = getMessage(`Writing ${files.length} files`);
862
1126
  console.log(text);
863
1127
  });
864
- context.on("files:processing:end", () => {
1128
+ context.on("kubb:files:processing:end", () => {
865
1129
  if (logLevel$7 <= logLevel.silent) return;
866
1130
  const text = getMessage("Files written successfully");
867
1131
  console.log(text);
868
1132
  if (state.currentConfigs.length === 1) closeGroup("File Generation");
869
1133
  showProgressStep();
870
1134
  });
871
- context.on("file:processing:update", () => {
1135
+ context.on("kubb:file:processing:update", () => {
872
1136
  if (logLevel$7 <= logLevel.silent) return;
873
1137
  state.processedFiles++;
874
1138
  });
875
- context.on("generation:end", (config) => {
1139
+ context.on("kubb:generation:end", ({ config }) => {
876
1140
  const text = getMessage(config.name ? `${styleText("blue", "✓")} Generation completed for ${styleText("dim", config.name)}` : `${styleText("blue", "✓")} Generation completed`);
877
1141
  console.log(text);
878
1142
  });
879
- context.on("format:start", () => {
1143
+ context.on("kubb:format:start", () => {
880
1144
  if (logLevel$7 <= logLevel.silent) return;
881
1145
  const text = getMessage("Format started");
882
1146
  if (state.currentConfigs.length === 1) openGroup("Formatting");
883
1147
  console.log(text);
884
1148
  });
885
- context.on("format:end", () => {
1149
+ context.on("kubb:format:end", () => {
886
1150
  if (logLevel$7 <= logLevel.silent) return;
887
1151
  const text = getMessage("Format completed");
888
1152
  console.log(text);
889
1153
  if (state.currentConfigs.length === 1) closeGroup("Formatting");
890
1154
  });
891
- context.on("lint:start", () => {
1155
+ context.on("kubb:lint:start", () => {
892
1156
  if (logLevel$7 <= logLevel.silent) return;
893
1157
  const text = getMessage("Lint started");
894
1158
  if (state.currentConfigs.length === 1) openGroup("Linting");
895
1159
  console.log(text);
896
1160
  });
897
- context.on("lint:end", () => {
1161
+ context.on("kubb:lint:end", () => {
898
1162
  if (logLevel$7 <= logLevel.silent) return;
899
1163
  const text = getMessage("Lint completed");
900
1164
  console.log(text);
901
1165
  if (state.currentConfigs.length === 1) closeGroup("Linting");
902
1166
  });
903
- context.on("hook:start", async ({ id, command, args }) => {
1167
+ context.on("kubb:hook:start", async ({ id, command, args }) => {
904
1168
  const commandWithArgs = formatCommandWithArgs(command, args);
905
1169
  const text = getMessage(`Hook ${styleText("dim", commandWithArgs)} started`);
906
1170
  if (logLevel$7 > logLevel.silent) {
@@ -920,14 +1184,14 @@ const githubActionsLogger = defineLogger({
920
1184
  }
921
1185
  });
922
1186
  });
923
- context.on("hook:end", ({ command, args }) => {
1187
+ context.on("kubb:hook:end", ({ command, args }) => {
924
1188
  if (logLevel$7 <= logLevel.silent) return;
925
1189
  const commandWithArgs = formatCommandWithArgs(command, args);
926
1190
  const text = getMessage(`Hook ${styleText("dim", commandWithArgs)} completed`);
927
1191
  console.log(text);
928
1192
  if (state.currentConfigs.length === 1) closeGroup(`Hook ${commandWithArgs}`);
929
1193
  });
930
- context.on("generation:summary", (config, { status, hrStart, failedPlugins }) => {
1194
+ context.on("kubb:generation:summary", ({ config, status, hrStart, failedPlugins }) => {
931
1195
  const pluginsCount = config.plugins?.length ?? 0;
932
1196
  const successCount = pluginsCount - failedPlugins.size;
933
1197
  const duration = formatHrtime(hrStart);
@@ -935,7 +1199,7 @@ const githubActionsLogger = defineLogger({
935
1199
  console.log(status === "success" ? `Kubb Summary: ${styleText("blue", "✓")} ${`${successCount} successful`}, ${pluginsCount} total, ${styleText("green", duration)}` : `Kubb Summary: ${styleText("blue", "✓")} ${`${successCount} successful`}, ✗ ${`${failedPlugins.size} failed`}, ${pluginsCount} total, ${styleText("green", duration)}`);
936
1200
  if (state.currentConfigs.length > 1) closeGroup(config.name ? `Generation for ${styleText("bold", config.name)}` : "Generation");
937
1201
  });
938
- context.on("lifecycle:end", () => {
1202
+ context.on("kubb:lifecycle:end", () => {
939
1203
  reset();
940
1204
  });
941
1205
  }
@@ -943,8 +1207,7 @@ const githubActionsLogger = defineLogger({
943
1207
  //#endregion
944
1208
  //#region src/loggers/plainLogger.ts
945
1209
  /**
946
- * Plain console adapter for non-TTY environments
947
- * Simple console.log output with indentation
1210
+ * Plain console adapter for non-TTY environments with simple `console.log` output.
948
1211
  */
949
1212
  const plainLogger = defineLogger({
950
1213
  name: "plain",
@@ -953,7 +1216,7 @@ const plainLogger = defineLogger({
953
1216
  function getMessage(message) {
954
1217
  return formatMessage(message, logLevel$6);
955
1218
  }
956
- context.on("info", (message, info) => {
1219
+ context.on("kubb:info", ({ message, info }) => {
957
1220
  if (logLevel$6 <= logLevel.silent) return;
958
1221
  const text = getMessage([
959
1222
  "ℹ",
@@ -962,7 +1225,7 @@ const plainLogger = defineLogger({
962
1225
  ].join(" "));
963
1226
  console.log(text);
964
1227
  });
965
- context.on("success", (message, info = "") => {
1228
+ context.on("kubb:success", ({ message, info = "" }) => {
966
1229
  if (logLevel$6 <= logLevel.silent) return;
967
1230
  const text = getMessage([
968
1231
  "✓",
@@ -971,7 +1234,7 @@ const plainLogger = defineLogger({
971
1234
  ].filter(Boolean).join(" "));
972
1235
  console.log(text);
973
1236
  });
974
- context.on("warn", (message, info) => {
1237
+ context.on("kubb:warn", ({ message, info }) => {
975
1238
  if (logLevel$6 < logLevel.warn) return;
976
1239
  const text = getMessage([
977
1240
  "⚠",
@@ -980,7 +1243,7 @@ const plainLogger = defineLogger({
980
1243
  ].filter(Boolean).join(" "));
981
1244
  console.log(text);
982
1245
  });
983
- context.on("error", (error) => {
1246
+ context.on("kubb:error", ({ error }) => {
984
1247
  const caused = toCause(error);
985
1248
  const text = getMessage(["✗", error.message].join(" "));
986
1249
  console.log(text);
@@ -994,74 +1257,74 @@ const plainLogger = defineLogger({
994
1257
  }
995
1258
  }
996
1259
  });
997
- context.on("lifecycle:start", () => {
1260
+ context.on("kubb:lifecycle:start", () => {
998
1261
  console.log("Kubb CLI 🧩");
999
1262
  });
1000
- context.on("config:start", () => {
1263
+ context.on("kubb:config:start", () => {
1001
1264
  if (logLevel$6 <= logLevel.silent) return;
1002
1265
  const text = getMessage("Configuration started");
1003
1266
  console.log(text);
1004
1267
  });
1005
- context.on("config:end", () => {
1268
+ context.on("kubb:config:end", () => {
1006
1269
  if (logLevel$6 <= logLevel.silent) return;
1007
1270
  const text = getMessage("Configuration completed");
1008
1271
  console.log(text);
1009
1272
  });
1010
- context.on("generation:start", () => {
1273
+ context.on("kubb:generation:start", () => {
1011
1274
  const text = getMessage("Generation started");
1012
1275
  console.log(text);
1013
1276
  });
1014
- context.on("plugin:start", (plugin) => {
1277
+ context.on("kubb:plugin:start", ({ plugin }) => {
1015
1278
  if (logLevel$6 <= logLevel.silent) return;
1016
1279
  const text = getMessage(`Generating ${plugin.name}`);
1017
1280
  console.log(text);
1018
1281
  });
1019
- context.on("plugin:end", (plugin, { duration, success }) => {
1282
+ context.on("kubb:plugin:end", ({ plugin, duration, success }) => {
1020
1283
  if (logLevel$6 <= logLevel.silent) return;
1021
1284
  const durationStr = formatMs(duration);
1022
1285
  const text = getMessage(success ? `${plugin.name} completed in ${durationStr}` : `${plugin.name} failed in ${durationStr}`);
1023
1286
  console.log(text);
1024
1287
  });
1025
- context.on("files:processing:start", (files) => {
1288
+ context.on("kubb:files:processing:start", ({ files }) => {
1026
1289
  if (logLevel$6 <= logLevel.silent) return;
1027
1290
  const text = getMessage(`Writing ${files.length} files`);
1028
1291
  console.log(text);
1029
1292
  });
1030
- context.on("file:processing:update", ({ file, config }) => {
1293
+ context.on("kubb:file:processing:update", ({ file, config }) => {
1031
1294
  if (logLevel$6 <= logLevel.silent) return;
1032
1295
  const text = getMessage(`Writing ${relative(config.root, file.path)}`);
1033
1296
  console.log(text);
1034
1297
  });
1035
- context.on("files:processing:end", () => {
1298
+ context.on("kubb:files:processing:end", () => {
1036
1299
  if (logLevel$6 <= logLevel.silent) return;
1037
1300
  const text = getMessage("Files written successfully");
1038
1301
  console.log(text);
1039
1302
  });
1040
- context.on("generation:end", (config) => {
1303
+ context.on("kubb:generation:end", ({ config }) => {
1041
1304
  const text = getMessage(config.name ? `Generation completed for ${config.name}` : "Generation completed");
1042
1305
  console.log(text);
1043
1306
  });
1044
- context.on("format:start", () => {
1307
+ context.on("kubb:format:start", () => {
1045
1308
  if (logLevel$6 <= logLevel.silent) return;
1046
1309
  const text = getMessage("Format started");
1047
1310
  console.log(text);
1048
1311
  });
1049
- context.on("format:end", () => {
1312
+ context.on("kubb:format:end", () => {
1050
1313
  if (logLevel$6 <= logLevel.silent) return;
1051
1314
  const text = getMessage("Format completed");
1052
1315
  console.log(text);
1053
1316
  });
1054
- context.on("lint:start", () => {
1317
+ context.on("kubb:lint:start", () => {
1055
1318
  if (logLevel$6 <= logLevel.silent) return;
1056
1319
  const text = getMessage("Lint started");
1057
1320
  console.log(text);
1058
1321
  });
1059
- context.on("lint:end", () => {
1322
+ context.on("kubb:lint:end", () => {
1060
1323
  if (logLevel$6 <= logLevel.silent) return;
1061
1324
  const text = getMessage("Lint completed");
1062
1325
  console.log(text);
1063
1326
  });
1064
- context.on("hook:start", async ({ id, command, args }) => {
1327
+ context.on("kubb:hook:start", async ({ id, command, args }) => {
1065
1328
  const commandWithArgs = formatCommandWithArgs(command, args);
1066
1329
  const text = getMessage(`Hook ${commandWithArgs} started`);
1067
1330
  if (logLevel$6 > logLevel.silent) console.log(text);
@@ -1078,12 +1341,12 @@ const plainLogger = defineLogger({
1078
1341
  }
1079
1342
  });
1080
1343
  });
1081
- context.on("hook:end", ({ command, args }) => {
1344
+ context.on("kubb:hook:end", ({ command, args }) => {
1082
1345
  if (logLevel$6 <= logLevel.silent) return;
1083
1346
  const text = getMessage(`Hook ${formatCommandWithArgs(command, args)} completed`);
1084
1347
  console.log(text);
1085
1348
  });
1086
- context.on("generation:summary", (config, { pluginTimings, status, hrStart, failedPlugins, filesCreated }) => {
1349
+ context.on("kubb:generation:summary", ({ config, pluginTimings, status, hrStart, failedPlugins, filesCreated }) => {
1087
1350
  const summary = getSummary({
1088
1351
  failedPlugins,
1089
1352
  filesCreated,
@@ -1156,25 +1419,25 @@ async function setupLogger(context, { logLevel: logLevel$5 }) {
1156
1419
  }
1157
1420
  //#endregion
1158
1421
  //#region src/utils/executeHooks.ts
1159
- async function executeHooks({ hooks, events }) {
1160
- const commands = Array.isArray(hooks.done) ? hooks.done : [hooks.done].filter(Boolean);
1422
+ async function executeHooks({ configHooks, hooks }) {
1423
+ const commands = Array.isArray(configHooks.done) ? configHooks.done : [configHooks.done].filter(Boolean);
1161
1424
  for (const command of commands) {
1162
1425
  const [cmd, ...args] = tokenize(command);
1163
1426
  if (!cmd) continue;
1164
1427
  const hookId = createHash("sha256").update(command).digest("hex");
1165
1428
  const hookEndPromise = new Promise((resolve, reject) => {
1166
- const handler = ({ id, success, error }) => {
1167
- if (id !== hookId) return;
1168
- events.off("hook:end", handler);
1169
- if (!success) {
1170
- reject(error ?? /* @__PURE__ */ new Error(`Hook failed: ${command}`));
1429
+ const handler = (ctx) => {
1430
+ if (ctx.id !== hookId) return;
1431
+ hooks.off("kubb:hook:end", handler);
1432
+ if (!ctx.success) {
1433
+ reject(ctx.error ?? /* @__PURE__ */ new Error(`Hook failed: ${command}`));
1171
1434
  return;
1172
1435
  }
1173
- events.emit("success", `${styleText("dim", command)} successfully executed`).then(resolve).catch(reject);
1436
+ hooks.emit("kubb:success", { message: `${styleText("dim", command)} successfully executed` }).then(resolve).catch(reject);
1174
1437
  };
1175
- events.on("hook:end", handler);
1438
+ hooks.on("kubb:hook:end", handler);
1176
1439
  });
1177
- await events.emit("hook:start", {
1440
+ await hooks.emit("kubb:hook:start", {
1178
1441
  id: hookId,
1179
1442
  command: cmd,
1180
1443
  args
@@ -1183,17 +1446,26 @@ async function executeHooks({ hooks, events }) {
1183
1446
  }
1184
1447
  }
1185
1448
  //#endregion
1449
+ //#region src/utils/getConfig.ts
1450
+ async function getConfigs(config, args) {
1451
+ const resolved = await (typeof config === "function" ? config(args) : config);
1452
+ return (Array.isArray(resolved) ? resolved : [resolved]).map((item) => ({
1453
+ ...item,
1454
+ plugins: item.plugins ?? []
1455
+ }));
1456
+ }
1457
+ //#endregion
1186
1458
  //#region src/utils/getCosmiConfig.ts
1187
- const jiti = createJiti(import.meta.url, {
1188
- jsx: {
1189
- runtime: "automatic",
1190
- importSource: "@kubb/react-fabric"
1191
- },
1192
- sourceMaps: true,
1193
- interopDefault: true
1194
- });
1459
+ const unrunInputOptions = { transform: { jsx: {
1460
+ runtime: "automatic",
1461
+ importSource: "@kubb/renderer-jsx"
1462
+ } } };
1195
1463
  const tsLoader = async (configFile) => {
1196
- return await jiti.import(configFile, { default: true });
1464
+ const { module } = await unrun({
1465
+ path: configFile,
1466
+ inputOptions: unrunInputOptions
1467
+ });
1468
+ return module;
1197
1469
  };
1198
1470
  async function getCosmiConfig(moduleName, config) {
1199
1471
  let result;
@@ -1204,10 +1476,14 @@ async function getCosmiConfig(moduleName, config) {
1204
1476
  `.${moduleName}rc.yaml`,
1205
1477
  `.${moduleName}rc.yml`,
1206
1478
  `.${moduleName}rc.ts`,
1479
+ `.${moduleName}rc.mts`,
1480
+ `.${moduleName}rc.cts`,
1207
1481
  `.${moduleName}rc.js`,
1208
1482
  `.${moduleName}rc.mjs`,
1209
1483
  `.${moduleName}rc.cjs`,
1210
1484
  `${moduleName}.config.ts`,
1485
+ `${moduleName}.config.mts`,
1486
+ `${moduleName}.config.cts`,
1211
1487
  `${moduleName}.config.js`,
1212
1488
  `${moduleName}.config.mjs`,
1213
1489
  `${moduleName}.config.cjs`
@@ -1223,7 +1499,11 @@ async function getCosmiConfig(moduleName, config) {
1223
1499
  }),
1224
1500
  ...searchPlaces
1225
1501
  ],
1226
- loaders: { ".ts": tsLoader }
1502
+ loaders: {
1503
+ ".ts": tsLoader,
1504
+ ".mts": tsLoader,
1505
+ ".cts": tsLoader
1506
+ }
1227
1507
  });
1228
1508
  try {
1229
1509
  result = config ? await explorer.load(config) : await explorer.search();
@@ -1251,91 +1531,88 @@ async function startWatcher(path, cb) {
1251
1531
  }
1252
1532
  //#endregion
1253
1533
  //#region src/runners/generate.ts
1254
- async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefix, noToolMessage, configName, outputPath, logLevel: logLevel$1, events, onStart, onEnd }) {
1534
+ async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefix, noToolMessage, configName, outputPath, logLevel: logLevel$1, hooks, onStart, onEnd }) {
1255
1535
  await onStart();
1256
1536
  let resolvedTool = toolValue;
1257
1537
  if (resolvedTool === "auto") {
1258
1538
  const detected = await detect();
1259
- if (!detected) await events.emit("warn", noToolMessage);
1539
+ if (!detected) await hooks.emit("kubb:warn", { message: noToolMessage });
1260
1540
  else {
1261
1541
  resolvedTool = detected;
1262
- await events.emit("info", `Auto-detected ${toolLabel}: ${styleText("dim", resolvedTool)}`);
1542
+ await hooks.emit("kubb:info", { message: `Auto-detected ${toolLabel}: ${styleText("dim", resolvedTool)}` });
1263
1543
  }
1264
1544
  }
1545
+ let toolError;
1265
1546
  if (resolvedTool && resolvedTool !== "auto" && resolvedTool in toolMap) {
1266
1547
  const toolConfig = toolMap[resolvedTool];
1267
1548
  try {
1268
1549
  const hookId = createHash("sha256").update([configName, resolvedTool].filter(Boolean).join("-")).digest("hex");
1269
1550
  const hookEndPromise = new Promise((resolve, reject) => {
1270
- const handler = ({ id, success, error }) => {
1271
- if (id !== hookId) return;
1272
- events.off("hook:end", handler);
1273
- if (!success) {
1274
- reject(error ?? /* @__PURE__ */ new Error(`${toolConfig.errorMessage}`));
1551
+ const handler = (ctx) => {
1552
+ if (ctx.id !== hookId) return;
1553
+ hooks.off("kubb:hook:end", handler);
1554
+ if (!ctx.success) {
1555
+ reject(ctx.error ?? /* @__PURE__ */ new Error(`${toolConfig.errorMessage}`));
1275
1556
  return;
1276
1557
  }
1277
- events.emit("success", [
1558
+ hooks.emit("kubb:success", { message: [
1278
1559
  `${successPrefix} with ${styleText("dim", resolvedTool)}`,
1279
1560
  logLevel$1 >= logLevel.info ? `on ${styleText("dim", outputPath)}` : void 0,
1280
1561
  "successfully"
1281
- ].filter(Boolean).join(" ")).then(resolve).catch(reject);
1562
+ ].filter(Boolean).join(" ") }).then(resolve).catch(reject);
1282
1563
  };
1283
- events.on("hook:end", handler);
1564
+ hooks.on("kubb:hook:end", handler);
1284
1565
  });
1285
- await events.emit("hook:start", {
1566
+ await hooks.emit("kubb:hook:start", {
1286
1567
  id: hookId,
1287
1568
  command: toolConfig.command,
1288
1569
  args: toolConfig.args(outputPath)
1289
1570
  });
1290
1571
  await hookEndPromise;
1291
1572
  } catch (caughtError) {
1292
- const err = new Error(toolConfig.errorMessage);
1293
- err.cause = caughtError;
1294
- await events.emit("error", err);
1573
+ const err = toError(caughtError);
1574
+ await hooks.emit("kubb:error", { error: err });
1575
+ toolError = err;
1295
1576
  }
1296
1577
  }
1297
1578
  await onEnd();
1579
+ if (toolError) throw toolError;
1298
1580
  }
1299
- async function generate({ input, config: userConfig, events, logLevel: logLevel$2 }) {
1300
- const inputPath = input ?? ("path" in userConfig.input ? userConfig.input.path : void 0);
1581
+ async function generate(options) {
1582
+ const { input, hooks, logLevel: logLevel$2 } = options;
1301
1583
  const hrStart = process$1.hrtime();
1584
+ const inputPath = input ?? ("path" in options.config.input ? options.config.input.path : void 0);
1302
1585
  const config = {
1303
- ...userConfig,
1304
- root: userConfig.root || process$1.cwd(),
1586
+ ...options.config,
1305
1587
  input: inputPath ? {
1306
- ...userConfig.input,
1588
+ ...options.config.input,
1307
1589
  path: inputPath
1308
- } : userConfig.input,
1309
- output: {
1310
- write: true,
1311
- barrelType: "named",
1312
- extension: { ".ts": ".ts" },
1313
- format: "prettier",
1314
- ...userConfig.output
1315
- }
1590
+ } : options.config.input,
1591
+ ...options.config.output
1316
1592
  };
1317
- await events.emit("generation:start", config);
1318
- await events.emit("info", config.name ? `Setup generation ${styleText("bold", config.name)}` : "Setup generation", inputPath);
1319
- const { sources, fabric, driver } = await setup({
1320
- config,
1321
- events
1593
+ const kubb = createKubb(config, { hooks });
1594
+ await kubb.setup();
1595
+ await hooks.emit("kubb:generation:start", { config });
1596
+ await hooks.emit("kubb:info", {
1597
+ message: config.name ? `Setup generation ${styleText("bold", config.name)}` : "Setup generation",
1598
+ info: inputPath
1322
1599
  });
1323
- await events.emit("info", config.name ? `Build generation ${styleText("bold", config.name)}` : "Build generation", inputPath);
1324
- const { files, failedPlugins, pluginTimings, error } = await safeBuild({
1325
- config,
1326
- events
1327
- }, {
1328
- driver,
1329
- fabric,
1330
- events,
1331
- sources
1600
+ await hooks.emit("kubb:info", {
1601
+ message: config.name ? `Build generation ${styleText("bold", config.name)}` : "Build generation",
1602
+ info: inputPath
1332
1603
  });
1333
- await events.emit("info", "Load summary");
1604
+ const { files, failedPlugins, pluginTimings, error, driver } = await kubb.safeBuild();
1605
+ await hooks.emit("kubb:info", { message: "Load summary" });
1334
1606
  if (failedPlugins.size > 0 || error) {
1335
1607
  const allErrors = [error, ...Array.from(failedPlugins).filter((it) => it.error).map((it) => it.error)].filter(Boolean);
1336
- for (const err of allErrors) await events.emit("error", err);
1337
- await events.emit("generation:end", config, files, sources);
1338
- await events.emit("generation:summary", config, {
1608
+ for (const err of allErrors) await hooks.emit("kubb:error", { error: err });
1609
+ await hooks.emit("kubb:generation:end", {
1610
+ config,
1611
+ files,
1612
+ sources: kubb.sources
1613
+ });
1614
+ await hooks.emit("kubb:generation:summary", {
1615
+ config,
1339
1616
  failedPlugins,
1340
1617
  filesCreated: files.length,
1341
1618
  status: "failed",
@@ -1345,7 +1622,7 @@ async function generate({ input, config: userConfig, events, logLevel: logLevel$
1345
1622
  await sendTelemetry(buildTelemetryEvent({
1346
1623
  command: "generate",
1347
1624
  kubbVersion: version,
1348
- plugins: driver.plugins.map((p) => ({
1625
+ plugins: Array.from(driver.plugins.values(), (p) => ({
1349
1626
  name: p.name,
1350
1627
  options: p.options
1351
1628
  })),
@@ -1355,8 +1632,15 @@ async function generate({ input, config: userConfig, events, logLevel: logLevel$
1355
1632
  }));
1356
1633
  process$1.exit(1);
1357
1634
  }
1358
- await events.emit("success", "Generation successfully", inputPath);
1359
- await events.emit("generation:end", config, files, sources);
1635
+ await hooks.emit("kubb:success", {
1636
+ message: "Generation successfully",
1637
+ info: inputPath
1638
+ });
1639
+ await hooks.emit("kubb:generation:end", {
1640
+ config,
1641
+ files,
1642
+ sources: kubb.sources
1643
+ });
1360
1644
  const outputPath = path.resolve(config.root, config.output.path);
1361
1645
  if (config.output.format) await runToolPass({
1362
1646
  toolValue: config.output.format,
@@ -1364,13 +1648,13 @@ async function generate({ input, config: userConfig, events, logLevel: logLevel$
1364
1648
  toolMap: formatters,
1365
1649
  toolLabel: "formatter",
1366
1650
  successPrefix: "Formatting",
1367
- noToolMessage: "No formatter found (biome, prettier, or oxfmt). Skipping formatting.",
1651
+ noToolMessage: "No formatter found (oxfmt, biome, or prettier). Skipping formatting.",
1368
1652
  configName: config.name,
1369
1653
  outputPath,
1370
1654
  logLevel: logLevel$2,
1371
- events,
1372
- onStart: () => events.emit("format:start"),
1373
- onEnd: () => events.emit("format:end")
1655
+ hooks,
1656
+ onStart: () => hooks.emit("kubb:format:start"),
1657
+ onEnd: () => hooks.emit("kubb:format:end")
1374
1658
  });
1375
1659
  if (config.output.lint) await runToolPass({
1376
1660
  toolValue: config.output.lint,
@@ -1378,23 +1662,24 @@ async function generate({ input, config: userConfig, events, logLevel: logLevel$
1378
1662
  toolMap: linters,
1379
1663
  toolLabel: "linter",
1380
1664
  successPrefix: "Linting",
1381
- noToolMessage: "No linter found (biome, oxlint, or eslint). Skipping linting.",
1665
+ noToolMessage: "No linter found (oxlint, biome, or eslint). Skipping linting.",
1382
1666
  configName: config.name,
1383
1667
  outputPath,
1384
1668
  logLevel: logLevel$2,
1385
- events,
1386
- onStart: () => events.emit("lint:start"),
1387
- onEnd: () => events.emit("lint:end")
1669
+ hooks,
1670
+ onStart: () => hooks.emit("kubb:lint:start"),
1671
+ onEnd: () => hooks.emit("kubb:lint:end")
1388
1672
  });
1389
1673
  if (config.hooks) {
1390
- await events.emit("hooks:start");
1674
+ await hooks.emit("kubb:hooks:start");
1391
1675
  await executeHooks({
1392
- hooks: config.hooks,
1393
- events
1676
+ configHooks: config.hooks,
1677
+ hooks
1394
1678
  });
1395
- await events.emit("hooks:end");
1679
+ await hooks.emit("kubb:hooks:end");
1396
1680
  }
1397
- await events.emit("generation:summary", config, {
1681
+ await hooks.emit("kubb:generation:summary", {
1682
+ config,
1398
1683
  failedPlugins,
1399
1684
  filesCreated: files.length,
1400
1685
  status: "success",
@@ -1404,7 +1689,7 @@ async function generate({ input, config: userConfig, events, logLevel: logLevel$
1404
1689
  await sendTelemetry(buildTelemetryEvent({
1405
1690
  command: "generate",
1406
1691
  kubbVersion: version,
1407
- plugins: driver.plugins.map((p) => ({
1692
+ plugins: Array.from(driver.plugins.values(), (p) => ({
1408
1693
  name: p.name,
1409
1694
  options: p.options
1410
1695
  })),
@@ -1415,29 +1700,38 @@ async function generate({ input, config: userConfig, events, logLevel: logLevel$
1415
1700
  }
1416
1701
  async function runGenerateCommand({ input, configPath, logLevel: logLevelKey, watch }) {
1417
1702
  const logLevel$3 = logLevel[logLevelKey] ?? logLevel.info;
1418
- const events = new AsyncEventEmitter();
1419
- await setupLogger(events, { logLevel: logLevel$3 });
1703
+ const hooks = new AsyncEventEmitter();
1704
+ await setupLogger(hooks, { logLevel: logLevel$3 });
1420
1705
  await executeIfOnline(async () => {
1421
1706
  try {
1422
1707
  const latestVersion = (await (await fetch(KUBB_NPM_PACKAGE_URL)).json()).version;
1423
- if (latestVersion && version < latestVersion) await events.emit("version:new", version, latestVersion);
1708
+ if (latestVersion && version < latestVersion) await hooks.emit("kubb:version:new", {
1709
+ currentVersion: version,
1710
+ latestVersion
1711
+ });
1424
1712
  } catch {}
1425
1713
  });
1426
1714
  try {
1427
1715
  const result = await getCosmiConfig("kubb", configPath);
1428
1716
  const configs = await getConfigs(result.config, { input });
1429
- await events.emit("config:start");
1430
- await events.emit("info", "Config loaded", path.relative(process$1.cwd(), result.filepath));
1431
- await events.emit("success", "Config loaded successfully", path.relative(process$1.cwd(), result.filepath));
1432
- await events.emit("config:end", configs);
1433
- await events.emit("lifecycle:start", version);
1717
+ await hooks.emit("kubb:config:start");
1718
+ await hooks.emit("kubb:info", {
1719
+ message: "Config loaded",
1720
+ info: path.relative(process$1.cwd(), result.filepath)
1721
+ });
1722
+ await hooks.emit("kubb:success", {
1723
+ message: "Config loaded successfully",
1724
+ info: path.relative(process$1.cwd(), result.filepath)
1725
+ });
1726
+ await hooks.emit("kubb:config:end", { configs });
1727
+ await hooks.emit("kubb:lifecycle:start", { version });
1434
1728
  for (const config of configs) if (isInputPath(config) && watch) await startWatcher([input || config.input.path], async (paths) => {
1435
- events.removeAll();
1729
+ hooks.removeAll();
1436
1730
  await generate({
1437
1731
  input,
1438
1732
  config,
1439
1733
  logLevel: logLevel$3,
1440
- events
1734
+ hooks
1441
1735
  });
1442
1736
  clack.log.step(styleText("yellow", `Watching for changes in ${paths.join(" and ")}`));
1443
1737
  });
@@ -1445,15 +1739,15 @@ async function runGenerateCommand({ input, configPath, logLevel: logLevelKey, wa
1445
1739
  input,
1446
1740
  config,
1447
1741
  logLevel: logLevel$3,
1448
- events
1742
+ hooks
1449
1743
  });
1450
- await events.emit("lifecycle:end");
1744
+ await hooks.emit("kubb:lifecycle:end");
1451
1745
  } catch (error) {
1452
- await events.emit("error", toError(error));
1746
+ await hooks.emit("kubb:error", { error: toError(error) });
1453
1747
  process$1.exit(1);
1454
1748
  }
1455
1749
  }
1456
1750
  //#endregion
1457
1751
  export { runGenerateCommand };
1458
1752
 
1459
- //# sourceMappingURL=generate-BHNyeQXl.js.map
1753
+ //# sourceMappingURL=generate-Dt_r0ELY.js.map