@kubb/cli 5.0.0-beta.6 → 5.0.0-beta.7

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 (117) hide show
  1. package/README.md +177 -26
  2. package/dist/{agent-BJEvbSiP.js → agent-DN7o8nlE.js} +7 -7
  3. package/dist/agent-DN7o8nlE.js.map +1 -0
  4. package/dist/{agent-CXNO6dgj.cjs → agent-Fm9_8BBH.cjs} +5 -5
  5. package/dist/agent-Fm9_8BBH.cjs.map +1 -0
  6. package/dist/{chunk--u3MIqq1.js → chunk-BvFE5Tac.js} +1 -0
  7. package/dist/{constants-BPJBMT_6.js → constants-B2JTeRBb.js} +1 -4
  8. package/dist/{constants-BPJBMT_6.js.map → constants-B2JTeRBb.js.map} +1 -1
  9. package/dist/{constants-Rcaqzyd-.cjs → constants-BINTA5VZ.cjs} +1 -4
  10. package/dist/{constants-Rcaqzyd-.cjs.map → constants-BINTA5VZ.cjs.map} +1 -1
  11. package/dist/{define-Ctii4bel.js → define-m_fp-Aqm.js} +2 -2
  12. package/dist/{define-Ctii4bel.js.map → define-m_fp-Aqm.js.map} +1 -1
  13. package/dist/{errors-CjPmyZHy.js → errors-CINO1EIv.js} +2 -2
  14. package/dist/{errors-CjPmyZHy.js.map → errors-CINO1EIv.js.map} +1 -1
  15. package/dist/{generate-BmulGxIM.js → generate-BY-juRdH.js} +5 -5
  16. package/dist/{generate-BmulGxIM.js.map → generate-BY-juRdH.js.map} +1 -1
  17. package/dist/{generate-BB2Q7I9s.cjs → generate-Bod9YCbF.cjs} +3 -3
  18. package/dist/{generate-BB2Q7I9s.cjs.map → generate-Bod9YCbF.cjs.map} +1 -1
  19. package/dist/index.cjs +9 -9
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.js +11 -11
  23. package/dist/index.js.map +1 -1
  24. package/dist/{init-Dpg8e1HN.cjs → init-BIkZU6mB.cjs} +4 -4
  25. package/dist/{init-Dpg8e1HN.cjs.map → init-BIkZU6mB.cjs.map} +1 -1
  26. package/dist/{init-BTp9if7K.js → init-Cs3Fp6nN.js} +6 -6
  27. package/dist/{init-BTp9if7K.js.map → init-Cs3Fp6nN.js.map} +1 -1
  28. package/dist/{mcp-C9RoU-Dg.js → mcp-BSNulBcC.js} +6 -6
  29. package/dist/{mcp-C9RoU-Dg.js.map → mcp-BSNulBcC.js.map} +1 -1
  30. package/dist/{mcp-wpl6sYYR.cjs → mcp-DcSrFhhP.cjs} +4 -4
  31. package/dist/{mcp-wpl6sYYR.cjs.map → mcp-DcSrFhhP.cjs.map} +1 -1
  32. package/dist/package-D5wmvFl4.js +6 -0
  33. package/dist/package-D5wmvFl4.js.map +1 -0
  34. package/dist/{package-iheSdfas.cjs → package-DrUndPET.cjs} +2 -2
  35. package/dist/package-DrUndPET.cjs.map +1 -0
  36. package/dist/{generate-DAsdUw3z.js → run-BAJubgdA.js} +298 -315
  37. package/dist/run-BAJubgdA.js.map +1 -0
  38. package/dist/{agent-VXKxLCho.js → run-BzpYYOQs.js} +46 -43
  39. package/dist/run-BzpYYOQs.js.map +1 -0
  40. package/dist/{validate-k9s_hFah.js → run-CCZ24VKk.js} +25 -20
  41. package/dist/run-CCZ24VKk.js.map +1 -0
  42. package/dist/{init-DCqcEq86.js → run-CF97BWVa.js} +77 -68
  43. package/dist/run-CF97BWVa.js.map +1 -0
  44. package/dist/{validate-BU4fPTMc.cjs → run-CQbj3ley.cjs} +23 -18
  45. package/dist/run-CQbj3ley.cjs.map +1 -0
  46. package/dist/{generate-B_p5dl68.cjs → run-CqKd6JNc.cjs} +295 -312
  47. package/dist/run-CqKd6JNc.cjs.map +1 -0
  48. package/dist/{mcp-DNUw8nqb.js → run-D0hmRpHy.js} +23 -23
  49. package/dist/run-D0hmRpHy.js.map +1 -0
  50. package/dist/{agent-D9CKYh4K.cjs → run-DwdAwnLG.cjs} +44 -41
  51. package/dist/run-DwdAwnLG.cjs.map +1 -0
  52. package/dist/{mcp-D1llTaRM.cjs → run-Lr0Ctnu0.cjs} +21 -21
  53. package/dist/run-Lr0Ctnu0.cjs.map +1 -0
  54. package/dist/{init-CJ80lKSP.cjs → run-YsoCk5we.cjs} +75 -66
  55. package/dist/run-YsoCk5we.cjs.map +1 -0
  56. package/dist/{shell-DLzN4fRo.js → shell-CN6DNqeC.js} +2 -2
  57. package/dist/{shell-DLzN4fRo.js.map → shell-CN6DNqeC.js.map} +1 -1
  58. package/dist/{telemetry-BLX0NzRk.cjs → telemetry-B2iWkY5e.cjs} +5 -7
  59. package/dist/telemetry-B2iWkY5e.cjs.map +1 -0
  60. package/dist/{telemetry-juq4QBf7.js → telemetry-BkektVz6.js} +6 -8
  61. package/dist/telemetry-BkektVz6.js.map +1 -0
  62. package/dist/{validate-DIDBROB2.cjs → validate-Bfpf_UIh.cjs} +4 -4
  63. package/dist/{validate-DIDBROB2.cjs.map → validate-Bfpf_UIh.cjs.map} +1 -1
  64. package/dist/{validate-BfJoCxrC.js → validate-lbUkWQ5o.js} +6 -6
  65. package/dist/{validate-BfJoCxrC.js.map → validate-lbUkWQ5o.js.map} +1 -1
  66. package/package.json +7 -12
  67. package/src/commands/agent/start.ts +2 -2
  68. package/src/commands/generate.ts +2 -2
  69. package/src/commands/init.ts +2 -2
  70. package/src/commands/mcp.ts +2 -2
  71. package/src/commands/validate.ts +2 -2
  72. package/src/constants.ts +0 -4
  73. package/src/index.ts +5 -3
  74. package/src/loggers/clackLogger.ts +45 -43
  75. package/src/loggers/fileSystemLogger.ts +11 -1
  76. package/src/loggers/githubActionsLogger.ts +13 -25
  77. package/src/loggers/plainLogger.ts +12 -23
  78. package/src/loggers/types.ts +6 -0
  79. package/src/loggers/utils.ts +155 -9
  80. package/src/runners/agent/run.ts +113 -0
  81. package/src/runners/agent/utils.ts +98 -0
  82. package/src/runners/generate/run.ts +276 -0
  83. package/src/runners/generate/utils.ts +209 -0
  84. package/src/runners/{init.ts → init/run.ts} +70 -66
  85. package/src/{utils/packageManager.ts → runners/init/utils.ts} +10 -0
  86. package/src/runners/mcp/run.ts +55 -0
  87. package/src/runners/{validate.ts → validate/run.ts} +25 -20
  88. package/src/{utils/telemetry.ts → telemetry.ts} +12 -5
  89. package/dist/agent-BJEvbSiP.js.map +0 -1
  90. package/dist/agent-CXNO6dgj.cjs.map +0 -1
  91. package/dist/agent-D9CKYh4K.cjs.map +0 -1
  92. package/dist/agent-VXKxLCho.js.map +0 -1
  93. package/dist/generate-B_p5dl68.cjs.map +0 -1
  94. package/dist/generate-DAsdUw3z.js.map +0 -1
  95. package/dist/init-CJ80lKSP.cjs.map +0 -1
  96. package/dist/init-DCqcEq86.js.map +0 -1
  97. package/dist/mcp-D1llTaRM.cjs.map +0 -1
  98. package/dist/mcp-DNUw8nqb.js.map +0 -1
  99. package/dist/package-iheSdfas.cjs.map +0 -1
  100. package/dist/package-vLafMWCe.js +0 -6
  101. package/dist/package-vLafMWCe.js.map +0 -1
  102. package/dist/telemetry-BLX0NzRk.cjs.map +0 -1
  103. package/dist/telemetry-juq4QBf7.js.map +0 -1
  104. package/dist/validate-BU4fPTMc.cjs.map +0 -1
  105. package/dist/validate-k9s_hFah.js.map +0 -1
  106. package/src/runners/agent.ts +0 -155
  107. package/src/runners/generate.ts +0 -333
  108. package/src/runners/mcp.ts +0 -56
  109. package/src/types.ts +0 -11
  110. package/src/utils/Writables.ts +0 -17
  111. package/src/utils/executeHooks.ts +0 -45
  112. package/src/utils/flags.ts +0 -9
  113. package/src/utils/getConfig.ts +0 -10
  114. package/src/utils/getCosmiConfig.ts +0 -75
  115. package/src/utils/getSummary.ts +0 -68
  116. package/src/utils/runHook.ts +0 -91
  117. package/src/utils/watcher.ts +0 -19
