@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.
- package/README.md +136 -16
- package/dist/cli/{index.js → bin.js} +3036 -1421
- package/dist/container/index.js +250 -0
- package/dist/context/index.js +219 -0
- package/dist/database/index.js +493 -0
- package/dist/frontend/index.js +7697 -0
- package/dist/health/index.js +364 -0
- package/dist/i18n/index.js +345 -0
- package/dist/index.js +11043 -6482
- package/dist/jobs/index.js +819 -0
- package/dist/lock/index.js +367 -0
- package/dist/logger/index.js +281 -0
- package/dist/metrics/index.js +289 -0
- package/dist/middleware/index.js +77 -0
- package/dist/migrations/index.js +571 -0
- package/dist/modules/index.js +3346 -0
- package/dist/notification/index.js +484 -0
- package/dist/observability/index.js +331 -0
- package/dist/openapi/index.js +776 -0
- package/dist/orm/index.js +1356 -0
- package/dist/router/index.js +886 -0
- package/dist/rpc/index.js +691 -0
- package/dist/schema/index.js +400 -0
- package/dist/telemetry/index.js +595 -0
- package/dist/template/index.js +640 -0
- package/dist/templates/index.js +640 -0
- package/dist/testing/index.js +1111 -0
- package/dist/types/index.js +60 -0
- package/package.json +121 -27
- package/src/cache/index.ts +2 -1
- package/src/cli/bin.ts +2 -2
- package/src/cli/commands/build.ts +183 -165
- package/src/cli/commands/dev.ts +96 -89
- package/src/cli/commands/generate.ts +142 -111
- package/src/cli/commands/help.ts +20 -16
- package/src/cli/commands/index.ts +3 -6
- package/src/cli/commands/migration.ts +124 -105
- package/src/cli/commands/new.ts +392 -438
- package/src/cli/commands/start.ts +81 -79
- package/src/cli/core/args.ts +68 -50
- package/src/cli/core/console.ts +89 -95
- package/src/cli/core/index.ts +4 -4
- package/src/cli/core/prompt.ts +65 -62
- package/src/cli/core/spinner.ts +23 -20
- package/src/cli/index.ts +46 -38
- package/src/cli/templates/database/index.ts +61 -0
- package/src/cli/templates/database/mysql.ts +14 -0
- package/src/cli/templates/database/none.ts +16 -0
- package/src/cli/templates/database/postgresql.ts +14 -0
- package/src/cli/templates/database/sqlite.ts +14 -0
- package/src/cli/templates/deploy.ts +29 -26
- package/src/cli/templates/docker.ts +41 -30
- package/src/cli/templates/frontend/index.ts +63 -0
- package/src/cli/templates/frontend/none.ts +17 -0
- package/src/cli/templates/frontend/react.ts +140 -0
- package/src/cli/templates/frontend/solid.ts +134 -0
- package/src/cli/templates/frontend/svelte.ts +131 -0
- package/src/cli/templates/frontend/vue.ts +130 -0
- package/src/cli/templates/generators/index.ts +339 -0
- package/src/cli/templates/generators/types.ts +56 -0
- package/src/cli/templates/index.ts +35 -2
- package/src/cli/templates/project/api.ts +81 -0
- package/src/cli/templates/project/default.ts +140 -0
- package/src/cli/templates/project/fullstack.ts +111 -0
- package/src/cli/templates/project/index.ts +95 -0
- package/src/cli/templates/project/minimal.ts +45 -0
- package/src/cli/templates/project/types.ts +94 -0
- package/src/cli/templates/project/website.ts +263 -0
- package/src/cli/utils/fs.ts +55 -41
- package/src/cli/utils/index.ts +3 -2
- package/src/cli/utils/strings.ts +47 -33
- package/src/cli/utils/version.ts +47 -0
- package/src/config/env-validation.ts +100 -0
- package/src/config/env.ts +169 -41
- package/src/config/index.ts +28 -20
- package/src/config/loader.ts +25 -16
- package/src/config/merge.ts +21 -10
- package/src/config/types.ts +545 -25
- package/src/config/validation.ts +215 -7
- package/src/container/forward-ref.ts +22 -22
- package/src/container/index.ts +34 -12
- package/src/context/index.ts +11 -1
- package/src/database/index.ts +7 -190
- package/src/database/orm/builder.ts +457 -0
- package/src/database/orm/casts/index.ts +130 -0
- package/src/database/orm/casts/types.ts +25 -0
- package/src/database/orm/compiler.ts +304 -0
- package/src/database/orm/hooks/index.ts +114 -0
- package/src/database/orm/index.ts +61 -0
- package/src/database/orm/model-registry.ts +59 -0
- package/src/database/orm/model.ts +821 -0
- package/src/database/orm/relationships/base.ts +146 -0
- package/src/database/orm/relationships/belongs-to-many.ts +179 -0
- package/src/database/orm/relationships/belongs-to.ts +56 -0
- package/src/database/orm/relationships/has-many.ts +45 -0
- package/src/database/orm/relationships/has-one.ts +41 -0
- package/src/database/orm/relationships/index.ts +11 -0
- package/src/database/orm/scopes/index.ts +55 -0
- package/src/events/__tests__/event-system.test.ts +235 -0
- package/src/events/config.ts +238 -0
- package/src/events/example-usage.ts +185 -0
- package/src/events/index.ts +278 -0
- package/src/events/manager.ts +385 -0
- package/src/events/registry.ts +182 -0
- package/src/events/types.ts +124 -0
- package/src/frontend/api-routes.ts +65 -23
- package/src/frontend/bundler.ts +76 -34
- package/src/frontend/console-client.ts +2 -2
- package/src/frontend/console-stream.ts +94 -38
- package/src/frontend/dev-server.ts +94 -46
- package/src/frontend/file-router.ts +61 -19
- package/src/frontend/frameworks/index.ts +37 -10
- package/src/frontend/frameworks/react.ts +10 -8
- package/src/frontend/frameworks/solid.ts +11 -9
- package/src/frontend/frameworks/svelte.ts +15 -9
- package/src/frontend/frameworks/vue.ts +13 -11
- package/src/frontend/hmr-client.ts +12 -10
- package/src/frontend/hmr.ts +146 -103
- package/src/frontend/index.ts +14 -5
- package/src/frontend/islands.ts +41 -22
- package/src/frontend/isr.ts +59 -37
- package/src/frontend/layout.ts +36 -21
- package/src/frontend/ssr/react.ts +74 -27
- package/src/frontend/ssr/solid.ts +54 -20
- package/src/frontend/ssr/svelte.ts +48 -14
- package/src/frontend/ssr/vue.ts +50 -18
- package/src/frontend/ssr.ts +83 -39
- package/src/frontend/types.ts +91 -56
- package/src/health/index.ts +21 -9
- package/src/i18n/engine.ts +305 -0
- package/src/i18n/index.ts +38 -0
- package/src/i18n/loader.ts +218 -0
- package/src/i18n/middleware.ts +164 -0
- package/src/i18n/negotiator.ts +162 -0
- package/src/i18n/types.ts +158 -0
- package/src/index.ts +179 -27
- package/src/jobs/drivers/memory.ts +315 -0
- package/src/jobs/drivers/redis.ts +459 -0
- package/src/jobs/index.ts +30 -0
- package/src/jobs/queue.ts +281 -0
- package/src/jobs/types.ts +295 -0
- package/src/jobs/worker.ts +380 -0
- package/src/logger/index.ts +1 -3
- package/src/logger/transports/index.ts +62 -22
- package/src/metrics/index.ts +25 -16
- package/src/migrations/index.ts +9 -0
- package/src/modules/filters.ts +13 -17
- package/src/modules/guards.ts +49 -26
- package/src/modules/index.ts +409 -298
- package/src/modules/interceptors.ts +58 -20
- package/src/modules/lazy.ts +11 -19
- package/src/modules/lifecycle.ts +15 -7
- package/src/modules/metadata.ts +15 -5
- package/src/modules/pipes.ts +94 -72
- package/src/notification/channels/base.ts +68 -0
- package/src/notification/channels/email.ts +105 -0
- package/src/notification/channels/push.ts +104 -0
- package/src/notification/channels/sms.ts +105 -0
- package/src/notification/channels/whatsapp.ts +104 -0
- package/src/notification/index.ts +48 -0
- package/src/notification/service.ts +354 -0
- package/src/notification/types.ts +344 -0
- package/src/observability/__tests__/observability.test.ts +483 -0
- package/src/observability/breadcrumbs.ts +114 -0
- package/src/observability/index.ts +136 -0
- package/src/observability/interceptor.ts +85 -0
- package/src/observability/service.ts +303 -0
- package/src/observability/trace.ts +37 -0
- package/src/observability/types.ts +196 -0
- package/src/openapi/__tests__/decorators.test.ts +335 -0
- package/src/openapi/__tests__/document-builder.test.ts +285 -0
- package/src/openapi/__tests__/route-scanner.test.ts +334 -0
- package/src/openapi/__tests__/schema-generator.test.ts +275 -0
- package/src/openapi/decorators.ts +328 -0
- package/src/openapi/document-builder.ts +274 -0
- package/src/openapi/index.ts +112 -0
- package/src/openapi/metadata.ts +112 -0
- package/src/openapi/route-scanner.ts +289 -0
- package/src/openapi/schema-generator.ts +256 -0
- package/src/openapi/swagger-module.ts +166 -0
- package/src/openapi/types.ts +398 -0
- package/src/orm/index.ts +10 -0
- package/src/rpc/index.ts +3 -1
- package/src/schema/index.ts +9 -0
- package/src/security/index.ts +15 -6
- package/src/ssg/index.ts +9 -8
- package/src/telemetry/index.ts +76 -22
- package/src/template/index.ts +7 -0
- package/src/templates/engine.ts +224 -0
- package/src/templates/index.ts +9 -0
- package/src/templates/loader.ts +331 -0
- package/src/templates/renderers/markdown.ts +212 -0
- package/src/templates/renderers/simple.ts +269 -0
- package/src/templates/types.ts +154 -0
- package/src/testing/index.ts +100 -27
- package/src/types/optional-deps.d.ts +347 -187
- package/src/validation/index.ts +92 -2
- package/src/validation/schemas.ts +536 -0
- package/tests/integration/fullstack.test.ts +4 -4
- package/tests/unit/database.test.ts +2 -72
- package/tests/unit/env-validation.test.ts +166 -0
- package/tests/unit/events.test.ts +910 -0
- package/tests/unit/i18n.test.ts +455 -0
- package/tests/unit/jobs.test.ts +493 -0
- package/tests/unit/notification.test.ts +988 -0
- package/tests/unit/observability.test.ts +453 -0
- package/tests/unit/orm/builder.test.ts +323 -0
- package/tests/unit/orm/casts.test.ts +179 -0
- package/tests/unit/orm/compiler.test.ts +220 -0
- package/tests/unit/orm/eager-loading.test.ts +285 -0
- package/tests/unit/orm/hooks.test.ts +191 -0
- package/tests/unit/orm/model.test.ts +373 -0
- package/tests/unit/orm/relationships.test.ts +303 -0
- package/tests/unit/orm/scopes.test.ts +74 -0
- package/tests/unit/templates-simple.test.ts +53 -0
- package/tests/unit/templates.test.ts +454 -0
- package/tests/unit/validation.test.ts +18 -24
- package/tsconfig.json +11 -3
|
@@ -4,17 +4,17 @@
|
|
|
4
4
|
* Start the production server
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
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
|
|
17
|
-
import {
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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,
|
|
65
|
-
name:
|
|
66
|
-
alias:
|
|
67
|
-
type:
|
|
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,
|
|
73
|
-
name:
|
|
74
|
-
alias:
|
|
75
|
-
type:
|
|
76
|
-
default:
|
|
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,
|
|
81
|
-
name:
|
|
82
|
-
alias:
|
|
83
|
-
type:
|
|
84
|
-
default:
|
|
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,
|
|
89
|
-
name:
|
|
90
|
-
alias:
|
|
91
|
-
type:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
122
|
-
cliConsole.log(`${colors.bold(
|
|
123
|
-
cliConsole.log(`${colors.bold(
|
|
124
|
-
cliConsole.log(`${colors.bold(
|
|
125
|
-
cliConsole.log(`${colors.bold(
|
|
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:
|
|
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(
|
|
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([
|
|
144
|
+
const proc = Bun.spawn(["bun", "run", entryPoint], {
|
|
145
145
|
cwd: projectRoot,
|
|
146
146
|
env: { ...process.env, ...env },
|
|
147
|
-
stdout:
|
|
148
|
-
stderr:
|
|
147
|
+
stdout: "inherit",
|
|
148
|
+
stderr: "inherit",
|
|
149
149
|
});
|
|
150
150
|
|
|
151
|
-
s.success(
|
|
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:
|
|
170
|
-
description:
|
|
171
|
+
name: "start",
|
|
172
|
+
description: "Start the production server",
|
|
171
173
|
options: [
|
|
172
174
|
{
|
|
173
|
-
name:
|
|
174
|
-
alias:
|
|
175
|
-
type:
|
|
175
|
+
name: "port",
|
|
176
|
+
alias: "p",
|
|
177
|
+
type: "number",
|
|
176
178
|
default: 3000,
|
|
177
|
-
description:
|
|
179
|
+
description: "Server port",
|
|
178
180
|
},
|
|
179
181
|
{
|
|
180
|
-
name:
|
|
181
|
-
alias:
|
|
182
|
-
type:
|
|
183
|
-
default:
|
|
184
|
-
description:
|
|
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:
|
|
188
|
-
alias:
|
|
189
|
-
type:
|
|
190
|
-
default:
|
|
191
|
-
description:
|
|
189
|
+
name: "workers",
|
|
190
|
+
alias: "w",
|
|
191
|
+
type: "string",
|
|
192
|
+
default: "auto",
|
|
193
|
+
description: "Number of worker threads",
|
|
192
194
|
},
|
|
193
195
|
{
|
|
194
|
-
name:
|
|
195
|
-
alias:
|
|
196
|
-
type:
|
|
197
|
-
description:
|
|
196
|
+
name: "config",
|
|
197
|
+
alias: "c",
|
|
198
|
+
type: "string",
|
|
199
|
+
description: "Path to config file",
|
|
198
200
|
},
|
|
199
201
|
],
|
|
200
202
|
examples: [
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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
|
+
);
|
package/src/cli/core/args.ts
CHANGED
|
@@ -15,7 +15,7 @@ export interface ParsedArgs {
|
|
|
15
15
|
export interface OptionDefinition {
|
|
16
16
|
name: string;
|
|
17
17
|
alias?: string;
|
|
18
|
-
type:
|
|
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(
|
|
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 ===
|
|
126
|
-
return (value === true || value ===
|
|
123
|
+
if (definition.type === "boolean") {
|
|
124
|
+
return (value === true || value === "true") as T;
|
|
127
125
|
}
|
|
128
126
|
|
|
129
|
-
if (definition.type ===
|
|
130
|
-
return (
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
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 +=
|
|
209
|
-
lines.push(usage +
|
|
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(
|
|
229
|
+
lines.push("Arguments:");
|
|
214
230
|
for (const pos of command.positionals) {
|
|
215
|
-
const required = pos.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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
278
|
+
lines.push("Usage:");
|
|
263
279
|
lines.push(` ${cliName} <command> [options]\n`);
|
|
264
280
|
|
|
265
|
-
lines.push(
|
|
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(
|
|
273
|
-
lines.push(
|
|
274
|
-
lines.push(
|
|
275
|
-
lines.push(
|
|
276
|
-
lines.push(
|
|
277
|
-
lines.push(
|
|
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(
|
|
296
|
+
lines.push(
|
|
297
|
+
`Run '${cliName} <command> --help' for more information about a command.\n`,
|
|
298
|
+
);
|
|
281
299
|
|
|
282
|
-
return lines.join(
|
|
283
|
-
}
|
|
300
|
+
return lines.join("\n");
|
|
301
|
+
}
|