@kubb/cli 4.12.6 → 4.12.8

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 (35) hide show
  1. package/dist/{generate-DrdKyOOH.cjs → generate-BIq4hG_7.cjs} +350 -176
  2. package/dist/generate-BIq4hG_7.cjs.map +1 -0
  3. package/dist/{generate-M-5j2zqa.js → generate-DbvDQY54.js} +351 -177
  4. package/dist/generate-DbvDQY54.js.map +1 -0
  5. package/dist/index.cjs +3 -5
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.js +3 -5
  8. package/dist/index.js.map +1 -1
  9. package/dist/mcp-B5FWDVjp.js.map +1 -1
  10. package/dist/mcp-D7d_8Bma.cjs.map +1 -1
  11. package/dist/{package-4h1lfDoB.cjs → package-DIKLcg4Q.cjs} +2 -2
  12. package/dist/package-DIKLcg4Q.cjs.map +1 -0
  13. package/dist/package-sWmJhaYS.js +6 -0
  14. package/dist/package-sWmJhaYS.js.map +1 -0
  15. package/dist/validate-Bt922JN-.js.map +1 -1
  16. package/dist/validate-D9LPzg3-.cjs.map +1 -1
  17. package/package.json +4 -4
  18. package/src/commands/generate.ts +10 -0
  19. package/src/commands/mcp.ts +1 -3
  20. package/src/commands/validate.ts +1 -3
  21. package/src/index.ts +0 -9
  22. package/src/loggers/clackLogger.ts +152 -86
  23. package/src/loggers/fileSystemLogger.ts +81 -15
  24. package/src/loggers/githubActionsLogger.ts +137 -57
  25. package/src/loggers/plainLogger.ts +33 -36
  26. package/src/runners/generate.ts +56 -45
  27. package/src/utils/Writables.ts +0 -8
  28. package/src/utils/executeHooks.ts +7 -4
  29. package/src/utils/getSummary.ts +3 -3
  30. package/dist/generate-DrdKyOOH.cjs.map +0 -1
  31. package/dist/generate-M-5j2zqa.js.map +0 -1
  32. package/dist/package-4h1lfDoB.cjs.map +0 -1
  33. package/dist/package-B857a-xb.js +0 -6
  34. package/dist/package-B857a-xb.js.map +0 -1
  35. package/src/utils/parseHrtimeToSeconds.ts +0 -4
@@ -1,4 +1,5 @@
1
1
  import { type Config, defineLogger, LogLevel } from '@kubb/core'
2
+ import { formatHrtime, formatMs } from '@kubb/core/utils'
2
3
  import { execa } from 'execa'
3
4
  import pc from 'picocolors'
4
5
 
