@buenojs/bueno 0.8.3 → 0.8.5

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 (218) hide show
  1. package/README.md +136 -16
  2. package/dist/cli/{index.js → bin.js} +3036 -1421
  3. package/dist/container/index.js +250 -0
  4. package/dist/context/index.js +219 -0
  5. package/dist/database/index.js +493 -0
  6. package/dist/frontend/index.js +7697 -0
  7. package/dist/health/index.js +364 -0
  8. package/dist/i18n/index.js +345 -0
  9. package/dist/index.js +11043 -6482
  10. package/dist/jobs/index.js +819 -0
  11. package/dist/lock/index.js +367 -0
  12. package/dist/logger/index.js +281 -0
  13. package/dist/metrics/index.js +289 -0
  14. package/dist/middleware/index.js +77 -0
  15. package/dist/migrations/index.js +571 -0
  16. package/dist/modules/index.js +3346 -0
  17. package/dist/notification/index.js +484 -0
  18. package/dist/observability/index.js +331 -0
  19. package/dist/openapi/index.js +776 -0
  20. package/dist/orm/index.js +1356 -0
  21. package/dist/router/index.js +886 -0
  22. package/dist/rpc/index.js +691 -0
  23. package/dist/schema/index.js +400 -0
  24. package/dist/telemetry/index.js +595 -0
  25. package/dist/template/index.js +640 -0
  26. package/dist/templates/index.js +640 -0
  27. package/dist/testing/index.js +1111 -0
  28. package/dist/types/index.js +60 -0
  29. package/package.json +121 -27
  30. package/src/cache/index.ts +2 -1
  31. package/src/cli/bin.ts +2 -2
  32. package/src/cli/commands/build.ts +183 -165
  33. package/src/cli/commands/dev.ts +96 -89
  34. package/src/cli/commands/generate.ts +142 -111
  35. package/src/cli/commands/help.ts +20 -16
  36. package/src/cli/commands/index.ts +3 -6
  37. package/src/cli/commands/migration.ts +124 -105
  38. package/src/cli/commands/new.ts +392 -438
  39. package/src/cli/commands/start.ts +81 -79
  40. package/src/cli/core/args.ts +68 -50
  41. package/src/cli/core/console.ts +89 -95
  42. package/src/cli/core/index.ts +4 -4
  43. package/src/cli/core/prompt.ts +65 -62
  44. package/src/cli/core/spinner.ts +23 -20
  45. package/src/cli/index.ts +46 -38
  46. package/src/cli/templates/database/index.ts +61 -0
  47. package/src/cli/templates/database/mysql.ts +14 -0
  48. package/src/cli/templates/database/none.ts +16 -0
  49. package/src/cli/templates/database/postgresql.ts +14 -0
  50. package/src/cli/templates/database/sqlite.ts +14 -0
  51. package/src/cli/templates/deploy.ts +29 -26
  52. package/src/cli/templates/docker.ts +41 -30
  53. package/src/cli/templates/frontend/index.ts +63 -0
  54. package/src/cli/templates/frontend/none.ts +17 -0
  55. package/src/cli/templates/frontend/react.ts +140 -0
  56. package/src/cli/templates/frontend/solid.ts +134 -0
  57. package/src/cli/templates/frontend/svelte.ts +131 -0
  58. package/src/cli/templates/frontend/vue.ts +130 -0
  59. package/src/cli/templates/generators/index.ts +339 -0
  60. package/src/cli/templates/generators/types.ts +56 -0
  61. package/src/cli/templates/index.ts +35 -2
  62. package/src/cli/templates/project/api.ts +81 -0
  63. package/src/cli/templates/project/default.ts +140 -0
  64. package/src/cli/templates/project/fullstack.ts +111 -0
  65. package/src/cli/templates/project/index.ts +95 -0
  66. package/src/cli/templates/project/minimal.ts +45 -0
  67. package/src/cli/templates/project/types.ts +94 -0
  68. package/src/cli/templates/project/website.ts +263 -0
  69. package/src/cli/utils/fs.ts +55 -41
  70. package/src/cli/utils/index.ts +3 -2
  71. package/src/cli/utils/strings.ts +47 -33
  72. package/src/cli/utils/version.ts +47 -0
  73. package/src/config/env-validation.ts +100 -0
  74. package/src/config/env.ts +169 -41
  75. package/src/config/index.ts +28 -20
  76. package/src/config/loader.ts +25 -16
  77. package/src/config/merge.ts +21 -10
  78. package/src/config/types.ts +545 -25
  79. package/src/config/validation.ts +215 -7
  80. package/src/container/forward-ref.ts +22 -22
  81. package/src/container/index.ts +34 -12
  82. package/src/context/index.ts +11 -1
  83. package/src/database/index.ts +7 -190
  84. package/src/database/orm/builder.ts +457 -0
  85. package/src/database/orm/casts/index.ts +130 -0
  86. package/src/database/orm/casts/types.ts +25 -0
  87. package/src/database/orm/compiler.ts +304 -0
  88. package/src/database/orm/hooks/index.ts +114 -0
  89. package/src/database/orm/index.ts +61 -0
  90. package/src/database/orm/model-registry.ts +59 -0
  91. package/src/database/orm/model.ts +821 -0
  92. package/src/database/orm/relationships/base.ts +146 -0
  93. package/src/database/orm/relationships/belongs-to-many.ts +179 -0
  94. package/src/database/orm/relationships/belongs-to.ts +56 -0
  95. package/src/database/orm/relationships/has-many.ts +45 -0
  96. package/src/database/orm/relationships/has-one.ts +41 -0
  97. package/src/database/orm/relationships/index.ts +11 -0
  98. package/src/database/orm/scopes/index.ts +55 -0
  99. package/src/events/__tests__/event-system.test.ts +235 -0
  100. package/src/events/config.ts +238 -0
  101. package/src/events/example-usage.ts +185 -0
  102. package/src/events/index.ts +278 -0
  103. package/src/events/manager.ts +385 -0
  104. package/src/events/registry.ts +182 -0
  105. package/src/events/types.ts +124 -0
  106. package/src/frontend/api-routes.ts +65 -23
  107. package/src/frontend/bundler.ts +76 -34
  108. package/src/frontend/console-client.ts +2 -2
  109. package/src/frontend/console-stream.ts +94 -38
  110. package/src/frontend/dev-server.ts +94 -46
  111. package/src/frontend/file-router.ts +61 -19
  112. package/src/frontend/frameworks/index.ts +37 -10
  113. package/src/frontend/frameworks/react.ts +10 -8
  114. package/src/frontend/frameworks/solid.ts +11 -9
  115. package/src/frontend/frameworks/svelte.ts +15 -9
  116. package/src/frontend/frameworks/vue.ts +13 -11
  117. package/src/frontend/hmr-client.ts +12 -10
  118. package/src/frontend/hmr.ts +146 -103
  119. package/src/frontend/index.ts +14 -5
  120. package/src/frontend/islands.ts +41 -22
  121. package/src/frontend/isr.ts +59 -37
  122. package/src/frontend/layout.ts +36 -21
  123. package/src/frontend/ssr/react.ts +74 -27
  124. package/src/frontend/ssr/solid.ts +54 -20
  125. package/src/frontend/ssr/svelte.ts +48 -14
  126. package/src/frontend/ssr/vue.ts +50 -18
  127. package/src/frontend/ssr.ts +83 -39
  128. package/src/frontend/types.ts +91 -56
  129. package/src/health/index.ts +21 -9
  130. package/src/i18n/engine.ts +305 -0
  131. package/src/i18n/index.ts +38 -0
  132. package/src/i18n/loader.ts +218 -0
  133. package/src/i18n/middleware.ts +164 -0
  134. package/src/i18n/negotiator.ts +162 -0
  135. package/src/i18n/types.ts +158 -0
  136. package/src/index.ts +179 -27
  137. package/src/jobs/drivers/memory.ts +315 -0
  138. package/src/jobs/drivers/redis.ts +459 -0
  139. package/src/jobs/index.ts +30 -0
  140. package/src/jobs/queue.ts +281 -0
  141. package/src/jobs/types.ts +295 -0
  142. package/src/jobs/worker.ts +380 -0
  143. package/src/logger/index.ts +1 -3
  144. package/src/logger/transports/index.ts +62 -22
  145. package/src/metrics/index.ts +25 -16
  146. package/src/migrations/index.ts +9 -0
  147. package/src/modules/filters.ts +13 -17
  148. package/src/modules/guards.ts +49 -26
  149. package/src/modules/index.ts +409 -298
  150. package/src/modules/interceptors.ts +58 -20
  151. package/src/modules/lazy.ts +11 -19
  152. package/src/modules/lifecycle.ts +15 -7
  153. package/src/modules/metadata.ts +15 -5
  154. package/src/modules/pipes.ts +94 -72
  155. package/src/notification/channels/base.ts +68 -0
  156. package/src/notification/channels/email.ts +105 -0
  157. package/src/notification/channels/push.ts +104 -0
  158. package/src/notification/channels/sms.ts +105 -0
  159. package/src/notification/channels/whatsapp.ts +104 -0
  160. package/src/notification/index.ts +48 -0
  161. package/src/notification/service.ts +354 -0
  162. package/src/notification/types.ts +344 -0
  163. package/src/observability/__tests__/observability.test.ts +483 -0
  164. package/src/observability/breadcrumbs.ts +114 -0
  165. package/src/observability/index.ts +136 -0
  166. package/src/observability/interceptor.ts +85 -0
  167. package/src/observability/service.ts +303 -0
  168. package/src/observability/trace.ts +37 -0
  169. package/src/observability/types.ts +196 -0
  170. package/src/openapi/__tests__/decorators.test.ts +335 -0
  171. package/src/openapi/__tests__/document-builder.test.ts +285 -0
  172. package/src/openapi/__tests__/route-scanner.test.ts +334 -0
  173. package/src/openapi/__tests__/schema-generator.test.ts +275 -0
  174. package/src/openapi/decorators.ts +328 -0
  175. package/src/openapi/document-builder.ts +274 -0
  176. package/src/openapi/index.ts +112 -0
  177. package/src/openapi/metadata.ts +112 -0
  178. package/src/openapi/route-scanner.ts +289 -0
  179. package/src/openapi/schema-generator.ts +256 -0
  180. package/src/openapi/swagger-module.ts +166 -0
  181. package/src/openapi/types.ts +398 -0
  182. package/src/orm/index.ts +10 -0
  183. package/src/rpc/index.ts +3 -1
  184. package/src/schema/index.ts +9 -0
  185. package/src/security/index.ts +15 -6
  186. package/src/ssg/index.ts +9 -8
  187. package/src/telemetry/index.ts +76 -22
  188. package/src/template/index.ts +7 -0
  189. package/src/templates/engine.ts +224 -0
  190. package/src/templates/index.ts +9 -0
  191. package/src/templates/loader.ts +331 -0
  192. package/src/templates/renderers/markdown.ts +212 -0
  193. package/src/templates/renderers/simple.ts +269 -0
  194. package/src/templates/types.ts +154 -0
  195. package/src/testing/index.ts +100 -27
  196. package/src/types/optional-deps.d.ts +347 -187
  197. package/src/validation/index.ts +92 -2
  198. package/src/validation/schemas.ts +536 -0
  199. package/tests/integration/fullstack.test.ts +4 -4
  200. package/tests/unit/database.test.ts +2 -72
  201. package/tests/unit/env-validation.test.ts +166 -0
  202. package/tests/unit/events.test.ts +910 -0
  203. package/tests/unit/i18n.test.ts +455 -0
  204. package/tests/unit/jobs.test.ts +493 -0
  205. package/tests/unit/notification.test.ts +988 -0
  206. package/tests/unit/observability.test.ts +453 -0
  207. package/tests/unit/orm/builder.test.ts +323 -0
  208. package/tests/unit/orm/casts.test.ts +179 -0
  209. package/tests/unit/orm/compiler.test.ts +220 -0
  210. package/tests/unit/orm/eager-loading.test.ts +285 -0
  211. package/tests/unit/orm/hooks.test.ts +191 -0
  212. package/tests/unit/orm/model.test.ts +373 -0
  213. package/tests/unit/orm/relationships.test.ts +303 -0
  214. package/tests/unit/orm/scopes.test.ts +74 -0
  215. package/tests/unit/templates-simple.test.ts +53 -0
  216. package/tests/unit/templates.test.ts +454 -0
  217. package/tests/unit/validation.test.ts +18 -24
  218. package/tsconfig.json +11 -3
