@kubb/cli 4.11.3 → 4.12.0

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 (52) hide show
  1. package/dist/generate-BujndwJK.cjs +1256 -0
  2. package/dist/generate-BujndwJK.cjs.map +1 -0
  3. package/dist/generate-BvrG5K00.js +1249 -0
  4. package/dist/generate-BvrG5K00.js.map +1 -0
  5. package/dist/index.cjs +9 -35
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.js +7 -30
  8. package/dist/index.js.map +1 -1
  9. package/dist/{mcp-BIRDY8xn.js → mcp-LLlOFV3c.js} +5 -6
  10. package/dist/mcp-LLlOFV3c.js.map +1 -0
  11. package/dist/{mcp-BQjDRDXR.cjs → mcp-N1IVyiXf.cjs} +5 -7
  12. package/dist/mcp-N1IVyiXf.cjs.map +1 -0
  13. package/dist/package-Bhc6C7cQ.js +6 -0
  14. package/dist/package-Bhc6C7cQ.js.map +1 -0
  15. package/dist/package-KuCpJxHt.cjs +12 -0
  16. package/dist/package-KuCpJxHt.cjs.map +1 -0
  17. package/dist/{validate-0i6Q9eIy.js → validate-BptoQ-63.js} +5 -6
  18. package/dist/validate-BptoQ-63.js.map +1 -0
  19. package/dist/{validate-6F-VPZR7.cjs → validate-Dn6hZ7Z4.cjs} +5 -7
  20. package/dist/validate-Dn6hZ7Z4.cjs.map +1 -0
  21. package/package.json +7 -7
  22. package/src/commands/generate.ts +52 -65
  23. package/src/commands/mcp.ts +4 -5
  24. package/src/commands/validate.ts +4 -5
  25. package/src/index.ts +8 -23
  26. package/src/loggers/clackLogger.ts +433 -0
  27. package/src/loggers/envDetection.ts +28 -0
  28. package/src/loggers/fileSystemLogger.ts +79 -0
  29. package/src/loggers/githubActionsLogger.ts +310 -0
  30. package/src/loggers/index.ts +7 -0
  31. package/src/loggers/plainLogger.ts +274 -0
  32. package/src/loggers/types.ts +1 -0
  33. package/src/loggers/utils.ts +49 -0
  34. package/src/runners/generate.ts +196 -208
  35. package/src/utils/Writables.ts +12 -8
  36. package/src/utils/executeHooks.ts +11 -18
  37. package/src/utils/getCosmiConfig.ts +6 -1
  38. package/src/utils/getSummary.ts +20 -42
  39. package/src/utils/randomColour.ts +26 -0
  40. package/src/utils/watcher.ts +2 -4
  41. package/dist/generate-CYBFB3tU.js +0 -221
  42. package/dist/generate-CYBFB3tU.js.map +0 -1
  43. package/dist/generate-CpBJ2Y-n.js +0 -342
  44. package/dist/generate-CpBJ2Y-n.js.map +0 -1
  45. package/dist/generate-DpHvARzf.cjs +0 -345
  46. package/dist/generate-DpHvARzf.cjs.map +0 -1
  47. package/dist/generate-KUqCSnZp.cjs +0 -225
  48. package/dist/generate-KUqCSnZp.cjs.map +0 -1
  49. package/dist/mcp-BIRDY8xn.js.map +0 -1
  50. package/dist/mcp-BQjDRDXR.cjs.map +0 -1
  51. package/dist/validate-0i6Q9eIy.js.map +0 -1
  52. package/dist/validate-6F-VPZR7.cjs.map +0 -1