@@ -1,333 +0,0 @@
1
- import { createHash } from 'node:crypto'
2
- import path from 'node:path'
3
- import process from 'node:process'
4
- import { styleText } from 'node:util'
5
- import * as clack from '@clack/prompts'
6
- import type { AsyncEventEmitter } from '@internals/utils'
7
- import { AsyncEventEmitter as AsyncEventEmitterClass, detectFormatter, detectLinter, executeIfOnline, formatters, linters, toError } from '@internals/utils'
8
- import { type CLIOptions, type Config, createKubb, isInputPath, type KubbHooks, logLevel as logLevelMap } from '@kubb/core'
9
- import { version } from '../../package.json'
10
- import { KUBB_NPM_PACKAGE_URL } from '../constants.ts'
11
- import { setupLogger } from '../loggers/utils.ts'
12
- import { executeHooks } from '../utils/executeHooks.ts'
13
- import { getConfigs } from '../utils/getConfig.ts'
14
- import { getCosmiConfig } from '../utils/getCosmiConfig.ts'
15
- import { buildTelemetryEvent, sendTelemetry } from '../utils/telemetry.ts'
16
- import { startWatcher } from '../utils/watcher.ts'
17
-
18
- type GenerateProps = {
19
- input?: string
20
- config: Config
21
- hooks: AsyncEventEmitter<KubbHooks>
22
- logLevel: number
23
- }
24
-
25
- type ToolMap = typeof formatters | typeof linters
26
-
27
- type RunToolPassOptions = {
28
- toolValue: string
29
- detect: () => Promise<string | null>
30
- toolMap: ToolMap
31
- /** Short noun used in "Auto-detected <toolLabel>:" message, e.g. "formatter" or "linter". */
32
- toolLabel: string
33
- /** Verb prefix for the success message, e.g. "Formatting" or "Linting". */
34
- successPrefix: string
35
- noToolMessage: string
36
- configName: string | undefined
37
- outputPath: string
38
- logLevel: number
39
- hooks: AsyncEventEmitter<KubbHooks>
40
- onStart: () => Promise<void>
41
- onEnd: () => Promise<void>
42
- }
43
-
44
- async function runToolPass({
45
- toolValue,
46
- detect,
47
- toolMap,
48
- toolLabel,
49
- successPrefix,
50
- noToolMessage,
51
- configName,
52
- outputPath,
53
- logLevel,
54
- hooks,
55
- onStart,
56
- onEnd,
57
- }: RunToolPassOptions) {
58
- await onStart()
59
-
60
- let resolvedTool = toolValue
61
- if (resolvedTool === 'auto') {
62
- const detected = await detect()
63
- if (!detected) {
64
- await hooks.emit('kubb:warn', { message: noToolMessage })
65
- } else {
66
- resolvedTool = detected
67
- await hooks.emit('kubb:info', { message: `Auto-detected ${toolLabel}: ${styleText('dim', resolvedTool)}` })
68
- }
69
- }
70
-
71
- let toolError: Error | undefined
72
-
73
- if (resolvedTool && resolvedTool !== 'auto' && resolvedTool in toolMap) {
74
- const toolConfig = toolMap[resolvedTool as keyof ToolMap]
75
-
76
- try {
77
- const hookId = createHash('sha256').update([configName, resolvedTool].filter(Boolean).join('-')).digest('hex')
78
-
79
- // Wire up the hook:end listener BEFORE emitting hook:start to avoid the race condition
80
- // where hook:end fires synchronously inside emit('kubb:hook:start') before the listener is registered.
81
- const hookEndPromise = new Promise<void>((resolve, reject) => {
82
- const handler = (ctx: { id?: string; command: string; args?: readonly string[]; success: boolean; error: Error | null }) => {
83
- if (ctx.id !== hookId) return
84
- hooks.off('kubb:hook:end', handler)
85
- if (!ctx.success) {
86
- reject(ctx.error ?? new Error(`${toolConfig.errorMessage}`))
87
- return
88
- }
89
- hooks
90
- .emit('kubb:success', {
91
- message: [
92
- `${successPrefix} with ${styleText('dim', resolvedTool)}`,
93
- logLevel >= logLevelMap.info ? `on ${styleText('dim', outputPath)}` : undefined,
94
- 'successfully',
95
- ]
96
- .filter(Boolean)
97
- .join(' '),
98
- })
99
- .then(resolve)
100
- .catch(reject)
101
- }
102
- hooks.on('kubb:hook:end', handler)
103
- })
104
-
105
- await hooks.emit('kubb:hook:start', {
106
- id: hookId,
107
- command: toolConfig.command,
108
- args: toolConfig.args(outputPath),
109
- })
110
-
111
- await hookEndPromise
112
- } catch (caughtError) {
113
- // Use the actual error from the hook. toolConfig.errorMessage (e.g. "Oxlint not found")
114
- // is misleading when the binary was found and ran but exited with a non-zero code.
115
- // runHook already emitted kubb:error for binary-not-found cases; here we surface the
116
- // real reason (e.g. "Hook execute failed: oxlint --fix …") for non-zero exits.
117
- const err = toError(caughtError)
118
- await hooks.emit('kubb:error', { error: err })
119
- toolError = err
120
- }
121
- }
122
-
123
- await onEnd()
124
-
125
- if (toolError) {
126
- throw toolError
127
- }
128
- }
129
-
130
- async function generate(options: GenerateProps): Promise<void> {
131
- const { input, hooks, logLevel } = options
132
-
133
- const hrStart = process.hrtime()
134
- const inputPath = input ?? (options.config.input && 'path' in options.config.input ? options.config.input.path : undefined)
135
-
136
- const config: Config = {
137
- ...options.config,
138
- input: inputPath
139
- ? {
140
- ...options.config.input,
141
- path: inputPath,
142
- }
143
- : options.config.input,
144
- ...options.config.output,
145
- } satisfies Config
146
-
147
- const kubb = createKubb(config, { hooks })
148
- await kubb.setup()
149
-
150
- await hooks.emit('kubb:generation:start', { config })
151
-
152
- await hooks.emit('kubb:info', { message: config.name ? `Setup generation ${styleText('bold', config.name)}` : 'Setup generation', info: inputPath })
153
-
154
- await hooks.emit('kubb:info', { message: config.name ? `Build generation ${styleText('bold', config.name)}` : 'Build generation', info: inputPath })
155
-
156
- const { files, failedPlugins, pluginTimings, error, driver } = await kubb.safeBuild()
157
-
158
- await hooks.emit('kubb:info', { message: 'Load summary' })
159
-
160
- // Handle build failures (either from failed plugins or general errors)
161
-
162
- const hasFailures = failedPlugins.size > 0 || error
163
- if (hasFailures) {
164
- // Collect all errors from failed plugins and general error
165
- const allErrors: Error[] = [
166
- error,
167
- ...Array.from(failedPlugins)
168
- .filter((it) => it.error)
169
- .map((it) => it.error),
170
- ].filter(Boolean)
171
-
172
- for (const err of allErrors) {
173
- await hooks.emit('kubb:error', { error: err })
174
- }
175
-
176
- await hooks.emit('kubb:generation:end', { config, files, sources: kubb.sources })
177
-
178
- await hooks.emit('kubb:generation:summary', {
179
- config,
180
- failedPlugins,
181
- filesCreated: files.length,
182
- status: 'failed',
183
- hrStart,
184
- pluginTimings: logLevel >= logLevelMap.verbose ? pluginTimings : undefined,
185
- })
186
-
187
- await sendTelemetry(
188
- buildTelemetryEvent({
189
- command: 'generate',
190
- kubbVersion: version,
191
- plugins: Array.from(driver.plugins.values(), (p) => ({
192
- name: p.name,
193
- options: p.options as Record<string, unknown>,
194
- })),
195
- hrStart,
196
- filesCreated: files.length,
197
- status: 'failed',
198
- }),
199
- )
200
-
201
- process.exit(1)
202
- }
203
-
204
- await hooks.emit('kubb:success', { message: 'Generation successfully', info: inputPath })
205
- await hooks.emit('kubb:generation:end', { config, files, sources: kubb.sources })
206
-
207
- const outputPath = path.resolve(config.root, config.output.path)
208
-
209
- if (config.output.format) {
210
- await runToolPass({
211
- toolValue: config.output.format,
212
- detect: detectFormatter,
213
- toolMap: formatters,
214
- toolLabel: 'formatter',
215
- successPrefix: 'Formatting',
216
- noToolMessage: 'No formatter found (oxfmt, biome, or prettier). Skipping formatting.',
217
- configName: config.name,
218
- outputPath,
219
- logLevel,
220
- hooks,
221
- onStart: () => hooks.emit('kubb:format:start'),
222
- onEnd: () => hooks.emit('kubb:format:end'),
223
- })
224
- }
225
-
226
- if (config.output.lint) {
227
- await runToolPass({
228
- toolValue: config.output.lint,
229
- detect: detectLinter,
230
- toolMap: linters,
231
- toolLabel: 'linter',
232
- successPrefix: 'Linting',
233
- noToolMessage: 'No linter found (oxlint, biome, or eslint). Skipping linting.',
234
- configName: config.name,
235
- outputPath,
236
- logLevel,
237
- hooks,
238
- onStart: () => hooks.emit('kubb:lint:start'),
239
- onEnd: () => hooks.emit('kubb:lint:end'),
240
- })
241
- }
242
-
243
- if (config.hooks) {
244
- await hooks.emit('kubb:hooks:start')
245
- await executeHooks({ configHooks: config.hooks, hooks })
246
-
247
- await hooks.emit('kubb:hooks:end')
248
- }
249
-
250
- // Only reached when there are no failures (process.exit(1) is called above otherwise)
251
- await hooks.emit('kubb:generation:summary', {
252
- config,
253
- failedPlugins,
254
- filesCreated: files.length,
255
- status: 'success',
256
- hrStart,
257
- pluginTimings,
258
- })
259
-
260
- const telemetryEvent = buildTelemetryEvent({
261
- command: 'generate',
262
- kubbVersion: version,
263
- plugins: Array.from(driver.plugins.values(), (p) => ({
264
- name: p.name,
265
- options: p.options as Record<string, unknown>,
266
- })),
267
- hrStart,
268
- filesCreated: files.length,
269
- status: 'success',
270
- })
271
-
272
- await sendTelemetry(telemetryEvent)
273
- }
274
-
275
- type GenerateCommandOptions = {
276
- input?: string
277
- configPath?: string
278
- logLevel: string
279
- watch: boolean
280
- }
281
-
282
- export async function runGenerateCommand({ input, configPath, logLevel: logLevelKey, watch }: GenerateCommandOptions): Promise<void> {
283
- const logLevel = logLevelMap[logLevelKey as keyof typeof logLevelMap] ?? logLevelMap.info
284
- const hooks = new AsyncEventEmitterClass<KubbHooks>()
285
-
286
- await setupLogger(hooks, { logLevel })
287
-
288
- await executeIfOnline(async () => {
289
- try {
290
- const res = await fetch(KUBB_NPM_PACKAGE_URL)
291
- const data = (await res.json()) as { version: string }
292
- const latestVersion = data.version
293
-
294
- if (latestVersion && version < latestVersion) {
295
- await hooks.emit('kubb:version:new', { currentVersion: version, latestVersion })
296
- }
297
- } catch {
298
- // Ignore network errors for version check
299
- }
300
- })
301
-
302
- try {
303
- const result = await getCosmiConfig('kubb', configPath)
304
- const configs = await getConfigs(result.config, { input } as CLIOptions)
305
-
306
- await hooks.emit('kubb:config:start')
307
- await hooks.emit('kubb:info', { message: 'Config loaded', info: path.relative(process.cwd(), result.filepath) })
308
- await hooks.emit('kubb:success', { message: 'Config loaded successfully', info: path.relative(process.cwd(), result.filepath) })
309
- await hooks.emit('kubb:config:end', { configs })
310
-
311
- await hooks.emit('kubb:lifecycle:start', { version })
312
-
313
- for (const config of configs) {
314
- if (isInputPath(config) && watch) {
315
- await startWatcher([input || config.input.path], async (paths) => {
316
- // remove to avoid duplicate listeners after each change
317
- hooks.removeAll()
318
-
319
- await generate({ input, config, logLevel, hooks })
320
-
321
- clack.log.step(styleText('yellow', `Watching for changes in ${paths.join(' and ')}`))
322
- })
323
- } else {
324
- await generate({ input, config, logLevel, hooks })
325
- }
326
- }
327
-
328
- await hooks.emit('kubb:lifecycle:end')
329
- } catch (error) {
330
- await hooks.emit('kubb:error', { error: toError(error) })
331
- process.exit(1)
332
- }
333
- }
@@ -1,56 +0,0 @@
1
- import process from 'node:process'
2
- import { styleText } from 'node:util'
3
- import { getErrorMessage } from '@internals/utils'
4
- import type * as McpModule from '@kubb/mcp'
5
- import { buildTelemetryEvent, sendTelemetry } from '../utils/telemetry.ts'
6
-
7
- type McpOptions = {
8
- version: string
9
- port?: string
10
- host?: string
11
- }
12
-
13
- export async function runMcp({ version, port, host }: McpOptions): Promise<void> {
14
- let mod: typeof McpModule
15
- try {
16
- mod = (await import('@kubb/mcp')) as typeof McpModule
17
- } catch (_e) {
18
- console.error(styleText('red', 'The @kubb/mcp package is not installed.'))
19
- console.error('')
20
- console.error('Install it with:')
21
- console.error(styleText('cyan', ' npm install @kubb/mcp'))
22
- console.error(styleText('cyan', ' # or'))
23
- console.error(styleText('cyan', ' pnpm install @kubb/mcp'))
24
- console.error('')
25
- process.exit(1)
26
- }
27
-
28
- const { run } = mod
29
- const hrStart = process.hrtime()
30
- try {
31
- console.log('⏳ Starting MCP server...')
32
- console.warn(styleText('yellow', 'This feature is still under development — use with caution'))
33
- run(undefined, {
34
- port: port !== undefined ? Number(port) : undefined,
35
- host,
36
- })
37
- await sendTelemetry(
38
- buildTelemetryEvent({
39
- command: 'mcp',
40
- kubbVersion: version,
41
- hrStart,
42
- status: 'success',
43
- }),
44
- )
45
- } catch (error) {
46
- await sendTelemetry(
47
- buildTelemetryEvent({
48
- command: 'mcp',
49
- kubbVersion: version,
50
- hrStart,
51
- status: 'failed',
52
- }),
53
- )
54
- console.error(getErrorMessage(error))
55
- }
56
- }
package/src/types.ts DELETED
@@ -1,11 +0,0 @@
1
- export type QuiteFlag = '--help' | '-h' | '--version' | '-v'
2
-
3
- export type GenerateFlag = '--config' | '-c' | '--log-level' | '-l' | '--watch' | '-w' | '--debug' | '-d' | '--verbose' | '-v' | '--silent' | '-s'
4
-
5
- export type ValidateFlag = '--input' | '-i'
6
-
7
- export type InitFlag = '--yes' | '-y'
8
-
9
- export type AgentStartFlag = '--config' | '-c' | '--port' | '-p' | '--host' | '--allow-write' | '--allow-all'
10
-
11
- export type Arg = QuiteFlag | GenerateFlag | ValidateFlag | InitFlag | AgentStartFlag
@@ -1,17 +0,0 @@
1
- import type { WritableOptions } from 'node:stream'
2
- import { Writable } from 'node:stream'
3
- import { styleText } from 'node:util'
4
- import type * as clack from '@clack/prompts'
5
-
6
- export class ClackWritable extends Writable {
7
- taskLog: ReturnType<typeof clack.taskLog>
8
- constructor(taskLog: ReturnType<typeof clack.taskLog>, opts?: WritableOptions) {
9
- super(opts)
10
-
11
- this.taskLog = taskLog
12
- }
13
- _write(chunk: Buffer, _encoding: BufferEncoding, callback: (error?: Error | null) => void): void {
14
- this.taskLog.message(`${styleText('dim', chunk.toString())}`)
15
- callback()
16
- }
17
- }
@@ -1,45 +0,0 @@
1
- import { createHash } from 'node:crypto'
2
- import { styleText } from 'node:util'
3
- import type { AsyncEventEmitter } from '@internals/utils'
4
- import { tokenize } from '@internals/utils'
5
- import type { Config, KubbHookEndContext, KubbHooks } from '@kubb/core'
6
-
7
- type ExecutingHooksProps = {
8
- configHooks: NonNullable<Config['hooks']>
9
- hooks: AsyncEventEmitter<KubbHooks>
10
- }
11
-
12
- export async function executeHooks({ configHooks, hooks }: ExecutingHooksProps): Promise<void> {
13
- const commands = Array.isArray(configHooks.done) ? configHooks.done : [configHooks.done].filter(Boolean)
14
-
15
- for (const command of commands) {
16
- const [cmd, ...args] = tokenize(command)
17
-
18
- if (!cmd) {
19
- continue
20
- }
21
-
22
- const hookId = createHash('sha256').update(command).digest('hex')
23
-
24
- // Wire up the hook:end listener BEFORE emitting hook:start to avoid the race condition
25
- // where hook:end fires synchronously inside emit('kubb:hook:start') before the listener is registered.
26
- const hookEndPromise = new Promise<void>((resolve, reject) => {
27
- const handler = (ctx: KubbHookEndContext) => {
28
- if (ctx.id !== hookId) return
29
- hooks.off('kubb:hook:end', handler)
30
- if (!ctx.success) {
31
- reject(ctx.error ?? new Error(`Hook failed: ${command}`))
32
- return
33
- }
34
- hooks
35
- .emit('kubb:success', { message: `${styleText('dim', command)} successfully executed` })
36
- .then(resolve)
37
- .catch(reject)
38
- }
39
- hooks.on('kubb:hook:end', handler)
40
- })
41
-
42
- await hooks.emit('kubb:hook:start', { id: hookId, command: cmd, args })
43
- await hookEndPromise
44
- }
45
- }
@@ -1,9 +0,0 @@
1
- /**
2
- * Type guard that confirms `value` is a member of `set`. Avoids type assertions with `Set<T extends string>`.
3
- */
4
- export function isFlag<T extends string>(set: ReadonlySet<T>, value: string): value is T {
5
- for (const flag of set) {
6
- if (flag === value) return true
7
- }
8
- return false
9
- }
@@ -1,10 +0,0 @@
1
- import type { CLIOptions, Config, PossibleConfig } from '@kubb/core'
2
-
3
- type ConfigInput = PossibleConfig<CLIOptions>
4
-
5
- export async function getConfigs(config: ConfigInput, args: CLIOptions): Promise<Array<Config>> {
6
- const resolved = await (typeof config === 'function' ? config(args as CLIOptions) : config)
7
- const userConfigs = Array.isArray(resolved) ? resolved : [resolved]
8
-
9
- return userConfigs.map((item) => ({ ...item, plugins: item.plugins ?? [] }) as Config)
10
- }
@@ -1,75 +0,0 @@
1
- import type { Config } from '@kubb/core'
2
- import { cosmiconfig } from 'cosmiconfig'
3
- import { createJiti } from 'jiti'
4
-
5
- type CosmiconfigResult = {
6
- filepath: string
7
- isEmpty?: boolean
8
- config: Config
9
- }
10
-
11
- const jiti = createJiti(import.meta.url, {
12
- jsx: {
13
- runtime: 'automatic',
14
- importSource: '@kubb/renderer-jsx',
15
- },
16
- moduleCache: false,
17
- })
18
-
19
- const tsLoader = async (configFile: string) => {
20
- return jiti.import(configFile, { default: true })
21
- }
22
-
23
- export async function getCosmiConfig(moduleName: string, config?: string): Promise<CosmiconfigResult> {
24
- let result: CosmiconfigResult
25
- const searchPlaces = [
26
- 'package.json',
27
- `.${moduleName}rc`,
28
- `.${moduleName}rc.json`,
29
- `.${moduleName}rc.yaml`,
30
- `.${moduleName}rc.yml`,
31
-
32
- `.${moduleName}rc.ts`,
33
- `.${moduleName}rc.mts`,
34
- `.${moduleName}rc.cts`,
35
- `.${moduleName}rc.js`,
36
- `.${moduleName}rc.mjs`,
37
- `.${moduleName}rc.cjs`,
38
-
39
- `${moduleName}.config.ts`,
40
- `${moduleName}.config.mts`,
41
- `${moduleName}.config.cts`,
42
- `${moduleName}.config.js`,
43
- `${moduleName}.config.mjs`,
44
- `${moduleName}.config.cjs`,
45
- ]
46
- const explorer = cosmiconfig(moduleName, {
47
- cache: false,
48
- searchPlaces: [
49
- ...searchPlaces.map((searchPlace) => {
50
- return `.config/${searchPlace}`
51
- }),
52
- ...searchPlaces.map((searchPlace) => {
53
- return `configs/${searchPlace}`
54
- }),
55
- ...searchPlaces,
56
- ],
57
- loaders: {
58
- '.ts': tsLoader,
59
- '.mts': tsLoader,
60
- '.cts': tsLoader,
61
- },
62
- })
63
-
64
- try {
65
- result = config ? ((await explorer.load(config)) as CosmiconfigResult) : ((await explorer.search()) as CosmiconfigResult)
66
- } catch (error) {
67
- throw new Error('Config failed loading', { cause: error })
68
- }
69
-
70
- if (result?.isEmpty || !result || !result.config) {
71
- throw new Error('Config not defined, create a kubb.config.js or pass through your config with the option --config')
72
- }
73
-
74
- return result as CosmiconfigResult
75
- }
@@ -1,68 +0,0 @@
1
- import path from 'node:path'
2
- import { styleText } from 'node:util'
3
- import { formatHrtime, randomCliColor } from '@internals/utils'
4
- import type { Config, Plugin } from '@kubb/core'
5
- import { SUMMARY_MAX_BAR_LENGTH, SUMMARY_TIME_SCALE_DIVISOR } from '../constants.ts'
6
-
7
- type SummaryProps = {
8
- failedPlugins: Set<{ plugin: Plugin; error: Error }>
9
- status: 'success' | 'failed'
10
- hrStart: [number, number]
11
- filesCreated: number
12
- config: Config
13
- pluginTimings?: Map<string, number>
14
- }
15
-
16
- export function getSummary({ failedPlugins, filesCreated, status, hrStart, config, pluginTimings }: SummaryProps): string[] {
17
- const duration = formatHrtime(hrStart)
18
-
19
- const pluginsCount = config.plugins?.length ?? 0
20
- const successCount = pluginsCount - failedPlugins.size
21
-
22
- const meta = {
23
- plugins:
24
- status === 'success'
25
- ? `${styleText('green', `${successCount} successful`)}, ${pluginsCount} total`
26
- : `${styleText('green', `${successCount} successful`)}, ${styleText('red', `${failedPlugins.size} failed`)}, ${pluginsCount} total`,
27
- pluginsFailed: status === 'failed' ? [...failedPlugins].map(({ plugin }) => randomCliColor(plugin.name)).join(', ') : undefined,
28
- filesCreated,
29
- time: styleText('green', duration),
30
- output: path.resolve(config.root, config.output.path),
31
- } as const
32
-
33
- const labels = {
34
- plugins: 'Plugins:',
35
- failed: 'Failed:',
36
- generated: 'Generated:',
37
- pluginTimings: 'Plugin Timings:',
38
- output: 'Output:',
39
- }
40
- const maxLength = Math.max(0, ...[...Object.values(labels), ...(pluginTimings ? Array.from(pluginTimings.keys()) : [])].map((s) => s.length))
41
-
42
- const summaryLines: string[] = []
43
- summaryLines.push(`${labels.plugins.padEnd(maxLength + 2)} ${meta.plugins}`)
44
-
45
- if (meta.pluginsFailed) {
46
- summaryLines.push(`${labels.failed.padEnd(maxLength + 2)} ${meta.pluginsFailed}`)
47
- }
48
-
49
- summaryLines.push(`${labels.generated.padEnd(maxLength + 2)} ${meta.filesCreated} files in ${meta.time}`)
50
-
51
- if (pluginTimings && pluginTimings.size > 0) {
52
- const sortedTimings = Array.from(pluginTimings.entries()).sort((a, b) => b[1] - a[1])
53
-
54
- summaryLines.push(`${labels.pluginTimings}`)
55
-
56
- sortedTimings.forEach(([name, time]) => {
57
- const timeStr = time >= 1000 ? `${(time / 1000).toFixed(2)}s` : `${Math.round(time)}ms`
58
- const barLength = Math.min(Math.ceil(time / SUMMARY_TIME_SCALE_DIVISOR), SUMMARY_MAX_BAR_LENGTH)
59
- const bar = styleText('dim', '█'.repeat(barLength))
60
-
61
- summaryLines.push(`${styleText('dim', '•')} ${name.padEnd(maxLength + 1)}${bar} ${timeStr}`)
62
- })
63
- }
64
-
65
- summaryLines.push(`${labels.output.padEnd(maxLength + 2)} ${meta.output}`)
66
-
67
- return summaryLines
68
- }