argsbarg 0.1.0 → 1.0.1
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/.cursor/rules/code.mdc +2 -2
- package/CHANGELOG.md +45 -0
- package/README.md +40 -28
- package/examples/minimal.ts +12 -7
- package/examples/nested.ts +16 -13
- package/justfile +32 -0
- package/package.json +6 -11
- package/plan.md +2 -2
- package/scripts/release.ts +249 -0
- package/src/completion.ts +33 -14
- package/src/context.ts +2 -1
- package/src/help.ts +58 -23
- package/src/index.test.ts +79 -35
- package/src/index.ts +3 -14
- package/src/parse.ts +56 -25
- package/src/runtime.ts +2 -2
- package/src/types.ts +45 -37
- package/src/validate.ts +15 -11
- package/bun.lock +0 -21
package/src/validate.ts
CHANGED
|
@@ -28,7 +28,7 @@ export function cliValidateRoot(root: CliCommand): void {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
// Check for reserved command names at root
|
|
31
|
-
for (const child of root.
|
|
31
|
+
for (const child of root.commands ?? []) {
|
|
32
32
|
if (reservedCommandNames.includes(child.key)) {
|
|
33
33
|
throw new CliSchemaValidationError(`Reserved command name: ${child.key}`);
|
|
34
34
|
}
|
|
@@ -38,6 +38,7 @@ export function cliValidateRoot(root: CliCommand): void {
|
|
|
38
38
|
walkCommand(root, true);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/** Recursively validates a command node: handlers vs children, options, and positionals. */
|
|
41
42
|
function walkCommand(cmd: CliCommand, isRoot: boolean = false): void {
|
|
42
43
|
// Fallback only on root
|
|
43
44
|
if (!isRoot && cmd.fallbackCommand !== undefined) {
|
|
@@ -55,7 +56,7 @@ function walkCommand(cmd: CliCommand, isRoot: boolean = false): void {
|
|
|
55
56
|
);
|
|
56
57
|
}
|
|
57
58
|
|
|
58
|
-
if ((cmd.
|
|
59
|
+
if ((cmd.commands ?? []).length > 0) {
|
|
59
60
|
if (cmd.handler !== undefined) {
|
|
60
61
|
throw new CliSchemaValidationError(`Routing command must not set handler: ${cmd.key}`);
|
|
61
62
|
}
|
|
@@ -67,7 +68,7 @@ function walkCommand(cmd: CliCommand, isRoot: boolean = false): void {
|
|
|
67
68
|
|
|
68
69
|
// Check for duplicate child names
|
|
69
70
|
const seenNames = new Set<string>();
|
|
70
|
-
for (const child of cmd.
|
|
71
|
+
for (const child of cmd.commands ?? []) {
|
|
71
72
|
if (seenNames.has(child.key)) {
|
|
72
73
|
throw new CliSchemaValidationError(`Duplicate command name: ${child.key}`);
|
|
73
74
|
}
|
|
@@ -93,17 +94,18 @@ function walkCommand(cmd: CliCommand, isRoot: boolean = false): void {
|
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
// Validate positionals
|
|
96
|
-
const positionals =
|
|
97
|
+
const positionals = cmd.positionals ?? [];
|
|
97
98
|
for (const p of positionals) {
|
|
98
|
-
if (p.argMin < 0) {
|
|
99
|
+
if (p.argMin !== undefined && p.argMin < 0) {
|
|
99
100
|
throw new CliSchemaValidationError(`argMin must be >= 0 for positional ${cmd.key}/${p.name}`);
|
|
100
101
|
}
|
|
101
|
-
if (p.argMax < 0) {
|
|
102
|
+
if (p.argMax !== undefined && p.argMax < 0) {
|
|
102
103
|
throw new CliSchemaValidationError(
|
|
103
104
|
`argMax must be >= 0 (use 0 for unlimited) for positional ${cmd.key}/${p.name}`,
|
|
104
105
|
);
|
|
105
106
|
}
|
|
106
|
-
|
|
107
|
+
const { argMin = 1, argMax = 1 } = p;
|
|
108
|
+
if (argMax > 0 && argMin > argMax) {
|
|
107
109
|
throw new CliSchemaValidationError(
|
|
108
110
|
`argMin must not exceed argMax for positional ${cmd.key}/${p.name}`,
|
|
109
111
|
);
|
|
@@ -113,7 +115,8 @@ function walkCommand(cmd: CliCommand, isRoot: boolean = false): void {
|
|
|
113
115
|
// Check positional ordering: required before optional
|
|
114
116
|
let sawOptional = false;
|
|
115
117
|
for (const p of positionals) {
|
|
116
|
-
|
|
118
|
+
const { argMin = 1 } = p;
|
|
119
|
+
if (argMin === 0) {
|
|
117
120
|
sawOptional = true;
|
|
118
121
|
} else if (sawOptional) {
|
|
119
122
|
throw new CliSchemaValidationError(`Required positional after optional in scope ${cmd.key}`);
|
|
@@ -122,15 +125,16 @@ function walkCommand(cmd: CliCommand, isRoot: boolean = false): void {
|
|
|
122
125
|
|
|
123
126
|
// Check unlimited positional must be last
|
|
124
127
|
for (let idx = 0; idx < positionals.length; idx++) {
|
|
125
|
-
|
|
128
|
+
const { argMax = 1 } = positionals[idx]!;
|
|
129
|
+
if (argMax === 0 && idx + 1 < positionals.length) {
|
|
126
130
|
throw new CliSchemaValidationError(
|
|
127
131
|
`Unlimited positional (argMax == 0) must be last in scope ${cmd.key}`,
|
|
128
132
|
);
|
|
129
133
|
}
|
|
130
134
|
}
|
|
131
135
|
|
|
132
|
-
// Recurse into
|
|
133
|
-
for (const child of cmd.
|
|
136
|
+
// Recurse into nested commands
|
|
137
|
+
for (const child of cmd.commands ?? []) {
|
|
134
138
|
walkCommand(child, false);
|
|
135
139
|
}
|
|
136
140
|
}
|
package/bun.lock
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"lockfileVersion": 1,
|
|
3
|
-
"configVersion": 1,
|
|
4
|
-
"workspaces": {
|
|
5
|
-
"": {
|
|
6
|
-
"name": "bun-argsbarg",
|
|
7
|
-
"devDependencies": {
|
|
8
|
-
"@types/bun": "^1.3.12",
|
|
9
|
-
},
|
|
10
|
-
},
|
|
11
|
-
},
|
|
12
|
-
"packages": {
|
|
13
|
-
"@types/bun": ["@types/bun@1.3.12", "", { "dependencies": { "bun-types": "1.3.12" } }, "sha512-DBv81elK+/VSwXHDlnH3Qduw+KxkTIWi7TXkAeh24zpi5l0B2kUg9Ga3tb4nJaPcOFswflgi/yAvMVBPrxMB+A=="],
|
|
14
|
-
|
|
15
|
-
"@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
|
|
16
|
-
|
|
17
|
-
"bun-types": ["bun-types@1.3.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA=="],
|
|
18
|
-
|
|
19
|
-
"undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
|
|
20
|
-
}
|
|
21
|
-
}
|