@guanghechen/commander 4.7.3 → 4.7.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/CHANGELOG.md +15 -0
- package/lib/cjs/browser.cjs +34 -13
- package/lib/cjs/node.cjs +51 -23
- package/lib/esm/browser.mjs +34 -13
- package/lib/esm/node.mjs +51 -23
- package/lib/types/browser.d.ts +4 -2
- package/lib/types/node.d.ts +4 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 4.7.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Fix help output ordering and remove duplicated negative options in help output.
|
|
8
|
+
|
|
9
|
+
## 4.7.4
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Fix commander completion metadata and negative option rules.
|
|
14
|
+
- Include built-in control options (help/version) in completion metadata.
|
|
15
|
+
- Prevent generating negative completions for reserved controls (--no-help/--no-version).
|
|
16
|
+
- Align completion option metadata with explicit type/args semantics.
|
|
17
|
+
|
|
3
18
|
## 4.7.3
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
package/lib/cjs/browser.cjs
CHANGED
|
@@ -715,8 +715,28 @@ class Command {
|
|
|
715
715
|
const desc = metadata.length > 0 ? `${arg.desc} ${metadata.join(' ')}` : arg.desc;
|
|
716
716
|
argumentsLines.push({ sig, desc });
|
|
717
717
|
}
|
|
718
|
+
const sortedOptions = [...allOptions].sort((a, b) => {
|
|
719
|
+
const optionRank = (option) => {
|
|
720
|
+
if (option.long === 'help') {
|
|
721
|
+
return 0;
|
|
722
|
+
}
|
|
723
|
+
if (option.long === 'version') {
|
|
724
|
+
return 1;
|
|
725
|
+
}
|
|
726
|
+
if (option.required === true) {
|
|
727
|
+
return 2;
|
|
728
|
+
}
|
|
729
|
+
return 3;
|
|
730
|
+
};
|
|
731
|
+
const rankA = optionRank(a);
|
|
732
|
+
const rankB = optionRank(b);
|
|
733
|
+
if (rankA !== rankB) {
|
|
734
|
+
return rankA - rankB;
|
|
735
|
+
}
|
|
736
|
+
return camelToKebabCase(a.long).localeCompare(camelToKebabCase(b.long));
|
|
737
|
+
});
|
|
718
738
|
const options = [];
|
|
719
|
-
for (const opt of
|
|
739
|
+
for (const opt of sortedOptions) {
|
|
720
740
|
const kebabLong = camelToKebabCase(opt.long);
|
|
721
741
|
let sig = opt.short ? `-${opt.short}, ` : ' ';
|
|
722
742
|
sig += `--${kebabLong}`;
|
|
@@ -734,21 +754,13 @@ class Command {
|
|
|
734
754
|
desc += ` [choices: ${opt.choices.map(choice => JSON.stringify(choice)).join(', ')}]`;
|
|
735
755
|
}
|
|
736
756
|
options.push({ sig, desc });
|
|
737
|
-
if (opt.type === 'boolean' &&
|
|
738
|
-
opt.args === 'none' &&
|
|
739
|
-
opt.long !== 'help' &&
|
|
740
|
-
opt.long !== 'version') {
|
|
741
|
-
options.push({
|
|
742
|
-
sig: ` --no-${kebabLong}`,
|
|
743
|
-
desc: `Negate --${kebabLong}`,
|
|
744
|
-
});
|
|
745
|
-
}
|
|
746
757
|
}
|
|
747
758
|
const commands = [];
|
|
748
759
|
if (this.#subcommandsList.length > 0) {
|
|
749
760
|
commands.push({ name: 'help', desc: 'Show help for a command' });
|
|
750
761
|
}
|
|
751
|
-
|
|
762
|
+
const sortedSubcommands = [...this.#subcommandsList].sort((a, b) => a.name.localeCompare(b.name));
|
|
763
|
+
for (const entry of sortedSubcommands) {
|
|
752
764
|
let name = entry.name;
|
|
753
765
|
if (entry.aliases.length > 0) {
|
|
754
766
|
name += `, ${entry.aliases.join(', ')}`;
|
|
@@ -864,7 +876,15 @@ class Command {
|
|
|
864
876
|
return ` ${outputLabel} ${desc}`;
|
|
865
877
|
}
|
|
866
878
|
getCompletionMeta() {
|
|
867
|
-
const
|
|
879
|
+
const optionMap = new Map();
|
|
880
|
+
for (const option of this.#resolveOptionPolicy().mergedOptions) {
|
|
881
|
+
optionMap.set(option.long, option);
|
|
882
|
+
}
|
|
883
|
+
optionMap.set('help', BUILTIN_HELP_OPTION);
|
|
884
|
+
if (this.#supportsBuiltinVersion()) {
|
|
885
|
+
optionMap.set('version', BUILTIN_VERSION_OPTION);
|
|
886
|
+
}
|
|
887
|
+
const allOptions = Array.from(optionMap.values());
|
|
868
888
|
const options = [];
|
|
869
889
|
const argumentsMeta = [];
|
|
870
890
|
for (const opt of allOptions) {
|
|
@@ -872,7 +892,8 @@ class Command {
|
|
|
872
892
|
long: opt.long,
|
|
873
893
|
short: opt.short,
|
|
874
894
|
desc: opt.desc,
|
|
875
|
-
|
|
895
|
+
type: opt.type,
|
|
896
|
+
args: opt.args,
|
|
876
897
|
choices: opt.choices?.map(choice => String(choice)),
|
|
877
898
|
});
|
|
878
899
|
}
|
package/lib/cjs/node.cjs
CHANGED
|
@@ -728,8 +728,28 @@ class Command {
|
|
|
728
728
|
const desc = metadata.length > 0 ? `${arg.desc} ${metadata.join(' ')}` : arg.desc;
|
|
729
729
|
argumentsLines.push({ sig, desc });
|
|
730
730
|
}
|
|
731
|
+
const sortedOptions = [...allOptions].sort((a, b) => {
|
|
732
|
+
const optionRank = (option) => {
|
|
733
|
+
if (option.long === 'help') {
|
|
734
|
+
return 0;
|
|
735
|
+
}
|
|
736
|
+
if (option.long === 'version') {
|
|
737
|
+
return 1;
|
|
738
|
+
}
|
|
739
|
+
if (option.required === true) {
|
|
740
|
+
return 2;
|
|
741
|
+
}
|
|
742
|
+
return 3;
|
|
743
|
+
};
|
|
744
|
+
const rankA = optionRank(a);
|
|
745
|
+
const rankB = optionRank(b);
|
|
746
|
+
if (rankA !== rankB) {
|
|
747
|
+
return rankA - rankB;
|
|
748
|
+
}
|
|
749
|
+
return camelToKebabCase$1(a.long).localeCompare(camelToKebabCase$1(b.long));
|
|
750
|
+
});
|
|
731
751
|
const options = [];
|
|
732
|
-
for (const opt of
|
|
752
|
+
for (const opt of sortedOptions) {
|
|
733
753
|
const kebabLong = camelToKebabCase$1(opt.long);
|
|
734
754
|
let sig = opt.short ? `-${opt.short}, ` : ' ';
|
|
735
755
|
sig += `--${kebabLong}`;
|
|
@@ -747,21 +767,13 @@ class Command {
|
|
|
747
767
|
desc += ` [choices: ${opt.choices.map(choice => JSON.stringify(choice)).join(', ')}]`;
|
|
748
768
|
}
|
|
749
769
|
options.push({ sig, desc });
|
|
750
|
-
if (opt.type === 'boolean' &&
|
|
751
|
-
opt.args === 'none' &&
|
|
752
|
-
opt.long !== 'help' &&
|
|
753
|
-
opt.long !== 'version') {
|
|
754
|
-
options.push({
|
|
755
|
-
sig: ` --no-${kebabLong}`,
|
|
756
|
-
desc: `Negate --${kebabLong}`,
|
|
757
|
-
});
|
|
758
|
-
}
|
|
759
770
|
}
|
|
760
771
|
const commands = [];
|
|
761
772
|
if (this.#subcommandsList.length > 0) {
|
|
762
773
|
commands.push({ name: 'help', desc: 'Show help for a command' });
|
|
763
774
|
}
|
|
764
|
-
|
|
775
|
+
const sortedSubcommands = [...this.#subcommandsList].sort((a, b) => a.name.localeCompare(b.name));
|
|
776
|
+
for (const entry of sortedSubcommands) {
|
|
765
777
|
let name = entry.name;
|
|
766
778
|
if (entry.aliases.length > 0) {
|
|
767
779
|
name += `, ${entry.aliases.join(', ')}`;
|
|
@@ -877,7 +889,15 @@ class Command {
|
|
|
877
889
|
return ` ${outputLabel} ${desc}`;
|
|
878
890
|
}
|
|
879
891
|
getCompletionMeta() {
|
|
880
|
-
const
|
|
892
|
+
const optionMap = new Map();
|
|
893
|
+
for (const option of this.#resolveOptionPolicy().mergedOptions) {
|
|
894
|
+
optionMap.set(option.long, option);
|
|
895
|
+
}
|
|
896
|
+
optionMap.set('help', BUILTIN_HELP_OPTION);
|
|
897
|
+
if (this.#supportsBuiltinVersion()) {
|
|
898
|
+
optionMap.set('version', BUILTIN_VERSION_OPTION);
|
|
899
|
+
}
|
|
900
|
+
const allOptions = Array.from(optionMap.values());
|
|
881
901
|
const options = [];
|
|
882
902
|
const argumentsMeta = [];
|
|
883
903
|
for (const opt of allOptions) {
|
|
@@ -885,7 +905,8 @@ class Command {
|
|
|
885
905
|
long: opt.long,
|
|
886
906
|
short: opt.short,
|
|
887
907
|
desc: opt.desc,
|
|
888
|
-
|
|
908
|
+
type: opt.type,
|
|
909
|
+
args: opt.args,
|
|
889
910
|
choices: opt.choices?.map(choice => String(choice)),
|
|
890
911
|
});
|
|
891
912
|
}
|
|
@@ -2133,6 +2154,12 @@ class Coerce {
|
|
|
2133
2154
|
function camelToKebabCase(str) {
|
|
2134
2155
|
return str.replace(/[A-Z]/g, m => '-' + m.toLowerCase());
|
|
2135
2156
|
}
|
|
2157
|
+
function canGenerateNegativeCompletion(opt) {
|
|
2158
|
+
return (opt.type === 'boolean' && opt.args === 'none' && opt.long !== 'help' && opt.long !== 'version');
|
|
2159
|
+
}
|
|
2160
|
+
function optionTakesValue(opt) {
|
|
2161
|
+
return opt.args !== 'none';
|
|
2162
|
+
}
|
|
2136
2163
|
const COMPLETION_SHELL_STATE = Symbol('completion-shell-state');
|
|
2137
2164
|
function getCommandPath(ctx) {
|
|
2138
2165
|
const names = ctx.chain
|
|
@@ -2295,7 +2322,7 @@ class BashCompletion {
|
|
|
2295
2322
|
if (opt.short)
|
|
2296
2323
|
optParts.push(this.#escapeWord(`-${opt.short}`));
|
|
2297
2324
|
optParts.push(this.#escapeWord(`--${kebabLong}`));
|
|
2298
|
-
if (
|
|
2325
|
+
if (canGenerateNegativeCompletion(opt)) {
|
|
2299
2326
|
optParts.push(this.#escapeWord(`--no-${kebabLong}`));
|
|
2300
2327
|
}
|
|
2301
2328
|
}
|
|
@@ -2327,7 +2354,7 @@ class BashCompletion {
|
|
|
2327
2354
|
return words.map(choice => this.#escapeWord(choice)).join(' ');
|
|
2328
2355
|
}
|
|
2329
2356
|
#appendChoiceLogicForCommand(lines, indent, cmd, depth) {
|
|
2330
|
-
const valueOptions = cmd.options.filter(
|
|
2357
|
+
const valueOptions = cmd.options.filter(optionTakesValue);
|
|
2331
2358
|
const valueOptionsWithChoices = valueOptions.filter(opt => opt.choices && opt.choices.length > 0);
|
|
2332
2359
|
const valueLongPatterns = valueOptions.map(opt => `--${camelToKebabCase(opt.long)}`);
|
|
2333
2360
|
const valueShortPatterns = valueOptions
|
|
@@ -2454,7 +2481,7 @@ class FishCompletion {
|
|
|
2454
2481
|
line += ` -xa '${opt.choices.map(choice => this.#escapeChoice(choice)).join(' ')}'`;
|
|
2455
2482
|
}
|
|
2456
2483
|
lines.push(line);
|
|
2457
|
-
if (
|
|
2484
|
+
if (canGenerateNegativeCompletion(opt)) {
|
|
2458
2485
|
let noLine = `complete -c ${this.#programName}`;
|
|
2459
2486
|
if (condition)
|
|
2460
2487
|
noLine += ` -n '${condition}'`;
|
|
@@ -2464,11 +2491,11 @@ class FishCompletion {
|
|
|
2464
2491
|
}
|
|
2465
2492
|
}
|
|
2466
2493
|
const valueOptionLongs = cmd.options
|
|
2467
|
-
.filter(
|
|
2494
|
+
.filter(optionTakesValue)
|
|
2468
2495
|
.map(opt => camelToKebabCase(opt.long))
|
|
2469
2496
|
.join(',');
|
|
2470
2497
|
const valueOptionShorts = cmd.options
|
|
2471
|
-
.filter(opt => opt
|
|
2498
|
+
.filter(opt => optionTakesValue(opt) && opt.short)
|
|
2472
2499
|
.map(opt => opt.short)
|
|
2473
2500
|
.join(',');
|
|
2474
2501
|
const argCount = cmd.arguments.length;
|
|
@@ -2667,7 +2694,7 @@ class PwshCompletion {
|
|
|
2667
2694
|
' if ($token.StartsWith("--")) {',
|
|
2668
2695
|
' if ($token.Contains("=")) { continue }',
|
|
2669
2696
|
' foreach ($opt in $cmd.options) {',
|
|
2670
|
-
' if ($token -eq "--$($opt.long)" -and $opt.
|
|
2697
|
+
' if ($token -eq "--$($opt.long)" -and $opt.args -ne "none") {',
|
|
2671
2698
|
' $expectValue = $true',
|
|
2672
2699
|
' break',
|
|
2673
2700
|
' }',
|
|
@@ -2677,7 +2704,7 @@ class PwshCompletion {
|
|
|
2677
2704
|
' if ($token.StartsWith("-") -and $token -ne "-") {',
|
|
2678
2705
|
' if ($token.Length -eq 2) {',
|
|
2679
2706
|
' foreach ($opt in $cmd.options) {',
|
|
2680
|
-
' if ($opt.short -and $token -eq "-$($opt.short)" -and $opt.
|
|
2707
|
+
' if ($opt.short -and $token -eq "-$($opt.short)" -and $opt.args -ne "none") {',
|
|
2681
2708
|
' $expectValue = $true',
|
|
2682
2709
|
' break',
|
|
2683
2710
|
' }',
|
|
@@ -2729,7 +2756,7 @@ class PwshCompletion {
|
|
|
2729
2756
|
' $opt.description',
|
|
2730
2757
|
' )',
|
|
2731
2758
|
' }',
|
|
2732
|
-
' if ($opt.
|
|
2759
|
+
' if ($opt.canNegate -and "--no-$($opt.long)" -like "$current*") {',
|
|
2733
2760
|
' $completions += [System.Management.Automation.CompletionResult]::new(',
|
|
2734
2761
|
' "--no-$($opt.long)",',
|
|
2735
2762
|
' "no-$($opt.long)",',
|
|
@@ -2779,8 +2806,9 @@ class PwshCompletion {
|
|
|
2779
2806
|
lines.push(`${indent} short = '${opt.short}'`);
|
|
2780
2807
|
lines.push(`${indent} long = '${kebabLong}'`);
|
|
2781
2808
|
lines.push(`${indent} description = '${this.#escape(opt.desc)}'`);
|
|
2782
|
-
lines.push(`${indent}
|
|
2783
|
-
lines.push(`${indent}
|
|
2809
|
+
lines.push(`${indent} type = '${opt.type}'`);
|
|
2810
|
+
lines.push(`${indent} args = '${opt.args}'`);
|
|
2811
|
+
lines.push(`${indent} canNegate = $${canGenerateNegativeCompletion(opt)}`);
|
|
2784
2812
|
if (opt.choices) {
|
|
2785
2813
|
lines.push(`${indent} choices = @('${opt.choices
|
|
2786
2814
|
.map(choice => this.#escape(choice))
|
package/lib/esm/browser.mjs
CHANGED
|
@@ -713,8 +713,28 @@ class Command {
|
|
|
713
713
|
const desc = metadata.length > 0 ? `${arg.desc} ${metadata.join(' ')}` : arg.desc;
|
|
714
714
|
argumentsLines.push({ sig, desc });
|
|
715
715
|
}
|
|
716
|
+
const sortedOptions = [...allOptions].sort((a, b) => {
|
|
717
|
+
const optionRank = (option) => {
|
|
718
|
+
if (option.long === 'help') {
|
|
719
|
+
return 0;
|
|
720
|
+
}
|
|
721
|
+
if (option.long === 'version') {
|
|
722
|
+
return 1;
|
|
723
|
+
}
|
|
724
|
+
if (option.required === true) {
|
|
725
|
+
return 2;
|
|
726
|
+
}
|
|
727
|
+
return 3;
|
|
728
|
+
};
|
|
729
|
+
const rankA = optionRank(a);
|
|
730
|
+
const rankB = optionRank(b);
|
|
731
|
+
if (rankA !== rankB) {
|
|
732
|
+
return rankA - rankB;
|
|
733
|
+
}
|
|
734
|
+
return camelToKebabCase(a.long).localeCompare(camelToKebabCase(b.long));
|
|
735
|
+
});
|
|
716
736
|
const options = [];
|
|
717
|
-
for (const opt of
|
|
737
|
+
for (const opt of sortedOptions) {
|
|
718
738
|
const kebabLong = camelToKebabCase(opt.long);
|
|
719
739
|
let sig = opt.short ? `-${opt.short}, ` : ' ';
|
|
720
740
|
sig += `--${kebabLong}`;
|
|
@@ -732,21 +752,13 @@ class Command {
|
|
|
732
752
|
desc += ` [choices: ${opt.choices.map(choice => JSON.stringify(choice)).join(', ')}]`;
|
|
733
753
|
}
|
|
734
754
|
options.push({ sig, desc });
|
|
735
|
-
if (opt.type === 'boolean' &&
|
|
736
|
-
opt.args === 'none' &&
|
|
737
|
-
opt.long !== 'help' &&
|
|
738
|
-
opt.long !== 'version') {
|
|
739
|
-
options.push({
|
|
740
|
-
sig: ` --no-${kebabLong}`,
|
|
741
|
-
desc: `Negate --${kebabLong}`,
|
|
742
|
-
});
|
|
743
|
-
}
|
|
744
755
|
}
|
|
745
756
|
const commands = [];
|
|
746
757
|
if (this.#subcommandsList.length > 0) {
|
|
747
758
|
commands.push({ name: 'help', desc: 'Show help for a command' });
|
|
748
759
|
}
|
|
749
|
-
|
|
760
|
+
const sortedSubcommands = [...this.#subcommandsList].sort((a, b) => a.name.localeCompare(b.name));
|
|
761
|
+
for (const entry of sortedSubcommands) {
|
|
750
762
|
let name = entry.name;
|
|
751
763
|
if (entry.aliases.length > 0) {
|
|
752
764
|
name += `, ${entry.aliases.join(', ')}`;
|
|
@@ -862,7 +874,15 @@ class Command {
|
|
|
862
874
|
return ` ${outputLabel} ${desc}`;
|
|
863
875
|
}
|
|
864
876
|
getCompletionMeta() {
|
|
865
|
-
const
|
|
877
|
+
const optionMap = new Map();
|
|
878
|
+
for (const option of this.#resolveOptionPolicy().mergedOptions) {
|
|
879
|
+
optionMap.set(option.long, option);
|
|
880
|
+
}
|
|
881
|
+
optionMap.set('help', BUILTIN_HELP_OPTION);
|
|
882
|
+
if (this.#supportsBuiltinVersion()) {
|
|
883
|
+
optionMap.set('version', BUILTIN_VERSION_OPTION);
|
|
884
|
+
}
|
|
885
|
+
const allOptions = Array.from(optionMap.values());
|
|
866
886
|
const options = [];
|
|
867
887
|
const argumentsMeta = [];
|
|
868
888
|
for (const opt of allOptions) {
|
|
@@ -870,7 +890,8 @@ class Command {
|
|
|
870
890
|
long: opt.long,
|
|
871
891
|
short: opt.short,
|
|
872
892
|
desc: opt.desc,
|
|
873
|
-
|
|
893
|
+
type: opt.type,
|
|
894
|
+
args: opt.args,
|
|
874
895
|
choices: opt.choices?.map(choice => String(choice)),
|
|
875
896
|
});
|
|
876
897
|
}
|
package/lib/esm/node.mjs
CHANGED
|
@@ -726,8 +726,28 @@ class Command {
|
|
|
726
726
|
const desc = metadata.length > 0 ? `${arg.desc} ${metadata.join(' ')}` : arg.desc;
|
|
727
727
|
argumentsLines.push({ sig, desc });
|
|
728
728
|
}
|
|
729
|
+
const sortedOptions = [...allOptions].sort((a, b) => {
|
|
730
|
+
const optionRank = (option) => {
|
|
731
|
+
if (option.long === 'help') {
|
|
732
|
+
return 0;
|
|
733
|
+
}
|
|
734
|
+
if (option.long === 'version') {
|
|
735
|
+
return 1;
|
|
736
|
+
}
|
|
737
|
+
if (option.required === true) {
|
|
738
|
+
return 2;
|
|
739
|
+
}
|
|
740
|
+
return 3;
|
|
741
|
+
};
|
|
742
|
+
const rankA = optionRank(a);
|
|
743
|
+
const rankB = optionRank(b);
|
|
744
|
+
if (rankA !== rankB) {
|
|
745
|
+
return rankA - rankB;
|
|
746
|
+
}
|
|
747
|
+
return camelToKebabCase$1(a.long).localeCompare(camelToKebabCase$1(b.long));
|
|
748
|
+
});
|
|
729
749
|
const options = [];
|
|
730
|
-
for (const opt of
|
|
750
|
+
for (const opt of sortedOptions) {
|
|
731
751
|
const kebabLong = camelToKebabCase$1(opt.long);
|
|
732
752
|
let sig = opt.short ? `-${opt.short}, ` : ' ';
|
|
733
753
|
sig += `--${kebabLong}`;
|
|
@@ -745,21 +765,13 @@ class Command {
|
|
|
745
765
|
desc += ` [choices: ${opt.choices.map(choice => JSON.stringify(choice)).join(', ')}]`;
|
|
746
766
|
}
|
|
747
767
|
options.push({ sig, desc });
|
|
748
|
-
if (opt.type === 'boolean' &&
|
|
749
|
-
opt.args === 'none' &&
|
|
750
|
-
opt.long !== 'help' &&
|
|
751
|
-
opt.long !== 'version') {
|
|
752
|
-
options.push({
|
|
753
|
-
sig: ` --no-${kebabLong}`,
|
|
754
|
-
desc: `Negate --${kebabLong}`,
|
|
755
|
-
});
|
|
756
|
-
}
|
|
757
768
|
}
|
|
758
769
|
const commands = [];
|
|
759
770
|
if (this.#subcommandsList.length > 0) {
|
|
760
771
|
commands.push({ name: 'help', desc: 'Show help for a command' });
|
|
761
772
|
}
|
|
762
|
-
|
|
773
|
+
const sortedSubcommands = [...this.#subcommandsList].sort((a, b) => a.name.localeCompare(b.name));
|
|
774
|
+
for (const entry of sortedSubcommands) {
|
|
763
775
|
let name = entry.name;
|
|
764
776
|
if (entry.aliases.length > 0) {
|
|
765
777
|
name += `, ${entry.aliases.join(', ')}`;
|
|
@@ -875,7 +887,15 @@ class Command {
|
|
|
875
887
|
return ` ${outputLabel} ${desc}`;
|
|
876
888
|
}
|
|
877
889
|
getCompletionMeta() {
|
|
878
|
-
const
|
|
890
|
+
const optionMap = new Map();
|
|
891
|
+
for (const option of this.#resolveOptionPolicy().mergedOptions) {
|
|
892
|
+
optionMap.set(option.long, option);
|
|
893
|
+
}
|
|
894
|
+
optionMap.set('help', BUILTIN_HELP_OPTION);
|
|
895
|
+
if (this.#supportsBuiltinVersion()) {
|
|
896
|
+
optionMap.set('version', BUILTIN_VERSION_OPTION);
|
|
897
|
+
}
|
|
898
|
+
const allOptions = Array.from(optionMap.values());
|
|
879
899
|
const options = [];
|
|
880
900
|
const argumentsMeta = [];
|
|
881
901
|
for (const opt of allOptions) {
|
|
@@ -883,7 +903,8 @@ class Command {
|
|
|
883
903
|
long: opt.long,
|
|
884
904
|
short: opt.short,
|
|
885
905
|
desc: opt.desc,
|
|
886
|
-
|
|
906
|
+
type: opt.type,
|
|
907
|
+
args: opt.args,
|
|
887
908
|
choices: opt.choices?.map(choice => String(choice)),
|
|
888
909
|
});
|
|
889
910
|
}
|
|
@@ -2131,6 +2152,12 @@ class Coerce {
|
|
|
2131
2152
|
function camelToKebabCase(str) {
|
|
2132
2153
|
return str.replace(/[A-Z]/g, m => '-' + m.toLowerCase());
|
|
2133
2154
|
}
|
|
2155
|
+
function canGenerateNegativeCompletion(opt) {
|
|
2156
|
+
return (opt.type === 'boolean' && opt.args === 'none' && opt.long !== 'help' && opt.long !== 'version');
|
|
2157
|
+
}
|
|
2158
|
+
function optionTakesValue(opt) {
|
|
2159
|
+
return opt.args !== 'none';
|
|
2160
|
+
}
|
|
2134
2161
|
const COMPLETION_SHELL_STATE = Symbol('completion-shell-state');
|
|
2135
2162
|
function getCommandPath(ctx) {
|
|
2136
2163
|
const names = ctx.chain
|
|
@@ -2293,7 +2320,7 @@ class BashCompletion {
|
|
|
2293
2320
|
if (opt.short)
|
|
2294
2321
|
optParts.push(this.#escapeWord(`-${opt.short}`));
|
|
2295
2322
|
optParts.push(this.#escapeWord(`--${kebabLong}`));
|
|
2296
|
-
if (
|
|
2323
|
+
if (canGenerateNegativeCompletion(opt)) {
|
|
2297
2324
|
optParts.push(this.#escapeWord(`--no-${kebabLong}`));
|
|
2298
2325
|
}
|
|
2299
2326
|
}
|
|
@@ -2325,7 +2352,7 @@ class BashCompletion {
|
|
|
2325
2352
|
return words.map(choice => this.#escapeWord(choice)).join(' ');
|
|
2326
2353
|
}
|
|
2327
2354
|
#appendChoiceLogicForCommand(lines, indent, cmd, depth) {
|
|
2328
|
-
const valueOptions = cmd.options.filter(
|
|
2355
|
+
const valueOptions = cmd.options.filter(optionTakesValue);
|
|
2329
2356
|
const valueOptionsWithChoices = valueOptions.filter(opt => opt.choices && opt.choices.length > 0);
|
|
2330
2357
|
const valueLongPatterns = valueOptions.map(opt => `--${camelToKebabCase(opt.long)}`);
|
|
2331
2358
|
const valueShortPatterns = valueOptions
|
|
@@ -2452,7 +2479,7 @@ class FishCompletion {
|
|
|
2452
2479
|
line += ` -xa '${opt.choices.map(choice => this.#escapeChoice(choice)).join(' ')}'`;
|
|
2453
2480
|
}
|
|
2454
2481
|
lines.push(line);
|
|
2455
|
-
if (
|
|
2482
|
+
if (canGenerateNegativeCompletion(opt)) {
|
|
2456
2483
|
let noLine = `complete -c ${this.#programName}`;
|
|
2457
2484
|
if (condition)
|
|
2458
2485
|
noLine += ` -n '${condition}'`;
|
|
@@ -2462,11 +2489,11 @@ class FishCompletion {
|
|
|
2462
2489
|
}
|
|
2463
2490
|
}
|
|
2464
2491
|
const valueOptionLongs = cmd.options
|
|
2465
|
-
.filter(
|
|
2492
|
+
.filter(optionTakesValue)
|
|
2466
2493
|
.map(opt => camelToKebabCase(opt.long))
|
|
2467
2494
|
.join(',');
|
|
2468
2495
|
const valueOptionShorts = cmd.options
|
|
2469
|
-
.filter(opt => opt
|
|
2496
|
+
.filter(opt => optionTakesValue(opt) && opt.short)
|
|
2470
2497
|
.map(opt => opt.short)
|
|
2471
2498
|
.join(',');
|
|
2472
2499
|
const argCount = cmd.arguments.length;
|
|
@@ -2665,7 +2692,7 @@ class PwshCompletion {
|
|
|
2665
2692
|
' if ($token.StartsWith("--")) {',
|
|
2666
2693
|
' if ($token.Contains("=")) { continue }',
|
|
2667
2694
|
' foreach ($opt in $cmd.options) {',
|
|
2668
|
-
' if ($token -eq "--$($opt.long)" -and $opt.
|
|
2695
|
+
' if ($token -eq "--$($opt.long)" -and $opt.args -ne "none") {',
|
|
2669
2696
|
' $expectValue = $true',
|
|
2670
2697
|
' break',
|
|
2671
2698
|
' }',
|
|
@@ -2675,7 +2702,7 @@ class PwshCompletion {
|
|
|
2675
2702
|
' if ($token.StartsWith("-") -and $token -ne "-") {',
|
|
2676
2703
|
' if ($token.Length -eq 2) {',
|
|
2677
2704
|
' foreach ($opt in $cmd.options) {',
|
|
2678
|
-
' if ($opt.short -and $token -eq "-$($opt.short)" -and $opt.
|
|
2705
|
+
' if ($opt.short -and $token -eq "-$($opt.short)" -and $opt.args -ne "none") {',
|
|
2679
2706
|
' $expectValue = $true',
|
|
2680
2707
|
' break',
|
|
2681
2708
|
' }',
|
|
@@ -2727,7 +2754,7 @@ class PwshCompletion {
|
|
|
2727
2754
|
' $opt.description',
|
|
2728
2755
|
' )',
|
|
2729
2756
|
' }',
|
|
2730
|
-
' if ($opt.
|
|
2757
|
+
' if ($opt.canNegate -and "--no-$($opt.long)" -like "$current*") {',
|
|
2731
2758
|
' $completions += [System.Management.Automation.CompletionResult]::new(',
|
|
2732
2759
|
' "--no-$($opt.long)",',
|
|
2733
2760
|
' "no-$($opt.long)",',
|
|
@@ -2777,8 +2804,9 @@ class PwshCompletion {
|
|
|
2777
2804
|
lines.push(`${indent} short = '${opt.short}'`);
|
|
2778
2805
|
lines.push(`${indent} long = '${kebabLong}'`);
|
|
2779
2806
|
lines.push(`${indent} description = '${this.#escape(opt.desc)}'`);
|
|
2780
|
-
lines.push(`${indent}
|
|
2781
|
-
lines.push(`${indent}
|
|
2807
|
+
lines.push(`${indent} type = '${opt.type}'`);
|
|
2808
|
+
lines.push(`${indent} args = '${opt.args}'`);
|
|
2809
|
+
lines.push(`${indent} canNegate = $${canGenerateNegativeCompletion(opt)}`);
|
|
2782
2810
|
if (opt.choices) {
|
|
2783
2811
|
lines.push(`${indent} choices = @('${opt.choices
|
|
2784
2812
|
.map(choice => this.#escape(choice))
|
package/lib/types/browser.d.ts
CHANGED
|
@@ -365,8 +365,10 @@ interface ICompletionOptionMeta {
|
|
|
365
365
|
short?: string;
|
|
366
366
|
/** Description */
|
|
367
367
|
desc: string;
|
|
368
|
-
/**
|
|
369
|
-
|
|
368
|
+
/** Option type */
|
|
369
|
+
type: ICommandOptionType;
|
|
370
|
+
/** Option args mode */
|
|
371
|
+
args: ICommandOptionArgs;
|
|
370
372
|
/** Allowed values */
|
|
371
373
|
choices?: string[];
|
|
372
374
|
}
|
package/lib/types/node.d.ts
CHANGED
|
@@ -365,8 +365,10 @@ interface ICompletionOptionMeta {
|
|
|
365
365
|
short?: string;
|
|
366
366
|
/** Description */
|
|
367
367
|
desc: string;
|
|
368
|
-
/**
|
|
369
|
-
|
|
368
|
+
/** Option type */
|
|
369
|
+
type: ICommandOptionType;
|
|
370
|
+
/** Option args mode */
|
|
371
|
+
args: ICommandOptionArgs;
|
|
370
372
|
/** Allowed values */
|
|
371
373
|
choices?: string[];
|
|
372
374
|
}
|