@@ -4,17 +4,17 @@
4
4
  * Start the production server
5
5
  */
6
6
 
7
- import { defineCommand } from './index';
8
- import { getOption, hasFlag, type ParsedArgs } from '../core/args';
9
- import { cliConsole, colors } from '../core/console';
10
- import { spinner } from '../core/spinner';
7
+ import { type ParsedArgs, getOption, hasFlag } from "../core/args";
8
+ import { cliConsole, colors } from "../core/console";
9
+ import { spinner } from "../core/spinner";
10
+ import { CLIError, CLIErrorType } from "../index";
11
11
  import {
12
12
  fileExists,
13
13
  getProjectRoot,
14
14
  isBuenoProject,
15
15
  joinPaths,
16
- } from '../utils/fs';
17
- import { CLIError, CLIErrorType } from '../index';
16
+ } from "../utils/fs";
17
+ import { defineCommand } from "./index";
18
18
 
19
19
  /**
20
20
  * Find the entry point for the application
@@ -22,10 +22,10 @@ import { CLIError, CLIErrorType } from '../index';
22
22
  async function findEntryPoint(projectRoot: string): Promise<string | null> {
23
23
  // Check for built files first
24
24
  const possibleBuiltEntries = [
25
- 'dist/index.js',
26
- 'dist/main.js',
27
- 'dist/server.js',
28
- 'dist/app.js',
25
+ "dist/index.js",
26
+ "dist/main.js",
27
+ "dist/server.js",
28
+ "dist/app.js",
29
29
  ];
30
30
 
31
31
  for (const entry of possibleBuiltEntries) {
@@ -37,13 +37,13 @@ async function findEntryPoint(projectRoot: string): Promise<string | null> {
37
37
 
38
38
  // Fall back to source files
39
39
  const possibleSourceEntries = [
40
- 'server/main.ts',
41
- 'src/main.ts',
42
- 'src/index.ts',
43
- 'main.ts',
44
- 'index.ts',
45
- 'server.ts',
46
- 'app.ts',
40
+ "server/main.ts",
41
+ "src/main.ts",
42
+ "src/index.ts",
43
+ "main.ts",
44
+ "index.ts",
45
+ "server.ts",
46
+ "app.ts",
47
47
  ];
48
48
 
49
49
  for (const entry of possibleSourceEntries) {
@@ -61,49 +61,49 @@ async function findEntryPoint(projectRoot: string): Promise<string | null> {
61
61
  */
