@kubb/cli 5.0.0-alpha.4 → 5.0.0-alpha.41

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 (122) hide show
  1. package/bin/kubb.js +6 -0
  2. package/dist/{agent-CIQijRVB.cjs → agent-9W6zfWlm.cjs} +5 -5
  3. package/dist/{agent-CIQijRVB.cjs.map → agent-9W6zfWlm.cjs.map} +1 -1
  4. package/dist/{agent-BTM0c8dD.js → agent-BsqSjdvW.js} +5 -5
  5. package/dist/{agent-BTM0c8dD.js.map → agent-BsqSjdvW.js.map} +1 -1
  6. package/dist/agent-CWitLsL9.cjs +109 -0
  7. package/dist/agent-CWitLsL9.cjs.map +1 -0
  8. package/dist/agent-poGbscec.js +105 -0
  9. package/dist/agent-poGbscec.js.map +1 -0
  10. package/dist/{constants-BTUap0zs.cjs → constants-D0XHAHeZ.cjs} +78 -8
  11. package/dist/constants-D0XHAHeZ.cjs.map +1 -0
  12. package/dist/{constants-CM3dJzjK.js → constants-DJM9zCXm.js} +73 -9
  13. package/dist/constants-DJM9zCXm.js.map +1 -0
  14. package/dist/define-Bdn8j5VM.cjs +54 -0
  15. package/dist/define-Bdn8j5VM.cjs.map +1 -0
  16. package/dist/define-Ctii4bel.js +43 -0
  17. package/dist/define-Ctii4bel.js.map +1 -0
  18. package/dist/{errors-DBW0N9w4.cjs → errors-CLCjoSg0.cjs} +22 -6
  19. package/dist/errors-CLCjoSg0.cjs.map +1 -0
  20. package/dist/errors-CjPmyZHy.js +43 -0
  21. package/dist/errors-CjPmyZHy.js.map +1 -0
  22. package/dist/{generate-D5CrYCLF.cjs → generate-BBaA9E80.cjs} +479 -250
  23. package/dist/generate-BBaA9E80.cjs.map +1 -0
  24. package/dist/{generate-DRz7eCom.js → generate-BYUi7qIe.js} +3 -3
  25. package/dist/{generate-DRz7eCom.js.map → generate-BYUi7qIe.js.map} +1 -1
  26. package/dist/{generate-Dw5sZGB-.js → generate-DfasfQTf.js} +472 -243
  27. package/dist/generate-DfasfQTf.js.map +1 -0
  28. package/dist/{generate-Bqt7o7A7.cjs → generate-DyXU57ji.cjs} +3 -3
  29. package/dist/{generate-Bqt7o7A7.cjs.map → generate-DyXU57ji.cjs.map} +1 -1
  30. package/dist/index.cjs +49 -21
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.ts +1 -1
  33. package/dist/index.js +49 -21
  34. package/dist/index.js.map +1 -1
  35. package/dist/{init-BH-IuVku.cjs → init-6X1up4xB.cjs} +4 -4
  36. package/dist/{init-BH-IuVku.cjs.map → init-6X1up4xB.cjs.map} +1 -1
  37. package/dist/{init-BKo0zEUz.js → init-DUbKThCV.js} +4 -4
  38. package/dist/{init-BKo0zEUz.js.map → init-DUbKThCV.js.map} +1 -1
  39. package/dist/{init-hmolV6B4.cjs → init-cAbMOLut.cjs} +24 -9
  40. package/dist/init-cAbMOLut.cjs.map +1 -0
  41. package/dist/{init-C-InrmSY.js → init-hcm7zvPn.js} +20 -5
  42. package/dist/init-hcm7zvPn.js.map +1 -0
  43. package/dist/{mcp-D2SHEg_d.js → mcp-B_FoDCTh.js} +11 -4
  44. package/dist/mcp-B_FoDCTh.js.map +1 -0
  45. package/dist/{mcp-BuEzqp9N.cjs → mcp-DjspvGi8.cjs} +4 -4
  46. package/dist/{mcp-BuEzqp9N.cjs.map → mcp-DjspvGi8.cjs.map} +1 -1
  47. package/dist/{mcp-chxay4lz.js → mcp-DnODI-YA.js} +4 -4
  48. package/dist/{mcp-chxay4lz.js.map → mcp-DnODI-YA.js.map} +1 -1
  49. package/dist/{mcp-ChHFPRzD.cjs → mcp-STc97s14.cjs} +12 -6
  50. package/dist/mcp-STc97s14.cjs.map +1 -0
  51. package/dist/package-B2Sfb1j1.js +6 -0
  52. package/dist/package-B2Sfb1j1.js.map +1 -0
  53. package/dist/{package-D4K2izUa.cjs → package-DG_gqE1R.cjs} +2 -2
  54. package/dist/package-DG_gqE1R.cjs.map +1 -0
  55. package/dist/{shell-7HPrTCJ5.cjs → shell-475fQKaX.cjs} +8 -3
  56. package/dist/shell-475fQKaX.cjs.map +1 -0
  57. package/dist/{shell-DqqWsHCD.js → shell-DLzN4fRo.js} +8 -3
  58. package/dist/shell-DLzN4fRo.js.map +1 -0
  59. package/dist/{telemetry-DxiR7clS.js → telemetry-CBISr5w4.js} +48 -6
  60. package/dist/telemetry-CBISr5w4.js.map +1 -0
  61. package/dist/{telemetry-Cn9X1I5B.cjs → telemetry-D_Bi2E3I.cjs} +50 -8
  62. package/dist/telemetry-D_Bi2E3I.cjs.map +1 -0
  63. package/dist/{validate-BqYfMrH7.cjs → validate-BL24GxcL.cjs} +4 -4
  64. package/dist/{validate-BqYfMrH7.cjs.map → validate-BL24GxcL.cjs.map} +1 -1
  65. package/dist/{validate-CfeXKup1.js → validate-C77Viejc.js} +4 -4
  66. package/dist/{validate-CfeXKup1.js.map → validate-C77Viejc.js.map} +1 -1
  67. package/dist/{validate-Bbrn3Q-A.cjs → validate-CqwT945Z.cjs} +6 -14
  68. package/dist/validate-CqwT945Z.cjs.map +1 -0
  69. package/dist/{validate-l8vLmwKA.js → validate-NZ0mduJ3.js} +5 -13
  70. package/dist/validate-NZ0mduJ3.js.map +1 -0
  71. package/package.json +8 -9
  72. package/src/constants.ts +57 -10
  73. package/src/index.ts +10 -12
  74. package/src/loggers/clackLogger.ts +54 -46
  75. package/src/loggers/fileSystemLogger.ts +13 -11
  76. package/src/loggers/githubActionsLogger.ts +22 -22
  77. package/src/loggers/plainLogger.ts +21 -21
  78. package/src/runners/agent.ts +54 -31
  79. package/src/runners/generate.ts +78 -99
  80. package/src/runners/init.ts +1 -1
  81. package/src/runners/validate.ts +3 -13
  82. package/src/types.ts +11 -0
  83. package/src/utils/executeHooks.ts +11 -11
  84. package/src/utils/flags.ts +10 -0
  85. package/src/utils/getConfig.ts +10 -0
  86. package/src/utils/getCosmiConfig.ts +9 -3
  87. package/src/utils/getSummary.ts +1 -1
  88. package/src/utils/runHook.ts +9 -9
  89. package/bin/kubb.cjs +0 -18
  90. package/dist/agent-C6o_6GSJ.cjs +0 -92
  91. package/dist/agent-C6o_6GSJ.cjs.map +0 -1
  92. package/dist/agent-L50VNhXv.js +0 -88
  93. package/dist/agent-L50VNhXv.js.map +0 -1
  94. package/dist/constants-BTUap0zs.cjs.map +0 -1
  95. package/dist/constants-CM3dJzjK.js.map +0 -1
  96. package/dist/define--M_JMcDC.js +0 -25
  97. package/dist/define--M_JMcDC.js.map +0 -1
  98. package/dist/define-D6Kfm7-Z.cjs +0 -36
  99. package/dist/define-D6Kfm7-Z.cjs.map +0 -1
  100. package/dist/errors-6mF_WKxg.js +0 -27
  101. package/dist/errors-6mF_WKxg.js.map +0 -1
  102. package/dist/errors-DBW0N9w4.cjs.map +0 -1
  103. package/dist/generate-D5CrYCLF.cjs.map +0 -1
  104. package/dist/generate-Dw5sZGB-.js.map +0 -1
  105. package/dist/init-C-InrmSY.js.map +0 -1
  106. package/dist/init-hmolV6B4.cjs.map +0 -1
  107. package/dist/jiti-Cd3S0xwr.cjs +0 -16
  108. package/dist/jiti-Cd3S0xwr.cjs.map +0 -1
  109. package/dist/jiti-e08mD2Ph.js +0 -11
  110. package/dist/jiti-e08mD2Ph.js.map +0 -1
  111. package/dist/mcp-ChHFPRzD.cjs.map +0 -1
  112. package/dist/mcp-D2SHEg_d.js.map +0 -1
  113. package/dist/package-D4K2izUa.cjs.map +0 -1
  114. package/dist/package-Pd8l9DAQ.js +0 -6
  115. package/dist/package-Pd8l9DAQ.js.map +0 -1
  116. package/dist/shell-7HPrTCJ5.cjs.map +0 -1
  117. package/dist/shell-DqqWsHCD.js.map +0 -1
  118. package/dist/telemetry-Cn9X1I5B.cjs.map +0 -1
  119. package/dist/telemetry-DxiR7clS.js.map +0 -1
  120. package/dist/validate-Bbrn3Q-A.cjs.map +0 -1
  121. package/dist/validate-l8vLmwKA.js.map +0 -1
  122. package/src/utils/getIntro.ts +0 -1
