@kubb/cli 5.0.0-beta.9 → 5.0.0-beta.93

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 (136) hide show
  1. package/LICENSE +17 -10
  2. package/README.md +48 -79
  3. package/bin/kubb.js +9 -3
  4. package/dist/Telemetry-7z2tIqPm.js +282 -0
  5. package/dist/Telemetry-7z2tIqPm.js.map +1 -0
  6. package/dist/{telemetry-B2iWkY5e.cjs → Telemetry-xcWb-UWT.cjs} +167 -116
  7. package/dist/Telemetry-xcWb-UWT.cjs.map +1 -0
  8. package/dist/{errors-CINO1EIv.js → errors-CMvLO2NE.js} +3 -15
  9. package/dist/{errors-CINO1EIv.js.map → errors-CMvLO2NE.js.map} +1 -1
  10. package/dist/{errors-CLCjoSg0.cjs → errors-DNxBUo3k.cjs} +2 -20
  11. package/dist/{errors-CLCjoSg0.cjs.map → errors-DNxBUo3k.cjs.map} +1 -1
  12. package/dist/generate-Cc9j2-lg.js +87 -0
  13. package/dist/generate-Cc9j2-lg.js.map +1 -0
  14. package/dist/generate-DwTTaSpB.cjs +87 -0
  15. package/dist/generate-DwTTaSpB.cjs.map +1 -0
  16. package/dist/index.cjs +33 -261
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.ts +6 -1
  19. package/dist/index.js +34 -262
  20. package/dist/index.js.map +1 -1
  21. package/dist/{init-DOSXtcyb.js → init-BlTepVY_.js} +13 -13
  22. package/dist/init-BlTepVY_.js.map +1 -0
  23. package/dist/{init-bKtEOvhK.cjs → init-CvVRvhfJ.cjs} +12 -13
  24. package/dist/init-CvVRvhfJ.cjs.map +1 -0
  25. package/dist/mcp-CTs7ogBF.js +21 -0
  26. package/dist/mcp-CTs7ogBF.js.map +1 -0
  27. package/dist/mcp-szP8HzB7.cjs +20 -0
  28. package/dist/mcp-szP8HzB7.cjs.map +1 -0
  29. package/dist/package-CfWW74Ug.js +6 -0
  30. package/dist/package-CfWW74Ug.js.map +1 -0
  31. package/dist/{package-DHGhrRW-.cjs → package-DPdskCYh.cjs} +2 -2
  32. package/dist/package-DPdskCYh.cjs.map +1 -0
  33. package/dist/{chunk-BvFE5Tac.js → rolldown-runtime-C0LytTxp.js} +0 -1
  34. package/dist/run-B8sdHsE4.js +1262 -0
  35. package/dist/run-B8sdHsE4.js.map +1 -0
  36. package/dist/{run-YsoCk5we.cjs → run-BNOCBw2y.cjs} +152 -98
  37. package/dist/run-BNOCBw2y.cjs.map +1 -0
  38. package/dist/{run-CQbj3ley.cjs → run-BdtVrLKu.cjs} +9 -15
  39. package/dist/run-BdtVrLKu.cjs.map +1 -0
  40. package/dist/{run-CF97BWVa.js → run-CINOocLR.js} +138 -84
  41. package/dist/run-CINOocLR.js.map +1 -0
  42. package/dist/{run-CCZ24VKk.js → run-CaOjZRiQ.js} +7 -13
  43. package/dist/run-CaOjZRiQ.js.map +1 -0
  44. package/dist/run-D2vd34xp.cjs +33 -0
  45. package/dist/run-D2vd34xp.cjs.map +1 -0
  46. package/dist/run-DFXppyRD.cjs +1265 -0
  47. package/dist/run-DFXppyRD.cjs.map +1 -0
  48. package/dist/run-lgrTO14E.js +32 -0
  49. package/dist/run-lgrTO14E.js.map +1 -0
  50. package/dist/tools-B23ltmWP.js +152 -0
  51. package/dist/tools-B23ltmWP.js.map +1 -0
  52. package/dist/tools-CeIABV0T.cjs +175 -0
  53. package/dist/tools-CeIABV0T.cjs.map +1 -0
  54. package/dist/{validate-Bj8vbvPt.cjs → validate-BhSbvuiq.cjs} +9 -10
  55. package/dist/validate-BhSbvuiq.cjs.map +1 -0
  56. package/dist/{validate-bHUrnYBv.js → validate-Cfi4pIS0.js} +10 -10
  57. package/dist/validate-Cfi4pIS0.js.map +1 -0
  58. package/package.json +14 -28
  59. package/dist/agent-C5F4itrc.js +0 -68
  60. package/dist/agent-C5F4itrc.js.map +0 -1
  61. package/dist/agent-d-lmeOr1.cjs +0 -70
  62. package/dist/agent-d-lmeOr1.cjs.map +0 -1
  63. package/dist/constants-B2JTeRBb.js +0 -42
  64. package/dist/constants-B2JTeRBb.js.map +0 -1
  65. package/dist/constants-BINTA5VZ.cjs +0 -77
  66. package/dist/constants-BINTA5VZ.cjs.map +0 -1
  67. package/dist/constants-BYGmiFs0.cjs +0 -139
  68. package/dist/constants-BYGmiFs0.cjs.map +0 -1
  69. package/dist/constants-DSJ-Xrbv.js +0 -116
  70. package/dist/constants-DSJ-Xrbv.js.map +0 -1
  71. package/dist/define-Bdn8j5VM.cjs +0 -54
  72. package/dist/define-Bdn8j5VM.cjs.map +0 -1
  73. package/dist/define-m_fp-Aqm.js +0 -43
  74. package/dist/define-m_fp-Aqm.js.map +0 -1
  75. package/dist/generate-BhfRufgh.js +0 -72
  76. package/dist/generate-BhfRufgh.js.map +0 -1
  77. package/dist/generate-BvuSxNYj.cjs +0 -71
  78. package/dist/generate-BvuSxNYj.cjs.map +0 -1
  79. package/dist/init-DOSXtcyb.js.map +0 -1
  80. package/dist/init-bKtEOvhK.cjs.map +0 -1
  81. package/dist/mcp-CKkbG0kp.cjs +0 -39
  82. package/dist/mcp-CKkbG0kp.cjs.map +0 -1
  83. package/dist/mcp-DzOfqX_j.js +0 -39
  84. package/dist/mcp-DzOfqX_j.js.map +0 -1
  85. package/dist/package-BgAYWN7y.js +0 -6
  86. package/dist/package-BgAYWN7y.js.map +0 -1
  87. package/dist/package-DHGhrRW-.cjs.map +0 -1
  88. package/dist/run-BObDb2qe.cjs +0 -1741
  89. package/dist/run-BObDb2qe.cjs.map +0 -1
  90. package/dist/run-BzpYYOQs.js +0 -121
  91. package/dist/run-BzpYYOQs.js.map +0 -1
  92. package/dist/run-CCZ24VKk.js.map +0 -1
  93. package/dist/run-CF97BWVa.js.map +0 -1
  94. package/dist/run-CQbj3ley.cjs.map +0 -1
  95. package/dist/run-D0hmRpHy.js +0 -49
  96. package/dist/run-D0hmRpHy.js.map +0 -1
  97. package/dist/run-DwdAwnLG.cjs +0 -125
  98. package/dist/run-DwdAwnLG.cjs.map +0 -1
  99. package/dist/run-Lr0Ctnu0.cjs +0 -50
  100. package/dist/run-Lr0Ctnu0.cjs.map +0 -1
  101. package/dist/run-P6D8TnXf.js +0 -1738
  102. package/dist/run-P6D8TnXf.js.map +0 -1
  103. package/dist/run-YsoCk5we.cjs.map +0 -1
  104. package/dist/shell-475fQKaX.cjs +0 -62
  105. package/dist/shell-475fQKaX.cjs.map +0 -1
  106. package/dist/shell-CN6DNqeC.js +0 -51
  107. package/dist/shell-CN6DNqeC.js.map +0 -1
  108. package/dist/telemetry-B2iWkY5e.cjs.map +0 -1
  109. package/dist/telemetry-BkektVz6.js +0 -243
  110. package/dist/telemetry-BkektVz6.js.map +0 -1
  111. package/dist/validate-Bj8vbvPt.cjs.map +0 -1
  112. package/dist/validate-bHUrnYBv.js.map +0 -1
  113. package/src/commands/agent/start.ts +0 -50
  114. package/src/commands/agent.ts +0 -10
  115. package/src/commands/generate.ts +0 -59
  116. package/src/commands/init.ts +0 -51
  117. package/src/commands/mcp.ts +0 -36
  118. package/src/commands/validate.ts +0 -22
  119. package/src/constants.ts +0 -48
  120. package/src/index.ts +0 -45
  121. package/src/loggers/clackLogger.ts +0 -460
  122. package/src/loggers/fileSystemLogger.ts +0 -151
  123. package/src/loggers/githubActionsLogger.ts +0 -367
  124. package/src/loggers/plainLogger.ts +0 -243
  125. package/src/loggers/types.ts +0 -7
  126. package/src/loggers/utils.ts +0 -252
  127. package/src/runners/agent/run.ts +0 -113
  128. package/src/runners/agent/utils.ts +0 -98
  129. package/src/runners/generate/run.ts +0 -276
  130. package/src/runners/generate/utils.ts +0 -209
  131. package/src/runners/init/run.ts +0 -211
  132. package/src/runners/init/utils.ts +0 -33
  133. package/src/runners/mcp/run.ts +0 -55
  134. package/src/runners/validate/run.ts +0 -63
  135. package/src/telemetry.ts +0 -280
  136. /package/dist/{chunk-ByKO4r7w.cjs → rolldown-runtime-Bx3C2hgW.cjs} +0 -0