@@ -0,0 +1,310 @@
1
+ import { type Config, defineLogger, LogLevel } from '@kubb/core'
2
+ import { execa } from 'execa'
3
+ import pc from 'picocolors'
4
+
5
+ /**
6
+ * GitHub Actions adapter for CI environments
7
+ * Uses ::group:: and ::endgroup:: annotations for collapsible sections
8
+ */
9
+ export const githubActionsLogger = defineLogger({
10
+ name: 'github-actions',
11
+ install(context, options) {
12
+ const logLevel = options?.logLevel || LogLevel.info
13
+ let currentConfigs: Array<Config> = []
14
+
15
+ function getMessage(message: string): string {
16
+ if (logLevel >= LogLevel.verbose) {
17
+ const timestamp = new Date().toLocaleTimeString('en-US', {
18
+ hour12: false,
19
+ hour: '2-digit',
20
+ minute: '2-digit',
21
+ second: '2-digit',
22
+ })
23
+
24
+ return [pc.dim(`[${timestamp}]`), message].join(' ')
25
+ }
26
+
27
+ return message
28
+ }
29
+
30
+ function openGroup(name: string) {
31
+ console.log(`::group::${name}`)
32
+ }
33
+
34
+ function closeGroup(_name: string) {
35
+ console.log('::endgroup::')
36
+ }
37
+
38
+ context.on('info', (message, info = '') => {
39
+ if (logLevel <= LogLevel.silent) {
40
+ return
41
+ }
42
+
43
+ const text = getMessage([pc.blue('ℹ'), message, pc.dim(info)].join(' '))
44
+
45
+ console.log(text)
46
+ })
47
+
48
+ context.on('success', (message, info = '') => {
49
+ if (logLevel <= LogLevel.silent) {
50
+ return
51
+ }
52
+
53
+ const text = getMessage([pc.blue('✓'), message, logLevel >= LogLevel.info ? pc.dim(info) : undefined].filter(Boolean).join(' '))
54
+
55
+ console.log(text)
56
+ })
57
+
58
+ context.on('warn', (message, info = '') => {
59
+ if (logLevel <= LogLevel.silent) {
60
+ return
61
+ }
62
+
63
+ const text = getMessage([pc.yellow('⚠'), message, logLevel >= LogLevel.info ? pc.dim(info) : undefined].filter(Boolean).join(' '))
64
+
65
+ console.warn(`::warning::${text}`)
66
+ })
67
+
68
+ context.on('error', (error) => {
69
+ if (logLevel <= LogLevel.silent) {
70
+ return
71
+ }
72
+ const message = error.message || String(error)
73
+ console.error(`::error::${message}`)
74
+ })
75
+
76
+ context.on('lifecycle:start', (version) => {
77
+ console.log(pc.yellow(`Kubb ${version} 🧩`))
78
+ })
79
+
80
+ context.on('config:start', () => {
81
+ if (logLevel <= LogLevel.silent) {
82
+ return
83
+ }
84
+
85
+ const text = getMessage('Configuration started')
86
+
87
+ openGroup('Configuration')
88
+
89
+ console.log(text)
90
+ })
91
+
92
+ context.on('config:end', (configs) => {
93
+ currentConfigs = configs
94
+
95
+ if (logLevel <= LogLevel.silent) {
96
+ return
97
+ }
98
+
99
+ const text = getMessage('Configuration completed')
100
+
101
+ console.log(text)
102
+
103
+ closeGroup('Configuration')
104
+ })
105
+
106
+ context.on('generation:start', (config) => {
107
+ const text = config.name ? `Generation for ${pc.bold(config.name)}` : 'Generation'
108
+
109
+ if (currentConfigs.length > 1) {
110
+ openGroup(text)
111
+ }
112
+
113
+ if (currentConfigs.length === 1) {
114
+ console.log(getMessage(text))
115
+ }
116
+ })
117
+
118
+ context.on('plugin:start', (plugin) => {
119
+ if (logLevel <= LogLevel.silent) {
120
+ return
121
+ }
122
+ const text = getMessage(`Generating ${pc.bold(plugin.name)}`)
123
+
124
+ if (currentConfigs.length === 1) {
125
+ openGroup(`Plugin: ${plugin.name}`)
126
+ }
127
+
128
+ console.log(text)
129
+ })
130
+
131
+ context.on('plugin:end', (plugin, duration) => {
132
+ if (logLevel <= LogLevel.silent) {
133
+ return
134
+ }
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)}`)
137
+
138
+ console.log(text)
139
+ if (currentConfigs.length > 1) {
140
+ console.log(' ')
141
+ }
142
+
143
+ if (currentConfigs.length === 1) {
144
+ closeGroup(`Plugin: ${plugin.name}`)
145
+ }
146
+ })
147
+
148
+ context.on('files:processing:start', (files) => {
149
+ if (logLevel <= LogLevel.silent) {
150
+ return
151
+ }
152
+ if (currentConfigs.length === 1) {
153
+ openGroup('File Generation')
154
+ }
155
+ const text = getMessage(`Writing ${files.length} files`)
156
+
157
+ console.log(text)
158
+ })
159
+
160
+ context.on('files:processing:end', () => {
161
+ if (logLevel <= LogLevel.silent) {
162
+ return
163
+ }
164
+ const text = getMessage('Files written successfully')
165
+
166
+ console.log(text)
167
+
168
+ if (currentConfigs.length === 1) {
169
+ closeGroup('File Generation')
170
+ }
171
+ })
172
+
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`)
175
+
176
+ console.log(text)
177
+ })
178
+
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)
192
+
193
+ cb()
194
+ } catch (err) {
195
+ const error = new Error('Hook execute failed')
196
+ error.cause = err
197
+
198
+ await context.emit('debug', {
199
+ date: new Date(),
200
+ logs: [(err as any).stdout],
201
+ })
202
+
203
+ await context.emit('error', error)
204
+ }
205
+ })
206
+
207
+ context.on('format:start', () => {
208
+ if (logLevel <= LogLevel.silent) {
209
+ return
210
+ }
211
+
212
+ const text = getMessage('Format started')
213
+
214
+ if (currentConfigs.length === 1) {
215
+ openGroup('Formatting')
216
+ }
217
+
218
+ console.log(text)
219
+ })
220
+
221
+ context.on('format:end', () => {
222
+ if (logLevel <= LogLevel.silent) {
223
+ return
224
+ }
225
+
226
+ const text = getMessage('Format completed')
227
+
228
+ console.log(text)
229
+
230
+ if (currentConfigs.length === 1) {
231
+ closeGroup('Formatting')
232
+ }
233
+ })
234
+
235
+ context.on('lint:start', () => {
236
+ if (logLevel <= LogLevel.silent) {
237
+ return
238
+ }
239
+
240
+ const text = getMessage('Lint started')
241
+
242
+ if (currentConfigs.length === 1) {
243
+ openGroup('Linting')
244
+ }
245
+
246
+ console.log(text)
247
+ })
248
+
249
+ context.on('lint:end', () => {
250
+ if (logLevel <= LogLevel.silent) {
251
+ return
252
+ }
253
+
254
+ const text = getMessage('Lint completed')
255
+
256
+ console.log(text)
257
+
258
+ if (currentConfigs.length === 1) {
259
+ closeGroup('Linting')
260
+ }
261
+ })
262
+
263
+ context.on('hook:start', (command) => {
264
+ if (logLevel <= LogLevel.silent) {
265
+ return
266
+ }
267
+
268
+ const text = getMessage(`Hook ${pc.dim(command)} started`)
269
+
270
+ if (currentConfigs.length === 1) {
271
+ openGroup(`Hook ${command}`)
272
+ }
273
+
274
+ console.log(text)
275
+ })
276
+
277
+ context.on('hook:end', (command) => {
278
+ if (logLevel <= LogLevel.silent) {
279
+ return
280
+ }
281
+
282
+ const text = getMessage(`Hook ${pc.dim(command)} completed`)
283
+
284
+ console.log(text)
285
+
286
+ if (currentConfigs.length === 1) {
287
+ closeGroup(`Hook ${command}`)
288
+ }
289
+ })
290
+
291
+ context.on('generation:summary', (config, { status, failedPlugins }) => {
292
+ const pluginsCount = config.plugins?.length || 0
293
+ const successCount = pluginsCount - failedPlugins.size
294
+
295
+ if (currentConfigs.length > 1) {
296
+ console.log(' ')
297
+ }
298
+
299
+ console.log(
300
+ status === 'success'
301
+ ? `Kubb Summary: ${pc.blue('✓')} ${`${successCount} successful`}, ${pluginsCount} total`
302
+ : `Kubb Summary: ${pc.blue('✓')} ${`${successCount} successful`}, ✗ ${`${failedPlugins.size} failed`}, ${pluginsCount} total`,
303
+ )
304
+
305
+ if (currentConfigs.length > 1) {
306
+ closeGroup(config.name ? `Generation for ${pc.bold(config.name)}` : 'Generation')
307
+ }
308
+ })
309
+ },
310
+ })
@@ -0,0 +1,7 @@
1
+ export { clackLogger } from './clackLogger.ts'
2
+ export { canUseTTY, isCIEnvironment, isGitHubActions } from './envDetection.ts'
3
+ export { fileSystemLogger } from './fileSystemLogger.ts'
4
+ export { githubActionsLogger } from './githubActionsLogger.ts'
5
+ export { plainLogger } from './plainLogger.ts'
6
+ export type { LoggerType } from './types.ts'
7
+ export { getLoggerByEnvironment } from './utils.ts'
@@ -0,0 +1,274 @@
1
+ import { relative } from 'node:path'
2
+ import { defineLogger, LogLevel } from '@kubb/core'
3
+ import { execa } from 'execa'
4
+ import { getSummary } from '../utils/getSummary.ts'
5
+
6
+ /**
7
+ * Plain console adapter for non-TTY environments
8
+ * Simple console.log output with indentation
9
+ */
10
+ export const plainLogger = defineLogger({
11
+ name: 'plain',
12
+ install(context, options) {
13
+ const logLevel = options?.logLevel || 3
14
+
15
+ function getMessage(message: string): string {
16
+ if (logLevel >= LogLevel.verbose) {
17
+ const timestamp = new Date().toLocaleTimeString('en-US', {
18
+ hour12: false,
19
+ hour: '2-digit',
20
+ minute: '2-digit',
21
+ second: '2-digit',
22
+ })
23
+
24
+ return [`[${timestamp}]`, message].join(' ')
25
+ }
26
+
27
+ return message
28
+ }
29
+
30
+ context.on('info', (message, info) => {
31
+ if (logLevel <= LogLevel.silent) {
32
+ return
33
+ }
34
+
35
+ const text = getMessage(['ℹ', message, info].join(' '))
36
+
37
+ console.log(text)
38
+ })
39
+
40
+ context.on('success', (message, info = '') => {
41
+ if (logLevel <= LogLevel.silent) {
42
+ return
43
+ }
44
+
45
+ const text = getMessage(['✓', message, logLevel >= LogLevel.info ? info : undefined].filter(Boolean).join(' '))
46
+
47
+ console.log(text)
48
+ })
49
+
50
+ context.on('warn', (message, info) => {
51
+ if (logLevel < LogLevel.warn) {
52
+ return
53
+ }
54
+
55
+ const text = getMessage(['⚠', message, logLevel >= LogLevel.info ? info : undefined].filter(Boolean).join(' '))
56
+
57
+ console.log(text)
58
+ })
59
+
60
+ context.on('error', (error) => {
61
+ const caused = error.cause as Error
62
+
63
+ const text = getMessage(['✗', error.message].join(' '))
64
+
65
+ console.log(text)
66
+
67
+ // Show stack trace in debug mode (first 3 frames)
68
+ if (logLevel >= LogLevel.debug && error.stack) {
69
+ const frames = error.stack.split('\n').slice(1, 4)
70
+ for (const frame of frames) {
71
+ console.log(getMessage(frame.trim()))
72
+ }
73
+
74
+ if (caused?.stack) {
75
+ console.log(`└─ caused by ${caused.message}`)
76
+
77
+ const frames = caused.stack.split('\n').slice(1, 4)
78
+ for (const frame of frames) {
79
+ console.log(getMessage(` ${frame.trim()}`))
80
+ }
81
+ }
82
+ }
83
+ })
84
+
85
+ context.on('lifecycle:start', () => {
86
+ console.log('Kubb CLI 🧩')
87
+ })
88
+
89
+ context.on('config:start', () => {
90
+ if (logLevel <= LogLevel.silent) {
91
+ return
92
+ }
93
+
94
+ const text = getMessage('Configuration started')
95
+
96
+ console.log(text)
97
+ })
98
+
99
+ context.on('config:end', () => {
100
+ if (logLevel <= LogLevel.silent) {
101
+ return
102
+ }
103
+
104
+ const text = getMessage('Configuration completed')
105
+
106
+ console.log(text)
107
+ })
108
+
109
+ context.on('generation:start', () => {
110
+ const text = getMessage('Configuration started')
111
+
112
+ console.log(text)
113
+ })
114
+
115
+ context.on('plugin:start', (plugin) => {
116
+ if (logLevel <= LogLevel.silent) {
117
+ return
118
+ }
119
+ const text = getMessage(`Generating ${plugin.name}`)
120
+
121
+ console.log(text)
122
+ })
123
+
124
+ context.on('plugin:end', (plugin, duration) => {
125
+ if (logLevel <= LogLevel.silent) {
126
+ return
127
+ }
128
+
129
+ const durationStr = duration >= 1000 ? `${(duration / 1000).toFixed(2)}s` : `${duration}ms`
130
+ const text = getMessage(`${plugin.name} completed in ${durationStr}`)
131
+
132
+ console.log(text)
133
+ })
134
+
135
+ context.on('files:processing:start', (files) => {
136
+ if (logLevel <= LogLevel.silent) {
137
+ return
138
+ }
139
+
140
+ const text = getMessage(`Writing ${files.length} files`)
141
+
142
+ console.log(text)
143
+ })
144
+
145
+ context.on('file:processing:update', ({ file, config }) => {
146
+ if (logLevel <= LogLevel.silent) {
147
+ return
148
+ }
149
+
150
+ const text = getMessage(`Writing ${relative(config.root, file.path)}`)
151
+
152
+ console.log(text)
153
+ })
154
+
155
+ context.on('files:processing:end', () => {
156
+ if (logLevel <= LogLevel.silent) {
157
+ return
158
+ }
159
+
160
+ const text = getMessage('Files written successfully')
161
+
162
+ console.log(text)
163
+ })
164
+
165
+ context.on('generation:end', (config) => {
166
+ const text = getMessage(config.name ? `Generation completed for ${config.name}` : 'Generation completed')
167
+
168
+ console.log(text)
169
+ })
170
+
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
+ context.on('format:start', () => {
200
+ if (logLevel <= LogLevel.silent) {
201
+ return
202
+ }
203
+
204
+ const text = getMessage('Format started')
205
+
206
+ console.log(text)
207
+ })
208
+
209
+ context.on('format:end', () => {
210
+ if (logLevel <= LogLevel.silent) {
211
+ return
212
+ }
213
+
214
+ const text = getMessage('Format completed')
215
+
216
+ console.log(text)
217
+ })
218
+
219
+ context.on('lint:start', () => {
220
+ if (logLevel <= LogLevel.silent) {
221
+ return
222
+ }
223
+
224
+ const text = getMessage('Lint started')
225
+
226
+ console.log(text)
227
+ })
228
+
229
+ context.on('lint:end', () => {
230
+ if (logLevel <= LogLevel.silent) {
231
+ return
232
+ }
233
+
234
+ const text = getMessage('Lint completed')
235
+
236
+ console.log(text)
237
+ })
238
+
239
+ context.on('hook:start', (command) => {
240
+ if (logLevel <= LogLevel.silent) {
241
+ return
242
+ }
243
+
244
+ const text = getMessage(`Hook ${command} started`)
245
+
246
+ console.log(text)
247
+ })
248
+
249
+ context.on('hook:end', (command) => {
250
+ if (logLevel <= LogLevel.silent) {
251
+ return
252
+ }
253
+
254
+ const text = getMessage(`Hook ${command} completed`)
255
+
256
+ console.log(text)
257
+ })
258
+
259
+ context.on('generation:summary', (config, { pluginTimings, status, hrStart, failedPlugins, filesCreated }) => {
260
+ const summary = getSummary({
261
+ failedPlugins,
262
+ filesCreated,
263
+ config,
264
+ status,
265
+ hrStart,
266
+ pluginTimings: logLevel >= LogLevel.verbose ? pluginTimings : undefined,
267
+ })
268
+
269
+ console.log('---------------------------')
270
+ console.log(summary.join('\n'))
271
+ console.log('---------------------------')
272
+ })
273
+ },
274
+ })
@@ -0,0 +1 @@
1
+ export type LoggerType = 'clack' | 'github-actions' | 'plain'
@@ -0,0 +1,49 @@
1
+ import type { Logger, LoggerContext, LoggerOptions } from '@kubb/core'
2
+ import { LogLevel } from '@kubb/core'
3
+ import { clackLogger } from './clackLogger.ts'
4
+ import { canUseTTY, isGitHubActions } from './envDetection.ts'
5
+ import { fileSystemLogger } from './fileSystemLogger.ts'
6
+ import { githubActionsLogger } from './githubActionsLogger.ts'
7
+ import { plainLogger } from './plainLogger.ts'
8
+ import type { LoggerType } from './types.ts'
9
+
10
+ export function detectLogger(): LoggerType {
11
+ if (isGitHubActions()) {
12
+ return 'github-actions'
13
+ }
14
+ if (canUseTTY()) {
15
+ return 'clack'
16
+ }
17
+ return 'plain'
18
+ }
19
+
20
+ const logMapper = {
21
+ clack: clackLogger,
22
+ plain: plainLogger,
23
+ 'github-actions': githubActionsLogger,
24
+ } as const satisfies Record<LoggerType, Logger>
25
+
26
+ export function getLoggerByEnvironment(): Logger {
27
+ const type = detectLogger()
28
+
29
+ return logMapper[type]
30
+ }
31
+
32
+ export async function setupLogger(context: LoggerContext, { logLevel }: LoggerOptions): Promise<void> {
33
+ const type = detectLogger()
34
+
35
+ const logger = logMapper[type] as Logger
36
+
37
+ if (!logger) {
38
+ throw new Error(`Unknown adapter type: ${type}`)
39
+ }
40
+
41
+ // Install primary logger
42
+ const cleanup = await logger.install(context, { logLevel })
43
+
44
+ if (logLevel >= LogLevel.debug) {
45
+ await fileSystemLogger.install(context, { logLevel })
46
+ }
47
+
48
+ return cleanup
49
+ }