cli-kiss 0.2.7 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -3
- package/dist/index.d.ts +200 -190
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/docs/.vitepress/config.mts +1 -1
- package/docs/.vitepress/theme/Layout.vue +16 -0
- package/docs/.vitepress/theme/index.ts +5 -1
- package/docs/.vitepress/theme/style.css +5 -1
- package/docs/guide/01_getting_started.md +2 -2
- package/docs/guide/02_commands.md +3 -3
- package/docs/guide/03_options.md +11 -11
- package/docs/guide/04_positionals.md +9 -9
- package/docs/guide/05_input_types.md +17 -16
- package/docs/guide/06_run_as_cli.md +1 -1
- package/docs/index.md +2 -2
- package/docs/public/favicon.ico +0 -0
- package/docs/public/logo.png +0 -0
- package/package.json +1 -1
- package/src/index.ts +1 -1
- package/src/lib/Command.ts +51 -40
- package/src/lib/Operation.ts +41 -25
- package/src/lib/Option.ts +198 -127
- package/src/lib/Positional.ts +51 -25
- package/src/lib/Reader.ts +188 -226
- package/src/lib/Run.ts +20 -9
- package/src/lib/Suggest.ts +78 -0
- package/src/lib/Type.ts +178 -154
- package/src/lib/Typo.ts +58 -55
- package/src/lib/Usage.ts +12 -12
- package/tests/unit.Reader.commons.ts +86 -123
- package/tests/unit.Reader.parsings.ts +14 -26
- package/tests/unit.Reader.shortBig.ts +75 -101
- package/tests/unit.command.aliases.ts +88 -0
- package/tests/unit.command.execute.ts +6 -6
- package/tests/unit.command.usage.ts +19 -13
- package/tests/unit.fuzzed.alternatives.ts +35 -26
- package/tests/unit.runner.colors.ts +8 -33
- package/tests/unit.runner.cycle.ts +141 -156
- package/tests/unit.runner.errors.ts +25 -22
- package/docs/public/hero.png +0 -0
- package/src/lib/Similarity.ts +0 -41
- package/tests/unit.Reader.aliases.ts +0 -62
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { expect, it } from "@jest/globals";
|
|
2
|
-
import { ReaderArgs,
|
|
2
|
+
import { ReaderArgs, ReaderOptionNextGuard } from "../src";
|
|
3
3
|
|
|
4
4
|
it("run", async function () {
|
|
5
5
|
const stream = new ReaderArgs([
|
|
@@ -19,136 +19,110 @@ it("run", async function () {
|
|
|
19
19
|
|
|
20
20
|
expect(stream.consumePositional()).toStrictEqual("positional-0");
|
|
21
21
|
|
|
22
|
-
const kSofUnset = stream.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
const kSofUnset = stream.registerOptionShort({
|
|
23
|
+
key: "sof-unset",
|
|
24
|
+
nextGuard: optionFlagNextGuard,
|
|
25
|
+
consumeGroupRestAsValue: false,
|
|
26
26
|
});
|
|
27
|
-
const kSofNormal = stream.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
const kSofNormal = stream.registerOptionShort({
|
|
28
|
+
key: "sof-normal",
|
|
29
|
+
nextGuard: optionFlagNextGuard,
|
|
30
|
+
consumeGroupRestAsValue: false,
|
|
31
31
|
});
|
|
32
|
-
const kSofPositive = stream.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
const kSofPositive = stream.registerOptionShort({
|
|
33
|
+
key: "sof-positive",
|
|
34
|
+
nextGuard: optionFlagNextGuard,
|
|
35
|
+
consumeGroupRestAsValue: false,
|
|
36
36
|
});
|
|
37
|
-
const kSofNegative = stream.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
const kSofNegative = stream.registerOptionShort({
|
|
38
|
+
key: "sof-negative",
|
|
39
|
+
nextGuard: optionFlagNextGuard,
|
|
40
|
+
consumeGroupRestAsValue: false,
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
-
const kAa = stream.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
const kAa = stream.registerOptionShort({
|
|
44
|
+
key: "aa",
|
|
45
|
+
nextGuard: optionFlagNextGuard,
|
|
46
|
+
consumeGroupRestAsValue: false,
|
|
47
47
|
});
|
|
48
|
-
const kBb = stream.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
const kBb = stream.registerOptionShort({
|
|
49
|
+
key: "bb",
|
|
50
|
+
nextGuard: optionFlagNextGuard,
|
|
51
|
+
consumeGroupRestAsValue: false,
|
|
52
52
|
});
|
|
53
|
-
const kCc = stream.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
const kCc = stream.registerOptionShort({
|
|
54
|
+
key: "cc",
|
|
55
|
+
nextGuard: optionFlagNextGuard,
|
|
56
|
+
consumeGroupRestAsValue: false,
|
|
57
57
|
});
|
|
58
58
|
|
|
59
59
|
expect(stream.consumePositional()).toStrictEqual("positional-1");
|
|
60
60
|
|
|
61
|
-
const kSovSplit = stream.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
const kSovSplit = stream.registerOptionShort({
|
|
62
|
+
key: "sov-split",
|
|
63
|
+
nextGuard: optionValuedNextGuard,
|
|
64
|
+
consumeGroupRestAsValue: true,
|
|
65
65
|
});
|
|
66
|
-
const kSovJoin = stream.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
const kSovJoin = stream.registerOptionShort({
|
|
67
|
+
key: "sov-join",
|
|
68
|
+
nextGuard: optionValuedNextGuard,
|
|
69
|
+
consumeGroupRestAsValue: true,
|
|
70
70
|
});
|
|
71
|
-
const kSovUnset = stream.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
const kSovUnset = stream.registerOptionShort({
|
|
72
|
+
key: "sov-unset",
|
|
73
|
+
nextGuard: optionValuedNextGuard,
|
|
74
|
+
consumeGroupRestAsValue: true,
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
const kDd = stream.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
const kDd = stream.registerOptionShort({
|
|
78
|
+
key: "dd",
|
|
79
|
+
nextGuard: optionFlagNextGuard,
|
|
80
|
+
consumeGroupRestAsValue: false,
|
|
81
81
|
});
|
|
82
|
-
const kEe = stream.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
const kEe = stream.registerOptionShort({
|
|
83
|
+
key: "ee",
|
|
84
|
+
nextGuard: optionFlagNextGuard,
|
|
85
|
+
consumeGroupRestAsValue: false,
|
|
86
86
|
});
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
|
|
88
|
+
const kFf = stream.registerOptionShort({
|
|
89
|
+
key: "ff",
|
|
90
|
+
nextGuard: optionFlagNextGuard,
|
|
91
|
+
consumeGroupRestAsValue: false,
|
|
91
92
|
});
|
|
92
|
-
const kGg = stream.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
const kGg = stream.registerOptionShort({
|
|
94
|
+
key: "gg",
|
|
95
|
+
nextGuard: optionFlagNextGuard,
|
|
96
|
+
consumeGroupRestAsValue: false,
|
|
96
97
|
});
|
|
97
98
|
|
|
98
99
|
expect(stream.consumePositional()).toStrictEqual("positional-2");
|
|
99
100
|
|
|
100
|
-
expect(
|
|
101
|
-
expect(
|
|
102
|
-
|
|
103
|
-
]);
|
|
104
|
-
expect(stream.getOptionValues(kSofPositive)).toStrictEqual([
|
|
105
|
-
{ inlined: "true", separated: [] },
|
|
106
|
-
]);
|
|
107
|
-
expect(stream.getOptionValues(kSofNegative)).toStrictEqual([
|
|
108
|
-
{ inlined: "false", separated: [] },
|
|
109
|
-
]);
|
|
101
|
+
expect(kSofUnset()).toStrictEqual([]);
|
|
102
|
+
expect(kSofNormal()).toStrictEqual([{ inlined: null, separated: [] }]);
|
|
103
|
+
expect(kSofPositive()).toStrictEqual([{ inlined: "true", separated: [] }]);
|
|
104
|
+
expect(kSofNegative()).toStrictEqual([{ inlined: "false", separated: [] }]);
|
|
110
105
|
|
|
111
|
-
expect(
|
|
112
|
-
|
|
113
|
-
]);
|
|
114
|
-
expect(stream.getOptionValues(kBb)).toStrictEqual([
|
|
115
|
-
{ inlined: null, separated: [] },
|
|
116
|
-
]);
|
|
117
|
-
expect(stream.getOptionValues(kCc)).toStrictEqual([
|
|
118
|
-
{ inlined: null, separated: [] },
|
|
119
|
-
]);
|
|
106
|
+
expect(kAa()).toStrictEqual([{ inlined: null, separated: [] }]);
|
|
107
|
+
expect(kBb()).toStrictEqual([{ inlined: null, separated: [] }]);
|
|
108
|
+
expect(kCc()).toStrictEqual([{ inlined: null, separated: [] }]);
|
|
120
109
|
|
|
121
|
-
expect(
|
|
122
|
-
expect(
|
|
110
|
+
expect(kSovUnset()).toStrictEqual([]);
|
|
111
|
+
expect(kSovSplit()).toStrictEqual([
|
|
123
112
|
{ inlined: null, separated: ["1.1"] },
|
|
124
113
|
{ inlined: null, separated: ["1.2"] },
|
|
125
114
|
]);
|
|
126
|
-
expect(
|
|
115
|
+
expect(kSovJoin()).toStrictEqual([
|
|
127
116
|
{ inlined: "2.1", separated: [] },
|
|
128
117
|
{ inlined: "2.2", separated: [] },
|
|
129
118
|
]);
|
|
130
119
|
|
|
131
|
-
expect(
|
|
132
|
-
|
|
133
|
-
]);
|
|
134
|
-
expect(
|
|
135
|
-
{ inlined: null, separated: [] },
|
|
136
|
-
]);
|
|
137
|
-
expect(stream.getOptionValues(kFf)).toStrictEqual([
|
|
138
|
-
{ inlined: null, separated: [] },
|
|
139
|
-
]);
|
|
140
|
-
expect(stream.getOptionValues(kGg)).toStrictEqual([
|
|
141
|
-
{ inlined: null, separated: [] },
|
|
142
|
-
]);
|
|
120
|
+
expect(kDd()).toStrictEqual([{ inlined: null, separated: [] }]);
|
|
121
|
+
expect(kEe()).toStrictEqual([{ inlined: null, separated: [] }]);
|
|
122
|
+
expect(kFf()).toStrictEqual([{ inlined: null, separated: [] }]);
|
|
123
|
+
expect(kGg()).toStrictEqual([{ inlined: null, separated: [] }]);
|
|
143
124
|
});
|
|
144
125
|
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
const optionValueFixedUniqueParsing: ReaderOptionParsing = {
|
|
151
|
-
consumeShortGroup: true,
|
|
152
|
-
consumeNextArg: (inlined, separated) =>
|
|
153
|
-
inlined === null && separated.length === 0,
|
|
154
|
-
};
|
|
126
|
+
const optionFlagNextGuard: ReaderOptionNextGuard = () => false;
|
|
127
|
+
const optionValuedNextGuard: ReaderOptionNextGuard = (value) =>
|
|
128
|
+
value.inlined === null && value.separated.length === 0;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { expect, it } from "@jest/globals";
|
|
2
|
+
import {
|
|
3
|
+
command,
|
|
4
|
+
operation,
|
|
5
|
+
optionFlag,
|
|
6
|
+
optionRepeatable,
|
|
7
|
+
optionSingleValue,
|
|
8
|
+
ReaderArgs,
|
|
9
|
+
typeString,
|
|
10
|
+
} from "../src";
|
|
11
|
+
|
|
12
|
+
it("run", async function () {
|
|
13
|
+
const cmd = command(
|
|
14
|
+
{ description: "Description" },
|
|
15
|
+
operation(
|
|
16
|
+
{
|
|
17
|
+
options: {
|
|
18
|
+
option: optionRepeatable({
|
|
19
|
+
long: "option",
|
|
20
|
+
type: typeString(),
|
|
21
|
+
aliases: {
|
|
22
|
+
longs: ["option-alias1", "option-alias2"],
|
|
23
|
+
shorts: ["pts", "o"],
|
|
24
|
+
},
|
|
25
|
+
}),
|
|
26
|
+
flag1: optionFlag({
|
|
27
|
+
long: "flag1",
|
|
28
|
+
aliases: { longs: ["flag1-alias"], shorts: ["fa"] },
|
|
29
|
+
}),
|
|
30
|
+
flag2: optionFlag({
|
|
31
|
+
long: "flag2",
|
|
32
|
+
aliases: { longs: ["flag2-alias"], shorts: ["fb"] },
|
|
33
|
+
}),
|
|
34
|
+
weird: optionRepeatable({
|
|
35
|
+
long: "2",
|
|
36
|
+
aliases: { shorts: ["2o"] },
|
|
37
|
+
type: typeString(),
|
|
38
|
+
}),
|
|
39
|
+
v1: optionSingleValue({
|
|
40
|
+
long: "v1",
|
|
41
|
+
aliases: { shorts: ["va"] },
|
|
42
|
+
type: typeString(),
|
|
43
|
+
impliedValueIfNotInlined: () => "bypass",
|
|
44
|
+
fallbackValueIfAbsent: () => undefined,
|
|
45
|
+
}),
|
|
46
|
+
v2: optionSingleValue({
|
|
47
|
+
long: "v2",
|
|
48
|
+
aliases: { shorts: ["vb"] },
|
|
49
|
+
type: typeString(),
|
|
50
|
+
impliedValueIfNotInlined: () => "bypass",
|
|
51
|
+
fallbackValueIfAbsent: () => undefined,
|
|
52
|
+
}),
|
|
53
|
+
},
|
|
54
|
+
positionals: [],
|
|
55
|
+
},
|
|
56
|
+
async function (_context, inputs) {
|
|
57
|
+
return inputs;
|
|
58
|
+
},
|
|
59
|
+
),
|
|
60
|
+
);
|
|
61
|
+
const readerArgs = new ReaderArgs([
|
|
62
|
+
"--option=1.1",
|
|
63
|
+
"--option-alias1=1.2",
|
|
64
|
+
"--option-alias2",
|
|
65
|
+
"1.3",
|
|
66
|
+
"-pts=1.4",
|
|
67
|
+
"-vbva=42",
|
|
68
|
+
"-o",
|
|
69
|
+
"1.5",
|
|
70
|
+
"--flag1-alias",
|
|
71
|
+
"--2=woops",
|
|
72
|
+
"-fb2o=1.6",
|
|
73
|
+
]);
|
|
74
|
+
const decoder = cmd.consumeAndMakeDecoder(readerArgs);
|
|
75
|
+
const interpreter = decoder.decodeAndMakeInterpreter();
|
|
76
|
+
const output = await interpreter.executeWithContext({});
|
|
77
|
+
expect(output).toStrictEqual({
|
|
78
|
+
options: {
|
|
79
|
+
option: ["1.1", "1.2", "1.3", "1.4", "1.5"],
|
|
80
|
+
flag1: true,
|
|
81
|
+
flag2: true,
|
|
82
|
+
weird: ["woops", "1.6"],
|
|
83
|
+
v1: "42",
|
|
84
|
+
v2: "bypass",
|
|
85
|
+
},
|
|
86
|
+
positionals: [],
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -12,9 +12,9 @@ import {
|
|
|
12
12
|
positionalRequired,
|
|
13
13
|
positionalVariadics,
|
|
14
14
|
ReaderArgs,
|
|
15
|
-
type,
|
|
16
15
|
typeList,
|
|
17
16
|
typeNumber,
|
|
17
|
+
typeString,
|
|
18
18
|
} from "../src";
|
|
19
19
|
|
|
20
20
|
const rootCommand = commandChained(
|
|
@@ -46,8 +46,8 @@ const rootCommand = commandChained(
|
|
|
46
46
|
options: {
|
|
47
47
|
string: optionSingleValue({
|
|
48
48
|
long: "string-option",
|
|
49
|
-
type:
|
|
50
|
-
|
|
49
|
+
type: typeString(),
|
|
50
|
+
fallbackValueIfAbsent: () => undefined,
|
|
51
51
|
}),
|
|
52
52
|
number: optionRepeatable({
|
|
53
53
|
long: "number-option",
|
|
@@ -66,7 +66,7 @@ const rootCommand = commandChained(
|
|
|
66
66
|
operation(
|
|
67
67
|
{
|
|
68
68
|
options: {},
|
|
69
|
-
positionals: [positionalRequired({ type:
|
|
69
|
+
positionals: [positionalRequired({ type: typeString() })],
|
|
70
70
|
},
|
|
71
71
|
async function (context, inputs) {
|
|
72
72
|
return { at: "sub1", context, inputs };
|
|
@@ -80,8 +80,8 @@ const rootCommand = commandChained(
|
|
|
80
80
|
options: {},
|
|
81
81
|
positionals: [
|
|
82
82
|
positionalRequired({ type: typeNumber() }),
|
|
83
|
-
positionalOptional({ type:
|
|
84
|
-
positionalVariadics({ type:
|
|
83
|
+
positionalOptional({ type: typeString(), default: () => "42" }),
|
|
84
|
+
positionalVariadics({ type: typeString() }),
|
|
85
85
|
],
|
|
86
86
|
},
|
|
87
87
|
async function (context, inputs) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { it } from "@jest/globals";
|
|
1
|
+
import { expect, it } from "@jest/globals";
|
|
2
2
|
import {
|
|
3
3
|
command,
|
|
4
4
|
Command,
|
|
@@ -12,10 +12,10 @@ import {
|
|
|
12
12
|
positionalRequired,
|
|
13
13
|
positionalVariadics,
|
|
14
14
|
ReaderArgs,
|
|
15
|
-
type,
|
|
16
15
|
typeChoice,
|
|
17
16
|
typeList,
|
|
18
17
|
typeNumber,
|
|
18
|
+
typeString,
|
|
19
19
|
typeTuple,
|
|
20
20
|
TypoSupport,
|
|
21
21
|
usageToStyledLines,
|
|
@@ -37,10 +37,9 @@ const rootCommand = commandChained<any, any, any>(
|
|
|
37
37
|
options: {
|
|
38
38
|
choiceOption: optionSingleValue({
|
|
39
39
|
long: "choice-option",
|
|
40
|
-
type: typeChoice("choice", ["unset", "
|
|
40
|
+
type: typeChoice("choice", ["unset", "choice1", "choice2"]),
|
|
41
41
|
description: "choice-option description",
|
|
42
|
-
|
|
43
|
-
defaultIfNotSpecified: () => "unset",
|
|
42
|
+
fallbackValueIfAbsent: () => "unset",
|
|
44
43
|
}),
|
|
45
44
|
booleanFlag: optionFlag({
|
|
46
45
|
short: "b",
|
|
@@ -80,13 +79,13 @@ const rootCommand = commandChained<any, any, any>(
|
|
|
80
79
|
stringOption: optionSingleValue({
|
|
81
80
|
short: "s",
|
|
82
81
|
long: "string-option",
|
|
83
|
-
type:
|
|
84
|
-
|
|
82
|
+
type: typeString("cool-stuff"),
|
|
83
|
+
fallbackValueIfAbsent: () => undefined,
|
|
85
84
|
description: "string-option description",
|
|
86
85
|
}),
|
|
87
86
|
complexOption: optionRepeatable({
|
|
88
87
|
long: "complex-option",
|
|
89
|
-
type: typeTuple([typeNumber(), typeList(
|
|
88
|
+
type: typeTuple([typeNumber(), typeList(typeString("string"))]),
|
|
90
89
|
description: "complex-option description",
|
|
91
90
|
}),
|
|
92
91
|
},
|
|
@@ -128,7 +127,7 @@ const rootCommand = commandChained<any, any, any>(
|
|
|
128
127
|
positionals: [
|
|
129
128
|
positionalRequired({
|
|
130
129
|
description: "Required positional string",
|
|
131
|
-
type:
|
|
130
|
+
type: typeString("pos-3.1"),
|
|
132
131
|
}),
|
|
133
132
|
],
|
|
134
133
|
},
|
|
@@ -173,11 +172,17 @@ const rootCommand = commandChained<any, any, any>(
|
|
|
173
172
|
options: {
|
|
174
173
|
duduValue: optionSingleValue({
|
|
175
174
|
long: "dudu",
|
|
176
|
-
type:
|
|
177
|
-
|
|
175
|
+
type: typeString("dudu-value"),
|
|
176
|
+
fallbackValueIfAbsent: () => "duduDefault",
|
|
178
177
|
hint: "Dudu option hint",
|
|
179
178
|
description: "Dudu option description",
|
|
180
179
|
}),
|
|
180
|
+
impliable: optionSingleValue({
|
|
181
|
+
long: "impliable",
|
|
182
|
+
type: typeString("text"),
|
|
183
|
+
impliedValueIfNotInlined: () => "implied",
|
|
184
|
+
fallbackValueIfAbsent: () => "absent",
|
|
185
|
+
}),
|
|
181
186
|
},
|
|
182
187
|
positionals: [
|
|
183
188
|
positionalRequired({
|
|
@@ -187,12 +192,12 @@ const rootCommand = commandChained<any, any, any>(
|
|
|
187
192
|
positionalOptional({
|
|
188
193
|
description: "Optional positional string",
|
|
189
194
|
hint: "Optional positional hint",
|
|
190
|
-
type:
|
|
195
|
+
type: typeString("pos-4"),
|
|
191
196
|
default: () => "42",
|
|
192
197
|
}),
|
|
193
198
|
positionalVariadics({
|
|
194
199
|
description: "Variadic positionals strings",
|
|
195
|
-
type:
|
|
200
|
+
type: typeString("pos-5"),
|
|
196
201
|
}),
|
|
197
202
|
],
|
|
198
203
|
},
|
|
@@ -308,6 +313,7 @@ it("run", async function () {
|
|
|
308
313
|
" {{-s}@darkCyan}+, {{--string-option}@darkCyan}+ {{<cool-stuff>}@darkBlue}+ string-option description",
|
|
309
314
|
" {{--complex-option}@darkCyan}+ {{<number,string[,string]...>}@darkBlue}+{{ [*]}-}* complex-option description",
|
|
310
315
|
" {{--dudu}@darkCyan}+ {{<dudu-value>}@darkBlue}+ Dudu option description {{(Dudu option hint)}-}*",
|
|
316
|
+
" {{--impliable}@darkCyan}+{{[=text]}-}*",
|
|
311
317
|
"",
|
|
312
318
|
"{{Examples:}@darkGreen}+",
|
|
313
319
|
" {{# Example usage of subcommand 2}-}*",
|
|
@@ -1,34 +1,43 @@
|
|
|
1
|
-
import { it } from "@jest/globals";
|
|
2
|
-
import {
|
|
1
|
+
import { expect, it } from "@jest/globals";
|
|
2
|
+
import { TypoString, TypoText } from "../src";
|
|
3
|
+
import { suggestTextPushMessage } from "../src/lib/Suggest";
|
|
3
4
|
|
|
4
5
|
it("run", async function () {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
expectReasonables(["--flag", "--blah", "--install"], "--inst", ["--install"]);
|
|
7
|
+
expectReasonables(["install", "dudu", "--blah"], "instlal", ["install"]);
|
|
8
|
+
expectReasonables(["hello", "kat", "cats"], "cat", ["cats", "kat"]);
|
|
9
|
+
expectReasonables(["cut", "kat"], "cat", ["cut", "kat"]);
|
|
10
|
+
expectReasonables(["abc", "ac", "ab"], "acb", ["abc", "ac", "ab"]);
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"abc",
|
|
24
|
-
"ac",
|
|
25
|
-
"ab",
|
|
12
|
+
const library = [
|
|
13
|
+
"install",
|
|
14
|
+
"install-package",
|
|
15
|
+
"install-package-latest",
|
|
16
|
+
"uninstall",
|
|
17
|
+
"update",
|
|
18
|
+
"list",
|
|
19
|
+
];
|
|
20
|
+
expectReasonables(library, "instal", ["install", "uninstall"]);
|
|
21
|
+
expectReasonables(library, "insta-package", ["install-package"]);
|
|
22
|
+
expectReasonables(library, "insta-package-lates", ["install-package-latest"]);
|
|
23
|
+
expectReasonables(library, "install-package-lat", [
|
|
24
|
+
"install-package-latest",
|
|
25
|
+
"install-package",
|
|
26
26
|
]);
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
function
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
function expectReasonables(
|
|
30
|
+
references: Array<string>,
|
|
31
|
+
query: string,
|
|
32
|
+
reasonables: Array<string>,
|
|
33
|
+
) {
|
|
34
|
+
const text = new TypoText();
|
|
35
|
+
suggestTextPushMessage(
|
|
36
|
+
text,
|
|
37
|
+
query,
|
|
38
|
+
references.map((key) => ({ reference: key, hint: new TypoString(key) })),
|
|
39
|
+
);
|
|
40
|
+
expect(text.computeRawString()).toStrictEqual(
|
|
41
|
+
" Did you mean: " + reasonables.join(", ") + " ?",
|
|
33
42
|
);
|
|
34
43
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { it } from "@jest/globals";
|
|
1
|
+
import { expect, it } from "@jest/globals";
|
|
2
2
|
import {
|
|
3
3
|
command,
|
|
4
4
|
operation,
|
|
@@ -33,12 +33,12 @@ const usageTty = usageToStyledLines({
|
|
|
33
33
|
}).join("\n");
|
|
34
34
|
|
|
35
35
|
const unknownOptionNone =
|
|
36
|
-
'Error: Unknown option: "--color"
|
|
36
|
+
'Error: Unknown option: "--color". Did you mean: --help, --version ?';
|
|
37
37
|
const unknownOptionMock =
|
|
38
|
-
'{{Error:}@darkRed}+ Unknown option: {{"--color"}@darkYellow}
|
|
38
|
+
'{{Error:}@darkRed}+ Unknown option: {{"--color"}@darkYellow}+. Did you mean: {{--help}@darkCyan}+, {{--version}@darkCyan}+ ?';
|
|
39
39
|
|
|
40
40
|
it("run", async function () {
|
|
41
|
-
await withEnv("FORCE_COLOR", "
|
|
41
|
+
await withEnv("FORCE_COLOR", "", async () => {
|
|
42
42
|
if (process.stdout.isTTY) {
|
|
43
43
|
await testAllHelpsSuccesses(usageTty);
|
|
44
44
|
} else {
|
|
@@ -55,9 +55,6 @@ it("run", async function () {
|
|
|
55
55
|
await withEnv("NO_COLOR", "", async () => {
|
|
56
56
|
await testAllHelpsSuccesses(usageTty);
|
|
57
57
|
});
|
|
58
|
-
await withEnv("MOCK_COLOR", "", async () => {
|
|
59
|
-
await testAllHelpsSuccesses(usageTty);
|
|
60
|
-
});
|
|
61
58
|
await withEnv("TERM", "dumb", async () => {
|
|
62
59
|
await testAllHelpsSuccesses(usageTty);
|
|
63
60
|
});
|
|
@@ -72,32 +69,12 @@ it("run", async function () {
|
|
|
72
69
|
await withEnv("FORCE_COLOR", "0", async () => {
|
|
73
70
|
await testAllHelpsSuccesses(usageNone);
|
|
74
71
|
});
|
|
75
|
-
await withEnv("MOCK_COLOR", "true", async () => {
|
|
76
|
-
await testAllHelpsSuccesses(usageMock);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
await withEnv("MOCK_COLOR", "1", async () => {
|
|
80
|
-
await testCase(
|
|
81
|
-
"flag",
|
|
82
|
-
["--color=42"],
|
|
83
|
-
[],
|
|
84
|
-
[
|
|
85
|
-
usageMock,
|
|
86
|
-
'{{Error:}@darkRed}+ {{--color}@darkCyan}+: {{<color-mode>}@darkBlue}+: Unknown value: {{"42"}@darkYellow}+: did you mean: {{"auto"}@darkYellow}+, {{"always"}@darkYellow}+, {{"never"}@darkYellow}+ ?',
|
|
87
|
-
],
|
|
88
|
-
1,
|
|
89
|
-
);
|
|
90
|
-
});
|
|
91
72
|
|
|
92
|
-
await
|
|
93
|
-
|
|
94
|
-
});
|
|
73
|
+
await testAllFlagsFailures("mock", usageMock, unknownOptionMock);
|
|
74
|
+
await testAllFlagsFailures("never", usageNone, unknownOptionNone);
|
|
95
75
|
await withEnv("FORCE_COLOR", "0", async () => {
|
|
96
76
|
await testAllFlagsFailures("env", usageNone, unknownOptionNone);
|
|
97
77
|
});
|
|
98
|
-
|
|
99
|
-
await testAllFlagsFailures("mock", usageMock, unknownOptionMock);
|
|
100
|
-
await testAllFlagsFailures("never", usageNone, unknownOptionNone);
|
|
101
78
|
});
|
|
102
79
|
});
|
|
103
80
|
|
|
@@ -106,24 +83,22 @@ async function testAllFlagsFailures(
|
|
|
106
83
|
usageErr: string,
|
|
107
84
|
message: string,
|
|
108
85
|
) {
|
|
86
|
+
await testCase(colorSetup, ["--color"], [], [usageErr, message], 1);
|
|
109
87
|
await testCase(colorSetup, ["--color=auto"], [], [usageErr, message], 1);
|
|
110
88
|
await testCase(colorSetup, ["--color=always"], [], [usageErr, message], 1);
|
|
111
89
|
await testCase(colorSetup, ["--color=never"], [], [usageErr, message], 1);
|
|
112
|
-
await testCase(colorSetup, ["--color=mock"], [], [usageErr, message], 1);
|
|
113
|
-
await testCase(colorSetup, ["--color"], [], [usageErr, message], 1);
|
|
114
90
|
}
|
|
115
91
|
|
|
116
92
|
async function testAllHelpsSuccesses(usageFromEnv: string) {
|
|
117
93
|
await testCase("flag", ["--color=auto", "--help"], [usageFromEnv], [], 0);
|
|
118
94
|
await testCase("flag", ["--color=always", "--help"], [usageTty], [], 0);
|
|
119
95
|
await testCase("flag", ["--color=never", "--help"], [usageNone], [], 0);
|
|
120
|
-
await testCase("flag", ["--color=mock", "--help"], [usageMock], [], 0);
|
|
121
96
|
await testCase("flag", ["--color", "--help"], [usageTty], [], 0);
|
|
122
97
|
await testCase("flag", ["--help"], [usageFromEnv], [], 0);
|
|
123
|
-
await testCase("env", ["--help"], [usageFromEnv], [], 0);
|
|
124
98
|
await testCase("always", ["--help"], [usageTty], [], 0);
|
|
125
99
|
await testCase("never", ["--help"], [usageNone], [], 0);
|
|
126
100
|
await testCase("mock", ["--help"], [usageMock], [], 0);
|
|
101
|
+
await testCase("env", ["--help"], [usageFromEnv], [], 0);
|
|
127
102
|
}
|
|
128
103
|
|
|
129
104
|
async function testCase(
|