@boneskull/bargs 1.0.0 → 3.0.0
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 +305 -299
- package/dist/bargs.cjs +464 -142
- package/dist/bargs.cjs.map +1 -1
- package/dist/bargs.d.cts +35 -17
- package/dist/bargs.d.cts.map +1 -1
- package/dist/bargs.d.ts +35 -17
- package/dist/bargs.d.ts.map +1 -1
- package/dist/bargs.js +462 -142
- package/dist/bargs.js.map +1 -1
- package/dist/help.cjs +1 -2
- package/dist/help.cjs.map +1 -1
- package/dist/help.d.cts +20 -3
- package/dist/help.d.cts.map +1 -1
- package/dist/help.d.ts +20 -3
- package/dist/help.d.ts.map +1 -1
- package/dist/help.js +1 -2
- package/dist/help.js.map +1 -1
- package/dist/index.cjs +27 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -78
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +15 -78
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -30
- package/dist/index.js.map +1 -1
- package/dist/opt.cjs +147 -80
- package/dist/opt.cjs.map +1 -1
- package/dist/opt.d.cts +88 -77
- package/dist/opt.d.cts.map +1 -1
- package/dist/opt.d.ts +88 -77
- package/dist/opt.d.ts.map +1 -1
- package/dist/opt.js +146 -79
- package/dist/opt.js.map +1 -1
- package/dist/parser.cjs +3 -230
- package/dist/parser.cjs.map +1 -1
- package/dist/parser.d.cts +3 -51
- package/dist/parser.d.cts.map +1 -1
- package/dist/parser.d.ts +3 -51
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +2 -223
- package/dist/parser.js.map +1 -1
- package/dist/types.cjs +1 -3
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +110 -122
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +110 -122
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -3
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
- package/dist/validate.cjs +0 -463
- package/dist/validate.cjs.map +0 -1
- package/dist/validate.d.cts +0 -28
- package/dist/validate.d.cts.map +0 -1
- package/dist/validate.d.ts +0 -28
- package/dist/validate.d.ts.map +0 -1
- package/dist/validate.js +0 -459
- package/dist/validate.js.map +0 -1
package/dist/bargs.js
CHANGED
|
@@ -1,183 +1,503 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Core bargs
|
|
2
|
+
* Core bargs API using parser combinator pattern.
|
|
3
3
|
*
|
|
4
|
-
* Provides `bargs()`
|
|
5
|
-
*
|
|
6
|
-
* `--version` flags, argument parsing, and handler invocation. Supports both
|
|
7
|
-
* simple CLIs with options/positionals and command-based CLIs with
|
|
8
|
-
* subcommands.
|
|
4
|
+
* Provides `bargs.create()` for building CLIs with a fluent API, plus
|
|
5
|
+
* combinator functions like `pipe()`, `map()`, and `handle()`.
|
|
9
6
|
*
|
|
10
7
|
* @packageDocumentation
|
|
11
8
|
*/
|
|
12
|
-
import { HelpError } from "./errors.js";
|
|
9
|
+
import { BargsError, HelpError } from "./errors.js";
|
|
13
10
|
import { generateCommandHelp, generateHelp } from "./help.js";
|
|
14
|
-
import {
|
|
11
|
+
import { parseSimple } from "./parser.js";
|
|
15
12
|
import { defaultTheme, getTheme } from "./theme.js";
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
13
|
+
export function handle(parserOrFn, maybeFn) {
|
|
14
|
+
// Direct form: handle(parser, fn) returns Command
|
|
15
|
+
// Check for Parser first since CallableParser is also a function
|
|
16
|
+
if (isParser(parserOrFn)) {
|
|
17
|
+
const parser = parserOrFn;
|
|
18
|
+
const parserWithTransform = parser;
|
|
19
|
+
const fn = maybeFn;
|
|
20
|
+
const cmd = {
|
|
21
|
+
__brand: 'Command',
|
|
22
|
+
__optionsSchema: parser.__optionsSchema,
|
|
23
|
+
__positionalsSchema: parser.__positionalsSchema,
|
|
24
|
+
handler: fn,
|
|
25
|
+
};
|
|
26
|
+
// Preserve transforms from the parser
|
|
27
|
+
if (parserWithTransform.__transform) {
|
|
28
|
+
cmd.__transform = parserWithTransform.__transform;
|
|
29
|
+
}
|
|
30
|
+
return cmd;
|
|
31
|
+
}
|
|
32
|
+
// Curried form: handle(fn) returns (parser) => Command
|
|
33
|
+
const fn = parserOrFn;
|
|
34
|
+
return (parser) => {
|
|
35
|
+
const parserWithTransform = parser;
|
|
36
|
+
const cmd = {
|
|
37
|
+
__brand: 'Command',
|
|
38
|
+
__optionsSchema: parser.__optionsSchema,
|
|
39
|
+
__positionalsSchema: parser.__positionalsSchema,
|
|
40
|
+
handler: fn,
|
|
41
|
+
};
|
|
42
|
+
// Preserve transforms from the parser
|
|
43
|
+
if (parserWithTransform.__transform) {
|
|
44
|
+
cmd.__transform = parserWithTransform.__transform;
|
|
45
|
+
}
|
|
46
|
+
return cmd;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export function map(parserOrFn, maybeFn) {
|
|
50
|
+
// Direct form: map(parser, fn) returns Parser
|
|
51
|
+
// Check for Parser first since CallableParser is also a function
|
|
52
|
+
if (isParser(parserOrFn)) {
|
|
53
|
+
const parser = parserOrFn;
|
|
54
|
+
const fn = maybeFn;
|
|
55
|
+
return {
|
|
56
|
+
...parser,
|
|
57
|
+
__brand: 'Parser',
|
|
58
|
+
__positionals: [],
|
|
59
|
+
__transform: fn,
|
|
60
|
+
__values: {},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// Curried form: map(fn) returns (parser) => Parser
|
|
64
|
+
const fn = parserOrFn;
|
|
65
|
+
return (parser) => {
|
|
66
|
+
return {
|
|
67
|
+
...parser,
|
|
68
|
+
__brand: 'Parser',
|
|
69
|
+
__positionals: [],
|
|
70
|
+
__transform: fn,
|
|
71
|
+
__values: {},
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export function merge(...parsers) {
|
|
76
|
+
if (parsers.length === 0) {
|
|
77
|
+
throw new BargsError('merge() requires at least one parser');
|
|
27
78
|
}
|
|
28
|
-
|
|
29
|
-
|
|
79
|
+
// Start with the first parser and fold the rest in
|
|
80
|
+
let result = parsers[0];
|
|
81
|
+
for (let i = 1; i < parsers.length; i++) {
|
|
82
|
+
const next = parsers[i];
|
|
83
|
+
// Merge options schemas
|
|
84
|
+
const mergedOptions = {
|
|
85
|
+
...result.__optionsSchema,
|
|
86
|
+
...next.__optionsSchema,
|
|
87
|
+
};
|
|
88
|
+
// Merge positionals schemas
|
|
89
|
+
const mergedPositionals = [
|
|
90
|
+
...result.__positionalsSchema,
|
|
91
|
+
...next.__positionalsSchema,
|
|
92
|
+
];
|
|
93
|
+
const resultWithTransform = result;
|
|
94
|
+
const nextWithTransform = next;
|
|
95
|
+
let mergedTransform;
|
|
96
|
+
if (resultWithTransform.__transform && nextWithTransform.__transform) {
|
|
97
|
+
// Chain transforms
|
|
98
|
+
const t1 = resultWithTransform.__transform;
|
|
99
|
+
const t2 = nextWithTransform.__transform;
|
|
100
|
+
mergedTransform = (r) => {
|
|
101
|
+
const r1 = t1(r);
|
|
102
|
+
if (r1 instanceof Promise) {
|
|
103
|
+
return r1.then(t2);
|
|
104
|
+
}
|
|
105
|
+
return t2(r1);
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
mergedTransform =
|
|
110
|
+
nextWithTransform.__transform ?? resultWithTransform.__transform;
|
|
111
|
+
}
|
|
112
|
+
result = {
|
|
113
|
+
__brand: 'Parser',
|
|
114
|
+
__optionsSchema: mergedOptions,
|
|
115
|
+
__positionals: [],
|
|
116
|
+
__positionalsSchema: mergedPositionals,
|
|
117
|
+
__values: {},
|
|
118
|
+
};
|
|
119
|
+
if (mergedTransform) {
|
|
120
|
+
result.__transform =
|
|
121
|
+
mergedTransform;
|
|
122
|
+
}
|
|
30
123
|
}
|
|
31
|
-
|
|
32
|
-
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
127
|
+
// CLI BUILDER
|
|
128
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
129
|
+
/**
|
|
130
|
+
* Create a new CLI.
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
*
|
|
134
|
+
* ```typescript
|
|
135
|
+
* const cli = await bargs
|
|
136
|
+
* .create('my-app', { version: '1.0.0' })
|
|
137
|
+
* .globals(
|
|
138
|
+
* map(opt.options({ verbose: opt.boolean() }), ({ values }) => ({
|
|
139
|
+
* values: { ...values, ts: Date.now() },
|
|
140
|
+
* positionals: [] as const,
|
|
141
|
+
* })),
|
|
142
|
+
* )
|
|
143
|
+
* .command(
|
|
144
|
+
* 'greet',
|
|
145
|
+
* pos.positionals(pos.string({ name: 'name', required: true })),
|
|
146
|
+
* ({ positionals }) => console.log(`Hello, ${positionals[0]}!`),
|
|
147
|
+
* )
|
|
148
|
+
* .parseAsync();
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
const create = (name, options = {}) => {
|
|
152
|
+
const theme = options.theme ? getTheme(options.theme) : defaultTheme;
|
|
153
|
+
return createCliBuilder({
|
|
154
|
+
commands: new Map(),
|
|
155
|
+
name,
|
|
156
|
+
options,
|
|
157
|
+
theme,
|
|
158
|
+
});
|
|
33
159
|
};
|
|
34
160
|
/**
|
|
35
|
-
* Check if
|
|
161
|
+
* Check if something is a Command (has __brand: 'Command').
|
|
36
162
|
*/
|
|
37
|
-
const
|
|
38
|
-
if (
|
|
163
|
+
const isCommand = (x) => {
|
|
164
|
+
if (x === null || x === undefined) {
|
|
39
165
|
return false;
|
|
40
166
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
// Check if any option has 'V' as an alias
|
|
45
|
-
return Object.values(options).some((opt) => opt.aliases?.includes('V'));
|
|
167
|
+
const obj = x;
|
|
168
|
+
return '__brand' in obj && obj.__brand === 'Command';
|
|
46
169
|
};
|
|
47
170
|
/**
|
|
48
|
-
*
|
|
171
|
+
* Create a CLI builder.
|
|
49
172
|
*/
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
173
|
+
const createCliBuilder = (state) => {
|
|
174
|
+
return {
|
|
175
|
+
// Overloaded command(): accepts either (name, Command, desc?) or (name, Parser, handler, desc?)
|
|
176
|
+
command(name, cmdOrParser, handlerOrDesc, maybeDesc) {
|
|
177
|
+
let cmd;
|
|
178
|
+
let description;
|
|
179
|
+
if (isCommand(cmdOrParser)) {
|
|
180
|
+
// Form 1: command(name, Command, description?)
|
|
181
|
+
cmd = cmdOrParser;
|
|
182
|
+
description = handlerOrDesc;
|
|
183
|
+
}
|
|
184
|
+
else if (isParser(cmdOrParser)) {
|
|
185
|
+
// Form 2: command(name, Parser, handler, description?)
|
|
186
|
+
const parser = cmdOrParser;
|
|
187
|
+
const handler = handlerOrDesc;
|
|
188
|
+
description = maybeDesc;
|
|
189
|
+
// Create Command from Parser + handler
|
|
190
|
+
const parserWithTransform = parser;
|
|
191
|
+
const newCmd = {
|
|
192
|
+
__brand: 'Command',
|
|
193
|
+
__optionsSchema: parser.__optionsSchema,
|
|
194
|
+
__positionalsSchema: parser.__positionalsSchema,
|
|
195
|
+
handler,
|
|
196
|
+
};
|
|
197
|
+
// Preserve transforms from the parser
|
|
198
|
+
if (parserWithTransform.__transform) {
|
|
199
|
+
newCmd.__transform = parserWithTransform.__transform;
|
|
200
|
+
}
|
|
201
|
+
cmd = newCmd;
|
|
61
202
|
}
|
|
62
203
|
else {
|
|
63
|
-
|
|
204
|
+
throw new Error('command() requires a Command or Parser as second argument');
|
|
205
|
+
}
|
|
206
|
+
state.commands.set(name, { cmd, description });
|
|
207
|
+
return this;
|
|
208
|
+
},
|
|
209
|
+
// Overloaded defaultCommand(): accepts name, Command, or (Parser, handler)
|
|
210
|
+
defaultCommand(nameOrCmdOrParser, maybeHandler) {
|
|
211
|
+
// Form 1: defaultCommand(name) - just set the name
|
|
212
|
+
if (typeof nameOrCmdOrParser === 'string') {
|
|
213
|
+
return createCliBuilder({
|
|
214
|
+
...state,
|
|
215
|
+
defaultCommandName: nameOrCmdOrParser,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
// Generate a unique name for the default command
|
|
219
|
+
const defaultName = '__default__';
|
|
220
|
+
if (isCommand(nameOrCmdOrParser)) {
|
|
221
|
+
// Form 2: defaultCommand(Command)
|
|
222
|
+
state.commands.set(defaultName, {
|
|
223
|
+
cmd: nameOrCmdOrParser,
|
|
224
|
+
description: undefined,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
else if (isParser(nameOrCmdOrParser)) {
|
|
228
|
+
// Form 3: defaultCommand(Parser, handler)
|
|
229
|
+
const parser = nameOrCmdOrParser;
|
|
230
|
+
const handler = maybeHandler;
|
|
231
|
+
const parserWithTransform = parser;
|
|
232
|
+
const newCmd = {
|
|
233
|
+
__brand: 'Command',
|
|
234
|
+
__optionsSchema: parser.__optionsSchema,
|
|
235
|
+
__positionalsSchema: parser.__positionalsSchema,
|
|
236
|
+
handler,
|
|
237
|
+
};
|
|
238
|
+
// Preserve transforms from the parser
|
|
239
|
+
if (parserWithTransform.__transform) {
|
|
240
|
+
newCmd.__transform = parserWithTransform.__transform;
|
|
241
|
+
}
|
|
242
|
+
state.commands.set(defaultName, {
|
|
243
|
+
cmd: newCmd,
|
|
244
|
+
description: undefined,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
throw new Error('defaultCommand() requires a name, Command, or Parser');
|
|
249
|
+
}
|
|
250
|
+
return createCliBuilder({
|
|
251
|
+
...state,
|
|
252
|
+
defaultCommandName: defaultName,
|
|
253
|
+
});
|
|
254
|
+
},
|
|
255
|
+
globals(parser) {
|
|
256
|
+
return createCliBuilder({
|
|
257
|
+
...state,
|
|
258
|
+
globalParser: parser,
|
|
259
|
+
});
|
|
260
|
+
},
|
|
261
|
+
parse(args = process.argv.slice(2)) {
|
|
262
|
+
const result = parseCore(state, args, false);
|
|
263
|
+
if (result instanceof Promise) {
|
|
264
|
+
throw new BargsError('Async transform or handler detected. Use parseAsync() instead of parse().');
|
|
265
|
+
}
|
|
266
|
+
return result;
|
|
267
|
+
},
|
|
268
|
+
async parseAsync(args = process.argv.slice(2)) {
|
|
269
|
+
return parseCore(state, args, true);
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
};
|
|
273
|
+
/**
|
|
274
|
+
* Core parse logic shared between parse() and parseAsync().
|
|
275
|
+
*/
|
|
276
|
+
const parseCore = (state, args, allowAsync) => {
|
|
277
|
+
const { commands, options, theme } = state;
|
|
278
|
+
// Handle --help
|
|
279
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
280
|
+
// Check for command-specific help
|
|
281
|
+
const helpIndex = args.findIndex((a) => a === '--help' || a === '-h');
|
|
282
|
+
const commandIndex = args.findIndex((a) => !a.startsWith('-'));
|
|
283
|
+
if (commandIndex >= 0 && commandIndex < helpIndex && commands.size > 0) {
|
|
284
|
+
const commandName = args[commandIndex];
|
|
285
|
+
if (commands.has(commandName)) {
|
|
286
|
+
console.log(generateCommandHelpNew(state, commandName, theme));
|
|
287
|
+
process.exit(0);
|
|
64
288
|
}
|
|
65
289
|
}
|
|
66
|
-
|
|
67
|
-
console.log(generateHelp(config, theme));
|
|
68
|
-
}
|
|
290
|
+
console.log(generateHelpNew(state, theme));
|
|
69
291
|
process.exit(0);
|
|
70
292
|
}
|
|
71
|
-
// Handle --version
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
console.log(config.version);
|
|
293
|
+
// Handle --version
|
|
294
|
+
if (args.includes('--version') && options.version) {
|
|
295
|
+
console.log(options.version);
|
|
75
296
|
process.exit(0);
|
|
76
297
|
}
|
|
77
|
-
|
|
298
|
+
// If we have commands, dispatch to the appropriate one
|
|
299
|
+
if (commands.size > 0) {
|
|
300
|
+
return runWithCommands(state, args, allowAsync);
|
|
301
|
+
}
|
|
302
|
+
// Simple CLI (no commands)
|
|
303
|
+
return runSimple(state, args, allowAsync);
|
|
78
304
|
};
|
|
79
305
|
/**
|
|
80
|
-
*
|
|
306
|
+
* Generate command-specific help.
|
|
81
307
|
*/
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
console.log(generateHelp(config, theme));
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
console.log(generateHelp(config, theme));
|
|
90
|
-
}
|
|
91
|
-
process.exit(1);
|
|
308
|
+
const generateCommandHelpNew = (state, commandName, theme) => {
|
|
309
|
+
const commandEntry = state.commands.get(commandName);
|
|
310
|
+
if (!commandEntry) {
|
|
311
|
+
return `Unknown command: ${commandName}`;
|
|
92
312
|
}
|
|
93
|
-
|
|
313
|
+
// TODO: Implement proper command help generation
|
|
314
|
+
const config = {
|
|
315
|
+
commands: {
|
|
316
|
+
[commandName]: {
|
|
317
|
+
description: commandEntry.description ?? '',
|
|
318
|
+
options: commandEntry.cmd.__optionsSchema,
|
|
319
|
+
positionals: commandEntry.cmd.__positionalsSchema,
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
name: state.name,
|
|
323
|
+
};
|
|
324
|
+
return generateCommandHelp(config, commandName, theme);
|
|
94
325
|
};
|
|
95
326
|
/**
|
|
96
|
-
*
|
|
97
|
-
* handler returns a thenable.
|
|
327
|
+
* Generate help for the new CLI structure.
|
|
98
328
|
*/
|
|
99
|
-
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
329
|
+
const generateHelpNew = (state, theme) => {
|
|
330
|
+
// TODO: Implement proper help generation for new structure
|
|
331
|
+
// For now, delegate to existing help generator with minimal config
|
|
332
|
+
const config = {
|
|
333
|
+
commands: Object.fromEntries(Array.from(state.commands.entries()).map(([name, { description }]) => [
|
|
334
|
+
name,
|
|
335
|
+
{ description: description ?? '' },
|
|
336
|
+
])),
|
|
337
|
+
description: state.options.description,
|
|
338
|
+
name: state.name,
|
|
339
|
+
options: state.globalParser?.__optionsSchema,
|
|
340
|
+
version: state.options.version,
|
|
341
|
+
};
|
|
342
|
+
return generateHelp(config, theme);
|
|
343
|
+
};
|
|
344
|
+
/**
|
|
345
|
+
* Check if something is a Parser (has __brand: 'Parser'). Parsers can be either
|
|
346
|
+
* objects or functions (CallableParser).
|
|
347
|
+
*/
|
|
348
|
+
const isParser = (x) => {
|
|
349
|
+
if (x === null || x === undefined) {
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
// Handle both plain objects and functions with Parser properties
|
|
353
|
+
const obj = x;
|
|
354
|
+
return '__brand' in obj && obj.__brand === 'Parser';
|
|
355
|
+
};
|
|
356
|
+
/**
|
|
357
|
+
* Run a simple CLI (no commands).
|
|
358
|
+
*/
|
|
359
|
+
const runSimple = (state, args, allowAsync) => {
|
|
360
|
+
const { globalParser } = state;
|
|
361
|
+
const optionsSchema = globalParser?.__optionsSchema ?? {};
|
|
362
|
+
const positionalsSchema = globalParser?.__positionalsSchema ?? [];
|
|
363
|
+
const parsed = parseSimple({
|
|
364
|
+
args,
|
|
365
|
+
options: optionsSchema,
|
|
366
|
+
positionals: positionalsSchema,
|
|
367
|
+
});
|
|
368
|
+
let result = {
|
|
369
|
+
positionals: parsed.positionals,
|
|
370
|
+
values: parsed.values,
|
|
371
|
+
};
|
|
372
|
+
// Apply transforms if any
|
|
373
|
+
const transform = globalParser?.__transform;
|
|
374
|
+
if (transform) {
|
|
375
|
+
const transformed = transform(result);
|
|
376
|
+
if (transformed instanceof Promise) {
|
|
377
|
+
if (!allowAsync) {
|
|
378
|
+
throw new BargsError('Async transform detected. Use parseAsync() instead of parse().');
|
|
131
379
|
}
|
|
132
|
-
return
|
|
380
|
+
return transformed.then((r) => ({
|
|
381
|
+
...r,
|
|
382
|
+
command: undefined,
|
|
383
|
+
}));
|
|
133
384
|
}
|
|
385
|
+
result = transformed;
|
|
134
386
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
387
|
+
return { ...result, command: undefined };
|
|
388
|
+
};
|
|
389
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
390
|
+
// PUBLIC API
|
|
391
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
139
392
|
/**
|
|
140
|
-
*
|
|
141
|
-
* supporting async handlers.
|
|
393
|
+
* Run a CLI with commands.
|
|
142
394
|
*/
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
//
|
|
153
|
-
|
|
154
|
-
|
|
395
|
+
const runWithCommands = (state, args, allowAsync) => {
|
|
396
|
+
const { commands, defaultCommandName, globalParser } = state;
|
|
397
|
+
// Find command name (first non-flag argument)
|
|
398
|
+
const commandIndex = args.findIndex((arg) => !arg.startsWith('-'));
|
|
399
|
+
const potentialCommandName = commandIndex >= 0 ? args[commandIndex] : undefined;
|
|
400
|
+
// Check if it's a known command
|
|
401
|
+
let commandName;
|
|
402
|
+
let remainingArgs;
|
|
403
|
+
if (potentialCommandName && commands.has(potentialCommandName)) {
|
|
404
|
+
// It's a known command - remove it from args
|
|
405
|
+
commandName = potentialCommandName;
|
|
406
|
+
remainingArgs = [
|
|
407
|
+
...args.slice(0, commandIndex),
|
|
408
|
+
...args.slice(commandIndex + 1),
|
|
409
|
+
];
|
|
410
|
+
}
|
|
411
|
+
else if (defaultCommandName) {
|
|
412
|
+
// Not a known command, but we have a default - use all args as positionals/options
|
|
413
|
+
commandName = defaultCommandName;
|
|
414
|
+
remainingArgs = args;
|
|
415
|
+
}
|
|
416
|
+
else if (potentialCommandName) {
|
|
417
|
+
// Not a known command and no default
|
|
418
|
+
throw new HelpError(`Unknown command: ${potentialCommandName}`);
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
// No command and no default
|
|
422
|
+
throw new HelpError('No command specified.');
|
|
423
|
+
}
|
|
424
|
+
const commandEntry = commands.get(commandName);
|
|
425
|
+
if (!commandEntry) {
|
|
426
|
+
throw new HelpError(`Unknown command: ${commandName}`);
|
|
427
|
+
}
|
|
428
|
+
const { cmd } = commandEntry;
|
|
429
|
+
// Merge global and command options schemas
|
|
430
|
+
const globalOptionsSchema = globalParser?.__optionsSchema ?? {};
|
|
431
|
+
const commandOptionsSchema = cmd.__optionsSchema;
|
|
432
|
+
const mergedOptionsSchema = {
|
|
433
|
+
...globalOptionsSchema,
|
|
434
|
+
...commandOptionsSchema,
|
|
435
|
+
};
|
|
436
|
+
const commandPositionalsSchema = cmd.__positionalsSchema;
|
|
437
|
+
// Parse with merged schema
|
|
438
|
+
const parsed = parseSimple({
|
|
439
|
+
args: remainingArgs,
|
|
440
|
+
options: mergedOptionsSchema,
|
|
441
|
+
positionals: commandPositionalsSchema,
|
|
442
|
+
});
|
|
443
|
+
let result = {
|
|
444
|
+
positionals: parsed.positionals,
|
|
445
|
+
values: parsed.values,
|
|
446
|
+
};
|
|
447
|
+
// Helper to check for async and throw if not allowed
|
|
448
|
+
const checkAsync = (value, context) => {
|
|
449
|
+
if (value instanceof Promise && !allowAsync) {
|
|
450
|
+
throw new BargsError(`Async ${context} detected. Use parseAsync() instead of parse().`);
|
|
155
451
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const transformed =
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
};
|
|
172
|
-
// Call handler if provided (async)
|
|
173
|
-
if (config.handler) {
|
|
174
|
-
await runHandler(config.handler, result);
|
|
452
|
+
};
|
|
453
|
+
// Get transforms
|
|
454
|
+
const globalTransform = globalParser?.__transform;
|
|
455
|
+
const commandTransform = cmd?.__transform;
|
|
456
|
+
// Apply transforms and run handler
|
|
457
|
+
const applyTransformsAndHandle = () => {
|
|
458
|
+
// Apply global transforms first
|
|
459
|
+
if (globalTransform) {
|
|
460
|
+
const transformed = globalTransform(result);
|
|
461
|
+
checkAsync(transformed, 'global transform');
|
|
462
|
+
if (transformed instanceof Promise) {
|
|
463
|
+
return transformed.then((r) => {
|
|
464
|
+
result = r;
|
|
465
|
+
return continueWithCommandTransform();
|
|
466
|
+
});
|
|
175
467
|
}
|
|
176
|
-
|
|
468
|
+
result = transformed;
|
|
177
469
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
470
|
+
return continueWithCommandTransform();
|
|
471
|
+
};
|
|
472
|
+
const continueWithCommandTransform = () => {
|
|
473
|
+
// Apply command transforms
|
|
474
|
+
if (commandTransform) {
|
|
475
|
+
const transformed = commandTransform(result);
|
|
476
|
+
checkAsync(transformed, 'command transform');
|
|
477
|
+
if (transformed instanceof Promise) {
|
|
478
|
+
return transformed.then((r) => {
|
|
479
|
+
result = r;
|
|
480
|
+
return runHandler();
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
result = transformed;
|
|
484
|
+
}
|
|
485
|
+
return runHandler();
|
|
486
|
+
};
|
|
487
|
+
const runHandler = () => {
|
|
488
|
+
const handlerResult = cmd.handler(result);
|
|
489
|
+
checkAsync(handlerResult, 'handler');
|
|
490
|
+
if (handlerResult instanceof Promise) {
|
|
491
|
+
return handlerResult.then(() => ({ ...result, command: commandName }));
|
|
492
|
+
}
|
|
493
|
+
return { ...result, command: commandName };
|
|
494
|
+
};
|
|
495
|
+
return applyTransformsAndHandle();
|
|
496
|
+
};
|
|
497
|
+
/**
|
|
498
|
+
* Main bargs namespace.
|
|
499
|
+
*/
|
|
500
|
+
export const bargs = {
|
|
501
|
+
create,
|
|
502
|
+
};
|
|
183
503
|
//# sourceMappingURL=bargs.js.map
|