@kubb/core 4.11.0 → 4.11.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.
- package/dist/{getBarrelFiles-BkDzzugQ.cjs → getBarrelFiles-8VEWWk9Z.cjs} +80 -111
- package/dist/getBarrelFiles-8VEWWk9Z.cjs.map +1 -0
- package/dist/{getBarrelFiles-BVMBhc50.d.cts → getBarrelFiles-B_2WDywH.d.cts} +3 -3
- package/dist/{getBarrelFiles-a-GlnjYa.js → getBarrelFiles-DQ0hksqD.js} +80 -111
- package/dist/getBarrelFiles-DQ0hksqD.js.map +1 -0
- package/dist/{getBarrelFiles-DjQ68d4e.d.ts → getBarrelFiles-ZIHk_1ln.d.ts} +3 -3
- package/dist/hooks.d.cts +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/index.cjs +261 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -7
- package/dist/index.d.ts +5 -7
- package/dist/index.js +262 -43
- package/dist/index.js.map +1 -1
- package/dist/{logger-DIA19Yfz.js → logger-CQn6sdC0.js} +72 -7
- package/dist/{logger-CPt4U57Z.cjs.map → logger-CQn6sdC0.js.map} +1 -1
- package/dist/{logger-CPt4U57Z.cjs → logger-US5g7KdM.cjs} +72 -7
- package/dist/logger-US5g7KdM.cjs.map +1 -0
- package/dist/{logger-C96jDrSt.d.ts → logger-mq06Cxxv.d.cts} +29 -4
- package/dist/{logger-BJDkLsF0.d.cts → logger-o16AyvGp.d.ts} +29 -4
- package/dist/logger.cjs +1 -1
- package/dist/logger.d.cts +1 -1
- package/dist/logger.d.ts +1 -1
- package/dist/logger.js +1 -1
- package/dist/{types-tSSA1oz8.d.cts → types-CCEy_FVr.d.cts} +36 -27
- package/dist/{types-69-evK37.d.ts → types-DgfEZ3IN.d.ts} +36 -27
- package/dist/utils.cjs +1 -1
- package/dist/utils.d.cts +2 -2
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +1 -1
- package/package.json +1 -1
- package/src/PluginManager.ts +81 -114
- package/src/build.ts +229 -25
- package/src/logger.ts +87 -9
- package/src/utils/ciDetection.ts +40 -0
- package/src/utils/diagnostics.ts +15 -0
- package/dist/getBarrelFiles-BkDzzugQ.cjs.map +0 -1
- package/dist/getBarrelFiles-a-GlnjYa.js.map +0 -1
- package/dist/logger-DIA19Yfz.js.map +0 -1
package/src/build.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { join, relative, resolve } from 'node:path'
|
|
2
|
+
import { performance } from 'node:perf_hooks'
|
|
2
3
|
import type { KubbFile } from '@kubb/fabric-core/types'
|
|
3
4
|
import type { Fabric } from '@kubb/react-fabric'
|
|
4
5
|
import { createFabric } from '@kubb/react-fabric'
|
|
@@ -12,6 +13,7 @@ import type { Logger } from './logger.ts'
|
|
|
12
13
|
import { createLogger } from './logger.ts'
|
|
13
14
|
import { PluginManager } from './PluginManager.ts'
|
|
14
15
|
import type { Config, Output, Plugin, UserConfig } from './types.ts'
|
|
16
|
+
import { getDiagnosticInfo } from './utils/diagnostics.ts'
|
|
15
17
|
import { URLPath } from './utils/URLPath.ts'
|
|
16
18
|
|
|
17
19
|
type BuildOptions = {
|
|
@@ -27,15 +29,12 @@ type BuildOutput = {
|
|
|
27
29
|
fabric: Fabric
|
|
28
30
|
files: Array<KubbFile.ResolvedFile>
|
|
29
31
|
pluginManager: PluginManager
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Only for safeBuild,
|
|
33
|
-
* @deprecated
|
|
34
|
-
*/
|
|
32
|
+
pluginTimings: Map<string, number>
|
|
35
33
|
error?: Error
|
|
36
34
|
}
|
|
37
35
|
|
|
38
36
|
type SetupResult = {
|
|
37
|
+
logger: Logger
|
|
39
38
|
fabric: Fabric
|
|
40
39
|
pluginManager: PluginManager
|
|
41
40
|
}
|
|
@@ -43,20 +42,50 @@ type SetupResult = {
|
|
|
43
42
|
export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
44
43
|
const { config: userConfig, logger = createLogger() } = options
|
|
45
44
|
|
|
45
|
+
const diagnosticInfo = getDiagnosticInfo()
|
|
46
|
+
|
|
46
47
|
if (Array.isArray(userConfig.input)) {
|
|
47
48
|
console.warn(pc.yellow('This feature is still under development — use with caution'))
|
|
48
49
|
}
|
|
49
50
|
|
|
51
|
+
logger.emit('debug', {
|
|
52
|
+
date: new Date(),
|
|
53
|
+
category: 'setup',
|
|
54
|
+
logs: [
|
|
55
|
+
'Configuration:',
|
|
56
|
+
` • Name: ${userConfig.name || 'unnamed'}`,
|
|
57
|
+
` • Root: ${userConfig.root || process.cwd()}`,
|
|
58
|
+
` • Output: ${userConfig.output?.path || 'not specified'}`,
|
|
59
|
+
` • Plugins: ${userConfig.plugins?.length || 0}`,
|
|
60
|
+
'Output Settings:',
|
|
61
|
+
` • Write: ${userConfig.output?.write !== false ? 'enabled' : 'disabled'}`,
|
|
62
|
+
` • Formater: ${userConfig.output?.format || 'none'}`,
|
|
63
|
+
` • Linter: ${userConfig.output?.lint || 'none'}`,
|
|
64
|
+
'Environment:',
|
|
65
|
+
Object.entries(diagnosticInfo)
|
|
66
|
+
.map(([key, value]) => ` • ${key}: ${value}`)
|
|
67
|
+
.join('\n'),
|
|
68
|
+
],
|
|
69
|
+
})
|
|
70
|
+
|
|
50
71
|
try {
|
|
51
72
|
if (isInputPath(userConfig) && !new URLPath(userConfig.input.path).isURL) {
|
|
52
73
|
await exists(userConfig.input.path)
|
|
74
|
+
|
|
75
|
+
logger.emit('debug', {
|
|
76
|
+
date: new Date(),
|
|
77
|
+
category: 'setup',
|
|
78
|
+
logs: [`✓ Input file validated: ${userConfig.input.path}`],
|
|
79
|
+
})
|
|
53
80
|
}
|
|
54
81
|
} catch (e) {
|
|
55
82
|
if (isInputPath(userConfig)) {
|
|
83
|
+
const error = e as Error
|
|
84
|
+
|
|
56
85
|
throw new Error(
|
|
57
86
|
`Cannot read file/URL defined in \`input.path\` or set with \`kubb generate PATH\` in the CLI of your Kubb config ${userConfig.input.path}`,
|
|
58
87
|
{
|
|
59
|
-
cause:
|
|
88
|
+
cause: error,
|
|
60
89
|
},
|
|
61
90
|
)
|
|
62
91
|
}
|
|
@@ -78,6 +107,11 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
|
78
107
|
}
|
|
79
108
|
|
|
80
109
|
if (definedConfig.output.clean) {
|
|
110
|
+
logger.emit('debug', {
|
|
111
|
+
date: new Date(),
|
|
112
|
+
category: 'setup',
|
|
113
|
+
logs: ['Cleaning output directories', ` • Output: ${definedConfig.output.path}`, ' • Cache: .kubb'],
|
|
114
|
+
})
|
|
81
115
|
await clean(definedConfig.output.path)
|
|
82
116
|
await clean(join(definedConfig.root, '.kubb'))
|
|
83
117
|
}
|
|
@@ -86,16 +120,122 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
|
86
120
|
fabric.use(fsPlugin, { dryRun: !definedConfig.output.write })
|
|
87
121
|
fabric.use(typescriptParser)
|
|
88
122
|
|
|
123
|
+
fabric.context.on('process:start', ({ files }) => {
|
|
124
|
+
logger.emit('progress_start', { id: 'files', size: files.length, message: 'Writing files ...' })
|
|
125
|
+
logger.emit('debug', {
|
|
126
|
+
date: new Date(),
|
|
127
|
+
category: 'file',
|
|
128
|
+
logs: [`Writing ${files.length} files...`],
|
|
129
|
+
})
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
fabric.context.on('process:progress', async ({ file, source }) => {
|
|
133
|
+
const message = file ? `Writing ${relative(definedConfig.root, file.path)}` : ''
|
|
134
|
+
logger.emit('progressed', { id: 'files', message })
|
|
135
|
+
|
|
136
|
+
if (source) {
|
|
137
|
+
await write(file.path, source, { sanity: false })
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
fabric.context.on('process:end', () => {
|
|
142
|
+
logger.emit('progress_stop', { id: 'files' })
|
|
143
|
+
logger.emit('debug', {
|
|
144
|
+
date: new Date(),
|
|
145
|
+
category: 'file',
|
|
146
|
+
logs: ['✓ File write process completed'],
|
|
147
|
+
})
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
logger.emit('debug', {
|
|
151
|
+
date: new Date(),
|
|
152
|
+
category: 'setup',
|
|
153
|
+
logs: [
|
|
154
|
+
'✓ Fabric initialized',
|
|
155
|
+
` • File writing: ${definedConfig.output.write ? 'enabled' : 'disabled (dry-run)'}`,
|
|
156
|
+
` • Barrel type: ${definedConfig.output.barrelType || 'none'}`,
|
|
157
|
+
],
|
|
158
|
+
})
|
|
159
|
+
|
|
89
160
|
const pluginManager = new PluginManager(definedConfig, { fabric, logger, concurrency: 5 })
|
|
90
161
|
|
|
162
|
+
pluginManager.on('executing', ({ plugin, hookName, strategy, parameters }) => {
|
|
163
|
+
logger.emit('debug', {
|
|
164
|
+
date: new Date(),
|
|
165
|
+
category: 'hook',
|
|
166
|
+
pluginName: plugin.name,
|
|
167
|
+
logs: [`Executing hook: ${hookName}`, ` • Strategy: ${strategy}`, ' • Parameters:', JSON.stringify(parameters, null, 2)],
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
pluginManager.on('executed', ({ plugin, hookName, duration, parameters }) => {
|
|
172
|
+
let message = ''
|
|
173
|
+
if (hookName === 'resolvePath') {
|
|
174
|
+
const [path] = parameters || []
|
|
175
|
+
message = `Resolving path '${path}'`
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (hookName === 'resolveName') {
|
|
179
|
+
const [name, type] = parameters || []
|
|
180
|
+
message = `Resolving name '${name}' and type '${type}'`
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
logger.emit('progressed', {
|
|
184
|
+
id: hookName,
|
|
185
|
+
message: `${plugin.name}: ${message}`,
|
|
186
|
+
})
|
|
187
|
+
logger.emit('debug', {
|
|
188
|
+
date: new Date(),
|
|
189
|
+
category: 'hook',
|
|
190
|
+
pluginName: plugin.name,
|
|
191
|
+
logs: [`✓ Completed in ${duration}ms`],
|
|
192
|
+
})
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
pluginManager.on('progress_start', ({ hookName, plugins }) => {
|
|
196
|
+
logger.emit('progress_start', { id: hookName, size: plugins.length, message: 'Running plugins...' })
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
pluginManager.on('progress_stop', ({ hookName }) => {
|
|
200
|
+
logger.emit('progress_stop', { id: hookName })
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
pluginManager.on('error', (error, { plugin, strategy, duration, parameters, hookName }) => {
|
|
204
|
+
const text = `${error.message} (plugin: ${plugin?.name || 'unknown'}, hook: ${hookName || 'unknown'})`
|
|
205
|
+
|
|
206
|
+
logger.emit('error', text, error)
|
|
207
|
+
|
|
208
|
+
logger.emit('debug', {
|
|
209
|
+
date: new Date(),
|
|
210
|
+
category: 'error',
|
|
211
|
+
pluginName: plugin.name,
|
|
212
|
+
logs: [
|
|
213
|
+
`✗ Hook '${hookName}' failed after ${duration}ms`,
|
|
214
|
+
` • Strategy: ${strategy}`,
|
|
215
|
+
` • Error: ${error.constructor.name} - ${error.message}`,
|
|
216
|
+
' • Stack Trace:',
|
|
217
|
+
error.stack || 'No stack trace available',
|
|
218
|
+
' • Parameters:',
|
|
219
|
+
JSON.stringify(parameters, null, 2),
|
|
220
|
+
],
|
|
221
|
+
})
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
logger.emit('debug', {
|
|
225
|
+
date: new Date(),
|
|
226
|
+
category: 'setup',
|
|
227
|
+
logs: ['✓ PluginManager initialized', ' • Concurrency: 5', ` • Total plugins: ${pluginManager.plugins.length}`],
|
|
228
|
+
})
|
|
229
|
+
|
|
91
230
|
return {
|
|
231
|
+
logger,
|
|
92
232
|
fabric,
|
|
93
233
|
pluginManager,
|
|
94
234
|
}
|
|
95
235
|
}
|
|
96
236
|
|
|
97
237
|
export async function build(options: BuildOptions, overrides?: SetupResult): Promise<BuildOutput> {
|
|
98
|
-
const { fabric, files, pluginManager, failedPlugins, error } = await safeBuild(options, overrides)
|
|
238
|
+
const { fabric, files, pluginManager, failedPlugins, pluginTimings, error } = await safeBuild(options, overrides)
|
|
99
239
|
|
|
100
240
|
if (error) {
|
|
101
241
|
throw error
|
|
@@ -106,14 +246,16 @@ export async function build(options: BuildOptions, overrides?: SetupResult): Pro
|
|
|
106
246
|
fabric,
|
|
107
247
|
files,
|
|
108
248
|
pluginManager,
|
|
249
|
+
pluginTimings,
|
|
109
250
|
error,
|
|
110
251
|
}
|
|
111
252
|
}
|
|
112
253
|
|
|
113
254
|
export async function safeBuild(options: BuildOptions, overrides?: SetupResult): Promise<BuildOutput> {
|
|
114
|
-
const { fabric, pluginManager } = overrides ? overrides : await setup(options)
|
|
255
|
+
const { fabric, pluginManager, logger } = overrides ? overrides : await setup(options)
|
|
115
256
|
|
|
116
257
|
const failedPlugins = new Set<{ plugin: Plugin; error: Error }>()
|
|
258
|
+
const pluginTimings = new Map<string, number>()
|
|
117
259
|
const config = pluginManager.config
|
|
118
260
|
|
|
119
261
|
try {
|
|
@@ -123,9 +265,69 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
123
265
|
const installer = plugin.install.bind(context)
|
|
124
266
|
|
|
125
267
|
try {
|
|
268
|
+
const startTime = performance.now()
|
|
269
|
+
const timestamp = new Date()
|
|
270
|
+
|
|
271
|
+
// Start plugin group
|
|
272
|
+
logger.emit('debug', {
|
|
273
|
+
date: timestamp,
|
|
274
|
+
pluginGroupMarker: 'start',
|
|
275
|
+
pluginName: plugin.name,
|
|
276
|
+
logs: [],
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
logger.emit('debug', {
|
|
280
|
+
date: timestamp,
|
|
281
|
+
category: 'plugin',
|
|
282
|
+
pluginName: plugin.name,
|
|
283
|
+
logs: ['Installing plugin...', ` • Plugin Key: ${JSON.stringify(plugin.key)}`],
|
|
284
|
+
})
|
|
285
|
+
|
|
126
286
|
await installer(context)
|
|
287
|
+
|
|
288
|
+
const duration = Math.round(performance.now() - startTime)
|
|
289
|
+
pluginTimings.set(plugin.name, duration)
|
|
290
|
+
|
|
291
|
+
logger.emit('debug', {
|
|
292
|
+
date: new Date(),
|
|
293
|
+
category: 'plugin',
|
|
294
|
+
pluginName: plugin.name,
|
|
295
|
+
logs: [`✓ Plugin installed successfully (${duration}ms)`],
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
// End plugin group
|
|
299
|
+
logger.emit('debug', {
|
|
300
|
+
date: new Date(),
|
|
301
|
+
pluginGroupMarker: 'end',
|
|
302
|
+
pluginName: plugin.name,
|
|
303
|
+
logs: [],
|
|
304
|
+
})
|
|
127
305
|
} catch (e) {
|
|
128
|
-
|
|
306
|
+
const error = e as Error
|
|
307
|
+
const errorTimestamp = new Date()
|
|
308
|
+
|
|
309
|
+
logger.emit('debug', {
|
|
310
|
+
date: errorTimestamp,
|
|
311
|
+
category: 'error',
|
|
312
|
+
pluginName: plugin.name,
|
|
313
|
+
logs: [
|
|
314
|
+
'✗ Plugin installation failed',
|
|
315
|
+
` • Plugin Key: ${JSON.stringify(plugin.key)}`,
|
|
316
|
+
` • Error: ${error.constructor.name} - ${error.message}`,
|
|
317
|
+
' • Stack Trace:',
|
|
318
|
+
error.stack || 'No stack trace available',
|
|
319
|
+
],
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
// End plugin group even on error
|
|
323
|
+
logger.emit('debug', {
|
|
324
|
+
date: errorTimestamp,
|
|
325
|
+
pluginGroupMarker: 'end',
|
|
326
|
+
pluginName: plugin.name,
|
|
327
|
+
logs: [],
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
failedPlugins.add({ plugin, error })
|
|
129
331
|
}
|
|
130
332
|
}
|
|
131
333
|
|
|
@@ -133,10 +335,20 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
133
335
|
const root = resolve(config.root)
|
|
134
336
|
const rootPath = resolve(root, config.output.path, 'index.ts')
|
|
135
337
|
|
|
338
|
+
logger.emit('debug', {
|
|
339
|
+
date: new Date(),
|
|
340
|
+
logs: ['Generating barrel file', ` • Type: ${config.output.barrelType}`, ` • Path: ${rootPath}`],
|
|
341
|
+
})
|
|
342
|
+
|
|
136
343
|
const barrelFiles = fabric.files.filter((file) => {
|
|
137
344
|
return file.sources.some((source) => source.isIndexable)
|
|
138
345
|
})
|
|
139
346
|
|
|
347
|
+
logger.emit('debug', {
|
|
348
|
+
date: new Date(),
|
|
349
|
+
logs: [`Found ${barrelFiles.length} indexable files for barrel export`],
|
|
350
|
+
})
|
|
351
|
+
|
|
140
352
|
const rootFile: KubbFile.File = {
|
|
141
353
|
path: rootPath,
|
|
142
354
|
baseName: 'index.ts',
|
|
@@ -175,24 +387,14 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
175
387
|
}
|
|
176
388
|
|
|
177
389
|
await fabric.upsertFile(rootFile)
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
fabric.context.on('process:start', ({ files }) => {
|
|
181
|
-
pluginManager.logger.emit('progress_start', { id: 'files', size: files.length, message: 'Writing files ...' })
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
fabric.context.on('process:progress', async ({ file, source }) => {
|
|
185
|
-
const message = file ? `Writing ${relative(config.root, file.path)}` : ''
|
|
186
|
-
pluginManager.logger.emit('progressed', { id: 'files', message })
|
|
187
390
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
391
|
+
logger.emit('debug', {
|
|
392
|
+
date: new Date(),
|
|
393
|
+
category: 'file',
|
|
394
|
+
logs: [`✓ Generated barrel file (${rootFile.exports?.length || 0} exports)`],
|
|
395
|
+
})
|
|
396
|
+
}
|
|
192
397
|
|
|
193
|
-
fabric.context.on('process:end', () => {
|
|
194
|
-
pluginManager.logger.emit('progress_stop', { id: 'files' })
|
|
195
|
-
})
|
|
196
398
|
const files = [...fabric.files]
|
|
197
399
|
|
|
198
400
|
await fabric.write({ extension: config.output.extension })
|
|
@@ -202,6 +404,7 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
202
404
|
fabric,
|
|
203
405
|
files,
|
|
204
406
|
pluginManager,
|
|
407
|
+
pluginTimings,
|
|
205
408
|
}
|
|
206
409
|
} catch (e) {
|
|
207
410
|
return {
|
|
@@ -209,6 +412,7 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
209
412
|
fabric,
|
|
210
413
|
files: [],
|
|
211
414
|
pluginManager,
|
|
415
|
+
pluginTimings,
|
|
212
416
|
error: e as Error,
|
|
213
417
|
}
|
|
214
418
|
}
|
package/src/logger.ts
CHANGED
|
@@ -4,16 +4,43 @@ import { createConsola } from 'consola'
|
|
|
4
4
|
import pc from 'picocolors'
|
|
5
5
|
import seedrandom from 'seedrandom'
|
|
6
6
|
import { write } from './fs/write.ts'
|
|
7
|
+
import { endGroup, isGitHubActions, startGroup } from './utils/ciDetection.ts'
|
|
7
8
|
import { EventEmitter } from './utils/EventEmitter.ts'
|
|
8
9
|
|
|
9
|
-
type DebugEvent = {
|
|
10
|
+
type DebugEvent = {
|
|
11
|
+
date: Date
|
|
12
|
+
logs: string[]
|
|
13
|
+
fileName?: string
|
|
14
|
+
/**
|
|
15
|
+
* Category of the debug log, used for GitHub Actions grouping
|
|
16
|
+
* - 'setup': Initial configuration and environment setup
|
|
17
|
+
* - 'plugin': Plugin installation and execution
|
|
18
|
+
* - 'hook': Plugin hook execution details
|
|
19
|
+
* - 'schema': Schema parsing and generation
|
|
20
|
+
* - 'file': File operations (read/write/generate)
|
|
21
|
+
* - 'error': Error details and stack traces
|
|
22
|
+
* - undefined: Generic logs (always inline)
|
|
23
|
+
*/
|
|
24
|
+
category?: 'setup' | 'plugin' | 'hook' | 'schema' | 'file' | 'error'
|
|
25
|
+
/**
|
|
26
|
+
* Plugin name for grouping plugin-specific logs together
|
|
27
|
+
*/
|
|
28
|
+
pluginName?: string
|
|
29
|
+
/**
|
|
30
|
+
* Indicates if this is the start or end of a plugin's execution
|
|
31
|
+
* - 'start': Start of plugin execution group
|
|
32
|
+
* - 'end': End of plugin execution group
|
|
33
|
+
*/
|
|
34
|
+
pluginGroupMarker?: 'start' | 'end'
|
|
35
|
+
}
|
|
10
36
|
|
|
11
37
|
type Events = {
|
|
12
38
|
start: [message: string]
|
|
13
39
|
success: [message: string]
|
|
14
|
-
error: [message: string,
|
|
40
|
+
error: [message: string, error: Error]
|
|
15
41
|
warning: [message: string]
|
|
16
42
|
debug: [DebugEvent]
|
|
43
|
+
verbose: [DebugEvent]
|
|
17
44
|
info: [message: string]
|
|
18
45
|
progress_start: [{ id: string; size: number; message?: string }]
|
|
19
46
|
progressed: [{ id: string; message?: string }]
|
|
@@ -22,10 +49,15 @@ type Events = {
|
|
|
22
49
|
|
|
23
50
|
export const LogMapper = {
|
|
24
51
|
silent: Number.NEGATIVE_INFINITY,
|
|
52
|
+
error: 0,
|
|
53
|
+
warn: 1,
|
|
25
54
|
info: 3,
|
|
26
|
-
|
|
55
|
+
verbose: 4,
|
|
56
|
+
debug: 5,
|
|
27
57
|
} as const
|
|
28
58
|
|
|
59
|
+
const DEBUG_LOG_TITLE_MAX_LENGTH = 50 // Characters - max length for group titles
|
|
60
|
+
|
|
29
61
|
export type Logger = {
|
|
30
62
|
/**
|
|
31
63
|
* Optional config name to show in CLI output
|
|
@@ -35,7 +67,7 @@ export type Logger = {
|
|
|
35
67
|
consola?: ConsolaInstance
|
|
36
68
|
on: EventEmitter<Events>['on']
|
|
37
69
|
emit: EventEmitter<Events>['emit']
|
|
38
|
-
writeLogs: () => Promise<
|
|
70
|
+
writeLogs: () => Promise<void>
|
|
39
71
|
}
|
|
40
72
|
|
|
41
73
|
type Props = {
|
|
@@ -79,9 +111,54 @@ export function createLogger({ logLevel = 3, name, consola: _consola }: Props =
|
|
|
79
111
|
consola.info(pc.yellow(message))
|
|
80
112
|
})
|
|
81
113
|
|
|
114
|
+
events.on('verbose', (message) => {
|
|
115
|
+
if (logLevel >= LogMapper.verbose) {
|
|
116
|
+
const formattedLogs = message.logs.join('\n')
|
|
117
|
+
consola.log(pc.dim(formattedLogs))
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
cachedLogs.add(message)
|
|
121
|
+
})
|
|
122
|
+
|
|
82
123
|
events.on('debug', (message) => {
|
|
83
|
-
|
|
84
|
-
|
|
124
|
+
const fullLog = message.logs.join('\n')
|
|
125
|
+
|
|
126
|
+
if (logLevel >= LogMapper.debug) {
|
|
127
|
+
// Handle plugin group markers in GitHub Actions
|
|
128
|
+
if (isGitHubActions()) {
|
|
129
|
+
if (message.pluginGroupMarker === 'start') {
|
|
130
|
+
// Start a new plugin group
|
|
131
|
+
const title = message.pluginName || 'Plugin'
|
|
132
|
+
console.log(startGroup(title))
|
|
133
|
+
|
|
134
|
+
return undefined // Don't log the marker itself
|
|
135
|
+
}
|
|
136
|
+
if (message.pluginGroupMarker === 'end') {
|
|
137
|
+
// End the plugin group
|
|
138
|
+
console.log(endGroup())
|
|
139
|
+
|
|
140
|
+
return undefined // Don't log the marker itself
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// For setup/file operations that aren't plugin-specific, create individual groups
|
|
144
|
+
if (!message.pluginName && message.category && ['setup', 'file'].includes(message.category)) {
|
|
145
|
+
const firstLine = message.logs[0] || 'Debug Details'
|
|
146
|
+
const title = firstLine.length > DEBUG_LOG_TITLE_MAX_LENGTH ? `${firstLine.substring(0, DEBUG_LOG_TITLE_MAX_LENGTH)}...` : firstLine
|
|
147
|
+
|
|
148
|
+
console.log(startGroup(title))
|
|
149
|
+
console.log(pc.dim(fullLog))
|
|
150
|
+
console.log(endGroup())
|
|
151
|
+
} else {
|
|
152
|
+
// Plugin-specific logs are shown inline within their plugin group
|
|
153
|
+
// Non-categorized logs are shown inline
|
|
154
|
+
consola.log(pc.dim(fullLog))
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
// Non-CI environments - show all logs inline (except group markers)
|
|
158
|
+
if (!message.pluginGroupMarker) {
|
|
159
|
+
consola.log(pc.dim(fullLog))
|
|
160
|
+
}
|
|
161
|
+
}
|
|
85
162
|
}
|
|
86
163
|
|
|
87
164
|
cachedLogs.add(message)
|
|
@@ -118,15 +195,16 @@ export function createLogger({ logLevel = 3, name, consola: _consola }: Props =
|
|
|
118
195
|
files[fileName] = []
|
|
119
196
|
}
|
|
120
197
|
|
|
121
|
-
|
|
198
|
+
if (log.logs.length) {
|
|
199
|
+
files[fileName] = [...files[fileName], `[${log.date.toLocaleString()}]: \n${log.logs.join('\n')}`]
|
|
200
|
+
}
|
|
122
201
|
})
|
|
202
|
+
|
|
123
203
|
await Promise.all(
|
|
124
204
|
Object.entries(files).map(async ([fileName, logs]) => {
|
|
125
205
|
return write(fileName, logs.join('\n'))
|
|
126
206
|
}),
|
|
127
207
|
)
|
|
128
|
-
|
|
129
|
-
return Object.keys(files)
|
|
130
208
|
},
|
|
131
209
|
}
|
|
132
210
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect if running in a CI environment
|
|
3
|
+
* Note: Currently exported for potential future use in plugins or extensions
|
|
4
|
+
*/
|
|
5
|
+
export function isCI(): boolean {
|
|
6
|
+
return !!(process.env.CI || process.env.CONTINUOUS_INTEGRATION || process.env.BUILD_NUMBER || process.env.RUN_ID)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Detect if running in GitHub Actions
|
|
11
|
+
*/
|
|
12
|
+
export function isGitHubActions(): boolean {
|
|
13
|
+
return process.env.GITHUB_ACTIONS === 'true'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* GitHub Actions group markers
|
|
18
|
+
*/
|
|
19
|
+
const GITHUB_ACTIONS_GROUP_START = '::group::'
|
|
20
|
+
const GITHUB_ACTIONS_GROUP_END = '::endgroup::'
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Create a collapsible group marker for GitHub Actions logs
|
|
24
|
+
*/
|
|
25
|
+
export function startGroup(title: string): string {
|
|
26
|
+
if (isCI() && isGitHubActions()) {
|
|
27
|
+
return `${GITHUB_ACTIONS_GROUP_START}${title}`
|
|
28
|
+
}
|
|
29
|
+
return ''
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* End a collapsible group in GitHub Actions logs
|
|
34
|
+
*/
|
|
35
|
+
export function endGroup(): string {
|
|
36
|
+
if (isGitHubActions()) {
|
|
37
|
+
return GITHUB_ACTIONS_GROUP_END
|
|
38
|
+
}
|
|
39
|
+
return ''
|
|
40
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { version as nodeVersion } from 'node:process'
|
|
2
|
+
import { version as KubbVersion } from '../../package.json'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Get diagnostic information for debugging
|
|
6
|
+
*/
|
|
7
|
+
export function getDiagnosticInfo() {
|
|
8
|
+
return {
|
|
9
|
+
nodeVersion,
|
|
10
|
+
KubbVersion,
|
|
11
|
+
platform: process.platform,
|
|
12
|
+
arch: process.arch,
|
|
13
|
+
cwd: process.cwd(),
|
|
14
|
+
} as const
|
|
15
|
+
}
|