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,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,
|
|
@@ -13,39 +13,43 @@ import {
|
|
|
13
13
|
it("run", async function () {
|
|
14
14
|
await testCase(
|
|
15
15
|
["hello"],
|
|
16
|
-
'{{Error:}@darkRed}+ Unexpected argument: {{"hello"}@darkYellow}
|
|
16
|
+
'{{Error:}@darkRed}+ Unexpected argument: {{"hello"}@darkYellow}+.', // TODO - should we recommend help here ?
|
|
17
17
|
);
|
|
18
18
|
await testCase(
|
|
19
19
|
["--nope"],
|
|
20
|
-
'{{Error:}@darkRed}+ Unknown option: {{"--nope"}@darkYellow}
|
|
20
|
+
'{{Error:}@darkRed}+ Unknown option: {{"--nope"}@darkYellow}+. Did you mean: {{--help}@darkCyan}+, {{--flag}@darkCyan}+, {{--repeatable}@darkCyan}+, {{...}-}* ?',
|
|
21
21
|
);
|
|
22
22
|
await testCase(
|
|
23
23
|
["--repeat"],
|
|
24
|
-
'{{Error:}@darkRed}+ Unknown option: {{"--repeat"}@darkYellow}
|
|
25
|
-
);
|
|
26
|
-
await testCase(
|
|
27
|
-
["--flag", "--flag"],
|
|
28
|
-
"{{Error:}@darkRed}+ {{--flag}@darkCyan}+: Must not be set multiple times",
|
|
29
|
-
);
|
|
30
|
-
await testCase(
|
|
31
|
-
["--flag=invalid"],
|
|
32
|
-
'{{Error:}@darkRed}+ {{--flag}@darkCyan}+: {{value}@darkMagenta}+: Not a boolean: {{"invalid"}@darkYellow}+',
|
|
24
|
+
'{{Error:}@darkRed}+ Unknown option: {{"--repeat"}@darkYellow}+. Did you mean: {{--repeatable}@darkCyan}+ ?',
|
|
33
25
|
);
|
|
34
26
|
await testCase(
|
|
35
27
|
["--single-value=a", "--single-value=b"],
|
|
36
|
-
"{{Error:}@darkRed}+ {{--single-value}@darkCyan}+: Must not be set multiple times",
|
|
28
|
+
"{{Error:}@darkRed}+ {{--single-value}@darkCyan}+: Must not be set multiple times.",
|
|
37
29
|
);
|
|
38
30
|
await testCase(
|
|
39
31
|
["--single-value"],
|
|
40
|
-
"{{Error:}@darkRed}+ {{--single-value}@darkCyan}+: Requires a value, but got end of input",
|
|
32
|
+
"{{Error:}@darkRed}+ {{--single-value}@darkCyan}+: Requires a value, but got end of input.",
|
|
33
|
+
);
|
|
34
|
+
await testCase(
|
|
35
|
+
[],
|
|
36
|
+
"{{Error:}@darkRed}+ {{--single-value}@darkCyan}+: {{<location>}@darkBlue}+: Is required, but was not set.",
|
|
41
37
|
);
|
|
42
38
|
await testCase(
|
|
43
39
|
["--single-value=invalid"],
|
|
44
|
-
'{{Error:}@darkRed}+ {{--single-value}@darkCyan}+: {{<location>}@darkBlue}+: Not an URL: {{"invalid"}@darkYellow}
|
|
40
|
+
'{{Error:}@darkRed}+ {{--single-value}@darkCyan}+: {{<location>}@darkBlue}+: Not an URL: {{"invalid"}@darkYellow}+.',
|
|
45
41
|
);
|
|
46
42
|
await testCase(
|
|
47
43
|
["--repeatable=invalid"],
|
|
48
|
-
'{{Error:}@darkRed}+ {{--repeatable}@darkCyan}+: {{<index>}@darkBlue}+: Not a number: {{"invalid"}@darkYellow}
|
|
44
|
+
'{{Error:}@darkRed}+ {{--repeatable}@darkCyan}+: {{<index>}@darkBlue}+: Not a number: {{"invalid"}@darkYellow}+.',
|
|
45
|
+
);
|
|
46
|
+
await testCase(
|
|
47
|
+
["--flag", "-f"],
|
|
48
|
+
"{{Error:}@darkRed}+ {{--flag}@darkCyan}+, {{-f}@darkCyan}+: Must not be set multiple times.",
|
|
49
|
+
);
|
|
50
|
+
await testCase(
|
|
51
|
+
["--flag=invalid"],
|
|
52
|
+
'{{Error:}@darkRed}+ {{--flag}@darkCyan}+: {{value}@darkMagenta}+: Not a boolean: {{"invalid"}@darkYellow}+.',
|
|
49
53
|
);
|
|
50
54
|
});
|
|
51
55
|
|
|
@@ -58,16 +62,15 @@ async function testCase(args: Array<string>, error: string) {
|
|
|
58
62
|
operation(
|
|
59
63
|
{
|
|
60
64
|
options: {
|
|
61
|
-
optionFlag: optionFlag({ long: "flag" }),
|
|
62
|
-
optionSingleValue: optionSingleValue({
|
|
63
|
-
long: "single-value",
|
|
64
|
-
type: typeUrl("location"),
|
|
65
|
-
defaultIfNotSpecified: () => undefined,
|
|
66
|
-
}),
|
|
65
|
+
optionFlag: optionFlag({ long: "flag", short: "f" }),
|
|
67
66
|
optionRepeatable: optionRepeatable({
|
|
68
67
|
long: "repeatable",
|
|
69
68
|
type: typeNumber("index"),
|
|
70
69
|
}),
|
|
70
|
+
optionSingleValue: optionSingleValue({
|
|
71
|
+
long: "single-value",
|
|
72
|
+
type: typeUrl("location"),
|
|
73
|
+
}),
|
|
71
74
|
},
|
|
72
75
|
positionals: [],
|
|
73
76
|
},
|
package/docs/public/hero.png
DELETED
|
Binary file
|
package/src/lib/Similarity.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
export function similaritySort<Value>(
|
|
2
|
-
reference: string,
|
|
3
|
-
candidates: { [key: string]: Value } | Array<{ key: string; value: Value }>,
|
|
4
|
-
): Array<Value> {
|
|
5
|
-
let entries = Array.isArray(candidates)
|
|
6
|
-
? candidates.map(({ key, value }) => [key, value] as const)
|
|
7
|
-
: Object.entries(candidates);
|
|
8
|
-
const ranked = entries.map(([key, value]) => {
|
|
9
|
-
const score =
|
|
10
|
-
damerauLevenshtein(reference, key) /
|
|
11
|
-
Math.max(reference.length, key.length);
|
|
12
|
-
return { key, value, score };
|
|
13
|
-
});
|
|
14
|
-
return ranked.sort((a, b) => a.score - b.score).map((v) => v.value);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function damerauLevenshtein(a: string, b: string): number {
|
|
18
|
-
const m = a.length;
|
|
19
|
-
const n = b.length;
|
|
20
|
-
const dp = Array.from({ length: m + 1 }, () => Array<number>(n + 1).fill(0));
|
|
21
|
-
for (let i = 0; i <= m; i++) {
|
|
22
|
-
dp[i]![0] = i;
|
|
23
|
-
}
|
|
24
|
-
for (let j = 0; j <= n; j++) {
|
|
25
|
-
dp[0]![j] = j;
|
|
26
|
-
}
|
|
27
|
-
for (let i = 1; i <= m; i++) {
|
|
28
|
-
for (let j = 1; j <= n; j++) {
|
|
29
|
-
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
30
|
-
dp[i]![j] = Math.min(
|
|
31
|
-
dp[i - 1]![j]! + 1,
|
|
32
|
-
dp[i]![j - 1]! + 1,
|
|
33
|
-
dp[i - 1]![j - 1]! + cost,
|
|
34
|
-
);
|
|
35
|
-
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
|
|
36
|
-
dp[i]![j] = Math.min(dp[i]![j]!, dp[i - 2]![j - 2]! + cost);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return dp[m]![n]!;
|
|
41
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { expect, it } from "@jest/globals";
|
|
2
|
-
import { ReaderArgs, ReaderOptionParsing } from "../src";
|
|
3
|
-
|
|
4
|
-
it("run", async function () {
|
|
5
|
-
const readerArgs = new ReaderArgs([
|
|
6
|
-
"--option=1.1",
|
|
7
|
-
"--option-alias1=1.2",
|
|
8
|
-
"--option-alias2",
|
|
9
|
-
"1.3",
|
|
10
|
-
"-pts=1.4",
|
|
11
|
-
"-o",
|
|
12
|
-
"1.5",
|
|
13
|
-
"--flag1-alias",
|
|
14
|
-
"-fa2=woops",
|
|
15
|
-
"-fa2o=1.6",
|
|
16
|
-
]);
|
|
17
|
-
|
|
18
|
-
const kOption = readerArgs.registerOption({
|
|
19
|
-
longs: ["option", "option-alias1", "option-alias2"],
|
|
20
|
-
shorts: ["pts", "o"],
|
|
21
|
-
parsing: optionValueFixedUniqueParsing,
|
|
22
|
-
});
|
|
23
|
-
const kFlag1 = readerArgs.registerOption({
|
|
24
|
-
longs: ["flag1", "flag1-alias"],
|
|
25
|
-
shorts: [],
|
|
26
|
-
parsing: optionFlagParsing,
|
|
27
|
-
});
|
|
28
|
-
const kFlag2 = readerArgs.registerOption({
|
|
29
|
-
longs: ["flag2"],
|
|
30
|
-
shorts: ["fa2"],
|
|
31
|
-
parsing: optionFlagParsing,
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
expect(readerArgs.consumePositional()).toStrictEqual(undefined);
|
|
35
|
-
|
|
36
|
-
expect(readerArgs.getOptionValues(kOption)).toStrictEqual([
|
|
37
|
-
{ inlined: "1.1", separated: [] },
|
|
38
|
-
{ inlined: "1.2", separated: [] },
|
|
39
|
-
{ inlined: null, separated: ["1.3"] },
|
|
40
|
-
{ inlined: "1.4", separated: [] },
|
|
41
|
-
{ inlined: null, separated: ["1.5"] },
|
|
42
|
-
{ inlined: "1.6", separated: [] },
|
|
43
|
-
]);
|
|
44
|
-
expect(readerArgs.getOptionValues(kFlag1)).toStrictEqual([
|
|
45
|
-
{ inlined: null, separated: [] },
|
|
46
|
-
]);
|
|
47
|
-
expect(readerArgs.getOptionValues(kFlag2)).toStrictEqual([
|
|
48
|
-
{ inlined: "woops", separated: [] },
|
|
49
|
-
{ inlined: null, separated: [] },
|
|
50
|
-
]);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
const optionFlagParsing: ReaderOptionParsing = {
|
|
54
|
-
consumeShortGroup: false,
|
|
55
|
-
consumeNextArg: () => false,
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const optionValueFixedUniqueParsing: ReaderOptionParsing = {
|
|
59
|
-
consumeShortGroup: true,
|
|
60
|
-
consumeNextArg: (inlined, separated) =>
|
|
61
|
-
inlined === null && separated.length === 0,
|
|
62
|
-
};
|