@@ -19,7 +19,7 @@ export const plainLogger = defineLogger({
19
19
  return formatMessage(message, logLevel)
20
20
  }
21
21
 
22
- context.on('info', (message, info) => {
22
+ context.on('kubb:info', (message, info) => {
23
23
  if (logLevel <= logLevelMap.silent) {
24
24
  return
25
25
  }
@@ -29,7 +29,7 @@ export const plainLogger = defineLogger({
29
29
  console.log(text)
30
30
  })
31
31
 
32
- context.on('success', (message, info = '') => {
32
+ context.on('kubb:success', (message, info = '') => {
33
33
  if (logLevel <= logLevelMap.silent) {
34
34
  return
35
35
  }
@@ -39,7 +39,7 @@ export const plainLogger = defineLogger({
39
39
  console.log(text)
40
40
  })
41
41
 
42
- context.on('warn', (message, info) => {
42
+ context.on('kubb:warn', (message, info) => {
43
43
  if (logLevel < logLevelMap.warn) {
44
44
  return
45
45
  }
@@ -49,7 +49,7 @@ export const plainLogger = defineLogger({
49
49
  console.log(text)
50
50
  })
51
51
 
52
- context.on('error', (error) => {
52
+ context.on('kubb:error', (error) => {
53
53
  const caused = toCause(error)
54
54
 
55
55
  const text = getMessage(['✗', error.message].join(' '))
@@ -74,11 +74,11 @@ export const plainLogger = defineLogger({
74
74
  }
75
75
  })
76
76
 
77
- context.on('lifecycle:start', () => {
77
+ context.on('kubb:lifecycle:start', () => {
78
78
  console.log('Kubb CLI 🧩')
79
79
  })
80
80
 
81
- context.on('config:start', () => {
81
+ context.on('kubb:config:start', () => {
82
82
  if (logLevel <= logLevelMap.silent) {
83
83
  return
84
84
  }
@@ -88,7 +88,7 @@ export const plainLogger = defineLogger({
88
88
  console.log(text)
89
89
  })
90
90
 
91
- context.on('config:end', () => {
91
+ context.on('kubb:config:end', () => {
92
92
  if (logLevel <= logLevelMap.silent) {
93
93
  return
94
94
  }
@@ -98,13 +98,13 @@ export const plainLogger = defineLogger({
98
98
  console.log(text)
99
99
  })
100
100
 
101
- context.on('generation:start', () => {
101
+ context.on('kubb:generation:start', () => {
102
102
  const text = getMessage('Generation started')
103
103
 
104
104
  console.log(text)
105
105
  })
106
106
 
107
- context.on('plugin:start', (plugin) => {
107
+ context.on('kubb:plugin:start', (plugin) => {
108
108
  if (logLevel <= logLevelMap.silent) {
109
109
  return
110
110
  }
@@ -113,7 +113,7 @@ export const plainLogger = defineLogger({
113
113
  console.log(text)
114
114
  })
115
115
 
116
- context.on('plugin:end', (plugin, { duration, success }) => {
116
+ context.on('kubb:plugin:end', (plugin, { duration, success }) => {
117
117
  if (logLevel <= logLevelMap.silent) {
118
118
  return
119
119
  }
@@ -124,7 +124,7 @@ export const plainLogger = defineLogger({
124
124
  console.log(text)
125
125
  })
126
126
 
127
- context.on('files:processing:start', (files) => {
127
+ context.on('kubb:files:processing:start', (files) => {
128
128
  if (logLevel <= logLevelMap.silent) {
129
129
  return
130
130
  }
@@ -134,7 +134,7 @@ export const plainLogger = defineLogger({
134
134
  console.log(text)
135
135
  })
136
136
 
137
- context.on('file:processing:update', ({ file, config }) => {
137
+ context.on('kubb:file:processing:update', ({ file, config }) => {
138
138
  if (logLevel <= logLevelMap.silent) {
139
139
  return
140
140
  }
@@ -144,7 +144,7 @@ export const plainLogger = defineLogger({
144
144
  console.log(text)
145
145
  })
146
146
 
147
- context.on('files:processing:end', () => {
147
+ context.on('kubb:files:processing:end', () => {
148
148
  if (logLevel <= logLevelMap.silent) {
149
149
  return
150
150
  }
@@ -154,13 +154,13 @@ export const plainLogger = defineLogger({
154
154
  console.log(text)
155
155
  })
156
156
 
157
- context.on('generation:end', (config) => {
157
+ context.on('kubb:generation:end', (config) => {
158
158
  const text = getMessage(config.name ? `Generation completed for ${config.name}` : 'Generation completed')
159
159
 
160
160
  console.log(text)
161
161
  })
162
162
 
163
- context.on('format:start', () => {
163
+ context.on('kubb:format:start', () => {
164
164
  if (logLevel <= logLevelMap.silent) {
165
165
  return
166
166
  }
@@ -170,7 +170,7 @@ export const plainLogger = defineLogger({
170
170
  console.log(text)
171
171
  })
172
172
 
173
- context.on('format:end', () => {
173
+ context.on('kubb:format:end', () => {
174
174
  if (logLevel <= logLevelMap.silent) {
175
175
  return
176
176
  }
@@ -180,7 +180,7 @@ export const plainLogger = defineLogger({
180
180
  console.log(text)
181
181
  })
182
182
 
183
- context.on('lint:start', () => {
183
+ context.on('kubb:lint:start', () => {
184
184
  if (logLevel <= logLevelMap.silent) {
185
185
  return
186
186
  }
@@ -190,7 +190,7 @@ export const plainLogger = defineLogger({
190
190
  console.log(text)
191
191
  })
192
192
 
193
- context.on('lint:end', () => {
193
+ context.on('kubb:lint:end', () => {
194
194
  if (logLevel <= logLevelMap.silent) {
195
195
  return
196
196
  }
@@ -200,7 +200,7 @@ export const plainLogger = defineLogger({
200
200
  console.log(text)
201
201
  })
202
202
 
203
- context.on('hook:start', async ({ id, command, args }) => {
203
+ context.on('kubb:hook:start', async ({ id, command, args }) => {
204
204
  const commandWithArgs = formatCommandWithArgs(command, args)
205
205
  const text = getMessage(`Hook ${commandWithArgs} started`)
206
206
 
@@ -226,7 +226,7 @@ export const plainLogger = defineLogger({
226
226
  })
227
227
  })
228
228
 
229
- context.on('hook:end', ({ command, args }) => {
229
+ context.on('kubb:hook:end', ({ command, args }) => {
230
230
  if (logLevel <= logLevelMap.silent) {
231
231
  return
232
232
  }
@@ -237,7 +237,7 @@ export const plainLogger = defineLogger({
237
237
  console.log(text)
238
238
  })
239
239
 
240
- context.on('generation:summary', (config, { pluginTimings, status, hrStart, failedPlugins, filesCreated }) => {
240
+ context.on('kubb:generation:summary', (config, { pluginTimings, status, hrStart, failedPlugins, filesCreated }) => {
241
241
  const summary = getSummary({
242
242
  failedPlugins,
243
243
  filesCreated,
@@ -17,6 +17,47 @@ type AgentStartOptions = {
17
17
  version: string
18
18
  }
19
19
 
20
+ type ResolvedAgentStartEnvironment = {
21
+ port: string
22
+ host: string
23
+ allowWrite: boolean
24
+ allowAll: boolean
25
+ agentConfigPath: string
26
+ env: NodeJS.ProcessEnv
27
+ }
28
+
29
+ /**
30
+ * Resolves the environment passed to the detached agent process using CLI values first, then environment values, then CLI defaults.
31
+ */
32
+ function resolveAgentStartEnvironment({ port, host, configPath, allowWrite, allowAll }: Omit<AgentStartOptions, 'version'>): ResolvedAgentStartEnvironment {
33
+ const resolvedPort = port ?? process.env.PORT ?? agentDefaults.port
34
+ const resolvedHost = host !== agentDefaults.host ? host : (process.env.HOST ?? agentDefaults.host)
35
+ const resolvedAllowAll = allowAll || process.env.KUBB_AGENT_ALLOW_ALL === 'true'
36
+ const resolvedAllowWrite = resolvedAllowAll || allowWrite || process.env.KUBB_AGENT_ALLOW_WRITE === 'true'
37
+ const agentRoot = process.env.KUBB_AGENT_ROOT ?? process.cwd()
38
+ const agentConfigPath = path.resolve(process.cwd(), configPath || process.env.KUBB_AGENT_CONFIG || agentDefaults.configFile)
39
+
40
+ return {
41
+ port: resolvedPort,
42
+ host: resolvedHost,
43
+ allowWrite: resolvedAllowWrite,
44
+ allowAll: resolvedAllowAll,
45
+ agentConfigPath,
46
+ env: {
47
+ ...process.env,
48
+ PORT: resolvedPort,
49
+ HOST: resolvedHost,
50
+ KUBB_AGENT_ROOT: agentRoot,
51
+ KUBB_AGENT_CONFIG: agentConfigPath,
52
+ KUBB_AGENT_ALLOW_WRITE: String(resolvedAllowWrite),
53
+ KUBB_AGENT_ALLOW_ALL: String(resolvedAllowAll),
54
+ KUBB_AGENT_TOKEN: process.env.KUBB_AGENT_TOKEN,
55
+ KUBB_AGENT_RETRY_TIMEOUT: process.env.KUBB_AGENT_RETRY_TIMEOUT ?? agentDefaults.retryTimeout,
56
+ KUBB_STUDIO_URL: process.env.KUBB_STUDIO_URL ?? agentDefaults.studioUrl,
57
+ },
58
+ }
59
+ }
60
+
20
61
  function isPortAvailable(port: number, host: string): Promise<boolean> {
21
62
  return new Promise((resolve) => {
22
63
  const server = net.createServer()
@@ -46,49 +87,31 @@ export async function runAgentStart({ port, host, configPath, allowWrite, allowA
46
87
  const agentDir = path.dirname(agentPkgPath)
47
88
  const serverPath = path.join(agentDir, agentDefaults.serverEntryPath)
48
89
 
49
- // CLI params take priority over process.env; process.env fills in what the CLI didn't specify;
50
- // agentDefaults are the last resort. Build env as: defaults ← process.env ← CLI.
51
- const PORT = port !== undefined ? port : (process.env.PORT ?? agentDefaults.port)
52
- const HOST = host !== agentDefaults.host ? host : (process.env.HOST ?? agentDefaults.host)
53
- const KUBB_AGENT_ROOT = process.env.KUBB_AGENT_ROOT ?? process.cwd()
54
- const KUBB_AGENT_CONFIG = path.resolve(process.cwd(), configPath || process.env.KUBB_AGENT_CONFIG || agentDefaults.configFile)
55
- const KUBB_AGENT_ALLOW_WRITE = allowAll || allowWrite ? 'true' : (process.env.KUBB_AGENT_ALLOW_WRITE ?? 'false')
56
- const KUBB_AGENT_ALLOW_ALL = allowAll ? 'true' : (process.env.KUBB_AGENT_ALLOW_ALL ?? 'false')
57
- const KUBB_AGENT_TOKEN = process.env.KUBB_AGENT_TOKEN
58
- const KUBB_AGENT_RETRY_TIMEOUT = process.env.KUBB_AGENT_RETRY_TIMEOUT ?? agentDefaults.retryTimeout
59
- const KUBB_STUDIO_URL = process.env.KUBB_STUDIO_URL ?? agentDefaults.studioUrl
90
+ const resolvedEnv = resolveAgentStartEnvironment({ port, host, configPath, allowWrite, allowAll })
91
+ const numericPort = Number(resolvedEnv.port)
60
92
 
61
- const env = {
62
- ...process.env,
63
- PORT,
64
- HOST,
65
- KUBB_AGENT_ROOT,
66
- KUBB_AGENT_CONFIG,
67
- KUBB_AGENT_ALLOW_WRITE,
68
- KUBB_AGENT_ALLOW_ALL,
69
- KUBB_AGENT_TOKEN,
70
- KUBB_AGENT_RETRY_TIMEOUT,
71
- KUBB_STUDIO_URL,
93
+ if (!Number.isInteger(numericPort) || numericPort <= 0) {
94
+ throw new Error(`Invalid port "${resolvedEnv.port}". Provide a positive integer with --port or PORT.`)
72
95
  }
73
96
 
74
97
  clack.log.step(styleText('cyan', 'Starting agent server...'))
75
- clack.log.info(styleText('dim', `Config: ${KUBB_AGENT_CONFIG}`))
76
- clack.log.info(styleText('dim', `Host: ${HOST}`))
77
- clack.log.info(styleText('dim', `Port: ${PORT}`))
78
- if (!KUBB_AGENT_ALLOW_WRITE && !KUBB_AGENT_ALLOW_ALL) {
98
+ clack.log.info(styleText('dim', `Config: ${resolvedEnv.agentConfigPath}`))
99
+ clack.log.info(styleText('dim', `Host: ${resolvedEnv.host}`))
100
+ clack.log.info(styleText('dim', `Port: ${resolvedEnv.port}`))
101
+ if (!resolvedEnv.allowWrite && !resolvedEnv.allowAll) {
79
102
  clack.log.warn(styleText('yellow', 'Filesystem writes disabled. Use --allow-write or --allow-all to enable.'))
80
103
  }
81
104
 
82
- if (!(await isPortAvailable(Number(PORT), HOST))) {
83
- clack.log.error(styleText('red', `Port ${PORT} is already in use. Stop the existing process or choose a different port with --port.`))
105
+ if (!(await isPortAvailable(numericPort, resolvedEnv.host))) {
106
+ clack.log.error(
107
+ styleText('red', `Port ${resolvedEnv.port} is already in use. Stop the existing process or choose a different port with --port.`),
108
+ )
84
109
  process.exit(1)
85
110
  }
86
111
 
87
- console.log(env)
88
-
89
112
  // Spawns the server as a detached background process so the CLI can exit independently.
90
113
  await spawnAsync('node', [serverPath], {
91
- env,
114
+ env: resolvedEnv.env,
92
115
  cwd: process.cwd(),
93
116
  })
94
117
 
@@ -4,26 +4,20 @@ import process from 'node:process'
4
4
  import { styleText } from 'node:util'
5
5
  import * as clack from '@clack/prompts'
6
6
  import type { AsyncEventEmitter } from '@internals/utils'
7
- import { AsyncEventEmitter as AsyncEventEmitterClass, executeIfOnline, toError } from '@internals/utils'
7
+ import { AsyncEventEmitter as AsyncEventEmitterClass, detectFormatter, detectLinter, executeIfOnline, formatters, linters, toError } from '@internals/utils'
8
8
  import {
9
9
  type CLIOptions,
10
10
  type Config,
11
- detectFormatter,
12
- detectLinter,
13
- formatters,
14
- getConfigs,
11
+ createKubb,
15
12
  isInputPath,
16
- type KubbEvents,
17
- linters,
13
+ type KubbHooks,
18
14
  logLevel as logLevelMap,
19
- PromiseManager,
20
- safeBuild,
21
- setup,
22
15
  } from '@kubb/core'
23
16
  import { version } from '../../package.json'
24
17
  import { KUBB_NPM_PACKAGE_URL } from '../constants.ts'
25
18
  import { setupLogger } from '../loggers/utils.ts'
26
19
  import { executeHooks } from '../utils/executeHooks.ts'
20
+ import { getConfigs } from '../utils/getConfig.ts'
27
21
  import { getCosmiConfig } from '../utils/getCosmiConfig.ts'
28
22
  import { buildTelemetryEvent, sendTelemetry } from '../utils/telemetry.ts'
29
23
  import { startWatcher } from '../utils/watcher.ts'
@@ -31,7 +25,7 @@ import { startWatcher } from '../utils/watcher.ts'
31
25
  type GenerateProps = {
32
26
  input?: string
33
27
  config: Config
34
- events: AsyncEventEmitter<KubbEvents>
28
+ hooks: AsyncEventEmitter<KubbHooks>
35
29
  logLevel: number
36
30
  }
37
31
 
@@ -39,7 +33,7 @@ type ToolMap = typeof formatters | typeof linters
39
33
 
40
34
  type RunToolPassOptions = {
41
35
  toolValue: string
42
- detect: () => Promise<string | undefined>
36
+ detect: () => Promise<string | null>
43
37
  toolMap: ToolMap
44
38
  /** Short noun used in "Auto-detected <toolLabel>:" message, e.g. "formatter" or "linter". */
45
39
  toolLabel: string
@@ -49,7 +43,7 @@ type RunToolPassOptions = {
49
43
  configName: string | undefined
50
44
  outputPath: string
51
45
  logLevel: number
52
- events: AsyncEventEmitter<KubbEvents>
46
+ hooks: AsyncEventEmitter<KubbHooks>
53
47
  onStart: () => Promise<void>
54
48
  onEnd: () => Promise<void>
55
49
  }
@@ -64,7 +58,7 @@ async function runToolPass({
64
58
  configName,
65
59
  outputPath,
66
60
  logLevel,
67
- events,
61
+ hooks,
68
62
  onStart,
69
63
  onEnd,
70
64
  }: RunToolPassOptions) {
@@ -74,13 +68,15 @@ async function runToolPass({
74
68
  if (resolvedTool === 'auto') {
75
69
  const detected = await detect()
76
70
  if (!detected) {
77
- await events.emit('warn', noToolMessage)
71
+ await hooks.emit('kubb:warn', noToolMessage)
78
72
  } else {
79
73
  resolvedTool = detected
80
- await events.emit('info', `Auto-detected ${toolLabel}: ${styleText('dim', resolvedTool)}`)
74
+ await hooks.emit('kubb:info', `Auto-detected ${toolLabel}: ${styleText('dim', resolvedTool)}`)
81
75
  }
82
76
  }
83
77
 
78
+ let toolError: Error | undefined
79
+
84
80
  if (resolvedTool && resolvedTool !== 'auto' && resolvedTool in toolMap) {
85
81
  const toolConfig = toolMap[resolvedTool as keyof ToolMap]
86
82
 
@@ -88,18 +84,18 @@ async function runToolPass({
88
84
  const hookId = createHash('sha256').update([configName, resolvedTool].filter(Boolean).join('-')).digest('hex')
89
85
 
90
86
  // Wire up the hook:end listener BEFORE emitting hook:start to avoid the race condition
91
- // where hook:end fires synchronously inside emit('hook:start') before the listener is registered.
87
+ // where hook:end fires synchronously inside emit('kubb:hook:start') before the listener is registered.
92
88
  const hookEndPromise = new Promise<void>((resolve, reject) => {
93
89
  const handler = ({ id, success, error }: { id?: string; command: string; args?: readonly string[]; success: boolean; error: Error | null }) => {
94
90
  if (id !== hookId) return
95
- events.off('hook:end', handler)
91
+ hooks.off('kubb:hook:end', handler)
96
92
  if (!success) {
97
93
  reject(error ?? new Error(`${toolConfig.errorMessage}`))
98
94
  return
99
95
  }
100
- events
96
+ hooks
101
97
  .emit(
102
- 'success',
98
+ 'kubb:success',
103
99
  [
104
100
  `${successPrefix} with ${styleText('dim', resolvedTool)}`,
105
101
  logLevel >= logLevelMap.info ? `on ${styleText('dim', outputPath)}` : undefined,
@@ -111,10 +107,10 @@ async function runToolPass({
111
107
  .then(resolve)
112
108
  .catch(reject)
113
109
  }
114
- events.on('hook:end', handler)
110
+ hooks.on('kubb:hook:end', handler)
115
111
  })
116
112
 
117
- await events.emit('hook:start', {
113
+ await hooks.emit('kubb:hook:start', {
118
114
  id: hookId,
119
115
  command: toolConfig.command,
120
116
  args: toolConfig.args(outputPath),
@@ -124,57 +120,47 @@ async function runToolPass({
124
120
  } catch (caughtError) {
125
121
  const err = new Error(toolConfig.errorMessage)
126
122
  err.cause = caughtError
127
- await events.emit('error', err)
123
+ await hooks.emit('kubb:error', err)
124
+ toolError = err
128
125
  }
129
126
  }
130
127
 
131
128
  await onEnd()
129
+
130
+ if (toolError) {
131
+ throw toolError
132
+ }
132
133
  }
133
134
 
134
- async function generate({ input, config: userConfig, events, logLevel }: GenerateProps): Promise<void> {
135
- const inputPath = input ?? ('path' in userConfig.input ? userConfig.input.path : undefined)
135
+ async function generate(options: GenerateProps): Promise<void> {
136
+ const { input, hooks, logLevel } = options
137
+
136
138
  const hrStart = process.hrtime()
139
+ const inputPath = input ?? ('path' in options.config.input ? options.config.input.path : undefined)
137
140
 
138
141
  const config: Config = {
139
- ...userConfig,
140
- root: userConfig.root || process.cwd(),
142
+ ...options.config,
141
143
  input: inputPath
142
144
  ? {
143
- ...userConfig.input,
145
+ ...options.config.input,
144
146
  path: inputPath,
145
147
  }
146
- : userConfig.input,
147
- output: {
148
- write: true,
149
- barrelType: 'named',
150
- extension: {
151
- '.ts': '.ts',
152
- },
153
- format: 'prettier',
154
- ...userConfig.output,
155
- },
156
- }
148
+ : options.config.input,
149
+ ...options.config.output,
150
+ } satisfies Config
157
151
 
158
- await events.emit('generation:start', config)
152
+ const kubb = createKubb(config, { hooks })
153
+ await kubb.setup()
159
154
 
160
- await events.emit('info', config.name ? `Setup generation ${styleText('bold', config.name)}` : 'Setup generation', inputPath)
155
+ await hooks.emit('kubb:generation:start', config)
161
156
 
162
- const { sources, fabric, pluginManager } = await setup({
163
- config,
164
- events,
165
- })
157
+ await hooks.emit('kubb:info', config.name ? `Setup generation ${styleText('bold', config.name)}` : 'Setup generation', inputPath)
166
158
 
167
- await events.emit('info', config.name ? `Build generation ${styleText('bold', config.name)}` : 'Build generation', inputPath)
159
+ await hooks.emit('kubb:info', config.name ? `Build generation ${styleText('bold', config.name)}` : 'Build generation', inputPath)
168
160
 
169
- const { files, failedPlugins, pluginTimings, error } = await safeBuild(
170
- {
171
- config,
172
- events,
173
- },
174
- { pluginManager, fabric, events, sources },
175
- )
161
+ const { files, failedPlugins, pluginTimings, error, driver } = await kubb.safeBuild()
176
162
 
177
- await events.emit('info', 'Load summary')
163
+ await hooks.emit('kubb:info', 'Load summary')
178
164
 
179
165
  // Handle build failures (either from failed plugins or general errors)
180
166
 
@@ -189,12 +175,12 @@ async function generate({ input, config: userConfig, events, logLevel }: Generat
189
175
  ].filter(Boolean)
190
176
 
191
177
  for (const err of allErrors) {
192
- await events.emit('error', err)
178
+ await hooks.emit('kubb:error', err)
193
179
  }
194
180
 
195
- await events.emit('generation:end', config, files, sources)
181
+ await hooks.emit('kubb:generation:end', config, files, kubb.sources)
196
182
 
197
- await events.emit('generation:summary', config, {
183
+ await hooks.emit('kubb:generation:summary', config, {
198
184
  failedPlugins,
199
185
  filesCreated: files.length,
200
186
  status: 'failed',
@@ -206,7 +192,7 @@ async function generate({ input, config: userConfig, events, logLevel }: Generat
206
192
  buildTelemetryEvent({
207
193
  command: 'generate',
208
194
  kubbVersion: version,
209
- plugins: pluginManager.plugins.map((p) => ({ name: p.name, options: p.options as Record<string, unknown> })),
195
+ plugins: Array.from(driver.plugins.values(), (p) => ({ name: p.name, options: p.options as Record<string, unknown> })),
210
196
  hrStart,
211
197
  filesCreated: files.length,
212
198
  status: 'failed',
@@ -216,8 +202,8 @@ async function generate({ input, config: userConfig, events, logLevel }: Generat
216
202
  process.exit(1)
217
203
  }
218
204
 
219
- await events.emit('success', 'Generation successfully', inputPath)
220
- await events.emit('generation:end', config, files, sources)
205
+ await hooks.emit('kubb:success', 'Generation successfully', inputPath)
206
+ await hooks.emit('kubb:generation:end', config, files, kubb.sources)
221
207
 
222
208
  const outputPath = path.resolve(config.root, config.output.path)
223
209
 
@@ -232,9 +218,9 @@ async function generate({ input, config: userConfig, events, logLevel }: Generat
232
218
  configName: config.name,
233
219
  outputPath,
234
220
  logLevel,
235
- events,
236
- onStart: () => events.emit('format:start'),
237
- onEnd: () => events.emit('format:end'),
221
+ hooks,
222
+ onStart: () => hooks.emit('kubb:format:start'),
223
+ onEnd: () => hooks.emit('kubb:format:end'),
238
224
  })
239
225
  }
240
226
 
@@ -249,21 +235,21 @@ async function generate({ input, config: userConfig, events, logLevel }: Generat
249
235
  configName: config.name,
250
236
  outputPath,
251
237
  logLevel,
252
- events,
253
- onStart: () => events.emit('lint:start'),
254
- onEnd: () => events.emit('lint:end'),
238
+ hooks,
239
+ onStart: () => hooks.emit('kubb:lint:start'),
240
+ onEnd: () => hooks.emit('kubb:lint:end'),
255
241
  })
256
242
  }
257
243
 
258
244
  if (config.hooks) {
259
- await events.emit('hooks:start')
260
- await executeHooks({ hooks: config.hooks, events })
245
+ await hooks.emit('kubb:hooks:start')
246
+ await executeHooks({ configHooks: config.hooks, hooks })
261
247
 
262
- await events.emit('hooks:end')
248
+ await hooks.emit('kubb:hooks:end')
263
249
  }
264
250
 
265
251
  // Only reached when there are no failures (process.exit(1) is called above otherwise)
266
- await events.emit('generation:summary', config, {
252
+ await hooks.emit('kubb:generation:summary', config, {
267
253
  failedPlugins,
268
254
  filesCreated: files.length,
269
255
  status: 'success',
@@ -274,7 +260,7 @@ async function generate({ input, config: userConfig, events, logLevel }: Generat
274
260
  const telemetryEvent = buildTelemetryEvent({
275
261
  command: 'generate',
276
262
  kubbVersion: version,
277
- plugins: pluginManager.plugins.map((p) => ({ name: p.name, options: p.options as Record<string, unknown> })),
263
+ plugins: Array.from(driver.plugins.values(), (p) => ({ name: p.name, options: p.options as Record<string, unknown> })),
278
264
  hrStart,
279
265
  filesCreated: files.length,
280
266
  status: 'success',
@@ -292,10 +278,9 @@ type GenerateCommandOptions = {
292
278
 
293
279
  export async function runGenerateCommand({ input, configPath, logLevel: logLevelKey, watch }: GenerateCommandOptions): Promise<void> {
294
280
  const logLevel = logLevelMap[logLevelKey as keyof typeof logLevelMap] ?? logLevelMap.info
295
- const events = new AsyncEventEmitterClass<KubbEvents>()
296
- const promiseManager = new PromiseManager()
281
+ const hooks = new AsyncEventEmitterClass<KubbHooks>()
297
282
 
298
- await setupLogger(events, { logLevel })
283
+ await setupLogger(hooks, { logLevel })
299
284
 
300
285
  await executeIfOnline(async () => {
301
286
  try {
@@ -304,7 +289,7 @@ export async function runGenerateCommand({ input, configPath, logLevel: logLevel
304
289
  const latestVersion = data.version
305
290
 
306
291
  if (latestVersion && version < latestVersion) {
307
- await events.emit('version:new', version, latestVersion)
292
+ await hooks.emit('kubb:version:new', version, latestVersion)
308
293
  }
309
294
  } catch {
310
295
  // Ignore network errors for version check
@@ -315,37 +300,31 @@ export async function runGenerateCommand({ input, configPath, logLevel: logLevel
315
300
  const result = await getCosmiConfig('kubb', configPath)
316
301
  const configs = await getConfigs(result.config, { input } as CLIOptions)
317
302
 
318
- await events.emit('config:start')
319
- await events.emit('info', 'Config loaded', path.relative(process.cwd(), result.filepath))
320
- await events.emit('success', 'Config loaded successfully', path.relative(process.cwd(), result.filepath))
321
- await events.emit('config:end', configs)
303
+ await hooks.emit('kubb:config:start')
304
+ await hooks.emit('kubb:info', 'Config loaded', path.relative(process.cwd(), result.filepath))
305
+ await hooks.emit('kubb:success', 'Config loaded successfully', path.relative(process.cwd(), result.filepath))
306
+ await hooks.emit('kubb:config:end', configs)
322
307
 
323
- await events.emit('lifecycle:start', version)
308
+ await hooks.emit('kubb:lifecycle:start', version)
324
309
 
325
- const promises = configs.map((config) => {
326
- return async () => {
327
- if (isInputPath(config) && watch) {
328
- await startWatcher([input || config.input.path], async (paths) => {
329
- // remove to avoid duplicate listeners after each change
330
- events.removeAll()
310
+ for (const config of configs) {
311
+ if (isInputPath(config) && watch) {
312
+ await startWatcher([input || config.input.path], async (paths) => {
313
+ // remove to avoid duplicate listeners after each change
314
+ hooks.removeAll()
331
315
 
332
- await generate({ input, config, logLevel, events })
316
+ await generate({ input, config, logLevel, hooks })
333
317
 
334
- clack.log.step(styleText('yellow', `Watching for changes in ${paths.join(' and ')}`))
335
- })
336
-
337
- return
338
- }
339
-
340
- await generate({ input, config, logLevel, events })
318
+ clack.log.step(styleText('yellow', `Watching for changes in ${paths.join(' and ')}`))
319
+ })
320
+ } else {
321
+ await generate({ input, config, logLevel, hooks })
341
322
  }
342
- })
343
-
344
- await promiseManager.run('seq', promises)
323
+ }
345
324
 
346
- await events.emit('lifecycle:end')
325
+ await hooks.emit('kubb:lifecycle:end')
347
326
  } catch (error) {
348
- await events.emit('error', toError(error))
327
+ await hooks.emit('kubb:error', toError(error))
349
328
  process.exit(1)
350
329
  }
351
330
  }
@@ -123,7 +123,7 @@ function generateConfigFile(selectedPlugins: PluginOption[], inputPath: string,
123
123
  })
124
124
  .join('\n')
125
125
 
126
- return `import { defineConfig } from '@kubb/core'
126
+ return `import { defineConfig } from 'kubb'
127
127
  ${imports}
128
128
 
129
129
  export default defineConfig({