@@ -1,460 +0,0 @@
1
- import { relative } from 'node:path'
2
- import process from 'node:process'
3
- import { styleText } from 'node:util'
4
- import * as clack from '@clack/prompts'
5
- import { formatMs, formatMsWithColor, getIntro, toCause } from '@internals/utils'
6
- import { defineLogger, logLevel as logLevelMap } from '@kubb/core'
7
- import { getSummary } from './utils.ts'
8
- import { buildProgressLine, formatCommandWithArgs, formatMessage } from './utils.ts'
9
- import { Writable } from 'node:stream'
10
- import type { WritableOptions } from 'node:stream'
11
-
12
- /**
13
- * Node.js `Writable` stream that forwards each chunk to a clack `taskLog` message.
14
- * Used to pipe hook subprocess output into the clack task log UI.
15
- */
16
- class ClackWritable extends Writable {
17
- taskLog: ReturnType<typeof clack.taskLog>
18
- constructor(taskLog: ReturnType<typeof clack.taskLog>, opts?: WritableOptions) {
19
- super(opts)
20
-
21
- this.taskLog = taskLog
22
- }
23
- _write(chunk: Buffer, _encoding: BufferEncoding, callback: (error?: Error | null) => void): void {
24
- this.taskLog.message(`${styleText('dim', chunk.toString())}`)
25
- callback()
26
- }
27
- }
28
-
29
- /**
30
- * TTY logger with beautiful UI and progress indicators for local development.
31
- */
32
- export const clackLogger = defineLogger({
33
- name: 'clack',
34
- install(context, options) {
35
- const logLevel = options?.logLevel ?? logLevelMap.info
36
- const state = {
37
- totalPlugins: 0,
38
- completedPlugins: 0,
39
- failedPlugins: 0,
40
- totalFiles: 0,
41
- processedFiles: 0,
42
- hrStart: process.hrtime(),
43
- spinner: clack.spinner(),
44
- isSpinning: false,
45
- activeProgress: new Map<string, { interval?: NodeJS.Timeout; progressBar: clack.ProgressResult }>(),
46
- }
47
-
48
- function reset() {
49
- for (const [_key, active] of state.activeProgress) {
50
- if (active.interval) {
51
- clearInterval(active.interval)
52
- }
53
- active.progressBar?.stop()
54
- }
55
-
56
- state.totalPlugins = 0
57
- state.completedPlugins = 0
58
- state.failedPlugins = 0
59
- state.totalFiles = 0
60
- state.processedFiles = 0
61
- state.hrStart = process.hrtime()
62
- state.spinner = clack.spinner()
63
- state.isSpinning = false
64
- state.activeProgress.clear()
65
- }
66
-
67
- function showProgressStep() {
68
- if (logLevel <= logLevelMap.silent) {
69
- return
70
- }
71
-
72
- const line = buildProgressLine(state)
73
- if (line) {
74
- clack.log.step(getMessage(line))
75
- }
76
- }
77
-
78
- function getMessage(message: string): string {
79
- return formatMessage(message, logLevel)
80
- }
81
-
82
- function startSpinner(text?: string) {
83
- state.spinner.start(text)
84
- state.isSpinning = true
85
- }
86
-
87
- function stopSpinner(text?: string) {
88
- state.spinner.stop(text)
89
- state.isSpinning = false
90
- }
91
-
92
- context.on('kubb:info', ({ message, info = '' }) => {
93
- if (logLevel <= logLevelMap.silent) {
94
- return
95
- }
96
-
97
- const text = getMessage([styleText('blue', 'ℹ'), message, styleText('dim', info)].join(' '))
98
-
99
- if (state.isSpinning) {
100
- state.spinner.message(text)
101
- } else {
102
- clack.log.info(text)
103
- }
104
- })
105
-
106
- context.on('kubb:success', ({ message, info = '' }) => {
107
- if (logLevel <= logLevelMap.silent) {
108
- return
109
- }
110
-
111
- const text = getMessage([styleText('blue', '✓'), message, logLevel >= logLevelMap.info ? styleText('dim', info) : undefined].filter(Boolean).join(' '))
112
-
113
- if (state.isSpinning) {
114
- stopSpinner(text)
115
- } else {
116
- clack.log.success(text)
117
- }
118
- })
119
-
120
- context.on('kubb:warn', ({ message, info }) => {
121
- if (logLevel < logLevelMap.warn) {
122
- return
123
- }
124
-
125
- const text = getMessage(
126
- [styleText('yellow', '⚠'), message, logLevel >= logLevelMap.info && info ? styleText('dim', info) : undefined].filter(Boolean).join(' '),
127
- )
128
-
129
- clack.log.warn(text)
130
- })
131
-
132
- context.on('kubb:error', ({ error }) => {
133
- const caused = toCause(error)
134
-
135
- const text = [styleText('red', '✗'), error.message].join(' ')
136
-
137
- if (state.isSpinning) {
138
- stopSpinner(getMessage(text))
139
- } else {
140
- clack.log.error(getMessage(text))
141
- }
142
-
143
- // Show stack trace in debug mode (first 3 frames)
144
- if (logLevel >= logLevelMap.debug && error.stack) {
145
- const frames = error.stack.split('\n').slice(1, 4)
146
- for (const frame of frames) {
147
- clack.log.message(getMessage(styleText('dim', frame.trim())))
148
- }
149
-
150
- if (caused?.stack) {
151
- clack.log.message(styleText('dim', `└─ caused by ${caused.message}`))
152
-
153
- const frames = caused.stack.split('\n').slice(1, 4)
154
- for (const frame of frames) {
155
- clack.log.message(getMessage(` ${styleText('dim', frame.trim())}`))
156
- }
157
- }
158
- }
159
- })
160
-
161
- context.on('kubb:version:new', ({ currentVersion, latestVersion }) => {
162
- if (logLevel <= logLevelMap.silent) {
163
- return
164
- }
165
-
166
- try {
167
- clack.box(
168
- `\`v${currentVersion}\` → \`v${latestVersion}\`
169
- Run \`npm install -g @kubb/cli\` to update`,
170
- 'Update available for `Kubb`',
171
- {
172
- width: 'auto',
173
- formatBorder: (s: string) => styleText('yellow', s),
174
- rounded: true,
175
- withGuide: false,
176
- contentAlign: 'center',
177
- titleAlign: 'center',
178
- },
179
- )
180
- } catch {
181
- console.log(`Update available for Kubb: v${currentVersion} → v${latestVersion}`)
182
- console.log('Run `npm install -g @kubb/cli` to update')
183
- }
184
- })
185
-
186
- context.on('kubb:lifecycle:start', async ({ version }) => {
187
- console.log(`\n${getIntro({ title: 'The ultimate toolkit for working with APIs', description: 'Ready to start', version, areEyesOpen: true })}\n`)
188
-
189
- reset()
190
- })
191
-
192
- context.on('kubb:config:start', () => {
193
- if (logLevel <= logLevelMap.silent) {
194
- return
195
- }
196
-
197
- const text = getMessage('Configuration started')
198
-
199
- clack.intro(text)
200
- startSpinner(getMessage('Configuration loading'))
201
- })
202
-
203
- context.on('kubb:config:end', () => {
204
- if (logLevel <= logLevelMap.silent) {
205
- return
206
- }
207
-
208
- const text = getMessage('Configuration completed')
209
-
210
- clack.outro(text)
211
- })
212
-
213
- context.on('kubb:generation:start', ({ config }) => {
214
- reset()
215
-
216
- // Initialize progress tracking for this generation
217
- state.totalPlugins = config.plugins?.length ?? 0
218
-
219
- const text = getMessage(['Generation started', config.name ? `for ${styleText('dim', config.name)}` : undefined].filter(Boolean).join(' '))
220
-
221
- clack.intro(text)
222
- })
223
-
224
- context.on('kubb:plugin:start', ({ plugin }) => {
225
- if (logLevel <= logLevelMap.silent) {
226
- return
227
- }
228
-
229
- stopSpinner()
230
-
231
- const progressBar = clack.progress({
232
- style: 'block',
233
- max: 100,
234
- size: 30,
235
- })
236
- const text = getMessage(`Generating ${styleText('bold', plugin.name)}`)
237
- progressBar.start(text)
238
-
239
- const interval = setInterval(() => {
240
- progressBar.advance()
241
- }, 100)
242
-
243
- state.activeProgress.set(plugin.name, { progressBar, interval })
244
- })
245
-
246
- context.on('kubb:plugin:end', ({ plugin, duration, success }) => {
247
- stopSpinner()
248
-
249
- const active = state.activeProgress.get(plugin.name)
250
-
251
- if (!active || logLevel === logLevelMap.silent) {
252
- return
253
- }
254
-
255
- clearInterval(active.interval)
256
-
257
- if (success) {
258
- state.completedPlugins++
259
- } else {
260
- state.failedPlugins++
261
- }
262
-
263
- const durationStr = formatMsWithColor(duration)
264
- const text = getMessage(
265
- success
266
- ? `${styleText('bold', plugin.name)} completed in ${durationStr}`
267
- : `${styleText('bold', plugin.name)} failed in ${styleText('red', formatMs(duration))}`,
268
- )
269
-
270
- active.progressBar.stop(text)
271
- state.activeProgress.delete(plugin.name)
272
-
273
- // Show progress step after each plugin
274
- showProgressStep()
275
- })
276
-
277
- context.on('kubb:files:processing:start', ({ files }) => {
278
- if (logLevel <= logLevelMap.silent) {
279
- return
280
- }
281
-
282
- stopSpinner()
283
-
284
- state.totalFiles = files.length
285
- state.processedFiles = 0
286
-
287
- const text = `Writing ${files.length} files`
288
- const progressBar = clack.progress({
289
- style: 'block',
290
- max: files.length,
291
- size: 30,
292
- })
293
-
294
- context.emit('kubb:info', { message: text })
295
- progressBar.start(getMessage(text))
296
- state.activeProgress.set('files', { progressBar })
297
- })
298
-
299
- context.on('kubb:file:processing:update', ({ file, config }) => {
300
- if (logLevel <= logLevelMap.silent) {
301
- return
302
- }
303
-
304
- stopSpinner()
305
-
306
- state.processedFiles++
307
-
308
- const text = `Writing ${relative(config.root, file.path)}`
309
- const active = state.activeProgress.get('files')
310
-
311
- if (!active) {
312
- return
313
- }
314
-
315
- active.progressBar.advance(undefined, text)
316
- })
317
- context.on('kubb:files:processing:end', () => {
318
- if (logLevel <= logLevelMap.silent) {
319
- return
320
- }
321
-
322
- stopSpinner()
323
-
324
- const text = getMessage('Files written successfully')
325
- const active = state.activeProgress.get('files')
326
-
327
- if (!active) {
328
- return
329
- }
330
-
331
- active.progressBar.stop(text)
332
- state.activeProgress.delete('files')
333
-
334
- // Show final progress step after files are written
335
- showProgressStep()
336
- })
337
-
338
- context.on('kubb:generation:end', ({ config }) => {
339
- const text = getMessage(config.name ? `Generation completed for ${styleText('dim', config.name)}` : 'Generation completed')
340
-
341
- clack.outro(text)
342
- })
343
-
344
- context.on('kubb:format:start', () => {
345
- if (logLevel <= logLevelMap.silent) {
346
- return
347
- }
348
-
349
- const text = getMessage('Format started')
350
-
351
- clack.intro(text)
352
- })
353
-
354
- context.on('kubb:format:end', () => {
355
- if (logLevel <= logLevelMap.silent) {
356
- return
357
- }
358
-
359
- const text = getMessage('Format completed')
360
-
361
- clack.outro(text)
362
- })
363
-
364
- context.on('kubb:lint:start', () => {
365
- if (logLevel <= logLevelMap.silent) {
366
- return
367
- }
368
-
369
- const text = getMessage('Lint started')
370
-
371
- clack.intro(text)
372
- })
373
-
374
- context.on('kubb:lint:end', () => {
375
- if (logLevel <= logLevelMap.silent) {
376
- return
377
- }
378
-
379
- const text = getMessage('Lint completed')
380
-
381
- clack.outro(text)
382
- })
383
-
384
- context.on('kubb:hook:start', ({ command, args }) => {
385
- if (logLevel <= logLevelMap.silent) {
386
- return
387
- }
388
-
389
- const commandWithArgs = formatCommandWithArgs(command, args)
390
- const text = getMessage(`Hook ${styleText('dim', commandWithArgs)} started`)
391
-
392
- clack.intro(text)
393
- })
394
-
395
- context.on('kubb:hook:end', ({ command, args }) => {
396
- if (logLevel <= logLevelMap.silent) {
397
- return
398
- }
399
-
400
- const commandWithArgs = formatCommandWithArgs(command, args)
401
- const text = getMessage(`Hook ${styleText('dim', commandWithArgs)} successfully executed`)
402
-
403
- clack.outro(text)
404
- })
405
-
406
- context.on('kubb:generation:summary', ({ config, pluginTimings, failedPlugins, filesCreated, status, hrStart }) => {
407
- const summary = getSummary({
408
- failedPlugins,
409
- filesCreated,
410
- config,
411
- status,
412
- hrStart,
413
- pluginTimings: logLevel >= logLevelMap.verbose ? pluginTimings : undefined,
414
- })
415
- const title = config.name || ''
416
-
417
- summary.unshift('\n')
418
- summary.push('\n')
419
-
420
- const borderColor = status === 'success' ? 'green' : 'red'
421
- try {
422
- clack.box(summary.join('\n'), getMessage(title), {
423
- width: 'auto',
424
- formatBorder: (s: string) => styleText(borderColor, s),
425
- rounded: true,
426
- withGuide: false,
427
- contentAlign: 'left',
428
- titleAlign: 'center',
429
- })
430
- } catch {
431
- console.log(summary.join('\n'))
432
- }
433
- })
434
-
435
- context.on('kubb:lifecycle:end', () => {
436
- reset()
437
- })
438
-
439
- return (commandWithArgs: string) => {
440
- if (logLevel <= logLevelMap.silent) {
441
- return {
442
- onStdout: (s: string) => console.log(s),
443
- onStderr: (s: string) => console.error(s),
444
- }
445
- }
446
-
447
- const logger = clack.taskLog({
448
- title: getMessage(['Executing hook', logLevel >= logLevelMap.info ? styleText('dim', commandWithArgs) : undefined].filter(Boolean).join(' ')),
449
- })
450
- const writable = new ClackWritable(logger)
451
-
452
- return {
453
- stream: true,
454
- onLine: (line: string) => writable.write(line),
455
- onStdout: (s: string) => logger.message(s),
456
- onStderr: (s: string) => logger.error(s),
457
- }
458
- }
459
- },
460
- })
@@ -1,151 +0,0 @@
1
- import { relative, resolve } from 'node:path'
2
- import process from 'node:process'
3
- import { formatMs, write } from '@internals/utils'
4
- import { defineLogger } from '@kubb/core'
5
-
6
- type CachedEvent = {
7
- /**
8
- * Timestamp when this event was captured, used to derive the log filename.
9
- */
10
- date: Date
11
- /**
12
- * Accumulated log lines for this event.
13
- */
14
- logs: string[]
15
- /**
16
- * Optional override for the output filename inside `.kubb/`. When omitted, the filename is derived from `date`.
17
- */
18
- fileName?: string
19
- }
20
-
21
- /**
22
- * FileSystem logger that captures debug events and writes them to `.kubb` directory files.
23
- *
24
- * @note Logs are written on `kubb:lifecycle:end` or process exit. Cached logs may be lost if the process crashes before either event.
25
- */
26
- export const fileSystemLogger = defineLogger({
27
- name: 'filesystem',
28
- install(context) {
29
- const state = {
30
- cachedLogs: new Set<CachedEvent>(),
31
- startDate: Date.now(),
32
- }
33
-
34
- function reset() {
35
- state.cachedLogs = new Set<CachedEvent>()
36
- state.startDate = Date.now()
37
- }
38
-
39
- async function writeLogs(name?: string) {
40
- if (state.cachedLogs.size === 0) {
41
- return []
42
- }
43
-
44
- const files: Record<string, string[]> = {}
45
-
46
- for (const log of state.cachedLogs) {
47
- const baseName = log.fileName || `${['kubb', name, state.startDate].filter(Boolean).join('-')}.log`
48
- const pathName = resolve(process.cwd(), '.kubb', baseName)
49
-
50
- if (!files[pathName]) {
51
- files[pathName] = []
52
- }
53
-
54
- if (log.logs.length > 0) {
55
- const prefix = `[${log.date.toLocaleString()}] `
56
- const indent = ' '.repeat(prefix.length)
57
- const [first, ...rest] = log.logs
58
- files[pathName].push([prefix + first, ...rest.map((line) => indent + line)].join('\n'))
59
- }
60
- }
61
-
62
- for (const [fileName, logs] of Object.entries(files)) {
63
- await write(fileName, logs.join('\n'))
64
- }
65
-
66
- return Object.keys(files)
67
- }
68
-
69
- context.on('kubb:info', ({ message, info }) => {
70
- state.cachedLogs.add({
71
- date: new Date(),
72
- logs: [`ℹ ${[message, info].filter(Boolean).join(' ')}`],
73
- })
74
- })
75
-
76
- context.on('kubb:success', ({ message, info }) => {
77
- state.cachedLogs.add({
78
- date: new Date(),
79
- logs: [`✓ ${[message, info].filter(Boolean).join(' ')}`],
80
- })
81
- })
82
-
83
- context.on('kubb:warn', ({ message, info }) => {
84
- state.cachedLogs.add({
85
- date: new Date(),
86
- logs: [`⚠ ${[message, info].filter(Boolean).join(' ')}`],
87
- })
88
- })
89
-
90
- context.on('kubb:error', ({ error }) => {
91
- state.cachedLogs.add({
92
- date: new Date(),
93
- logs: [`✗ ${error.message}`, error.stack || 'unknown stack'],
94
- })
95
- })
96
-
97
- context.on('kubb:debug', ({ date, fileName, logs }) => {
98
- state.cachedLogs.add({
99
- date,
100
- fileName,
101
- logs,
102
- })
103
- })
104
-
105
- context.on('kubb:plugin:start', ({ plugin }) => {
106
- state.cachedLogs.add({
107
- date: new Date(),
108
- logs: [`► Generating ${plugin.name}`],
109
- })
110
- })
111
-
112
- context.on('kubb:plugin:end', ({ plugin, duration, success }) => {
113
- const durationStr = formatMs(duration)
114
-
115
- state.cachedLogs.add({
116
- date: new Date(),
117
- logs: [success ? `✓ ${plugin.name} completed in ${durationStr}` : `✗ ${plugin.name} failed in ${durationStr}`],
118
- })
119
- })
120
-
121
- context.on('kubb:files:processing:start', ({ files }) => {
122
- state.cachedLogs.add({
123
- date: new Date(),
124
- logs: [`► Writing ${files.length} files`, ...files.map((file) => ` ${file.path}`)],
125
- })
126
- })
127
-
128
- context.on('kubb:generation:end', async ({ config }) => {
129
- const writtenFilePaths = await writeLogs(config.name)
130
- if (writtenFilePaths.length > 0) {
131
- const files = writtenFilePaths.map((f) => relative(process.cwd(), f))
132
- await context.emit('kubb:info', { message: 'Debug files written to:', info: files.join(', ') })
133
- }
134
- reset()
135
- })
136
-
137
- // Fallback: Write logs on process exit to handle crashes
138
- const exitHandler = () => {
139
- // Synchronous write on exit - best effort
140
- if (state.cachedLogs.size > 0) {
141
- writeLogs().catch(() => {
142
- // Ignore errors on exit
143
- })
144
- }
145
- }
146
-
147
- process.once('exit', exitHandler)
148
- process.once('SIGINT', exitHandler)
149
- process.once('SIGTERM', exitHandler)
150
- },
151
- })