@@ -10,7 +11,50 @@ export const githubActionsLogger = defineLogger({
10
11
  name: 'github-actions',
11
12
  install(context, options) {
12
13
  const logLevel = options?.logLevel || LogLevel.info
13
- let currentConfigs: Array<Config> = []
14
+ const state = {
15
+ totalPlugins: 0,
16
+ completedPlugins: 0,
17
+ failedPlugins: 0,
18
+ totalFiles: 0,
19
+ processedFiles: 0,
20
+ hrStart: process.hrtime(),
21
+ currentConfigs: [] as Array<Config>,
22
+ }
23
+
24
+ function reset() {
25
+ state.totalPlugins = 0
26
+ state.completedPlugins = 0
27
+ state.failedPlugins = 0
28
+ state.totalFiles = 0
29
+ state.processedFiles = 0
30
+ state.hrStart = process.hrtime()
31
+ }
32
+
33
+ function showProgressStep() {
34
+ if (logLevel <= LogLevel.silent) {
35
+ return
36
+ }
37
+
38
+ const parts: string[] = []
39
+ const duration = formatHrtime(state.hrStart)
40
+
41
+ if (state.totalPlugins > 0) {
42
+ const pluginStr =
43
+ state.failedPlugins > 0
44
+ ? `Plugins ${pc.green(state.completedPlugins.toString())}/${state.totalPlugins} ${pc.red(`(${state.failedPlugins} failed)`)}`
45
+ : `Plugins ${pc.green(state.completedPlugins.toString())}/${state.totalPlugins}`
46
+ parts.push(pluginStr)
47
+ }
48
+
49
+ if (state.totalFiles > 0) {
50
+ parts.push(`Files ${pc.green(state.processedFiles.toString())}/${state.totalFiles}`)
51
+ }
52
+
53
+ if (parts.length > 0) {
54
+ parts.push(`${pc.green(duration)} elapsed`)
55
+ console.log(getMessage(parts.join(pc.dim(' | '))))
56
+ }
57
+ }
14
58
 
15
59
  function getMessage(message: string): string {
16
60
  if (logLevel >= LogLevel.verbose) {
@@ -75,6 +119,7 @@ export const githubActionsLogger = defineLogger({
75
119
 
76
120
  context.on('lifecycle:start', (version) => {
77
121
  console.log(pc.yellow(`Kubb ${version} 🧩`))
122
+ reset()
78
123
  })
79
124
 
80
125
  context.on('config:start', () => {
@@ -90,7 +135,7 @@ export const githubActionsLogger = defineLogger({
90
135
  })
91
136
 
92
137
  context.on('config:end', (configs) => {
93
- currentConfigs = configs
138
+ state.currentConfigs = configs
94
139
 
95
140
  if (logLevel <= LogLevel.silent) {
96
141
  return
@@ -104,15 +149,20 @@ export const githubActionsLogger = defineLogger({
104
149
  })
105
150
 
106
151
  context.on('generation:start', (config) => {
152
+ // Initialize progress tracking
153
+ state.totalPlugins = config.plugins?.length || 0
154
+
107
155
  const text = config.name ? `Generation for ${pc.bold(config.name)}` : 'Generation'
108
156
 
109
- if (currentConfigs.length > 1) {
157
+ if (state.currentConfigs.length > 1) {
110
158
  openGroup(text)
111
159
  }
112
160
 
113
- if (currentConfigs.length === 1) {
161
+ if (state.currentConfigs.length === 1) {
114
162
  console.log(getMessage(text))
115
163
  }
164
+
165
+ reset()
116
166
  })
117
167
 
118
168
  context.on('plugin:start', (plugin) => {
@@ -121,35 +171,51 @@ export const githubActionsLogger = defineLogger({
121
171
  }
122
172
  const text = getMessage(`Generating ${pc.bold(plugin.name)}`)
123
173
 
124
- if (currentConfigs.length === 1) {
174
+ if (state.currentConfigs.length === 1) {
125
175
  openGroup(`Plugin: ${plugin.name}`)
126
176
  }
127
177
 
128
178
  console.log(text)
129
179
  })
130
180
 
131
- context.on('plugin:end', (plugin, duration) => {
181
+ context.on('plugin:end', (plugin, { duration, success }) => {
132
182
  if (logLevel <= LogLevel.silent) {
133
183
  return
134
184
  }
135
- const durationStr = duration >= 1000 ? `${(duration / 1000).toFixed(2)}s` : `${duration}ms`
136
- const text = getMessage(`${pc.bold(plugin.name)} completed in ${pc.green(durationStr)}`)
185
+
186
+ if (success) {
187
+ state.completedPlugins++
188
+ } else {
189
+ state.failedPlugins++
190
+ }
191
+
192
+ const durationStr = formatMs(duration)
193
+ const text = getMessage(
194
+ success ? `${pc.bold(plugin.name)} completed in ${pc.green(durationStr)}` : `${pc.bold(plugin.name)} failed in ${pc.red(durationStr)}`,
195
+ )
137
196
 
138
197
  console.log(text)
139
- if (currentConfigs.length > 1) {
198
+ if (state.currentConfigs.length > 1) {
140
199
  console.log(' ')
141
200
  }
142
201
 
143
- if (currentConfigs.length === 1) {
202
+ if (state.currentConfigs.length === 1) {
144
203
  closeGroup(`Plugin: ${plugin.name}`)
145
204
  }
205
+
206
+ // Show progress step after each plugin
207
+ showProgressStep()
146
208
  })
147
209
 
148
210
  context.on('files:processing:start', (files) => {
149
211
  if (logLevel <= LogLevel.silent) {
150
212
  return
151
213
  }
152
- if (currentConfigs.length === 1) {
214
+
215
+ state.totalFiles = files.length
216
+ state.processedFiles = 0
217
+
218
+ if (state.currentConfigs.length === 1) {
153
219
  openGroup('File Generation')
154
220
  }
155
221
  const text = getMessage(`Writing ${files.length} files`)
@@ -165,43 +231,32 @@ export const githubActionsLogger = defineLogger({
165
231
 
166
232
  console.log(text)
167
233
 
168
- if (currentConfigs.length === 1) {
234
+ if (state.currentConfigs.length === 1) {
169
235
  closeGroup('File Generation')
170
236
  }
171
237
  })
172
238
 
173
- context.on('generation:end', (config) => {
174
- const text = getMessage(config.name ? `${pc.blue('✓')} Generation completed for ${pc.dim(config.name)}` : `${pc.blue('✓')} Generation completed`)
239
+ context.on('file:processing:update', () => {
240
+ if (logLevel <= LogLevel.silent) {
241
+ return
242
+ }
175
243
 
176
- console.log(text)
244
+ state.processedFiles++
177
245
  })
178
246
 
179
- context.on('hook:execute', async ({ command, args }, cb) => {
180
- try {
181
- const result = await execa(command, args, {
182
- detached: true,
183
- stripFinalNewline: true,
184
- })
185
-
186
- await context.emit('debug', {
187
- date: new Date(),
188
- logs: [result.stdout],
189
- })
190
-
191
- console.log(result.stdout)
247
+ context.on('files:processing:end', () => {
248
+ if (logLevel <= LogLevel.silent) {
249
+ return
250
+ }
192
251
 
193
- cb()
194
- } catch (err) {
195
- const error = new Error('Hook execute failed')
196
- error.cause = err
252
+ // Show final progress step after files are written
253
+ showProgressStep()
254
+ })
197
255
 
198
- await context.emit('debug', {
199
- date: new Date(),
200
- logs: [(err as any).stdout],
201
- })
256
+ context.on('generation:end', (config) => {
257
+ const text = getMessage(config.name ? `${pc.blue('✓')} Generation completed for ${pc.dim(config.name)}` : `${pc.blue('✓')} Generation completed`)
202
258
 
203
- await context.emit('error', error)
204
- }
259
+ console.log(text)
205
260
  })
206
261
 
207
262
  context.on('format:start', () => {
@@ -211,7 +266,7 @@ export const githubActionsLogger = defineLogger({
211
266
 
212
267
  const text = getMessage('Format started')
213
268
 
214
- if (currentConfigs.length === 1) {
269
+ if (state.currentConfigs.length === 1) {
215
270
  openGroup('Formatting')
216
271
  }
217
272
 
@@ -227,7 +282,7 @@ export const githubActionsLogger = defineLogger({
227
282
 
228
283
  console.log(text)
229
284
 
230
- if (currentConfigs.length === 1) {
285
+ if (state.currentConfigs.length === 1) {
231
286
  closeGroup('Formatting')
232
287
  }
233
288
  })
@@ -239,7 +294,7 @@ export const githubActionsLogger = defineLogger({
239
294
 
240
295
  const text = getMessage('Lint started')
241
296
 
242
- if (currentConfigs.length === 1) {
297
+ if (state.currentConfigs.length === 1) {
243
298
  openGroup('Linting')
244
299
  }
245
300
 
@@ -255,26 +310,50 @@ export const githubActionsLogger = defineLogger({
255
310
 
256
311
  console.log(text)
257
312
 
258
- if (currentConfigs.length === 1) {
313
+ if (state.currentConfigs.length === 1) {
259
314
  closeGroup('Linting')
260
315
  }
261
316
  })
262
317
 
263
- context.on('hook:start', (command) => {
264
- if (logLevel <= LogLevel.silent) {
265
- return
266
- }
267
-
318
+ context.on('hook:start', async ({ id, command, args }) => {
268
319
  const text = getMessage(`Hook ${pc.dim(command)} started`)
269
320
 
270
- if (currentConfigs.length === 1) {
271
- openGroup(`Hook ${command}`)
321
+ if (logLevel > LogLevel.silent) {
322
+ if (state.currentConfigs.length === 1) {
323
+ openGroup(`Hook ${command}`)
324
+ }
325
+
326
+ console.log(text)
272
327
  }
273
328
 
274
- console.log(text)
329
+ try {
330
+ const result = await execa(command, args, {
331
+ detached: true,
332
+ stripFinalNewline: true,
333
+ })
334
+
335
+ await context.emit('debug', {
336
+ date: new Date(),
337
+ logs: [result.stdout],
338
+ })
339
+
340
+ console.log(result.stdout)
341
+
342
+ await context.emit('hook:end', { command, id })
343
+ } catch (err) {
344
+ const error = new Error('Hook execute failed')
345
+ error.cause = err
346
+
347
+ await context.emit('debug', {
348
+ date: new Date(),
349
+ logs: [(err as any).stdout],
350
+ })
351
+
352
+ await context.emit('error', error)
353
+ }
275
354
  })
276
355
 
277
- context.on('hook:end', (command) => {
356
+ context.on('hook:end', ({ command }) => {
278
357
  if (logLevel <= LogLevel.silent) {
279
358
  return
280
359
  }
@@ -283,26 +362,27 @@ export const githubActionsLogger = defineLogger({
283
362
 
284
363
  console.log(text)
285
364
 
286
- if (currentConfigs.length === 1) {
365
+ if (state.currentConfigs.length === 1) {
287
366
  closeGroup(`Hook ${command}`)
288
367
  }
289
368
  })
290
369
 
291
- context.on('generation:summary', (config, { status, failedPlugins }) => {
370
+ context.on('generation:summary', (config, { status, hrStart, failedPlugins }) => {
292
371
  const pluginsCount = config.plugins?.length || 0
293
372
  const successCount = pluginsCount - failedPlugins.size
373
+ const duration = formatHrtime(hrStart)
294
374
 
295
- if (currentConfigs.length > 1) {
375
+ if (state.currentConfigs.length > 1) {
296
376
  console.log(' ')
297
377
  }
298
378
 
299
379
  console.log(
300
380
  status === 'success'
301
- ? `Kubb Summary: ${pc.blue('✓')} ${`${successCount} successful`}, ${pluginsCount} total`
302
- : `Kubb Summary: ${pc.blue('✓')} ${`${successCount} successful`}, ✗ ${`${failedPlugins.size} failed`}, ${pluginsCount} total`,
381
+ ? `Kubb Summary: ${pc.blue('✓')} ${`${successCount} successful`}, ${pluginsCount} total, ${pc.green(duration)}`
382
+ : `Kubb Summary: ${pc.blue('✓')} ${`${successCount} successful`}, ✗ ${`${failedPlugins.size} failed`}, ${pluginsCount} total, ${pc.green(duration)}`,
303
383
  )
304
384
 
305
- if (currentConfigs.length > 1) {
385
+ if (state.currentConfigs.length > 1) {
306
386
  closeGroup(config.name ? `Generation for ${pc.bold(config.name)}` : 'Generation')
307
387
  }
308
388
  })
@@ -1,5 +1,6 @@
1
1
  import { relative } from 'node:path'
2
2
  import { defineLogger, LogLevel } from '@kubb/core'
3
+ import { formatMs } from '@kubb/core/utils'
3
4
  import { execa } from 'execa'
4
5
  import { getSummary } from '../utils/getSummary.ts'
5
6
 
@@ -121,13 +122,13 @@ export const plainLogger = defineLogger({
121
122
  console.log(text)
122
123
  })
123
124
 
124
- context.on('plugin:end', (plugin, duration) => {
125
+ context.on('plugin:end', (plugin, { duration, success }) => {
125
126
  if (logLevel <= LogLevel.silent) {
126
127
  return
127
128
  }
128
129
 
129
- const durationStr = duration >= 1000 ? `${(duration / 1000).toFixed(2)}s` : `${duration}ms`
130
- const text = getMessage(`${plugin.name} completed in ${durationStr}`)
130
+ const durationStr = formatMs(duration)
131
+ const text = getMessage(success ? `${plugin.name} completed in ${durationStr}` : `${plugin.name} failed in ${durationStr}`)
131
132
 
132
133
  console.log(text)
133
134
  })
@@ -168,34 +169,6 @@ export const plainLogger = defineLogger({
168
169
  console.log(text)
169
170
  })
170
171
 
171
- context.on('hook:execute', async ({ command, args }, cb) => {
172
- try {
173
- const result = await execa(command, args, {
174
- detached: true,
175
- stripFinalNewline: true,
176
- })
177
-
178
- await context.emit('debug', {
179
- date: new Date(),
180
- logs: [result.stdout],
181
- })
182
-
183
- console.log(result.stdout)
184
-
185
- cb()
186
- } catch (err) {
187
- const error = new Error('Hook execute failed')
188
- error.cause = err
189
-
190
- await context.emit('debug', {
191
- date: new Date(),
192
- logs: [(err as any).stdout],
193
- })
194
-
195
- await context.emit('error', error)
196
- }
197
- })
198
-
199
172
  context.on('format:start', () => {
200
173
  if (logLevel <= LogLevel.silent) {
201
174
  return
@@ -236,14 +209,38 @@ export const plainLogger = defineLogger({
236
209
  console.log(text)
237
210
  })
238
211
 
239
- context.on('hook:start', (command) => {
240
- if (logLevel <= LogLevel.silent) {
241
- return
212
+ context.on('hook:start', async ({ id, command, args }) => {
213
+ const text = getMessage(`Hook ${command} started`)
214
+
215
+ if (logLevel > LogLevel.silent) {
216
+ console.log(text)
242
217
  }
243
218
 
244
- const text = getMessage(`Hook ${command} started`)
219
+ try {
220
+ const result = await execa(command, args, {
221
+ detached: true,
222
+ stripFinalNewline: true,
223
+ })
245
224
 
246
- console.log(text)
225
+ await context.emit('debug', {
226
+ date: new Date(),
227
+ logs: [result.stdout],
228
+ })
229
+
230
+ console.log(result.stdout)
231
+
232
+ await context.emit('hook:end', { command, id })
233
+ } catch (err) {
234
+ const error = new Error('Hook execute failed')
235
+ error.cause = err
236
+
237
+ await context.emit('debug', {
238
+ date: new Date(),
239
+ logs: [(err as any).stdout],
240
+ })
241
+
242
+ await context.emit('error', error)
243
+ }
247
244
  })
248
245
 
249
246
  context.on('hook:end', (command) => {
@@ -1,3 +1,4 @@
1
+ import { createHash } from 'node:crypto'
1
2
  import path from 'node:path'
2
3
  import process from 'node:process'
3
4
  import { type Config, type KubbEvents, LogLevel, safeBuild, setup } from '@kubb/core'
@@ -106,13 +107,15 @@ export async function generate({ input, config, events, logLevel }: GenerateProp
106
107
 
107
108
  if (config.output.format === 'prettier') {
108
109
  try {
109
- await events.emit(
110
- 'hook:execute',
111
- {
112
- command: 'prettier',
113
- args: ['--ignore-unknown', '--write', path.resolve(definedConfig.root, definedConfig.output.path)],
114
- },
115
- async () => {
110
+ const hookId = createHash('sha256').update(config.output.format).digest('hex')
111
+ await events.emit('hook:start', {
112
+ id: hookId,
113
+ command: 'prettier',
114
+ args: ['--ignore-unknown', '--write', path.resolve(definedConfig.root, definedConfig.output.path)],
115
+ })
116
+
117
+ await events.on('hook:end', async ({ id }) => {
118
+ if (id === hookId) {
116
119
  await events.emit(
117
120
  'success',
118
121
  [
@@ -123,8 +126,8 @@ export async function generate({ input, config, events, logLevel }: GenerateProp
123
126
  .filter(Boolean)
124
127
  .join(' '),
125
128
  )
126
- },
127
- )
129
+ }
130
+ })
128
131
  } catch (caughtError) {
129
132
  await events.emit('error', caughtError as Error)
130
133
  }
@@ -134,13 +137,15 @@ export async function generate({ input, config, events, logLevel }: GenerateProp
134
137
 
135
138
  if (config.output.format === 'biome') {
136
139
  try {
137
- await events.emit(
138
- 'hook:execute',
139
- {
140
- command: 'biome',
141
- args: ['format', '--write', path.resolve(definedConfig.root, definedConfig.output.path)],
142
- },
143
- async () => {
140
+ const hookId = createHash('sha256').update(config.output.format).digest('hex')
141
+ await events.emit('hook:start', {
142
+ id: hookId,
143
+ command: 'biome',
144
+ args: ['format', '--write', path.resolve(definedConfig.root, definedConfig.output.path)],
145
+ })
146
+
147
+ await events.on('hook:end', async ({ id }) => {
148
+ if (id === hookId) {
144
149
  await events.emit(
145
150
  'success',
146
151
  [
@@ -151,8 +156,8 @@ export async function generate({ input, config, events, logLevel }: GenerateProp
151
156
  .filter(Boolean)
152
157
  .join(' '),
153
158
  )
154
- },
155
- )
159
+ }
160
+ })
156
161
  } catch (caughtError) {
157
162
  const error = new Error('Biome not found')
158
163
  error.cause = caughtError
@@ -179,13 +184,15 @@ export async function generate({ input, config, events, logLevel }: GenerateProp
179
184
 
180
185
  if (config.output.lint === 'eslint') {
181
186
  try {
182
- await events.emit(
183
- 'hook:execute',
184
- {
185
- command: 'eslint',
186
- args: [path.resolve(definedConfig.root, definedConfig.output.path), '--fix'],
187
- },
188
- async () => {
187
+ const hookId = createHash('sha256').update(config.output.lint).digest('hex')
188
+ await events.emit('hook:start', {
189
+ id: hookId,
190
+ command: 'eslint',
191
+ args: [path.resolve(definedConfig.root, definedConfig.output.path), '--fix'],
192
+ })
193
+
194
+ await events.on('hook:end', async ({ id }) => {
195
+ if (id === hookId) {
189
196
  await events.emit(
190
197
  'success',
191
198
  [
@@ -196,8 +203,8 @@ export async function generate({ input, config, events, logLevel }: GenerateProp
196
203
  .filter(Boolean)
197
204
  .join(' '),
198
205
  )
199
- },
200
- )
206
+ }
207
+ })
201
208
  } catch (caughtError) {
202
209
  const error = new Error('Eslint not found')
203
210
  error.cause = caughtError
@@ -207,13 +214,15 @@ export async function generate({ input, config, events, logLevel }: GenerateProp
207
214
 
208
215
  if (config.output.lint === 'biome') {
209
216
  try {
210
- await events.emit(
211
- 'hook:execute',
212
- {
213
- command: 'biome',
214
- args: ['lint', '--fix', path.resolve(definedConfig.root, definedConfig.output.path)],
215
- },
216
- async () => {
217
+ const hookId = createHash('sha256').update(config.output.lint).digest('hex')
218
+ await events.emit('hook:start', {
219
+ id: hookId,
220
+ command: 'biome',
221
+ args: ['lint', '--fix', path.resolve(definedConfig.root, definedConfig.output.path)],
222
+ })
223
+
224
+ await events.on('hook:end', async ({ id }) => {
225
+ if (id === hookId) {
217
226
  await events.emit(
218
227
  'success',
219
228
  [
@@ -224,8 +233,8 @@ export async function generate({ input, config, events, logLevel }: GenerateProp
224
233
  .filter(Boolean)
225
234
  .join(' '),
226
235
  )
227
- },
228
- )
236
+ }
237
+ })
229
238
  } catch (caughtError) {
230
239
  const error = new Error('Biome not found')
231
240
  error.cause = caughtError
@@ -235,13 +244,15 @@ export async function generate({ input, config, events, logLevel }: GenerateProp
235
244
 
236
245
  if (config.output.lint === 'oxlint') {
237
246
  try {
238
- await events.emit(
239
- 'hook:execute',
240
- {
241
- command: 'oxlint',
242
- args: ['--fix', path.resolve(definedConfig.root, definedConfig.output.path)],
243
- },
244
- async () => {
247
+ const hookId = createHash('sha256').update(config.output.lint).digest('hex')
248
+ await events.emit('hook:start', {
249
+ id: hookId,
250
+ command: 'oxlint',
251
+ args: ['--fix', path.resolve(definedConfig.root, definedConfig.output.path)],
252
+ })
253
+
254
+ await events.on('hook:end', async ({ id }) => {
255
+ if (id === hookId) {
245
256
  await events.emit(
246
257
  'success',
247
258
  [
@@ -252,8 +263,8 @@ export async function generate({ input, config, events, logLevel }: GenerateProp
252
263
  .filter(Boolean)
253
264
  .join(' '),
254
265
  )
255
- },
256
- )
266
+ }
267
+ })
257
268
  } catch (caughtError) {
258
269
  const error = new Error('Oxlint not found')
259
270
  error.cause = caughtError
@@ -15,11 +15,3 @@ export class ClackWritable extends Writable {
15
15
  callback()
16
16
  }
17
17
  }
18
-
19
- export class StdoutWritable extends Writable {
20
- _write(chunk: any, _encoding: BufferEncoding, callback: (error?: Error | null) => void): void {
21
- process.stdout.write(`${pc.dim(chunk?.toString())}`)
22
-
23
- callback()
24
- }
25
- }
@@ -1,3 +1,4 @@
1
+ import { createHash } from 'node:crypto'
1
2
  import type { Config, KubbEvents } from '@kubb/core'
2
3
  import type { AsyncEventEmitter } from '@kubb/core/utils'
3
4
 
@@ -19,12 +20,14 @@ export async function executeHooks({ hooks, events }: ExecutingHooksProps): Prom
19
20
  continue
20
21
  }
21
22
 
22
- await events.emit('hook:start', command)
23
+ const hookId = createHash('sha256').update(command).digest('hex')
23
24
 
24
- await events.emit('hook:execute', { command: cmd, args }, async () => {
25
- await events.emit('success', `${pc.dim(command)} successfully executed`)
25
+ await events.emit('hook:start', { id: hookId, command: cmd, args })
26
26
 
27
- await events.emit('hook:end', command)
27
+ await events.on('hook:end', async ({ id }) => {
28
+ if (id === hookId) {
29
+ await events.emit('success', `${pc.dim(command)} successfully executed`)
30
+ }
28
31
  })
29
32
  }
30
33
  }
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path'
2
2
  import type { Config, Plugin } from '@kubb/core'
3
+ import { formatHrtime } from '@kubb/core/utils'
3
4
  import pc from 'picocolors'
4
- import { parseHrtimeToSeconds } from './parseHrtimeToSeconds.ts'
5
5
  import { randomCliColour } from './randomColour.ts'
6
6
 
7
7
  type SummaryProps = {
@@ -14,7 +14,7 @@ type SummaryProps = {
14
14
  }
15
15
 
16
16
  export function getSummary({ failedPlugins, filesCreated, status, hrStart, config, pluginTimings }: SummaryProps): string[] {
17
- const elapsedSeconds = parseHrtimeToSeconds(process.hrtime(hrStart))
17
+ const duration = formatHrtime(hrStart)
18
18
 
19
19
  const pluginsCount = config.plugins?.length || 0
20
20
  const successCount = pluginsCount - failedPlugins.size
@@ -26,7 +26,7 @@ export function getSummary({ failedPlugins, filesCreated, status, hrStart, confi
26
26
  : `${pc.green(`${successCount} successful`)}, ${pc.red(`${failedPlugins.size} failed`)}, ${pluginsCount} total`,
27
27
  pluginsFailed: status === 'failed' ? [...failedPlugins]?.map(({ plugin }) => randomCliColour(plugin.name))?.join(', ') : undefined,
28
28
  filesCreated: filesCreated,
29
- time: `${elapsedSeconds}s`,
29
+ time: pc.green(duration),
30
30
  output: path.isAbsolute(config.root) ? path.resolve(config.root, config.output.path) : config.root,
31
31
  } as const
32
32