62
62
  async function handleStart(args: ParsedArgs): Promise<void> {
63
63
  // Get options
64
- const port = getOption(args, 'port', {
65
- name: 'port',
66
- alias: 'p',
67
- type: 'number',
64
+ const port = getOption(args, "port", {
65
+ name: "port",
66
+ alias: "p",
67
+ type: "number",
68
68
  default: 3000,
69
- description: '',
69
+ description: "",
70
70
  });
71
71
 
72
- const host = getOption<string>(args, 'host', {
73
- name: 'host',
74
- alias: 'H',
75
- type: 'string',
76
- default: '0.0.0.0',
77
- description: '',
72
+ const host = getOption<string>(args, "host", {
73
+ name: "host",
74
+ alias: "H",
75
+ type: "string",
76
+ default: "0.0.0.0",
77
+ description: "",
78
78
  });
79
79
 
80
- const workers = getOption(args, 'workers', {
81
- name: 'workers',
82
- alias: 'w',
83
- type: 'string',
84
- default: 'auto',
85
- description: '',
80
+ const workers = getOption(args, "workers", {
81
+ name: "workers",
82
+ alias: "w",
83
+ type: "string",
84
+ default: "auto",
85
+ description: "",
86
86
  });
87
87
 
88
- const configPath = getOption<string>(args, 'config', {
89
- name: 'config',
90
- alias: 'c',
91
- type: 'string',
92
- description: '',
88
+ const configPath = getOption<string>(args, "config", {
89
+ name: "config",
90
+ alias: "c",
91
+ type: "string",
92
+ description: "",
93
93
  });
94
94
 
95
95
  // Check if in a Bueno project
96
96
  const projectRoot = await getProjectRoot();
97
97
  if (!projectRoot) {
98
98
  throw new CLIError(
99
- 'Not in a project directory. Run this command from a Bueno project.',
99
+ "Not in a project directory. Run this command from a Bueno project.",
100
100
  CLIErrorType.NOT_FOUND,
101
101
  );
102
102
  }
103
103
 
104
104
  if (!(await isBuenoProject())) {
105
105
  throw new CLIError(
106
- 'Not a Bueno project. Make sure you have a bueno.config.ts or bueno in your dependencies.',
106
+ "Not a Bueno project. Make sure you have a bueno.config.ts or bueno in your dependencies.",
107
107
  CLIErrorType.NOT_FOUND,
108
108
  );
109
109
  }
@@ -112,22 +112,22 @@ async function handleStart(args: ParsedArgs): Promise<void> {
112
112
  const entryPoint = await findEntryPoint(projectRoot);
113
113
  if (!entryPoint) {
114
114
  throw new CLIError(
115
- 'Could not find entry point. Make sure you have built the application or have a main.ts file.',
115
+ "Could not find entry point. Make sure you have built the application or have a main.ts file.",
116
116
  CLIErrorType.FILE_NOT_FOUND,
117
117
  );
118
118
  }
119
119
 
120
120
  // Display startup info
121
- cliConsole.header('Starting Production Server');
122
- cliConsole.log(`${colors.bold('Entry:')} ${entryPoint}`);
123
- cliConsole.log(`${colors.bold('Port:')} ${port}`);
124
- cliConsole.log(`${colors.bold('Host:')} ${host}`);
125
- cliConsole.log(`${colors.bold('Workers:')} ${workers}`);
126
- cliConsole.log('');
121
+ cliConsole.header("Starting Production Server");
122
+ cliConsole.log(`${colors.bold("Entry:")} ${entryPoint}`);
123
+ cliConsole.log(`${colors.bold("Port:")} ${port}`);
124
+ cliConsole.log(`${colors.bold("Host:")} ${host}`);
125
+ cliConsole.log(`${colors.bold("Workers:")} ${workers}`);
126
+ cliConsole.log("");
127
127
 
128
128
  // Set environment variables
129
129
  const env: Record<string, string> = {
130
- NODE_ENV: 'production',
130
+ NODE_ENV: "production",
131
131
  PORT: String(port),
132
132
  HOST: host,
133
133
  };
@@ -137,18 +137,20 @@ async function handleStart(args: ParsedArgs): Promise<void> {
137
137
  }
138
138
 
139
139
  // Start the server using Bun
140
- const s = spinner('Starting production server...');
140
+ const s = spinner("Starting production server...");
141
141
 
142
142
  try {
143
143
  // Use Bun's spawn to run the production server
144
- const proc = Bun.spawn(['bun', 'run', entryPoint], {
144
+ const proc = Bun.spawn(["bun", "run", entryPoint], {
145
145
  cwd: projectRoot,
146
146
  env: { ...process.env, ...env },
147
- stdout: 'inherit',
148
- stderr: 'inherit',
147
+ stdout: "inherit",
148
+ stderr: "inherit",
149
149
  });
150
150
 
151
- s.success(`Production server running at ${colors.cyan(`http://${host}:${port}`)}`);
151
+ s.success(
152
+ `Production server running at ${colors.cyan(`http://${host}:${port}`)}`,
153
+ );
152
154
 
153
155
  // Wait for the process to exit
154
156
  const exitCode = await proc.exited;
@@ -166,43 +168,43 @@ async function handleStart(args: ParsedArgs): Promise<void> {
166
168
  // Register the command
167
169
  defineCommand(
168
170
  {
169
- name: 'start',
170
- description: 'Start the production server',
171
+ name: "start",
172
+ description: "Start the production server",
171
173
  options: [
172
174
  {
173
- name: 'port',
174
- alias: 'p',
175
- type: 'number',
175
+ name: "port",
176
+ alias: "p",
177
+ type: "number",
176
178
  default: 3000,
177
- description: 'Server port',
179
+ description: "Server port",
178
180
  },
179
181
  {
180
- name: 'host',
181
- alias: 'H',
182
- type: 'string',
183
- default: '0.0.0.0',
184
- description: 'Server hostname',
182
+ name: "host",
183
+ alias: "H",
184
+ type: "string",
185
+ default: "0.0.0.0",
186
+ description: "Server hostname",
185
187
  },
186
188
  {
187
- name: 'workers',
188
- alias: 'w',
189
- type: 'string',
190
- default: 'auto',
191
- description: 'Number of worker threads',
189
+ name: "workers",
190
+ alias: "w",
191
+ type: "string",
192
+ default: "auto",
193
+ description: "Number of worker threads",
192
194
  },
193
195
  {
194
- name: 'config',
195
- alias: 'c',
196
- type: 'string',
197
- description: 'Path to config file',
196
+ name: "config",
197
+ alias: "c",
198
+ type: "string",
199
+ description: "Path to config file",
198
200
  },
199
201
  ],
200
202
  examples: [
201
- 'bueno start',
202
- 'bueno start --port 8080',
203
- 'bueno start --host 0.0.0.0',
204
- 'bueno start --workers 4',
203
+ "bueno start",
204
+ "bueno start --port 8080",
205
+ "bueno start --host 0.0.0.0",
206
+ "bueno start --workers 4",
205
207
  ],
206
208
  },
207
209
  handleStart,
208
- );
210
+ );
@@ -15,7 +15,7 @@ export interface ParsedArgs {
15
15
  export interface OptionDefinition {
16
16
  name: string;
17
17
  alias?: string;
18
- type: 'string' | 'boolean' | 'number';
18
+ type: "string" | "boolean" | "number";
19
19
  default?: string | boolean | number;
20
20
  description: string;
21
21
  }
@@ -32,11 +32,9 @@ export interface CommandDefinition {
32
32
  /**
33
33
  * Parse command line arguments
34
34
  */
35
- export function parseArgs(
36
- argv: string[] = process.argv.slice(2),
37
- ): ParsedArgs {
35
+ export function parseArgs(argv: string[] = process.argv.slice(2)): ParsedArgs {
38
36
  const result: ParsedArgs = {
39
- command: '',
37
+ command: "",
40
38
  positionals: [],
41
39
  options: {},
42
40
  flags: new Set(),
@@ -48,8 +46,8 @@ export function parseArgs(
48
46
  if (!arg) continue;
49
47
 
50
48
  // Long option: --option=value or --option value
51
- if (arg.startsWith('--')) {
52
- const eqIndex = arg.indexOf('=');
49
+ if (arg.startsWith("--")) {
50
+ const eqIndex = arg.indexOf("=");
53
51
  if (eqIndex !== -1) {
54
52
  // --option=value
55
53
  const name = arg.slice(2, eqIndex);
@@ -61,7 +59,7 @@ export function parseArgs(
61
59
  const nextArg = argv[i + 1];
62
60
 
63
61
  // Check if it's a flag (no value or next arg starts with -)
64
- if (!nextArg || nextArg.startsWith('-')) {
62
+ if (!nextArg || nextArg.startsWith("-")) {
65
63
  result.options[name] = true;
66
64
  result.flags.add(name);
67
65
  } else {
@@ -71,7 +69,7 @@ export function parseArgs(
71
69
  }
72
70
  }
73
71
  // Short option: -o value or -abc (multiple flags)
74
- else if (arg.startsWith('-') && arg.length > 1) {
72
+ else if (arg.startsWith("-") && arg.length > 1) {
75
73
  const chars = arg.slice(1);
76
74
 
77
75
  // Check if it's a combined flag like -abc
@@ -86,7 +84,7 @@ export function parseArgs(
86
84
  const name = chars;
87
85
  const nextArg = argv[i + 1];
88
86
 
89
- if (!nextArg || nextArg.startsWith('-')) {
87
+ if (!nextArg || nextArg.startsWith("-")) {
90
88
  result.options[name] = true;
91
89
  result.flags.add(name);
92
90
  } else {
@@ -116,18 +114,24 @@ export function getOption<T extends string | boolean | number>(
116
114
  name: string,
117
115
  definition: OptionDefinition,
118
116
  ): T {
119
- const value = parsed.options[name] ?? parsed.options[definition.alias ?? ''];
117
+ const value = parsed.options[name] ?? parsed.options[definition.alias ?? ""];
120
118
 
121
119
  if (value === undefined) {
122
120
  return definition.default as T;
123
121
  }
124
122
 
125
- if (definition.type === 'boolean') {
126
- return (value === true || value === 'true') as T;
123
+ if (definition.type === "boolean") {
124
+ return (value === true || value === "true") as T;
127
125
  }
128
126
 
129
- if (definition.type === 'number') {
130
- return (typeof value === 'number' ? value : typeof value === 'string' ? parseInt(value, 10) : NaN) as T;
127
+ if (definition.type === "number") {
128
+ return (
129
+ typeof value === "number"
130
+ ? value
131
+ : typeof value === "string"
132
+ ? Number.parseInt(value, 10)
133
+ : Number.NaN
134
+ ) as T;
131
135
  }
132
136
 
133
137
  return value as T;
@@ -136,14 +140,22 @@ export function getOption<T extends string | boolean | number>(
136
140
  /**
137
141
  * Check if a flag is set
138
142
  */
139
- export function hasFlag(parsed: ParsedArgs, name: string, alias?: string): boolean {
143
+ export function hasFlag(
144
+ parsed: ParsedArgs,
145
+ name: string,
146
+ alias?: string,
147
+ ): boolean {
140
148
  return parsed.flags.has(name) || (alias ? parsed.flags.has(alias) : false);
141
149
  }
142
150
 
143
151
  /**
144
152
  * Check if an option is set (either as flag or with value)
145
153
  */
146
- export function hasOption(parsed: ParsedArgs, name: string, alias?: string): boolean {
154
+ export function hasOption(
155
+ parsed: ParsedArgs,
156
+ name: string,
157
+ alias?: string,
158
+ ): boolean {
147
159
  return name in parsed.options || (alias ? alias in parsed.options : false);
148
160
  }
149
161
 
@@ -151,18 +163,22 @@ export function hasOption(parsed: ParsedArgs, name: string, alias?: string): boo
151
163
  * Get all values for an option that can be specified multiple times
152
164
  * Parses raw argv to collect all occurrences of the option
153
165
  */
154
- export function getOptionValues(parsed: ParsedArgs, name: string, alias?: string): string[] {
166
+ export function getOptionValues(
167
+ parsed: ParsedArgs,
168
+ name: string,
169
+ alias?: string,
170
+ ): string[] {
155
171
  const values: string[] = [];
156
172
  const argv = process.argv.slice(2);
157
-
173
+
158
174
  for (let i = 0; i < argv.length; i++) {
159
175
  const arg = argv[i];
160
176
  if (!arg) continue;
161
-
177
+
162
178
  // Long option: --name value or --name=value
163
179
  if (arg === `--${name}`) {
164
180
  const nextArg = argv[i + 1];
165
- if (nextArg && !nextArg.startsWith('-')) {
181
+ if (nextArg && !nextArg.startsWith("-")) {
166
182
  values.push(nextArg);
167
183
  i++; // Skip next arg
168
184
  }
@@ -173,13 +189,13 @@ export function getOptionValues(parsed: ParsedArgs, name: string, alias?: string
173
189
  // Short option: -n value
174
190
  else if (alias && arg === `-${alias}`) {
175
191
  const nextArg = argv[i + 1];
176
- if (nextArg && !nextArg.startsWith('-')) {
192
+ if (nextArg && !nextArg.startsWith("-")) {
177
193
  values.push(nextArg);
178
194
  i++; // Skip next arg
179
195
  }
180
196
  }
181
197
  }
182
-
198
+
183
199
  return values;
184
200
  }
185
201
 
@@ -188,7 +204,7 @@ export function getOptionValues(parsed: ParsedArgs, name: string, alias?: string
188
204
  */
189
205
  export function generateHelpText(
190
206
  command: CommandDefinition,
191
- cliName = 'bueno',
207
+ cliName = "bueno",
192
208
  ): string {
193
209
  const lines: string[] = [];
194
210
 
@@ -196,7 +212,7 @@ export function generateHelpText(
196
212
  lines.push(`\n${command.description}\n`);
197
213
 
198
214
  // Usage
199
- lines.push('Usage:');
215
+ lines.push("Usage:");
200
216
  let usage = ` ${cliName} ${command.name}`;
201
217
 
202
218
  if (command.positionals) {
@@ -205,48 +221,48 @@ export function generateHelpText(
205
221
  }
206
222
  }
207
223
 
208
- usage += ' [options]';
209
- lines.push(usage + '\n');
224
+ usage += " [options]";
225
+ lines.push(usage + "\n");
210
226
 
211
227
  // Positionals
212
228
  if (command.positionals && command.positionals.length > 0) {
213
- lines.push('Arguments:');
229
+ lines.push("Arguments:");
214
230
  for (const pos of command.positionals) {
215
- const required = pos.required ? ' (required)' : '';
231
+ const required = pos.required ? " (required)" : "";
216
232
  lines.push(` ${pos.name.padEnd(20)} ${pos.description}${required}`);
217
233
  }
218
- lines.push('');
234
+ lines.push("");
219
235
  }
220
236
 
221
237
  // Options
222
238
  if (command.options && command.options.length > 0) {
223
- lines.push('Options:');
239
+ lines.push("Options:");
224
240
  for (const opt of command.options) {
225
241
  let flag = `--${opt.name}`;
226
242
  if (opt.alias) {
227
243
  flag = `-${opt.alias}, ${flag}`;
228
244
  }
229
245
 
230
- let defaultValue = '';
246
+ let defaultValue = "";
231
247
  if (opt.default !== undefined) {
232
248
  defaultValue = ` (default: ${opt.default})`;
233
249
  }
234
250
 
235
251
  lines.push(` ${flag.padEnd(20)} ${opt.description}${defaultValue}`);
236
252
  }
237
- lines.push('');
253
+ lines.push("");
238
254
  }
239
255
 
240
256
  // Examples
241
257
  if (command.examples && command.examples.length > 0) {
242
- lines.push('Examples:');
258
+ lines.push("Examples:");
243
259
  for (const example of command.examples) {
244
260
  lines.push(` ${example}`);
245
261
  }
246
- lines.push('');
262
+ lines.push("");
247
263
  }
248
264
 
249
- return lines.join('\n');
265
+ return lines.join("\n");
250
266
  }
251
267
 
252
268
  /**
@@ -254,30 +270,32 @@ export function generateHelpText(
254
270
  */
255
271
  export function generateGlobalHelpText(
256
272
  commands: CommandDefinition[],
257
- cliName = 'bueno',
273
+ cliName = "bueno",
258
274
  ): string {
259
275
  const lines: string[] = [];
260
276
 
261
277
  lines.push(`\n${cliName} - A Bun-Native Full-Stack Framework CLI\n`);
262
- lines.push('Usage:');
278
+ lines.push("Usage:");
263
279
  lines.push(` ${cliName} <command> [options]\n`);
264
280
 
265
- lines.push('Commands:');
281
+ lines.push("Commands:");
266
282
  for (const cmd of commands) {
267
283
  const name = cmd.alias ? `${cmd.name} (${cmd.alias})` : cmd.name;
268
284
  lines.push(` ${name.padEnd(20)} ${cmd.description}`);
269
285
  }
270
- lines.push('');
286
+ lines.push("");
271
287
 
272
- lines.push('Global Options:');
273
- lines.push(' --help, -h Show help for command');
274
- lines.push(' --version, -v Show CLI version');
275
- lines.push(' --verbose Enable verbose output');
276
- lines.push(' --quiet Suppress non-essential output');
277
- lines.push(' --no-color Disable colored output');
278
- lines.push('');
288
+ lines.push("Global Options:");
289
+ lines.push(" --help, -h Show help for command");
290
+ lines.push(" --version, -v Show CLI version");
291
+ lines.push(" --verbose Enable verbose output");
292
+ lines.push(" --quiet Suppress non-essential output");
293
+ lines.push(" --no-color Disable colored output");
294
+ lines.push("");
279
295
 
280
- lines.push(`Run '${cliName} <command> --help' for more information about a command.\n`);
296
+ lines.push(
297
+ `Run '${cliName} <command> --help' for more information about a command.\n`,
298
+ );
281
299
 
282
- return lines.join('\n');
283
- }
300
+ return lines.join("\n");
301
+ }