@optique/core 0.7.0-dev.150 → 0.7.0-dev.153
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/dist/constructs.cjs +94 -12
- package/dist/constructs.d.cts +80 -4
- package/dist/constructs.d.ts +80 -4
- package/dist/constructs.js +95 -13
- package/dist/facade.cjs +41 -20
- package/dist/facade.d.cts +10 -0
- package/dist/facade.d.ts +10 -0
- package/dist/facade.js +41 -20
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/parser.d.cts +2 -2
- package/dist/parser.d.ts +2 -2
- package/dist/usage.cjs +33 -0
- package/dist/usage.d.cts +23 -1
- package/dist/usage.d.ts +23 -1
- package/dist/usage.js +33 -1
- package/package.json +1 -1
package/dist/constructs.cjs
CHANGED
|
@@ -4,6 +4,65 @@ const require_suggestion = require('./suggestion.cjs');
|
|
|
4
4
|
|
|
5
5
|
//#region src/constructs.ts
|
|
6
6
|
/**
|
|
7
|
+
* Extracts required (non-optional) usage terms from a usage array.
|
|
8
|
+
* @param usage The usage to extract required terms from
|
|
9
|
+
* @returns Usage containing only required (non-optional) terms
|
|
10
|
+
*/
|
|
11
|
+
function extractRequiredUsage(usage) {
|
|
12
|
+
const required = [];
|
|
13
|
+
for (const term of usage) if (term.type === "optional") continue;
|
|
14
|
+
else if (term.type === "exclusive") {
|
|
15
|
+
const requiredBranches = term.terms.map((branch) => extractRequiredUsage(branch)).filter((branch) => branch.length > 0);
|
|
16
|
+
if (requiredBranches.length > 0) required.push({
|
|
17
|
+
type: "exclusive",
|
|
18
|
+
terms: requiredBranches
|
|
19
|
+
});
|
|
20
|
+
} else if (term.type === "multiple") {
|
|
21
|
+
if (term.min > 0) {
|
|
22
|
+
const requiredTerms = extractRequiredUsage(term.terms);
|
|
23
|
+
if (requiredTerms.length > 0) required.push({
|
|
24
|
+
type: "multiple",
|
|
25
|
+
terms: requiredTerms,
|
|
26
|
+
min: term.min
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
} else required.push(term);
|
|
30
|
+
return required;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Analyzes parsers to determine what types of inputs are expected.
|
|
34
|
+
* @param parsers The parsers being combined
|
|
35
|
+
* @returns Context about what types of inputs are expected
|
|
36
|
+
*/
|
|
37
|
+
function analyzeNoMatchContext(parsers) {
|
|
38
|
+
const combinedUsage = [{
|
|
39
|
+
type: "exclusive",
|
|
40
|
+
terms: parsers.map((p) => p.usage)
|
|
41
|
+
}];
|
|
42
|
+
const requiredUsage = extractRequiredUsage(combinedUsage);
|
|
43
|
+
return {
|
|
44
|
+
hasOptions: require_usage.extractOptionNames(requiredUsage).size > 0,
|
|
45
|
+
hasCommands: require_usage.extractCommandNames(requiredUsage).size > 0,
|
|
46
|
+
hasArguments: require_usage.extractArgumentMetavars(requiredUsage).size > 0
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Generates a contextual error message based on what types of inputs
|
|
51
|
+
* the parsers expect (options, commands, or arguments).
|
|
52
|
+
* @param context Context about what types of inputs are expected
|
|
53
|
+
* @returns An appropriate error message
|
|
54
|
+
*/
|
|
55
|
+
function generateNoMatchError(context) {
|
|
56
|
+
const { hasOptions, hasCommands, hasArguments } = context;
|
|
57
|
+
if (hasArguments && !hasOptions && !hasCommands) return require_message.message`Missing required argument.`;
|
|
58
|
+
else if (hasCommands && !hasOptions && !hasArguments) return require_message.message`No matching command found.`;
|
|
59
|
+
else if (hasOptions && !hasCommands && !hasArguments) return require_message.message`No matching option found.`;
|
|
60
|
+
else if (hasCommands && hasOptions && !hasArguments) return require_message.message`No matching option or command found.`;
|
|
61
|
+
else if (hasArguments && hasOptions && !hasCommands) return require_message.message`No matching option or argument found.`;
|
|
62
|
+
else if (hasArguments && hasCommands && !hasOptions) return require_message.message`No matching command or argument found.`;
|
|
63
|
+
else return require_message.message`No matching option, command, or argument found.`;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
7
66
|
* @since 0.5.0
|
|
8
67
|
*/
|
|
9
68
|
function or(...args) {
|
|
@@ -16,6 +75,7 @@ function or(...args) {
|
|
|
16
75
|
parsers = args;
|
|
17
76
|
options = void 0;
|
|
18
77
|
}
|
|
78
|
+
const noMatchContext = analyzeNoMatchContext(parsers);
|
|
19
79
|
return {
|
|
20
80
|
$valueType: [],
|
|
21
81
|
$stateType: [],
|
|
@@ -26,10 +86,14 @@ function or(...args) {
|
|
|
26
86
|
}],
|
|
27
87
|
initialState: void 0,
|
|
28
88
|
complete(state) {
|
|
29
|
-
if (state == null)
|
|
30
|
-
|
|
31
|
-
error
|
|
32
|
-
|
|
89
|
+
if (state == null) {
|
|
90
|
+
const customNoMatch = options?.errors?.noMatch;
|
|
91
|
+
const error = customNoMatch ? typeof customNoMatch === "function" ? customNoMatch(noMatchContext) : customNoMatch : generateNoMatchError(noMatchContext);
|
|
92
|
+
return {
|
|
93
|
+
success: false,
|
|
94
|
+
error
|
|
95
|
+
};
|
|
96
|
+
}
|
|
33
97
|
const [i, result] = state;
|
|
34
98
|
if (result.success) return parsers[i].complete(result.next.state);
|
|
35
99
|
return {
|
|
@@ -40,7 +104,10 @@ function or(...args) {
|
|
|
40
104
|
parse(context) {
|
|
41
105
|
let error = {
|
|
42
106
|
consumed: 0,
|
|
43
|
-
error: context.buffer.length < 1 ?
|
|
107
|
+
error: context.buffer.length < 1 ? (() => {
|
|
108
|
+
const customNoMatch = options?.errors?.noMatch;
|
|
109
|
+
return customNoMatch ? typeof customNoMatch === "function" ? customNoMatch(noMatchContext) : customNoMatch : generateNoMatchError(noMatchContext);
|
|
110
|
+
})() : (() => {
|
|
44
111
|
const token = context.buffer[0];
|
|
45
112
|
const defaultMsg = require_message.message`Unexpected option or subcommand: ${require_message.optionName(token)}.`;
|
|
46
113
|
if (options?.errors?.unexpectedInput != null) return typeof options.errors.unexpectedInput === "function" ? options.errors.unexpectedInput(token) : options.errors.unexpectedInput;
|
|
@@ -151,6 +218,7 @@ function longestMatch(...args) {
|
|
|
151
218
|
parsers = args;
|
|
152
219
|
options = void 0;
|
|
153
220
|
}
|
|
221
|
+
const noMatchContext = analyzeNoMatchContext(parsers);
|
|
154
222
|
return {
|
|
155
223
|
$valueType: [],
|
|
156
224
|
$stateType: [],
|
|
@@ -161,10 +229,14 @@ function longestMatch(...args) {
|
|
|
161
229
|
}],
|
|
162
230
|
initialState: void 0,
|
|
163
231
|
complete(state) {
|
|
164
|
-
if (state == null)
|
|
165
|
-
|
|
166
|
-
error
|
|
167
|
-
|
|
232
|
+
if (state == null) {
|
|
233
|
+
const customNoMatch = options?.errors?.noMatch;
|
|
234
|
+
const error = customNoMatch ? typeof customNoMatch === "function" ? customNoMatch(noMatchContext) : customNoMatch : generateNoMatchError(noMatchContext);
|
|
235
|
+
return {
|
|
236
|
+
success: false,
|
|
237
|
+
error
|
|
238
|
+
};
|
|
239
|
+
}
|
|
168
240
|
const [i, result] = state;
|
|
169
241
|
if (result.success) return parsers[i].complete(result.next.state);
|
|
170
242
|
return {
|
|
@@ -176,7 +248,10 @@ function longestMatch(...args) {
|
|
|
176
248
|
let bestMatch = null;
|
|
177
249
|
let error = {
|
|
178
250
|
consumed: 0,
|
|
179
|
-
error: context.buffer.length < 1 ?
|
|
251
|
+
error: context.buffer.length < 1 ? (() => {
|
|
252
|
+
const customNoMatch = options?.errors?.noMatch;
|
|
253
|
+
return customNoMatch ? typeof customNoMatch === "function" ? customNoMatch(noMatchContext) : customNoMatch : generateNoMatchError(noMatchContext);
|
|
254
|
+
})() : (() => {
|
|
180
255
|
const token = context.buffer[0];
|
|
181
256
|
const defaultMsg = require_message.message`Unexpected option or subcommand: ${require_message.optionName(token)}.`;
|
|
182
257
|
if (options?.errors?.unexpectedInput != null) return typeof options.errors.unexpectedInput === "function" ? options.errors.unexpectedInput(token) : options.errors.unexpectedInput;
|
|
@@ -242,6 +317,7 @@ function longestMatch(...args) {
|
|
|
242
317
|
},
|
|
243
318
|
getDocFragments(state, _defaultValue) {
|
|
244
319
|
let description;
|
|
320
|
+
let footer;
|
|
245
321
|
let fragments;
|
|
246
322
|
if (state.kind === "unavailable" || state.state == null) fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }).fragments);
|
|
247
323
|
else {
|
|
@@ -252,12 +328,14 @@ function longestMatch(...args) {
|
|
|
252
328
|
state: result.next.state
|
|
253
329
|
});
|
|
254
330
|
description = docResult.description;
|
|
331
|
+
footer = docResult.footer;
|
|
255
332
|
fragments = docResult.fragments;
|
|
256
333
|
} else fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }).fragments);
|
|
257
334
|
}
|
|
258
335
|
return {
|
|
259
336
|
description,
|
|
260
|
-
fragments
|
|
337
|
+
fragments,
|
|
338
|
+
footer
|
|
261
339
|
};
|
|
262
340
|
}
|
|
263
341
|
};
|
|
@@ -275,6 +353,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
|
|
|
275
353
|
}
|
|
276
354
|
const parserPairs = Object.entries(parsers);
|
|
277
355
|
parserPairs.sort(([_, parserA], [__, parserB]) => parserB.priority - parserA.priority);
|
|
356
|
+
const noMatchContext = analyzeNoMatchContext(Object.values(parsers));
|
|
278
357
|
return {
|
|
279
358
|
$valueType: [],
|
|
280
359
|
$stateType: [],
|
|
@@ -305,7 +384,10 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
|
|
|
305
384
|
if (customMessage) return typeof customMessage === "function" ? customMessage(token) : customMessage;
|
|
306
385
|
const baseError = require_message.message`Unexpected option or argument: ${token}.`;
|
|
307
386
|
return require_suggestion.createErrorWithSuggestions(baseError, token, context.usage, "both", options.errors?.suggestions);
|
|
308
|
-
})() :
|
|
387
|
+
})() : (() => {
|
|
388
|
+
const customEndOfInput = options.errors?.endOfInput;
|
|
389
|
+
return customEndOfInput ? typeof customEndOfInput === "function" ? customEndOfInput(noMatchContext) : customEndOfInput : generateNoMatchError(noMatchContext);
|
|
390
|
+
})()
|
|
309
391
|
};
|
|
310
392
|
let currentContext = context;
|
|
311
393
|
let anySuccess = false;
|
package/dist/constructs.d.cts
CHANGED
|
@@ -13,6 +13,25 @@ interface OrOptions {
|
|
|
13
13
|
*/
|
|
14
14
|
errors?: OrErrorOptions;
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Context information about what types of inputs are expected,
|
|
18
|
+
* used for generating contextual error messages.
|
|
19
|
+
* @since 0.9.0
|
|
20
|
+
*/
|
|
21
|
+
interface NoMatchContext {
|
|
22
|
+
/**
|
|
23
|
+
* Whether any of the parsers expect options.
|
|
24
|
+
*/
|
|
25
|
+
readonly hasOptions: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Whether any of the parsers expect commands.
|
|
28
|
+
*/
|
|
29
|
+
readonly hasCommands: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Whether any of the parsers expect arguments.
|
|
32
|
+
*/
|
|
33
|
+
readonly hasArguments: boolean;
|
|
34
|
+
}
|
|
16
35
|
/**
|
|
17
36
|
* Options for customizing error messages in the {@link or} parser.
|
|
18
37
|
* @since 0.5.0
|
|
@@ -20,8 +39,27 @@ interface OrOptions {
|
|
|
20
39
|
interface OrErrorOptions {
|
|
21
40
|
/**
|
|
22
41
|
* Custom error message when no parser matches.
|
|
42
|
+
* Can be a static message or a function that receives context about what
|
|
43
|
+
* types of inputs are expected, allowing for more precise error messages.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* // Static message (overrides all cases)
|
|
48
|
+
* { noMatch: message`Invalid input.` }
|
|
49
|
+
*
|
|
50
|
+
* // Dynamic message based on context (for i18n, etc.)
|
|
51
|
+
* {
|
|
52
|
+
* noMatch: ({ hasOptions, hasCommands, hasArguments }) => {
|
|
53
|
+
* if (hasArguments && !hasOptions && !hasCommands) {
|
|
54
|
+
* return message`인수가 필요합니다.`; // Korean: "Argument required"
|
|
55
|
+
* }
|
|
56
|
+
* // ... other cases
|
|
57
|
+
* }
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
* @since 0.9.0 - Function form added
|
|
23
61
|
*/
|
|
24
|
-
noMatch?: Message;
|
|
62
|
+
noMatch?: Message | ((context: NoMatchContext) => Message);
|
|
25
63
|
/**
|
|
26
64
|
* Custom error message for unexpected input.
|
|
27
65
|
* Can be a static message or a function that receives the unexpected token.
|
|
@@ -306,8 +344,27 @@ interface LongestMatchOptions {
|
|
|
306
344
|
interface LongestMatchErrorOptions {
|
|
307
345
|
/**
|
|
308
346
|
* Custom error message when no parser matches.
|
|
347
|
+
* Can be a static message or a function that receives context about what
|
|
348
|
+
* types of inputs are expected, allowing for more precise error messages.
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* ```typescript
|
|
352
|
+
* // Static message (overrides all cases)
|
|
353
|
+
* { noMatch: message`Invalid input.` }
|
|
354
|
+
*
|
|
355
|
+
* // Dynamic message based on context (for i18n, etc.)
|
|
356
|
+
* {
|
|
357
|
+
* noMatch: ({ hasOptions, hasCommands, hasArguments }) => {
|
|
358
|
+
* if (hasArguments && !hasOptions && !hasCommands) {
|
|
359
|
+
* return message`引数が必要です。`; // Japanese: "Argument required"
|
|
360
|
+
* }
|
|
361
|
+
* // ... other cases
|
|
362
|
+
* }
|
|
363
|
+
* }
|
|
364
|
+
* ```
|
|
365
|
+
* @since 0.9.0 - Function form added
|
|
309
366
|
*/
|
|
310
|
-
noMatch?: Message;
|
|
367
|
+
noMatch?: Message | ((context: NoMatchContext) => Message);
|
|
311
368
|
/**
|
|
312
369
|
* Custom error message for unexpected input.
|
|
313
370
|
* Can be a static message or a function that receives the unexpected token.
|
|
@@ -447,8 +504,27 @@ interface ObjectErrorOptions {
|
|
|
447
504
|
readonly unexpectedInput?: Message | ((token: string) => Message);
|
|
448
505
|
/**
|
|
449
506
|
* Error message when end of input is reached unexpectedly.
|
|
507
|
+
* Can be a static message or a function that receives context about what
|
|
508
|
+
* types of inputs are expected, allowing for more precise error messages.
|
|
509
|
+
*
|
|
510
|
+
* @example
|
|
511
|
+
* ```typescript
|
|
512
|
+
* // Static message (overrides all cases)
|
|
513
|
+
* { endOfInput: message`Invalid input.` }
|
|
514
|
+
*
|
|
515
|
+
* // Dynamic message based on context (for i18n, etc.)
|
|
516
|
+
* {
|
|
517
|
+
* endOfInput: ({ hasOptions, hasCommands, hasArguments }) => {
|
|
518
|
+
* if (hasArguments && !hasOptions && !hasCommands) {
|
|
519
|
+
* return message`Argument manquant.`; // French: "Missing argument"
|
|
520
|
+
* }
|
|
521
|
+
* // ... other cases
|
|
522
|
+
* }
|
|
523
|
+
* }
|
|
524
|
+
* ```
|
|
525
|
+
* @since 0.9.0 - Function form added
|
|
450
526
|
*/
|
|
451
|
-
readonly endOfInput?: Message;
|
|
527
|
+
readonly endOfInput?: Message | ((context: NoMatchContext) => Message);
|
|
452
528
|
/**
|
|
453
529
|
* Custom function to format suggestion messages.
|
|
454
530
|
* If provided, this will be used instead of the default "Did you mean?"
|
|
@@ -1183,4 +1259,4 @@ declare function concat<TA extends readonly unknown[], TB extends readonly unkno
|
|
|
1183
1259
|
*/
|
|
1184
1260
|
declare function group<TValue, TState>(label: string, parser: Parser<TValue, TState>): Parser<TValue, TState>;
|
|
1185
1261
|
//#endregion
|
|
1186
|
-
export { LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, group, longestMatch, merge, object, or, tuple };
|
|
1262
|
+
export { LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, group, longestMatch, merge, object, or, tuple };
|
package/dist/constructs.d.ts
CHANGED
|
@@ -13,6 +13,25 @@ interface OrOptions {
|
|
|
13
13
|
*/
|
|
14
14
|
errors?: OrErrorOptions;
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Context information about what types of inputs are expected,
|
|
18
|
+
* used for generating contextual error messages.
|
|
19
|
+
* @since 0.9.0
|
|
20
|
+
*/
|
|
21
|
+
interface NoMatchContext {
|
|
22
|
+
/**
|
|
23
|
+
* Whether any of the parsers expect options.
|
|
24
|
+
*/
|
|
25
|
+
readonly hasOptions: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Whether any of the parsers expect commands.
|
|
28
|
+
*/
|
|
29
|
+
readonly hasCommands: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Whether any of the parsers expect arguments.
|
|
32
|
+
*/
|
|
33
|
+
readonly hasArguments: boolean;
|
|
34
|
+
}
|
|
16
35
|
/**
|
|
17
36
|
* Options for customizing error messages in the {@link or} parser.
|
|
18
37
|
* @since 0.5.0
|
|
@@ -20,8 +39,27 @@ interface OrOptions {
|
|
|
20
39
|
interface OrErrorOptions {
|
|
21
40
|
/**
|
|
22
41
|
* Custom error message when no parser matches.
|
|
42
|
+
* Can be a static message or a function that receives context about what
|
|
43
|
+
* types of inputs are expected, allowing for more precise error messages.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* // Static message (overrides all cases)
|
|
48
|
+
* { noMatch: message`Invalid input.` }
|
|
49
|
+
*
|
|
50
|
+
* // Dynamic message based on context (for i18n, etc.)
|
|
51
|
+
* {
|
|
52
|
+
* noMatch: ({ hasOptions, hasCommands, hasArguments }) => {
|
|
53
|
+
* if (hasArguments && !hasOptions && !hasCommands) {
|
|
54
|
+
* return message`인수가 필요합니다.`; // Korean: "Argument required"
|
|
55
|
+
* }
|
|
56
|
+
* // ... other cases
|
|
57
|
+
* }
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
* @since 0.9.0 - Function form added
|
|
23
61
|
*/
|
|
24
|
-
noMatch?: Message;
|
|
62
|
+
noMatch?: Message | ((context: NoMatchContext) => Message);
|
|
25
63
|
/**
|
|
26
64
|
* Custom error message for unexpected input.
|
|
27
65
|
* Can be a static message or a function that receives the unexpected token.
|
|
@@ -306,8 +344,27 @@ interface LongestMatchOptions {
|
|
|
306
344
|
interface LongestMatchErrorOptions {
|
|
307
345
|
/**
|
|
308
346
|
* Custom error message when no parser matches.
|
|
347
|
+
* Can be a static message or a function that receives context about what
|
|
348
|
+
* types of inputs are expected, allowing for more precise error messages.
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* ```typescript
|
|
352
|
+
* // Static message (overrides all cases)
|
|
353
|
+
* { noMatch: message`Invalid input.` }
|
|
354
|
+
*
|
|
355
|
+
* // Dynamic message based on context (for i18n, etc.)
|
|
356
|
+
* {
|
|
357
|
+
* noMatch: ({ hasOptions, hasCommands, hasArguments }) => {
|
|
358
|
+
* if (hasArguments && !hasOptions && !hasCommands) {
|
|
359
|
+
* return message`引数が必要です。`; // Japanese: "Argument required"
|
|
360
|
+
* }
|
|
361
|
+
* // ... other cases
|
|
362
|
+
* }
|
|
363
|
+
* }
|
|
364
|
+
* ```
|
|
365
|
+
* @since 0.9.0 - Function form added
|
|
309
366
|
*/
|
|
310
|
-
noMatch?: Message;
|
|
367
|
+
noMatch?: Message | ((context: NoMatchContext) => Message);
|
|
311
368
|
/**
|
|
312
369
|
* Custom error message for unexpected input.
|
|
313
370
|
* Can be a static message or a function that receives the unexpected token.
|
|
@@ -447,8 +504,27 @@ interface ObjectErrorOptions {
|
|
|
447
504
|
readonly unexpectedInput?: Message | ((token: string) => Message);
|
|
448
505
|
/**
|
|
449
506
|
* Error message when end of input is reached unexpectedly.
|
|
507
|
+
* Can be a static message or a function that receives context about what
|
|
508
|
+
* types of inputs are expected, allowing for more precise error messages.
|
|
509
|
+
*
|
|
510
|
+
* @example
|
|
511
|
+
* ```typescript
|
|
512
|
+
* // Static message (overrides all cases)
|
|
513
|
+
* { endOfInput: message`Invalid input.` }
|
|
514
|
+
*
|
|
515
|
+
* // Dynamic message based on context (for i18n, etc.)
|
|
516
|
+
* {
|
|
517
|
+
* endOfInput: ({ hasOptions, hasCommands, hasArguments }) => {
|
|
518
|
+
* if (hasArguments && !hasOptions && !hasCommands) {
|
|
519
|
+
* return message`Argument manquant.`; // French: "Missing argument"
|
|
520
|
+
* }
|
|
521
|
+
* // ... other cases
|
|
522
|
+
* }
|
|
523
|
+
* }
|
|
524
|
+
* ```
|
|
525
|
+
* @since 0.9.0 - Function form added
|
|
450
526
|
*/
|
|
451
|
-
readonly endOfInput?: Message;
|
|
527
|
+
readonly endOfInput?: Message | ((context: NoMatchContext) => Message);
|
|
452
528
|
/**
|
|
453
529
|
* Custom function to format suggestion messages.
|
|
454
530
|
* If provided, this will be used instead of the default "Did you mean?"
|
|
@@ -1183,4 +1259,4 @@ declare function concat<TA extends readonly unknown[], TB extends readonly unkno
|
|
|
1183
1259
|
*/
|
|
1184
1260
|
declare function group<TValue, TState>(label: string, parser: Parser<TValue, TState>): Parser<TValue, TState>;
|
|
1185
1261
|
//#endregion
|
|
1186
|
-
export { LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, group, longestMatch, merge, object, or, tuple };
|
|
1262
|
+
export { LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, group, longestMatch, merge, object, or, tuple };
|
package/dist/constructs.js
CHANGED
|
@@ -1,9 +1,68 @@
|
|
|
1
1
|
import { message, optionName, values } from "./message.js";
|
|
2
|
-
import { extractOptionNames } from "./usage.js";
|
|
2
|
+
import { extractArgumentMetavars, extractCommandNames, extractOptionNames } from "./usage.js";
|
|
3
3
|
import { createErrorWithSuggestions } from "./suggestion.js";
|
|
4
4
|
|
|
5
5
|
//#region src/constructs.ts
|
|
6
6
|
/**
|
|
7
|
+
* Extracts required (non-optional) usage terms from a usage array.
|
|
8
|
+
* @param usage The usage to extract required terms from
|
|
9
|
+
* @returns Usage containing only required (non-optional) terms
|
|
10
|
+
*/
|
|
11
|
+
function extractRequiredUsage(usage) {
|
|
12
|
+
const required = [];
|
|
13
|
+
for (const term of usage) if (term.type === "optional") continue;
|
|
14
|
+
else if (term.type === "exclusive") {
|
|
15
|
+
const requiredBranches = term.terms.map((branch) => extractRequiredUsage(branch)).filter((branch) => branch.length > 0);
|
|
16
|
+
if (requiredBranches.length > 0) required.push({
|
|
17
|
+
type: "exclusive",
|
|
18
|
+
terms: requiredBranches
|
|
19
|
+
});
|
|
20
|
+
} else if (term.type === "multiple") {
|
|
21
|
+
if (term.min > 0) {
|
|
22
|
+
const requiredTerms = extractRequiredUsage(term.terms);
|
|
23
|
+
if (requiredTerms.length > 0) required.push({
|
|
24
|
+
type: "multiple",
|
|
25
|
+
terms: requiredTerms,
|
|
26
|
+
min: term.min
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
} else required.push(term);
|
|
30
|
+
return required;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Analyzes parsers to determine what types of inputs are expected.
|
|
34
|
+
* @param parsers The parsers being combined
|
|
35
|
+
* @returns Context about what types of inputs are expected
|
|
36
|
+
*/
|
|
37
|
+
function analyzeNoMatchContext(parsers) {
|
|
38
|
+
const combinedUsage = [{
|
|
39
|
+
type: "exclusive",
|
|
40
|
+
terms: parsers.map((p) => p.usage)
|
|
41
|
+
}];
|
|
42
|
+
const requiredUsage = extractRequiredUsage(combinedUsage);
|
|
43
|
+
return {
|
|
44
|
+
hasOptions: extractOptionNames(requiredUsage).size > 0,
|
|
45
|
+
hasCommands: extractCommandNames(requiredUsage).size > 0,
|
|
46
|
+
hasArguments: extractArgumentMetavars(requiredUsage).size > 0
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Generates a contextual error message based on what types of inputs
|
|
51
|
+
* the parsers expect (options, commands, or arguments).
|
|
52
|
+
* @param context Context about what types of inputs are expected
|
|
53
|
+
* @returns An appropriate error message
|
|
54
|
+
*/
|
|
55
|
+
function generateNoMatchError(context) {
|
|
56
|
+
const { hasOptions, hasCommands, hasArguments } = context;
|
|
57
|
+
if (hasArguments && !hasOptions && !hasCommands) return message`Missing required argument.`;
|
|
58
|
+
else if (hasCommands && !hasOptions && !hasArguments) return message`No matching command found.`;
|
|
59
|
+
else if (hasOptions && !hasCommands && !hasArguments) return message`No matching option found.`;
|
|
60
|
+
else if (hasCommands && hasOptions && !hasArguments) return message`No matching option or command found.`;
|
|
61
|
+
else if (hasArguments && hasOptions && !hasCommands) return message`No matching option or argument found.`;
|
|
62
|
+
else if (hasArguments && hasCommands && !hasOptions) return message`No matching command or argument found.`;
|
|
63
|
+
else return message`No matching option, command, or argument found.`;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
7
66
|
* @since 0.5.0
|
|
8
67
|
*/
|
|
9
68
|
function or(...args) {
|
|
@@ -16,6 +75,7 @@ function or(...args) {
|
|
|
16
75
|
parsers = args;
|
|
17
76
|
options = void 0;
|
|
18
77
|
}
|
|
78
|
+
const noMatchContext = analyzeNoMatchContext(parsers);
|
|
19
79
|
return {
|
|
20
80
|
$valueType: [],
|
|
21
81
|
$stateType: [],
|
|
@@ -26,10 +86,14 @@ function or(...args) {
|
|
|
26
86
|
}],
|
|
27
87
|
initialState: void 0,
|
|
28
88
|
complete(state) {
|
|
29
|
-
if (state == null)
|
|
30
|
-
|
|
31
|
-
error
|
|
32
|
-
|
|
89
|
+
if (state == null) {
|
|
90
|
+
const customNoMatch = options?.errors?.noMatch;
|
|
91
|
+
const error = customNoMatch ? typeof customNoMatch === "function" ? customNoMatch(noMatchContext) : customNoMatch : generateNoMatchError(noMatchContext);
|
|
92
|
+
return {
|
|
93
|
+
success: false,
|
|
94
|
+
error
|
|
95
|
+
};
|
|
96
|
+
}
|
|
33
97
|
const [i, result] = state;
|
|
34
98
|
if (result.success) return parsers[i].complete(result.next.state);
|
|
35
99
|
return {
|
|
@@ -40,7 +104,10 @@ function or(...args) {
|
|
|
40
104
|
parse(context) {
|
|
41
105
|
let error = {
|
|
42
106
|
consumed: 0,
|
|
43
|
-
error: context.buffer.length < 1 ?
|
|
107
|
+
error: context.buffer.length < 1 ? (() => {
|
|
108
|
+
const customNoMatch = options?.errors?.noMatch;
|
|
109
|
+
return customNoMatch ? typeof customNoMatch === "function" ? customNoMatch(noMatchContext) : customNoMatch : generateNoMatchError(noMatchContext);
|
|
110
|
+
})() : (() => {
|
|
44
111
|
const token = context.buffer[0];
|
|
45
112
|
const defaultMsg = message`Unexpected option or subcommand: ${optionName(token)}.`;
|
|
46
113
|
if (options?.errors?.unexpectedInput != null) return typeof options.errors.unexpectedInput === "function" ? options.errors.unexpectedInput(token) : options.errors.unexpectedInput;
|
|
@@ -151,6 +218,7 @@ function longestMatch(...args) {
|
|
|
151
218
|
parsers = args;
|
|
152
219
|
options = void 0;
|
|
153
220
|
}
|
|
221
|
+
const noMatchContext = analyzeNoMatchContext(parsers);
|
|
154
222
|
return {
|
|
155
223
|
$valueType: [],
|
|
156
224
|
$stateType: [],
|
|
@@ -161,10 +229,14 @@ function longestMatch(...args) {
|
|
|
161
229
|
}],
|
|
162
230
|
initialState: void 0,
|
|
163
231
|
complete(state) {
|
|
164
|
-
if (state == null)
|
|
165
|
-
|
|
166
|
-
error
|
|
167
|
-
|
|
232
|
+
if (state == null) {
|
|
233
|
+
const customNoMatch = options?.errors?.noMatch;
|
|
234
|
+
const error = customNoMatch ? typeof customNoMatch === "function" ? customNoMatch(noMatchContext) : customNoMatch : generateNoMatchError(noMatchContext);
|
|
235
|
+
return {
|
|
236
|
+
success: false,
|
|
237
|
+
error
|
|
238
|
+
};
|
|
239
|
+
}
|
|
168
240
|
const [i, result] = state;
|
|
169
241
|
if (result.success) return parsers[i].complete(result.next.state);
|
|
170
242
|
return {
|
|
@@ -176,7 +248,10 @@ function longestMatch(...args) {
|
|
|
176
248
|
let bestMatch = null;
|
|
177
249
|
let error = {
|
|
178
250
|
consumed: 0,
|
|
179
|
-
error: context.buffer.length < 1 ?
|
|
251
|
+
error: context.buffer.length < 1 ? (() => {
|
|
252
|
+
const customNoMatch = options?.errors?.noMatch;
|
|
253
|
+
return customNoMatch ? typeof customNoMatch === "function" ? customNoMatch(noMatchContext) : customNoMatch : generateNoMatchError(noMatchContext);
|
|
254
|
+
})() : (() => {
|
|
180
255
|
const token = context.buffer[0];
|
|
181
256
|
const defaultMsg = message`Unexpected option or subcommand: ${optionName(token)}.`;
|
|
182
257
|
if (options?.errors?.unexpectedInput != null) return typeof options.errors.unexpectedInput === "function" ? options.errors.unexpectedInput(token) : options.errors.unexpectedInput;
|
|
@@ -242,6 +317,7 @@ function longestMatch(...args) {
|
|
|
242
317
|
},
|
|
243
318
|
getDocFragments(state, _defaultValue) {
|
|
244
319
|
let description;
|
|
320
|
+
let footer;
|
|
245
321
|
let fragments;
|
|
246
322
|
if (state.kind === "unavailable" || state.state == null) fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }).fragments);
|
|
247
323
|
else {
|
|
@@ -252,12 +328,14 @@ function longestMatch(...args) {
|
|
|
252
328
|
state: result.next.state
|
|
253
329
|
});
|
|
254
330
|
description = docResult.description;
|
|
331
|
+
footer = docResult.footer;
|
|
255
332
|
fragments = docResult.fragments;
|
|
256
333
|
} else fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }).fragments);
|
|
257
334
|
}
|
|
258
335
|
return {
|
|
259
336
|
description,
|
|
260
|
-
fragments
|
|
337
|
+
fragments,
|
|
338
|
+
footer
|
|
261
339
|
};
|
|
262
340
|
}
|
|
263
341
|
};
|
|
@@ -275,6 +353,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
|
|
|
275
353
|
}
|
|
276
354
|
const parserPairs = Object.entries(parsers);
|
|
277
355
|
parserPairs.sort(([_, parserA], [__, parserB]) => parserB.priority - parserA.priority);
|
|
356
|
+
const noMatchContext = analyzeNoMatchContext(Object.values(parsers));
|
|
278
357
|
return {
|
|
279
358
|
$valueType: [],
|
|
280
359
|
$stateType: [],
|
|
@@ -305,7 +384,10 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
|
|
|
305
384
|
if (customMessage) return typeof customMessage === "function" ? customMessage(token) : customMessage;
|
|
306
385
|
const baseError = message`Unexpected option or argument: ${token}.`;
|
|
307
386
|
return createErrorWithSuggestions(baseError, token, context.usage, "both", options.errors?.suggestions);
|
|
308
|
-
})() :
|
|
387
|
+
})() : (() => {
|
|
388
|
+
const customEndOfInput = options.errors?.endOfInput;
|
|
389
|
+
return customEndOfInput ? typeof customEndOfInput === "function" ? customEndOfInput(noMatchContext) : customEndOfInput : generateNoMatchError(noMatchContext);
|
|
390
|
+
})()
|
|
309
391
|
};
|
|
310
392
|
let currentContext = context;
|
|
311
393
|
let anySuccess = false;
|
package/dist/facade.cjs
CHANGED
|
@@ -54,27 +54,41 @@ function createVersionParser(mode) {
|
|
|
54
54
|
/**
|
|
55
55
|
* Creates completion parsers based on the specified mode.
|
|
56
56
|
*/
|
|
57
|
-
function createCompletionParser(mode, programName, availableShells) {
|
|
57
|
+
function createCompletionParser(mode, programName, availableShells, name = "both") {
|
|
58
58
|
const shellList = [];
|
|
59
59
|
for (const shell in availableShells) {
|
|
60
60
|
if (shellList.length > 0) shellList.push(require_message.text(", "));
|
|
61
61
|
shellList.push(require_message.value(shell));
|
|
62
62
|
}
|
|
63
|
-
const
|
|
63
|
+
const completionInner = require_constructs.object({
|
|
64
64
|
shell: require_modifiers.optional(require_primitives.argument(require_valueparser.string({ metavar: "SHELL" }), { description: require_message.message`Shell type (${shellList}). Generate completion script when used alone, or provide completions when followed by arguments.` })),
|
|
65
65
|
args: require_modifiers.multiple(require_primitives.argument(require_valueparser.string({ metavar: "ARG" }), { description: require_message.message`Command line arguments for completion suggestions (used by shell integration; you usually don't need to provide this).` }))
|
|
66
|
-
})
|
|
66
|
+
});
|
|
67
|
+
const commandName = name === "plural" ? "completions" : "completion";
|
|
68
|
+
const completionCommandConfig = {
|
|
67
69
|
brief: require_message.message`Generate shell completion script or provide completions.`,
|
|
68
70
|
description: require_message.message`Generate shell completion script or provide completions.`,
|
|
69
71
|
footer: require_message.message`Examples:
|
|
70
|
-
Bash: ${require_message.commandLine(`eval "$(${programName}
|
|
71
|
-
zsh: ${require_message.commandLine(`eval "$(${programName}
|
|
72
|
-
fish: ${require_message.commandLine(`eval "$(${programName}
|
|
73
|
-
PowerShell: ${require_message.commandLine(`${programName}
|
|
74
|
-
Nushell: ${require_message.commandLine(`${programName}
|
|
72
|
+
Bash: ${require_message.commandLine(`eval "$(${programName} ${commandName} bash)"`)}
|
|
73
|
+
zsh: ${require_message.commandLine(`eval "$(${programName} ${commandName} zsh)"`)}
|
|
74
|
+
fish: ${require_message.commandLine(`eval "$(${programName} ${commandName} fish)"`)}
|
|
75
|
+
PowerShell: ${require_message.commandLine(`${programName} ${commandName} pwsh > ${programName}-completion.ps1; . ./${programName}-completion.ps1`)}
|
|
76
|
+
Nushell: ${require_message.commandLine(`${programName} ${commandName} nu | save ${programName}-completion.nu; source ./${programName}-completion.nu`)}
|
|
75
77
|
`
|
|
76
|
-
}
|
|
77
|
-
const
|
|
78
|
+
};
|
|
79
|
+
const completionCommands = [];
|
|
80
|
+
if (name === "singular" || name === "both") completionCommands.push(require_primitives.command("completion", completionInner, completionCommandConfig));
|
|
81
|
+
if (name === "plural" || name === "both") completionCommands.push(require_primitives.command("completions", completionInner, completionCommandConfig));
|
|
82
|
+
const completionCommand = require_constructs.longestMatch(...completionCommands);
|
|
83
|
+
const completionOptionNames = [];
|
|
84
|
+
if (name === "singular" || name === "both") completionOptionNames.push("--completion");
|
|
85
|
+
if (name === "plural" || name === "both") completionOptionNames.push("--completions");
|
|
86
|
+
const completionOptionArgs = [
|
|
87
|
+
...completionOptionNames,
|
|
88
|
+
require_valueparser.string({ metavar: "SHELL" }),
|
|
89
|
+
{ description: require_message.message`Generate shell completion script.` }
|
|
90
|
+
];
|
|
91
|
+
const completionOption = require_primitives.option(...completionOptionArgs);
|
|
78
92
|
switch (mode) {
|
|
79
93
|
case "command": return {
|
|
80
94
|
completionCommand,
|
|
@@ -412,6 +426,7 @@ function run(parser, programName, args, options = {}) {
|
|
|
412
426
|
const versionValue = options.version?.value ?? "";
|
|
413
427
|
const onVersion = options.version?.onShow ?? (() => ({}));
|
|
414
428
|
const completionMode = options.completion?.mode ?? "both";
|
|
429
|
+
const completionName = options.completion?.name ?? "both";
|
|
415
430
|
const onCompletion = options.completion?.onShow ?? (() => ({}));
|
|
416
431
|
const defaultShells = {
|
|
417
432
|
bash: require_completion.bash,
|
|
@@ -438,20 +453,26 @@ function run(parser, programName, args, options = {}) {
|
|
|
438
453
|
const completionParsers = completion === "none" ? {
|
|
439
454
|
completionCommand: null,
|
|
440
455
|
completionOption: null
|
|
441
|
-
} : createCompletionParser(completion, programName, availableShells);
|
|
456
|
+
} : createCompletionParser(completion, programName, availableShells, completionName);
|
|
442
457
|
if (options.completion) {
|
|
443
458
|
const hasHelpOption = args.includes("--help");
|
|
444
|
-
if ((completionMode === "command" || completionMode === "both") && args.length >= 1 && args[0] === "completion" && !hasHelpOption) return handleCompletion(args.slice(1), programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth);
|
|
459
|
+
if ((completionMode === "command" || completionMode === "both") && args.length >= 1 && ((completionName === "singular" || completionName === "both" ? args[0] === "completion" : false) || (completionName === "plural" || completionName === "both" ? args[0] === "completions" : false)) && !hasHelpOption) return handleCompletion(args.slice(1), programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth);
|
|
445
460
|
if (completionMode === "option" || completionMode === "both") for (let i = 0; i < args.length; i++) {
|
|
446
461
|
const arg = args[i];
|
|
447
|
-
|
|
448
|
-
|
|
462
|
+
const singularMatch = completionName === "singular" || completionName === "both" ? arg.startsWith("--completion=") : false;
|
|
463
|
+
const pluralMatch = completionName === "plural" || completionName === "both" ? arg.startsWith("--completions=") : false;
|
|
464
|
+
if (singularMatch || pluralMatch) {
|
|
465
|
+
const shell = arg.slice(arg.indexOf("=") + 1);
|
|
449
466
|
const completionArgs = args.slice(i + 1);
|
|
450
467
|
return handleCompletion([shell, ...completionArgs], programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth);
|
|
451
|
-
} else
|
|
452
|
-
const
|
|
453
|
-
const
|
|
454
|
-
|
|
468
|
+
} else {
|
|
469
|
+
const singularMatchExact = completionName === "singular" || completionName === "both" ? arg === "--completion" : false;
|
|
470
|
+
const pluralMatchExact = completionName === "plural" || completionName === "both" ? arg === "--completions" : false;
|
|
471
|
+
if ((singularMatchExact || pluralMatchExact) && i + 1 < args.length) {
|
|
472
|
+
const shell = args[i + 1];
|
|
473
|
+
const completionArgs = args.slice(i + 2);
|
|
474
|
+
return handleCompletion([shell, ...completionArgs], programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth);
|
|
475
|
+
}
|
|
455
476
|
}
|
|
456
477
|
}
|
|
457
478
|
}
|
|
@@ -474,7 +495,7 @@ function run(parser, programName, args, options = {}) {
|
|
|
474
495
|
const versionAsCommand = version === "command" || version === "both";
|
|
475
496
|
const completionAsCommand = completion === "command" || completion === "both";
|
|
476
497
|
const requestedCommand = classified.commands[0];
|
|
477
|
-
if (requestedCommand === "completion" && completionAsCommand && completionParsers.completionCommand) helpGeneratorParser = completionParsers.completionCommand;
|
|
498
|
+
if ((requestedCommand === "completion" || requestedCommand === "completions") && completionAsCommand && completionParsers.completionCommand) helpGeneratorParser = completionParsers.completionCommand;
|
|
478
499
|
else if (requestedCommand === "help" && helpAsCommand && helpParsers.helpCommand) helpGeneratorParser = helpParsers.helpCommand;
|
|
479
500
|
else if (requestedCommand === "version" && versionAsCommand && versionParsers.versionCommand) helpGeneratorParser = versionParsers.versionCommand;
|
|
480
501
|
else {
|
|
@@ -494,7 +515,7 @@ function run(parser, programName, args, options = {}) {
|
|
|
494
515
|
}
|
|
495
516
|
const doc = require_parser.getDocPage(helpGeneratorParser, classified.commands);
|
|
496
517
|
if (doc != null) {
|
|
497
|
-
const isMetaCommandHelp = requestedCommand === "completion" || requestedCommand === "help" || requestedCommand === "version";
|
|
518
|
+
const isMetaCommandHelp = (completionName === "singular" || completionName === "both" ? requestedCommand === "completion" : false) || (completionName === "plural" || completionName === "both" ? requestedCommand === "completions" : false) || requestedCommand === "help" || requestedCommand === "version";
|
|
498
519
|
const augmentedDoc = {
|
|
499
520
|
...doc,
|
|
500
521
|
brief: !isMetaCommandHelp ? brief ?? doc.brief : doc.brief,
|
package/dist/facade.d.cts
CHANGED
|
@@ -104,6 +104,16 @@ interface RunOptions<THelp, TError> {
|
|
|
104
104
|
* @default `"both"`
|
|
105
105
|
*/
|
|
106
106
|
readonly mode?: "command" | "option" | "both";
|
|
107
|
+
/**
|
|
108
|
+
* Determines whether to use singular or plural naming for completion command/option.
|
|
109
|
+
*
|
|
110
|
+
* - `"singular"`: Use `completion` / `--completion`
|
|
111
|
+
* - `"plural"`: Use `completions` / `--completions`
|
|
112
|
+
* - `"both"`: Use both singular and plural forms
|
|
113
|
+
*
|
|
114
|
+
* @default `"both"`
|
|
115
|
+
*/
|
|
116
|
+
readonly name?: "singular" | "plural" | "both";
|
|
107
117
|
/**
|
|
108
118
|
* Available shell completions. By default, includes `bash`, `fish`, `nu`,
|
|
109
119
|
* `pwsh`, and `zsh`. You can provide additional custom shell completions or
|
package/dist/facade.d.ts
CHANGED
|
@@ -104,6 +104,16 @@ interface RunOptions<THelp, TError> {
|
|
|
104
104
|
* @default `"both"`
|
|
105
105
|
*/
|
|
106
106
|
readonly mode?: "command" | "option" | "both";
|
|
107
|
+
/**
|
|
108
|
+
* Determines whether to use singular or plural naming for completion command/option.
|
|
109
|
+
*
|
|
110
|
+
* - `"singular"`: Use `completion` / `--completion`
|
|
111
|
+
* - `"plural"`: Use `completions` / `--completions`
|
|
112
|
+
* - `"both"`: Use both singular and plural forms
|
|
113
|
+
*
|
|
114
|
+
* @default `"both"`
|
|
115
|
+
*/
|
|
116
|
+
readonly name?: "singular" | "plural" | "both";
|
|
107
117
|
/**
|
|
108
118
|
* Available shell completions. By default, includes `bash`, `fish`, `nu`,
|
|
109
119
|
* `pwsh`, and `zsh`. You can provide additional custom shell completions or
|
package/dist/facade.js
CHANGED
|
@@ -54,27 +54,41 @@ function createVersionParser(mode) {
|
|
|
54
54
|
/**
|
|
55
55
|
* Creates completion parsers based on the specified mode.
|
|
56
56
|
*/
|
|
57
|
-
function createCompletionParser(mode, programName, availableShells) {
|
|
57
|
+
function createCompletionParser(mode, programName, availableShells, name = "both") {
|
|
58
58
|
const shellList = [];
|
|
59
59
|
for (const shell in availableShells) {
|
|
60
60
|
if (shellList.length > 0) shellList.push(text(", "));
|
|
61
61
|
shellList.push(value(shell));
|
|
62
62
|
}
|
|
63
|
-
const
|
|
63
|
+
const completionInner = object({
|
|
64
64
|
shell: optional(argument(string({ metavar: "SHELL" }), { description: message`Shell type (${shellList}). Generate completion script when used alone, or provide completions when followed by arguments.` })),
|
|
65
65
|
args: multiple(argument(string({ metavar: "ARG" }), { description: message`Command line arguments for completion suggestions (used by shell integration; you usually don't need to provide this).` }))
|
|
66
|
-
})
|
|
66
|
+
});
|
|
67
|
+
const commandName = name === "plural" ? "completions" : "completion";
|
|
68
|
+
const completionCommandConfig = {
|
|
67
69
|
brief: message`Generate shell completion script or provide completions.`,
|
|
68
70
|
description: message`Generate shell completion script or provide completions.`,
|
|
69
71
|
footer: message`Examples:
|
|
70
|
-
Bash: ${commandLine(`eval "$(${programName}
|
|
71
|
-
zsh: ${commandLine(`eval "$(${programName}
|
|
72
|
-
fish: ${commandLine(`eval "$(${programName}
|
|
73
|
-
PowerShell: ${commandLine(`${programName}
|
|
74
|
-
Nushell: ${commandLine(`${programName}
|
|
72
|
+
Bash: ${commandLine(`eval "$(${programName} ${commandName} bash)"`)}
|
|
73
|
+
zsh: ${commandLine(`eval "$(${programName} ${commandName} zsh)"`)}
|
|
74
|
+
fish: ${commandLine(`eval "$(${programName} ${commandName} fish)"`)}
|
|
75
|
+
PowerShell: ${commandLine(`${programName} ${commandName} pwsh > ${programName}-completion.ps1; . ./${programName}-completion.ps1`)}
|
|
76
|
+
Nushell: ${commandLine(`${programName} ${commandName} nu | save ${programName}-completion.nu; source ./${programName}-completion.nu`)}
|
|
75
77
|
`
|
|
76
|
-
}
|
|
77
|
-
const
|
|
78
|
+
};
|
|
79
|
+
const completionCommands = [];
|
|
80
|
+
if (name === "singular" || name === "both") completionCommands.push(command("completion", completionInner, completionCommandConfig));
|
|
81
|
+
if (name === "plural" || name === "both") completionCommands.push(command("completions", completionInner, completionCommandConfig));
|
|
82
|
+
const completionCommand = longestMatch(...completionCommands);
|
|
83
|
+
const completionOptionNames = [];
|
|
84
|
+
if (name === "singular" || name === "both") completionOptionNames.push("--completion");
|
|
85
|
+
if (name === "plural" || name === "both") completionOptionNames.push("--completions");
|
|
86
|
+
const completionOptionArgs = [
|
|
87
|
+
...completionOptionNames,
|
|
88
|
+
string({ metavar: "SHELL" }),
|
|
89
|
+
{ description: message`Generate shell completion script.` }
|
|
90
|
+
];
|
|
91
|
+
const completionOption = option(...completionOptionArgs);
|
|
78
92
|
switch (mode) {
|
|
79
93
|
case "command": return {
|
|
80
94
|
completionCommand,
|
|
@@ -412,6 +426,7 @@ function run(parser, programName, args, options = {}) {
|
|
|
412
426
|
const versionValue = options.version?.value ?? "";
|
|
413
427
|
const onVersion = options.version?.onShow ?? (() => ({}));
|
|
414
428
|
const completionMode = options.completion?.mode ?? "both";
|
|
429
|
+
const completionName = options.completion?.name ?? "both";
|
|
415
430
|
const onCompletion = options.completion?.onShow ?? (() => ({}));
|
|
416
431
|
const defaultShells = {
|
|
417
432
|
bash,
|
|
@@ -438,20 +453,26 @@ function run(parser, programName, args, options = {}) {
|
|
|
438
453
|
const completionParsers = completion === "none" ? {
|
|
439
454
|
completionCommand: null,
|
|
440
455
|
completionOption: null
|
|
441
|
-
} : createCompletionParser(completion, programName, availableShells);
|
|
456
|
+
} : createCompletionParser(completion, programName, availableShells, completionName);
|
|
442
457
|
if (options.completion) {
|
|
443
458
|
const hasHelpOption = args.includes("--help");
|
|
444
|
-
if ((completionMode === "command" || completionMode === "both") && args.length >= 1 && args[0] === "completion" && !hasHelpOption) return handleCompletion(args.slice(1), programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth);
|
|
459
|
+
if ((completionMode === "command" || completionMode === "both") && args.length >= 1 && ((completionName === "singular" || completionName === "both" ? args[0] === "completion" : false) || (completionName === "plural" || completionName === "both" ? args[0] === "completions" : false)) && !hasHelpOption) return handleCompletion(args.slice(1), programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth);
|
|
445
460
|
if (completionMode === "option" || completionMode === "both") for (let i = 0; i < args.length; i++) {
|
|
446
461
|
const arg = args[i];
|
|
447
|
-
|
|
448
|
-
|
|
462
|
+
const singularMatch = completionName === "singular" || completionName === "both" ? arg.startsWith("--completion=") : false;
|
|
463
|
+
const pluralMatch = completionName === "plural" || completionName === "both" ? arg.startsWith("--completions=") : false;
|
|
464
|
+
if (singularMatch || pluralMatch) {
|
|
465
|
+
const shell = arg.slice(arg.indexOf("=") + 1);
|
|
449
466
|
const completionArgs = args.slice(i + 1);
|
|
450
467
|
return handleCompletion([shell, ...completionArgs], programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth);
|
|
451
|
-
} else
|
|
452
|
-
const
|
|
453
|
-
const
|
|
454
|
-
|
|
468
|
+
} else {
|
|
469
|
+
const singularMatchExact = completionName === "singular" || completionName === "both" ? arg === "--completion" : false;
|
|
470
|
+
const pluralMatchExact = completionName === "plural" || completionName === "both" ? arg === "--completions" : false;
|
|
471
|
+
if ((singularMatchExact || pluralMatchExact) && i + 1 < args.length) {
|
|
472
|
+
const shell = args[i + 1];
|
|
473
|
+
const completionArgs = args.slice(i + 2);
|
|
474
|
+
return handleCompletion([shell, ...completionArgs], programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth);
|
|
475
|
+
}
|
|
455
476
|
}
|
|
456
477
|
}
|
|
457
478
|
}
|
|
@@ -474,7 +495,7 @@ function run(parser, programName, args, options = {}) {
|
|
|
474
495
|
const versionAsCommand = version === "command" || version === "both";
|
|
475
496
|
const completionAsCommand = completion === "command" || completion === "both";
|
|
476
497
|
const requestedCommand = classified.commands[0];
|
|
477
|
-
if (requestedCommand === "completion" && completionAsCommand && completionParsers.completionCommand) helpGeneratorParser = completionParsers.completionCommand;
|
|
498
|
+
if ((requestedCommand === "completion" || requestedCommand === "completions") && completionAsCommand && completionParsers.completionCommand) helpGeneratorParser = completionParsers.completionCommand;
|
|
478
499
|
else if (requestedCommand === "help" && helpAsCommand && helpParsers.helpCommand) helpGeneratorParser = helpParsers.helpCommand;
|
|
479
500
|
else if (requestedCommand === "version" && versionAsCommand && versionParsers.versionCommand) helpGeneratorParser = versionParsers.versionCommand;
|
|
480
501
|
else {
|
|
@@ -494,7 +515,7 @@ function run(parser, programName, args, options = {}) {
|
|
|
494
515
|
}
|
|
495
516
|
const doc = getDocPage(helpGeneratorParser, classified.commands);
|
|
496
517
|
if (doc != null) {
|
|
497
|
-
const isMetaCommandHelp = requestedCommand === "completion" || requestedCommand === "help" || requestedCommand === "version";
|
|
518
|
+
const isMetaCommandHelp = (completionName === "singular" || completionName === "both" ? requestedCommand === "completion" : false) || (completionName === "plural" || completionName === "both" ? requestedCommand === "completions" : false) || requestedCommand === "help" || requestedCommand === "version";
|
|
498
519
|
const augmentedDoc = {
|
|
499
520
|
...doc,
|
|
500
521
|
brief: !isMetaCommandHelp ? brief ?? doc.brief : doc.brief,
|
package/dist/index.cjs
CHANGED
|
@@ -19,6 +19,7 @@ exports.commandLine = require_message.commandLine;
|
|
|
19
19
|
exports.concat = require_constructs.concat;
|
|
20
20
|
exports.constant = require_primitives.constant;
|
|
21
21
|
exports.envVar = require_message.envVar;
|
|
22
|
+
exports.extractArgumentMetavars = require_usage.extractArgumentMetavars;
|
|
22
23
|
exports.extractCommandNames = require_usage.extractCommandNames;
|
|
23
24
|
exports.extractOptionNames = require_usage.extractOptionNames;
|
|
24
25
|
exports.fish = require_completion.fish;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Message, MessageFormatOptions, MessageTerm, commandLine, envVar, formatMessage, message, metavar, optionName, optionNames, text, value, values } from "./message.cjs";
|
|
2
|
-
import { OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, extractCommandNames, extractOptionNames, formatUsage, formatUsageTerm, normalizeUsage } from "./usage.cjs";
|
|
2
|
+
import { OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, extractArgumentMetavars, extractCommandNames, extractOptionNames, formatUsage, formatUsageTerm, normalizeUsage } from "./usage.cjs";
|
|
3
3
|
import { DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, ShowDefaultOptions, formatDocPage } from "./doc.cjs";
|
|
4
4
|
import { ChoiceOptions, FloatOptions, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, StringOptions, UrlOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, choice, float, integer, isValueParser, locale, string, url, uuid } from "./valueparser.cjs";
|
|
5
5
|
import { MultipleErrorOptions, MultipleOptions, WithDefaultError, WithDefaultOptions, map, multiple, optional, withDefault } from "./modifiers.cjs";
|
|
6
6
|
import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, argument, command, constant, flag, option } from "./primitives.cjs";
|
|
7
7
|
import { DocState, InferValue, Parser, ParserContext, ParserResult, Result, Suggestion, getDocPage, parse, suggest } from "./parser.cjs";
|
|
8
|
-
import { LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, group, longestMatch, merge, object, or, tuple } from "./constructs.cjs";
|
|
8
|
+
import { LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, group, longestMatch, merge, object, or, tuple } from "./constructs.cjs";
|
|
9
9
|
import { ShellCompletion, bash, fish, nu, pwsh, zsh } from "./completion.cjs";
|
|
10
10
|
import { RunError, RunOptions, run } from "./facade.cjs";
|
|
11
|
-
export { ArgumentErrorOptions, ArgumentOptions, ChoiceOptions, CommandErrorOptions, CommandOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, FlagErrorOptions, FlagOptions, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, Message, MessageFormatOptions, MessageTerm, MultipleErrorOptions, MultipleOptions, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionName, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, Result, RunError, RunOptions, ShellCompletion, ShowDefaultOptions, StringOptions, Suggestion, TupleOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, WithDefaultError, WithDefaultOptions, argument, bash, choice, command, commandLine, concat, constant, envVar, extractCommandNames, extractOptionNames, fish, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, group, integer, isValueParser, locale, longestMatch, map, merge, message, metavar, multiple, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, pwsh, run, string, suggest, text, tuple, url, uuid, value, values, withDefault, zsh };
|
|
11
|
+
export { ArgumentErrorOptions, ArgumentOptions, ChoiceOptions, CommandErrorOptions, CommandOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, FlagErrorOptions, FlagOptions, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, Message, MessageFormatOptions, MessageTerm, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionName, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, Result, RunError, RunOptions, ShellCompletion, ShowDefaultOptions, StringOptions, Suggestion, TupleOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, WithDefaultError, WithDefaultOptions, argument, bash, choice, command, commandLine, concat, constant, envVar, extractArgumentMetavars, extractCommandNames, extractOptionNames, fish, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, group, integer, isValueParser, locale, longestMatch, map, merge, message, metavar, multiple, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, pwsh, run, string, suggest, text, tuple, url, uuid, value, values, withDefault, zsh };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Message, MessageFormatOptions, MessageTerm, commandLine, envVar, formatMessage, message, metavar, optionName, optionNames, text, value, values } from "./message.js";
|
|
2
|
-
import { OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, extractCommandNames, extractOptionNames, formatUsage, formatUsageTerm, normalizeUsage } from "./usage.js";
|
|
2
|
+
import { OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, extractArgumentMetavars, extractCommandNames, extractOptionNames, formatUsage, formatUsageTerm, normalizeUsage } from "./usage.js";
|
|
3
3
|
import { DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, ShowDefaultOptions, formatDocPage } from "./doc.js";
|
|
4
4
|
import { ChoiceOptions, FloatOptions, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, StringOptions, UrlOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, choice, float, integer, isValueParser, locale, string, url, uuid } from "./valueparser.js";
|
|
5
5
|
import { MultipleErrorOptions, MultipleOptions, WithDefaultError, WithDefaultOptions, map, multiple, optional, withDefault } from "./modifiers.js";
|
|
6
6
|
import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, argument, command, constant, flag, option } from "./primitives.js";
|
|
7
7
|
import { DocState, InferValue, Parser, ParserContext, ParserResult, Result, Suggestion, getDocPage, parse, suggest } from "./parser.js";
|
|
8
|
-
import { LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, group, longestMatch, merge, object, or, tuple } from "./constructs.js";
|
|
8
|
+
import { LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, group, longestMatch, merge, object, or, tuple } from "./constructs.js";
|
|
9
9
|
import { ShellCompletion, bash, fish, nu, pwsh, zsh } from "./completion.js";
|
|
10
10
|
import { RunError, RunOptions, run } from "./facade.js";
|
|
11
|
-
export { ArgumentErrorOptions, ArgumentOptions, ChoiceOptions, CommandErrorOptions, CommandOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, FlagErrorOptions, FlagOptions, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, Message, MessageFormatOptions, MessageTerm, MultipleErrorOptions, MultipleOptions, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionName, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, Result, RunError, RunOptions, ShellCompletion, ShowDefaultOptions, StringOptions, Suggestion, TupleOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, WithDefaultError, WithDefaultOptions, argument, bash, choice, command, commandLine, concat, constant, envVar, extractCommandNames, extractOptionNames, fish, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, group, integer, isValueParser, locale, longestMatch, map, merge, message, metavar, multiple, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, pwsh, run, string, suggest, text, tuple, url, uuid, value, values, withDefault, zsh };
|
|
11
|
+
export { ArgumentErrorOptions, ArgumentOptions, ChoiceOptions, CommandErrorOptions, CommandOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, FlagErrorOptions, FlagOptions, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, Message, MessageFormatOptions, MessageTerm, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionName, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, Result, RunError, RunOptions, ShellCompletion, ShowDefaultOptions, StringOptions, Suggestion, TupleOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, WithDefaultError, WithDefaultOptions, argument, bash, choice, command, commandLine, concat, constant, envVar, extractArgumentMetavars, extractCommandNames, extractOptionNames, fish, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, group, integer, isValueParser, locale, longestMatch, map, merge, message, metavar, multiple, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, pwsh, run, string, suggest, text, tuple, url, uuid, value, values, withDefault, zsh };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { commandLine, envVar, formatMessage, message, metavar, optionName, optionNames, text, value, values } from "./message.js";
|
|
2
|
-
import { extractCommandNames, extractOptionNames, formatUsage, formatUsageTerm, normalizeUsage } from "./usage.js";
|
|
2
|
+
import { extractArgumentMetavars, extractCommandNames, extractOptionNames, formatUsage, formatUsageTerm, normalizeUsage } from "./usage.js";
|
|
3
3
|
import { concat, group, longestMatch, merge, object, or, tuple } from "./constructs.js";
|
|
4
4
|
import { formatDocPage } from "./doc.js";
|
|
5
5
|
import { bash, fish, nu, pwsh, zsh } from "./completion.js";
|
|
@@ -9,4 +9,4 @@ import { argument, command, constant, flag, option } from "./primitives.js";
|
|
|
9
9
|
import { getDocPage, parse, suggest } from "./parser.js";
|
|
10
10
|
import { RunError, run } from "./facade.js";
|
|
11
11
|
|
|
12
|
-
export { RunError, WithDefaultError, argument, bash, choice, command, commandLine, concat, constant, envVar, extractCommandNames, extractOptionNames, fish, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, group, integer, isValueParser, locale, longestMatch, map, merge, message, metavar, multiple, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, pwsh, run, string, suggest, text, tuple, url, uuid, value, values, withDefault, zsh };
|
|
12
|
+
export { RunError, WithDefaultError, argument, bash, choice, command, commandLine, concat, constant, envVar, extractArgumentMetavars, extractCommandNames, extractOptionNames, fish, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, group, integer, isValueParser, locale, longestMatch, map, merge, message, metavar, multiple, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, pwsh, run, string, suggest, text, tuple, url, uuid, value, values, withDefault, zsh };
|
package/dist/parser.d.cts
CHANGED
|
@@ -4,7 +4,7 @@ import { DocFragments, DocPage } from "./doc.cjs";
|
|
|
4
4
|
import { ValueParserResult } from "./valueparser.cjs";
|
|
5
5
|
import { MultipleErrorOptions, MultipleOptions, WithDefaultError, WithDefaultOptions, map, multiple, optional, withDefault } from "./modifiers.cjs";
|
|
6
6
|
import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, argument, command, constant, flag, option } from "./primitives.cjs";
|
|
7
|
-
import { LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, group, longestMatch, merge, object, or, tuple } from "./constructs.cjs";
|
|
7
|
+
import { LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, group, longestMatch, merge, object, or, tuple } from "./constructs.cjs";
|
|
8
8
|
|
|
9
9
|
//#region src/parser.d.ts
|
|
10
10
|
|
|
@@ -323,4 +323,4 @@ declare function suggest<T>(parser: Parser<T, unknown>, args: readonly [string,
|
|
|
323
323
|
*/
|
|
324
324
|
declare function getDocPage(parser: Parser<unknown, unknown>, args?: readonly string[]): DocPage | undefined;
|
|
325
325
|
//#endregion
|
|
326
|
-
export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, DocState, FlagErrorOptions, FlagOptions, InferValue, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, MultipleErrorOptions, MultipleOptions, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, Result, Suggestion, TupleOptions, WithDefaultError, WithDefaultOptions, argument, command, concat, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, suggest, tuple, withDefault };
|
|
326
|
+
export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, DocState, FlagErrorOptions, FlagOptions, InferValue, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, Result, Suggestion, TupleOptions, WithDefaultError, WithDefaultOptions, argument, command, concat, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, suggest, tuple, withDefault };
|
package/dist/parser.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { DocFragments, DocPage } from "./doc.js";
|
|
|
4
4
|
import { ValueParserResult } from "./valueparser.js";
|
|
5
5
|
import { MultipleErrorOptions, MultipleOptions, WithDefaultError, WithDefaultOptions, map, multiple, optional, withDefault } from "./modifiers.js";
|
|
6
6
|
import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, argument, command, constant, flag, option } from "./primitives.js";
|
|
7
|
-
import { LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, group, longestMatch, merge, object, or, tuple } from "./constructs.js";
|
|
7
|
+
import { LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, group, longestMatch, merge, object, or, tuple } from "./constructs.js";
|
|
8
8
|
|
|
9
9
|
//#region src/parser.d.ts
|
|
10
10
|
|
|
@@ -323,4 +323,4 @@ declare function suggest<T>(parser: Parser<T, unknown>, args: readonly [string,
|
|
|
323
323
|
*/
|
|
324
324
|
declare function getDocPage(parser: Parser<unknown, unknown>, args?: readonly string[]): DocPage | undefined;
|
|
325
325
|
//#endregion
|
|
326
|
-
export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, DocState, FlagErrorOptions, FlagOptions, InferValue, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, MultipleErrorOptions, MultipleOptions, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, Result, Suggestion, TupleOptions, WithDefaultError, WithDefaultOptions, argument, command, concat, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, suggest, tuple, withDefault };
|
|
326
|
+
export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, DocState, FlagErrorOptions, FlagOptions, InferValue, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, Result, Suggestion, TupleOptions, WithDefaultError, WithDefaultOptions, argument, command, concat, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, suggest, tuple, withDefault };
|
package/dist/usage.cjs
CHANGED
|
@@ -63,6 +63,38 @@ function extractCommandNames(usage) {
|
|
|
63
63
|
return names;
|
|
64
64
|
}
|
|
65
65
|
/**
|
|
66
|
+
* Extracts all argument metavars from a Usage array.
|
|
67
|
+
*
|
|
68
|
+
* This function recursively traverses the usage structure and collects
|
|
69
|
+
* all argument metavariable names, similar to {@link extractOptionNames}
|
|
70
|
+
* and {@link extractCommandNames}.
|
|
71
|
+
*
|
|
72
|
+
* @param usage The usage structure to extract argument metavars from.
|
|
73
|
+
* @returns A Set of all argument metavars found in the usage structure.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* const usage: Usage = [
|
|
78
|
+
* { type: "argument", metavar: "FILE" },
|
|
79
|
+
* { type: "argument", metavar: "OUTPUT" },
|
|
80
|
+
* ];
|
|
81
|
+
* const metavars = extractArgumentMetavars(usage);
|
|
82
|
+
* // metavars = Set(["FILE", "OUTPUT"])
|
|
83
|
+
* ```
|
|
84
|
+
* @since 0.9.0
|
|
85
|
+
*/
|
|
86
|
+
function extractArgumentMetavars(usage) {
|
|
87
|
+
const metavars = /* @__PURE__ */ new Set();
|
|
88
|
+
function traverseUsage(terms) {
|
|
89
|
+
if (!terms || !Array.isArray(terms)) return;
|
|
90
|
+
for (const term of terms) if (term.type === "argument") metavars.add(term.metavar);
|
|
91
|
+
else if (term.type === "optional" || term.type === "multiple") traverseUsage(term.terms);
|
|
92
|
+
else if (term.type === "exclusive") for (const exclusiveUsage of term.terms) traverseUsage(exclusiveUsage);
|
|
93
|
+
}
|
|
94
|
+
traverseUsage(usage);
|
|
95
|
+
return metavars;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
66
98
|
* Formats a usage description into a human-readable string representation
|
|
67
99
|
* suitable for command-line help text.
|
|
68
100
|
*
|
|
@@ -299,6 +331,7 @@ function* formatUsageTermInternal(term, options) {
|
|
|
299
331
|
}
|
|
300
332
|
|
|
301
333
|
//#endregion
|
|
334
|
+
exports.extractArgumentMetavars = extractArgumentMetavars;
|
|
302
335
|
exports.extractCommandNames = extractCommandNames;
|
|
303
336
|
exports.extractOptionNames = extractOptionNames;
|
|
304
337
|
exports.formatUsage = formatUsage;
|
package/dist/usage.d.cts
CHANGED
|
@@ -158,6 +158,28 @@ declare function extractOptionNames(usage: Usage): Set<string>;
|
|
|
158
158
|
* @since 0.7.0
|
|
159
159
|
*/
|
|
160
160
|
declare function extractCommandNames(usage: Usage): Set<string>;
|
|
161
|
+
/**
|
|
162
|
+
* Extracts all argument metavars from a Usage array.
|
|
163
|
+
*
|
|
164
|
+
* This function recursively traverses the usage structure and collects
|
|
165
|
+
* all argument metavariable names, similar to {@link extractOptionNames}
|
|
166
|
+
* and {@link extractCommandNames}.
|
|
167
|
+
*
|
|
168
|
+
* @param usage The usage structure to extract argument metavars from.
|
|
169
|
+
* @returns A Set of all argument metavars found in the usage structure.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* const usage: Usage = [
|
|
174
|
+
* { type: "argument", metavar: "FILE" },
|
|
175
|
+
* { type: "argument", metavar: "OUTPUT" },
|
|
176
|
+
* ];
|
|
177
|
+
* const metavars = extractArgumentMetavars(usage);
|
|
178
|
+
* // metavars = Set(["FILE", "OUTPUT"])
|
|
179
|
+
* ```
|
|
180
|
+
* @since 0.9.0
|
|
181
|
+
*/
|
|
182
|
+
declare function extractArgumentMetavars(usage: Usage): Set<string>;
|
|
161
183
|
/**
|
|
162
184
|
* Options for formatting usage descriptions.
|
|
163
185
|
*/
|
|
@@ -256,4 +278,4 @@ interface UsageTermFormatOptions extends UsageFormatOptions {
|
|
|
256
278
|
*/
|
|
257
279
|
declare function formatUsageTerm(term: UsageTerm, options?: UsageTermFormatOptions): string;
|
|
258
280
|
//#endregion
|
|
259
|
-
export { OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, extractCommandNames, extractOptionNames, formatUsage, formatUsageTerm, normalizeUsage };
|
|
281
|
+
export { OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, extractArgumentMetavars, extractCommandNames, extractOptionNames, formatUsage, formatUsageTerm, normalizeUsage };
|
package/dist/usage.d.ts
CHANGED
|
@@ -158,6 +158,28 @@ declare function extractOptionNames(usage: Usage): Set<string>;
|
|
|
158
158
|
* @since 0.7.0
|
|
159
159
|
*/
|
|
160
160
|
declare function extractCommandNames(usage: Usage): Set<string>;
|
|
161
|
+
/**
|
|
162
|
+
* Extracts all argument metavars from a Usage array.
|
|
163
|
+
*
|
|
164
|
+
* This function recursively traverses the usage structure and collects
|
|
165
|
+
* all argument metavariable names, similar to {@link extractOptionNames}
|
|
166
|
+
* and {@link extractCommandNames}.
|
|
167
|
+
*
|
|
168
|
+
* @param usage The usage structure to extract argument metavars from.
|
|
169
|
+
* @returns A Set of all argument metavars found in the usage structure.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* const usage: Usage = [
|
|
174
|
+
* { type: "argument", metavar: "FILE" },
|
|
175
|
+
* { type: "argument", metavar: "OUTPUT" },
|
|
176
|
+
* ];
|
|
177
|
+
* const metavars = extractArgumentMetavars(usage);
|
|
178
|
+
* // metavars = Set(["FILE", "OUTPUT"])
|
|
179
|
+
* ```
|
|
180
|
+
* @since 0.9.0
|
|
181
|
+
*/
|
|
182
|
+
declare function extractArgumentMetavars(usage: Usage): Set<string>;
|
|
161
183
|
/**
|
|
162
184
|
* Options for formatting usage descriptions.
|
|
163
185
|
*/
|
|
@@ -256,4 +278,4 @@ interface UsageTermFormatOptions extends UsageFormatOptions {
|
|
|
256
278
|
*/
|
|
257
279
|
declare function formatUsageTerm(term: UsageTerm, options?: UsageTermFormatOptions): string;
|
|
258
280
|
//#endregion
|
|
259
|
-
export { OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, extractCommandNames, extractOptionNames, formatUsage, formatUsageTerm, normalizeUsage };
|
|
281
|
+
export { OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, extractArgumentMetavars, extractCommandNames, extractOptionNames, formatUsage, formatUsageTerm, normalizeUsage };
|
package/dist/usage.js
CHANGED
|
@@ -62,6 +62,38 @@ function extractCommandNames(usage) {
|
|
|
62
62
|
return names;
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
|
+
* Extracts all argument metavars from a Usage array.
|
|
66
|
+
*
|
|
67
|
+
* This function recursively traverses the usage structure and collects
|
|
68
|
+
* all argument metavariable names, similar to {@link extractOptionNames}
|
|
69
|
+
* and {@link extractCommandNames}.
|
|
70
|
+
*
|
|
71
|
+
* @param usage The usage structure to extract argument metavars from.
|
|
72
|
+
* @returns A Set of all argument metavars found in the usage structure.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const usage: Usage = [
|
|
77
|
+
* { type: "argument", metavar: "FILE" },
|
|
78
|
+
* { type: "argument", metavar: "OUTPUT" },
|
|
79
|
+
* ];
|
|
80
|
+
* const metavars = extractArgumentMetavars(usage);
|
|
81
|
+
* // metavars = Set(["FILE", "OUTPUT"])
|
|
82
|
+
* ```
|
|
83
|
+
* @since 0.9.0
|
|
84
|
+
*/
|
|
85
|
+
function extractArgumentMetavars(usage) {
|
|
86
|
+
const metavars = /* @__PURE__ */ new Set();
|
|
87
|
+
function traverseUsage(terms) {
|
|
88
|
+
if (!terms || !Array.isArray(terms)) return;
|
|
89
|
+
for (const term of terms) if (term.type === "argument") metavars.add(term.metavar);
|
|
90
|
+
else if (term.type === "optional" || term.type === "multiple") traverseUsage(term.terms);
|
|
91
|
+
else if (term.type === "exclusive") for (const exclusiveUsage of term.terms) traverseUsage(exclusiveUsage);
|
|
92
|
+
}
|
|
93
|
+
traverseUsage(usage);
|
|
94
|
+
return metavars;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
65
97
|
* Formats a usage description into a human-readable string representation
|
|
66
98
|
* suitable for command-line help text.
|
|
67
99
|
*
|
|
@@ -298,4 +330,4 @@ function* formatUsageTermInternal(term, options) {
|
|
|
298
330
|
}
|
|
299
331
|
|
|
300
332
|
//#endregion
|
|
301
|
-
export { extractCommandNames, extractOptionNames, formatUsage, formatUsageTerm, normalizeUsage };
|
|
333
|
+
export { extractArgumentMetavars, extractCommandNames, extractOptionNames, formatUsage, formatUsageTerm, normalizeUsage };
|