@optique/core 0.9.3 → 0.9.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constructs.cjs +72 -12
- package/dist/constructs.js +74 -14
- package/dist/doc.d.cts +6 -0
- package/dist/doc.d.ts +6 -0
- package/dist/facade.cjs +8 -6
- package/dist/facade.js +8 -6
- package/dist/parser.cjs +2 -1
- package/dist/parser.js +2 -1
- package/dist/primitives.cjs +1 -0
- package/dist/primitives.js +1 -0
- package/dist/suggestion.cjs +1 -0
- package/dist/suggestion.js +1 -1
- package/package.json +1 -1
package/dist/constructs.cjs
CHANGED
|
@@ -4,6 +4,57 @@ const require_suggestion = require('./suggestion.cjs');
|
|
|
4
4
|
|
|
5
5
|
//#region src/constructs.ts
|
|
6
6
|
/**
|
|
7
|
+
* Collects option names and command names that are valid at the current
|
|
8
|
+
* parse position by walking the usage tree. Only "leading" candidates
|
|
9
|
+
* (those reachable before a required positional argument) are collected.
|
|
10
|
+
*/
|
|
11
|
+
function collectLeadingCandidates(terms, optionNames, commandNames) {
|
|
12
|
+
if (!terms || !Array.isArray(terms)) return true;
|
|
13
|
+
for (const term of terms) {
|
|
14
|
+
if (term.type === "option") {
|
|
15
|
+
for (const name of term.names) optionNames.add(name);
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
if (term.type === "command") {
|
|
19
|
+
commandNames.add(term.name);
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
if (term.type === "argument") return false;
|
|
23
|
+
if (term.type === "optional") {
|
|
24
|
+
collectLeadingCandidates(term.terms, optionNames, commandNames);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (term.type === "multiple") {
|
|
28
|
+
collectLeadingCandidates(term.terms, optionNames, commandNames);
|
|
29
|
+
if (term.min === 0) continue;
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
if (term.type === "exclusive") {
|
|
33
|
+
let allAlternativesSkippable = true;
|
|
34
|
+
for (const exclusiveUsage of term.terms) {
|
|
35
|
+
const alternativeSkippable = collectLeadingCandidates(exclusiveUsage, optionNames, commandNames);
|
|
36
|
+
allAlternativesSkippable = allAlternativesSkippable && alternativeSkippable;
|
|
37
|
+
}
|
|
38
|
+
if (allAlternativesSkippable) continue;
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
function createUnexpectedInputErrorWithScopedSuggestions(baseError, invalidInput, parsers, customFormatter) {
|
|
45
|
+
const options = /* @__PURE__ */ new Set();
|
|
46
|
+
const commands = /* @__PURE__ */ new Set();
|
|
47
|
+
for (const parser of parsers) collectLeadingCandidates(parser.usage, options, commands);
|
|
48
|
+
const candidates = new Set([...options, ...commands]);
|
|
49
|
+
const suggestions = require_suggestion.findSimilar(invalidInput, candidates, require_suggestion.DEFAULT_FIND_SIMILAR_OPTIONS);
|
|
50
|
+
const suggestionMsg = customFormatter ? customFormatter(suggestions) : require_suggestion.createSuggestionMessage(suggestions);
|
|
51
|
+
return suggestionMsg.length > 0 ? [
|
|
52
|
+
...baseError,
|
|
53
|
+
require_message.text("\n\n"),
|
|
54
|
+
...suggestionMsg
|
|
55
|
+
] : baseError;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
7
58
|
* Checks if the given token is an option name that requires a value
|
|
8
59
|
* (i.e., has a metavar) within the given usage terms.
|
|
9
60
|
* @param usage The usage terms to search through.
|
|
@@ -202,16 +253,6 @@ function getNoMatchError(options, noMatchContext) {
|
|
|
202
253
|
return customNoMatch ? typeof customNoMatch === "function" ? customNoMatch(noMatchContext) : customNoMatch : generateNoMatchError(noMatchContext);
|
|
203
254
|
}
|
|
204
255
|
/**
|
|
205
|
-
* Creates default error for parse() method when buffer is not empty.
|
|
206
|
-
* Shared by or() and longestMatch().
|
|
207
|
-
* @internal
|
|
208
|
-
*/
|
|
209
|
-
function createUnexpectedInputError(token, usage, options) {
|
|
210
|
-
const defaultMsg = require_message.message`Unexpected option or subcommand: ${require_message.optionName(token)}.`;
|
|
211
|
-
if (options?.errors?.unexpectedInput != null) return typeof options.errors.unexpectedInput === "function" ? options.errors.unexpectedInput(token) : options.errors.unexpectedInput;
|
|
212
|
-
return require_suggestion.createErrorWithSuggestions(defaultMsg, token, usage, "both", options?.errors?.suggestions);
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
256
|
* @since 0.5.0
|
|
216
257
|
*/
|
|
217
258
|
function or(...args) {
|
|
@@ -230,7 +271,12 @@ function or(...args) {
|
|
|
230
271
|
const syncParsers = parsers;
|
|
231
272
|
const getInitialError = (context) => ({
|
|
232
273
|
consumed: 0,
|
|
233
|
-
error: context.buffer.length < 1 ? getNoMatchError(options, noMatchContext) :
|
|
274
|
+
error: context.buffer.length < 1 ? getNoMatchError(options, noMatchContext) : (() => {
|
|
275
|
+
const token = context.buffer[0];
|
|
276
|
+
const defaultMsg = require_message.message`Unexpected option or subcommand: ${require_message.optionName(token)}.`;
|
|
277
|
+
if (options?.errors?.unexpectedInput != null) return typeof options.errors.unexpectedInput === "function" ? options.errors.unexpectedInput(token) : options.errors.unexpectedInput;
|
|
278
|
+
return createUnexpectedInputErrorWithScopedSuggestions(defaultMsg, token, parsers, options?.errors?.suggestions);
|
|
279
|
+
})()
|
|
234
280
|
});
|
|
235
281
|
const parseSync = (context) => {
|
|
236
282
|
let error = getInitialError(context);
|
|
@@ -314,7 +360,9 @@ function or(...args) {
|
|
|
314
360
|
},
|
|
315
361
|
suggest: createExclusiveSuggest(parsers, isAsync),
|
|
316
362
|
getDocFragments(state, _defaultValue) {
|
|
363
|
+
let brief;
|
|
317
364
|
let description;
|
|
365
|
+
let footer;
|
|
318
366
|
let fragments;
|
|
319
367
|
if (state.kind === "unavailable" || state.state == null) fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }, void 0).fragments);
|
|
320
368
|
else {
|
|
@@ -324,7 +372,9 @@ function or(...args) {
|
|
|
324
372
|
state: parserResult.next.state
|
|
325
373
|
} : { kind: "unavailable" };
|
|
326
374
|
const docFragments = parsers[index].getDocFragments(innerState, void 0);
|
|
375
|
+
brief = docFragments.brief;
|
|
327
376
|
description = docFragments.description;
|
|
377
|
+
footer = docFragments.footer;
|
|
328
378
|
fragments = docFragments.fragments;
|
|
329
379
|
}
|
|
330
380
|
const entries = fragments.filter((f) => f.type === "entry");
|
|
@@ -335,7 +385,9 @@ function or(...args) {
|
|
|
335
385
|
else sections.push(fragment);
|
|
336
386
|
}
|
|
337
387
|
return {
|
|
388
|
+
brief,
|
|
338
389
|
description,
|
|
390
|
+
footer,
|
|
339
391
|
fragments: [...sections.map((s) => ({
|
|
340
392
|
...s,
|
|
341
393
|
type: "section"
|
|
@@ -366,7 +418,12 @@ function longestMatch(...args) {
|
|
|
366
418
|
const syncParsers = parsers;
|
|
367
419
|
const getInitialError = (context) => ({
|
|
368
420
|
consumed: 0,
|
|
369
|
-
error: context.buffer.length < 1 ? getNoMatchError(options, noMatchContext) :
|
|
421
|
+
error: context.buffer.length < 1 ? getNoMatchError(options, noMatchContext) : (() => {
|
|
422
|
+
const token = context.buffer[0];
|
|
423
|
+
const defaultMsg = require_message.message`Unexpected option or subcommand: ${require_message.optionName(token)}.`;
|
|
424
|
+
if (options?.errors?.unexpectedInput != null) return typeof options.errors.unexpectedInput === "function" ? options.errors.unexpectedInput(token) : options.errors.unexpectedInput;
|
|
425
|
+
return createUnexpectedInputErrorWithScopedSuggestions(defaultMsg, token, parsers, options?.errors?.suggestions);
|
|
426
|
+
})()
|
|
370
427
|
});
|
|
371
428
|
const parseSync = (context) => {
|
|
372
429
|
let bestMatch = null;
|
|
@@ -452,6 +509,7 @@ function longestMatch(...args) {
|
|
|
452
509
|
},
|
|
453
510
|
suggest: createExclusiveSuggest(parsers, isAsync),
|
|
454
511
|
getDocFragments(state, _defaultValue) {
|
|
512
|
+
let brief;
|
|
455
513
|
let description;
|
|
456
514
|
let footer;
|
|
457
515
|
let fragments;
|
|
@@ -463,12 +521,14 @@ function longestMatch(...args) {
|
|
|
463
521
|
kind: "available",
|
|
464
522
|
state: result.next.state
|
|
465
523
|
});
|
|
524
|
+
brief = docResult.brief;
|
|
466
525
|
description = docResult.description;
|
|
467
526
|
footer = docResult.footer;
|
|
468
527
|
fragments = docResult.fragments;
|
|
469
528
|
} else fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }).fragments);
|
|
470
529
|
}
|
|
471
530
|
return {
|
|
531
|
+
brief,
|
|
472
532
|
description,
|
|
473
533
|
fragments,
|
|
474
534
|
footer
|
package/dist/constructs.js
CHANGED
|
@@ -1,9 +1,60 @@
|
|
|
1
|
-
import { message, optionName, values } from "./message.js";
|
|
1
|
+
import { message, optionName, text, values } from "./message.js";
|
|
2
2
|
import { extractArgumentMetavars, extractCommandNames, extractOptionNames } from "./usage.js";
|
|
3
|
-
import { createErrorWithSuggestions, deduplicateSuggestions } from "./suggestion.js";
|
|
3
|
+
import { DEFAULT_FIND_SIMILAR_OPTIONS, createErrorWithSuggestions, createSuggestionMessage, deduplicateSuggestions, findSimilar } from "./suggestion.js";
|
|
4
4
|
|
|
5
5
|
//#region src/constructs.ts
|
|
6
6
|
/**
|
|
7
|
+
* Collects option names and command names that are valid at the current
|
|
8
|
+
* parse position by walking the usage tree. Only "leading" candidates
|
|
9
|
+
* (those reachable before a required positional argument) are collected.
|
|
10
|
+
*/
|
|
11
|
+
function collectLeadingCandidates(terms, optionNames, commandNames) {
|
|
12
|
+
if (!terms || !Array.isArray(terms)) return true;
|
|
13
|
+
for (const term of terms) {
|
|
14
|
+
if (term.type === "option") {
|
|
15
|
+
for (const name of term.names) optionNames.add(name);
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
if (term.type === "command") {
|
|
19
|
+
commandNames.add(term.name);
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
if (term.type === "argument") return false;
|
|
23
|
+
if (term.type === "optional") {
|
|
24
|
+
collectLeadingCandidates(term.terms, optionNames, commandNames);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (term.type === "multiple") {
|
|
28
|
+
collectLeadingCandidates(term.terms, optionNames, commandNames);
|
|
29
|
+
if (term.min === 0) continue;
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
if (term.type === "exclusive") {
|
|
33
|
+
let allAlternativesSkippable = true;
|
|
34
|
+
for (const exclusiveUsage of term.terms) {
|
|
35
|
+
const alternativeSkippable = collectLeadingCandidates(exclusiveUsage, optionNames, commandNames);
|
|
36
|
+
allAlternativesSkippable = allAlternativesSkippable && alternativeSkippable;
|
|
37
|
+
}
|
|
38
|
+
if (allAlternativesSkippable) continue;
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
function createUnexpectedInputErrorWithScopedSuggestions(baseError, invalidInput, parsers, customFormatter) {
|
|
45
|
+
const options = /* @__PURE__ */ new Set();
|
|
46
|
+
const commands = /* @__PURE__ */ new Set();
|
|
47
|
+
for (const parser of parsers) collectLeadingCandidates(parser.usage, options, commands);
|
|
48
|
+
const candidates = new Set([...options, ...commands]);
|
|
49
|
+
const suggestions = findSimilar(invalidInput, candidates, DEFAULT_FIND_SIMILAR_OPTIONS);
|
|
50
|
+
const suggestionMsg = customFormatter ? customFormatter(suggestions) : createSuggestionMessage(suggestions);
|
|
51
|
+
return suggestionMsg.length > 0 ? [
|
|
52
|
+
...baseError,
|
|
53
|
+
text("\n\n"),
|
|
54
|
+
...suggestionMsg
|
|
55
|
+
] : baseError;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
7
58
|
* Checks if the given token is an option name that requires a value
|
|
8
59
|
* (i.e., has a metavar) within the given usage terms.
|
|
9
60
|
* @param usage The usage terms to search through.
|
|
@@ -202,16 +253,6 @@ function getNoMatchError(options, noMatchContext) {
|
|
|
202
253
|
return customNoMatch ? typeof customNoMatch === "function" ? customNoMatch(noMatchContext) : customNoMatch : generateNoMatchError(noMatchContext);
|
|
203
254
|
}
|
|
204
255
|
/**
|
|
205
|
-
* Creates default error for parse() method when buffer is not empty.
|
|
206
|
-
* Shared by or() and longestMatch().
|
|
207
|
-
* @internal
|
|
208
|
-
*/
|
|
209
|
-
function createUnexpectedInputError(token, usage, options) {
|
|
210
|
-
const defaultMsg = message`Unexpected option or subcommand: ${optionName(token)}.`;
|
|
211
|
-
if (options?.errors?.unexpectedInput != null) return typeof options.errors.unexpectedInput === "function" ? options.errors.unexpectedInput(token) : options.errors.unexpectedInput;
|
|
212
|
-
return createErrorWithSuggestions(defaultMsg, token, usage, "both", options?.errors?.suggestions);
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
256
|
* @since 0.5.0
|
|
216
257
|
*/
|
|
217
258
|
function or(...args) {
|
|
@@ -230,7 +271,12 @@ function or(...args) {
|
|
|
230
271
|
const syncParsers = parsers;
|
|
231
272
|
const getInitialError = (context) => ({
|
|
232
273
|
consumed: 0,
|
|
233
|
-
error: context.buffer.length < 1 ? getNoMatchError(options, noMatchContext) :
|
|
274
|
+
error: context.buffer.length < 1 ? getNoMatchError(options, noMatchContext) : (() => {
|
|
275
|
+
const token = context.buffer[0];
|
|
276
|
+
const defaultMsg = message`Unexpected option or subcommand: ${optionName(token)}.`;
|
|
277
|
+
if (options?.errors?.unexpectedInput != null) return typeof options.errors.unexpectedInput === "function" ? options.errors.unexpectedInput(token) : options.errors.unexpectedInput;
|
|
278
|
+
return createUnexpectedInputErrorWithScopedSuggestions(defaultMsg, token, parsers, options?.errors?.suggestions);
|
|
279
|
+
})()
|
|
234
280
|
});
|
|
235
281
|
const parseSync = (context) => {
|
|
236
282
|
let error = getInitialError(context);
|
|
@@ -314,7 +360,9 @@ function or(...args) {
|
|
|
314
360
|
},
|
|
315
361
|
suggest: createExclusiveSuggest(parsers, isAsync),
|
|
316
362
|
getDocFragments(state, _defaultValue) {
|
|
363
|
+
let brief;
|
|
317
364
|
let description;
|
|
365
|
+
let footer;
|
|
318
366
|
let fragments;
|
|
319
367
|
if (state.kind === "unavailable" || state.state == null) fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }, void 0).fragments);
|
|
320
368
|
else {
|
|
@@ -324,7 +372,9 @@ function or(...args) {
|
|
|
324
372
|
state: parserResult.next.state
|
|
325
373
|
} : { kind: "unavailable" };
|
|
326
374
|
const docFragments = parsers[index].getDocFragments(innerState, void 0);
|
|
375
|
+
brief = docFragments.brief;
|
|
327
376
|
description = docFragments.description;
|
|
377
|
+
footer = docFragments.footer;
|
|
328
378
|
fragments = docFragments.fragments;
|
|
329
379
|
}
|
|
330
380
|
const entries = fragments.filter((f) => f.type === "entry");
|
|
@@ -335,7 +385,9 @@ function or(...args) {
|
|
|
335
385
|
else sections.push(fragment);
|
|
336
386
|
}
|
|
337
387
|
return {
|
|
388
|
+
brief,
|
|
338
389
|
description,
|
|
390
|
+
footer,
|
|
339
391
|
fragments: [...sections.map((s) => ({
|
|
340
392
|
...s,
|
|
341
393
|
type: "section"
|
|
@@ -366,7 +418,12 @@ function longestMatch(...args) {
|
|
|
366
418
|
const syncParsers = parsers;
|
|
367
419
|
const getInitialError = (context) => ({
|
|
368
420
|
consumed: 0,
|
|
369
|
-
error: context.buffer.length < 1 ? getNoMatchError(options, noMatchContext) :
|
|
421
|
+
error: context.buffer.length < 1 ? getNoMatchError(options, noMatchContext) : (() => {
|
|
422
|
+
const token = context.buffer[0];
|
|
423
|
+
const defaultMsg = message`Unexpected option or subcommand: ${optionName(token)}.`;
|
|
424
|
+
if (options?.errors?.unexpectedInput != null) return typeof options.errors.unexpectedInput === "function" ? options.errors.unexpectedInput(token) : options.errors.unexpectedInput;
|
|
425
|
+
return createUnexpectedInputErrorWithScopedSuggestions(defaultMsg, token, parsers, options?.errors?.suggestions);
|
|
426
|
+
})()
|
|
370
427
|
});
|
|
371
428
|
const parseSync = (context) => {
|
|
372
429
|
let bestMatch = null;
|
|
@@ -452,6 +509,7 @@ function longestMatch(...args) {
|
|
|
452
509
|
},
|
|
453
510
|
suggest: createExclusiveSuggest(parsers, isAsync),
|
|
454
511
|
getDocFragments(state, _defaultValue) {
|
|
512
|
+
let brief;
|
|
455
513
|
let description;
|
|
456
514
|
let footer;
|
|
457
515
|
let fragments;
|
|
@@ -463,12 +521,14 @@ function longestMatch(...args) {
|
|
|
463
521
|
kind: "available",
|
|
464
522
|
state: result.next.state
|
|
465
523
|
});
|
|
524
|
+
brief = docResult.brief;
|
|
466
525
|
description = docResult.description;
|
|
467
526
|
footer = docResult.footer;
|
|
468
527
|
fragments = docResult.fragments;
|
|
469
528
|
} else fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }).fragments);
|
|
470
529
|
}
|
|
471
530
|
return {
|
|
531
|
+
brief,
|
|
472
532
|
description,
|
|
473
533
|
fragments,
|
|
474
534
|
footer
|
package/dist/doc.d.cts
CHANGED
|
@@ -60,6 +60,12 @@ type DocFragment = {
|
|
|
60
60
|
* a final document page.
|
|
61
61
|
*/
|
|
62
62
|
interface DocFragments {
|
|
63
|
+
/**
|
|
64
|
+
* An optional brief that provides a short summary for the collection
|
|
65
|
+
* of fragments.
|
|
66
|
+
* @since 0.7.12
|
|
67
|
+
*/
|
|
68
|
+
readonly brief?: Message;
|
|
63
69
|
/**
|
|
64
70
|
* An optional description that applies to the entire collection of fragments.
|
|
65
71
|
*/
|
package/dist/doc.d.ts
CHANGED
|
@@ -60,6 +60,12 @@ type DocFragment = {
|
|
|
60
60
|
* a final document page.
|
|
61
61
|
*/
|
|
62
62
|
interface DocFragments {
|
|
63
|
+
/**
|
|
64
|
+
* An optional brief that provides a short summary for the collection
|
|
65
|
+
* of fragments.
|
|
66
|
+
* @since 0.7.12
|
|
67
|
+
*/
|
|
68
|
+
readonly brief?: Message;
|
|
63
69
|
/**
|
|
64
70
|
* An optional description that applies to the entire collection of fragments.
|
|
65
71
|
*/
|
package/dist/facade.cjs
CHANGED
|
@@ -455,9 +455,9 @@ function runParser(parser, programName, args, options = {}) {
|
|
|
455
455
|
} else {
|
|
456
456
|
const singularMatchExact = completionName === "singular" || completionName === "both" ? arg === "--completion" : false;
|
|
457
457
|
const pluralMatchExact = completionName === "plural" || completionName === "both" ? arg === "--completions" : false;
|
|
458
|
-
if (
|
|
459
|
-
const shell = args[i + 1];
|
|
460
|
-
const completionArgs = args.slice(i + 2);
|
|
458
|
+
if (singularMatchExact || pluralMatchExact) {
|
|
459
|
+
const shell = i + 1 < args.length ? args[i + 1] : "";
|
|
460
|
+
const completionArgs = i + 1 < args.length ? args.slice(i + 2) : [];
|
|
461
461
|
return handleCompletion([shell, ...completionArgs], programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionMode, completionName);
|
|
462
462
|
}
|
|
463
463
|
}
|
|
@@ -556,11 +556,13 @@ function runParser(parser, programName, args, options = {}) {
|
|
|
556
556
|
const displayHelp = (doc) => {
|
|
557
557
|
if (doc != null) {
|
|
558
558
|
const isMetaCommandHelp = (completionName === "singular" || completionName === "both" ? requestedCommand === "completion" : false) || (completionName === "plural" || completionName === "both" ? requestedCommand === "completions" : false) || requestedCommand === "help" || requestedCommand === "version";
|
|
559
|
+
const isSubcommandHelp = classified.commands.length > 0;
|
|
560
|
+
const shouldOverride = !isMetaCommandHelp && !isSubcommandHelp;
|
|
559
561
|
const augmentedDoc = {
|
|
560
562
|
...doc,
|
|
561
|
-
brief:
|
|
562
|
-
description:
|
|
563
|
-
footer:
|
|
563
|
+
brief: shouldOverride ? brief ?? doc.brief : doc.brief ?? brief,
|
|
564
|
+
description: shouldOverride ? description ?? doc.description : doc.description ?? description,
|
|
565
|
+
footer: shouldOverride ? footer ?? doc.footer : doc.footer ?? footer
|
|
564
566
|
};
|
|
565
567
|
stdout(require_doc.formatDocPage(programName, augmentedDoc, {
|
|
566
568
|
colors,
|
package/dist/facade.js
CHANGED
|
@@ -455,9 +455,9 @@ function runParser(parser, programName, args, options = {}) {
|
|
|
455
455
|
} else {
|
|
456
456
|
const singularMatchExact = completionName === "singular" || completionName === "both" ? arg === "--completion" : false;
|
|
457
457
|
const pluralMatchExact = completionName === "plural" || completionName === "both" ? arg === "--completions" : false;
|
|
458
|
-
if (
|
|
459
|
-
const shell = args[i + 1];
|
|
460
|
-
const completionArgs = args.slice(i + 2);
|
|
458
|
+
if (singularMatchExact || pluralMatchExact) {
|
|
459
|
+
const shell = i + 1 < args.length ? args[i + 1] : "";
|
|
460
|
+
const completionArgs = i + 1 < args.length ? args.slice(i + 2) : [];
|
|
461
461
|
return handleCompletion([shell, ...completionArgs], programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionMode, completionName);
|
|
462
462
|
}
|
|
463
463
|
}
|
|
@@ -556,11 +556,13 @@ function runParser(parser, programName, args, options = {}) {
|
|
|
556
556
|
const displayHelp = (doc) => {
|
|
557
557
|
if (doc != null) {
|
|
558
558
|
const isMetaCommandHelp = (completionName === "singular" || completionName === "both" ? requestedCommand === "completion" : false) || (completionName === "plural" || completionName === "both" ? requestedCommand === "completions" : false) || requestedCommand === "help" || requestedCommand === "version";
|
|
559
|
+
const isSubcommandHelp = classified.commands.length > 0;
|
|
560
|
+
const shouldOverride = !isMetaCommandHelp && !isSubcommandHelp;
|
|
559
561
|
const augmentedDoc = {
|
|
560
562
|
...doc,
|
|
561
|
-
brief:
|
|
562
|
-
description:
|
|
563
|
-
footer:
|
|
563
|
+
brief: shouldOverride ? brief ?? doc.brief : doc.brief ?? brief,
|
|
564
|
+
description: shouldOverride ? description ?? doc.description : doc.description ?? description,
|
|
565
|
+
footer: shouldOverride ? footer ?? doc.footer : doc.footer ?? footer
|
|
564
566
|
};
|
|
565
567
|
stdout(formatDocPage(programName, augmentedDoc, {
|
|
566
568
|
colors,
|
package/dist/parser.cjs
CHANGED
|
@@ -337,7 +337,7 @@ async function getDocPageAsyncImpl(parser, args) {
|
|
|
337
337
|
* Shared by both sync and async implementations.
|
|
338
338
|
*/
|
|
339
339
|
function buildDocPage(parser, context, args) {
|
|
340
|
-
const { description, fragments, footer } = parser.getDocFragments({
|
|
340
|
+
const { brief, description, fragments, footer } = parser.getDocFragments({
|
|
341
341
|
kind: "available",
|
|
342
342
|
state: context.state
|
|
343
343
|
}, void 0);
|
|
@@ -363,6 +363,7 @@ function buildDocPage(parser, context, args) {
|
|
|
363
363
|
return {
|
|
364
364
|
usage,
|
|
365
365
|
sections,
|
|
366
|
+
...brief != null && { brief },
|
|
366
367
|
...description != null && { description },
|
|
367
368
|
...footer != null && { footer }
|
|
368
369
|
};
|
package/dist/parser.js
CHANGED
|
@@ -337,7 +337,7 @@ async function getDocPageAsyncImpl(parser, args) {
|
|
|
337
337
|
* Shared by both sync and async implementations.
|
|
338
338
|
*/
|
|
339
339
|
function buildDocPage(parser, context, args) {
|
|
340
|
-
const { description, fragments, footer } = parser.getDocFragments({
|
|
340
|
+
const { brief, description, fragments, footer } = parser.getDocFragments({
|
|
341
341
|
kind: "available",
|
|
342
342
|
state: context.state
|
|
343
343
|
}, void 0);
|
|
@@ -363,6 +363,7 @@ function buildDocPage(parser, context, args) {
|
|
|
363
363
|
return {
|
|
364
364
|
usage,
|
|
365
365
|
sections,
|
|
366
|
+
...brief != null && { brief },
|
|
366
367
|
...description != null && { description },
|
|
367
368
|
...footer != null && { footer }
|
|
368
369
|
};
|
package/dist/primitives.cjs
CHANGED
|
@@ -867,6 +867,7 @@ function command(name, parser, options = {}) {
|
|
|
867
867
|
const innerFragments = parser.getDocFragments(innerState, defaultValue);
|
|
868
868
|
return {
|
|
869
869
|
...innerFragments,
|
|
870
|
+
brief: innerFragments.brief ?? options.brief,
|
|
870
871
|
description: innerFragments.description ?? options.description,
|
|
871
872
|
footer: innerFragments.footer ?? options.footer
|
|
872
873
|
};
|
package/dist/primitives.js
CHANGED
|
@@ -867,6 +867,7 @@ function command(name, parser, options = {}) {
|
|
|
867
867
|
const innerFragments = parser.getDocFragments(innerState, defaultValue);
|
|
868
868
|
return {
|
|
869
869
|
...innerFragments,
|
|
870
|
+
brief: innerFragments.brief ?? options.brief,
|
|
870
871
|
description: innerFragments.description ?? options.description,
|
|
871
872
|
footer: innerFragments.footer ?? options.footer
|
|
872
873
|
};
|
package/dist/suggestion.cjs
CHANGED
|
@@ -232,5 +232,6 @@ function deduplicateSuggestions(suggestions) {
|
|
|
232
232
|
//#endregion
|
|
233
233
|
exports.DEFAULT_FIND_SIMILAR_OPTIONS = DEFAULT_FIND_SIMILAR_OPTIONS;
|
|
234
234
|
exports.createErrorWithSuggestions = createErrorWithSuggestions;
|
|
235
|
+
exports.createSuggestionMessage = createSuggestionMessage;
|
|
235
236
|
exports.deduplicateSuggestions = deduplicateSuggestions;
|
|
236
237
|
exports.findSimilar = findSimilar;
|
package/dist/suggestion.js
CHANGED
|
@@ -230,4 +230,4 @@ function deduplicateSuggestions(suggestions) {
|
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
//#endregion
|
|
233
|
-
export { DEFAULT_FIND_SIMILAR_OPTIONS, createErrorWithSuggestions, deduplicateSuggestions, findSimilar };
|
|
233
|
+
export { DEFAULT_FIND_SIMILAR_OPTIONS, createErrorWithSuggestions, createSuggestionMessage, deduplicateSuggestions, findSimilar };
|