cli-kiss 0.0.3 → 0.0.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/index.d.ts +57 -42
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/lib/Command.ts +36 -38
- package/src/lib/Execution.ts +10 -13
- package/src/lib/Grid.ts +6 -2
- package/src/lib/Option.ts +2 -0
- package/src/lib/Reader.ts +4 -4
- package/src/lib/Run.ts +65 -50
- package/src/lib/Type.ts +27 -2
- package/src/lib/Typo.ts +21 -9
- package/src/lib/Usage.ts +63 -59
- package/tests/{unit.command.run.ts → unit.command.execute.ts} +26 -16
- package/tests/unit.command.usage.ts +81 -74
package/src/lib/Usage.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { GridCell, GridRow, gridToPrintableLines } from "./Grid";
|
|
|
3
3
|
import { TypoSupport, TypoText, typoPrintableString } from "./Typo";
|
|
4
4
|
|
|
5
5
|
export function usageToPrintableLines(params: {
|
|
6
|
-
cliName: string
|
|
6
|
+
cliName: Lowercase<string>;
|
|
7
7
|
commandUsage: CommandUsage;
|
|
8
8
|
typoSupport: TypoSupport;
|
|
9
9
|
}) {
|
|
@@ -11,42 +11,61 @@ export function usageToPrintableLines(params: {
|
|
|
11
11
|
|
|
12
12
|
const lines = new Array<string>();
|
|
13
13
|
|
|
14
|
-
lines.push(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
lines.push(
|
|
15
|
+
typoPrintableString(typoSupport, textDescription(commandUsage.description)),
|
|
16
|
+
);
|
|
17
|
+
if (commandUsage.details) {
|
|
18
|
+
for (const detailLine of commandUsage.details) {
|
|
19
|
+
lines.push(typoPrintableString(typoSupport, textDetails(detailLine)));
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
typoPrintableString(typoSupport, textName(cliName)),
|
|
23
|
+
lines.push("");
|
|
24
|
+
lines.push(typoPrintableString(typoSupport, textCategory("Usage:")));
|
|
25
|
+
const breadcrumbs = [
|
|
26
|
+
" ",
|
|
27
|
+
typoPrintableString(typoSupport, textFixed(cliName)),
|
|
28
28
|
].concat(
|
|
29
29
|
commandUsage.breadcrumbs.map((breadcrumb) => {
|
|
30
|
-
if (
|
|
31
|
-
return typoPrintableString(typoSupport,
|
|
30
|
+
if ("argument" in breadcrumb) {
|
|
31
|
+
return typoPrintableString(typoSupport, textInput(breadcrumb.argument));
|
|
32
|
+
}
|
|
33
|
+
if ("command" in breadcrumb) {
|
|
34
|
+
return typoPrintableString(typoSupport, textFixed(breadcrumb.command));
|
|
32
35
|
}
|
|
33
|
-
|
|
36
|
+
throw new Error(`Unknown breadcrumb: ${JSON.stringify(breadcrumb)}`);
|
|
34
37
|
}),
|
|
35
38
|
);
|
|
36
|
-
lines.push("");
|
|
37
|
-
lines.push(`${breadcrumbPrefix} ${breadcrumbsItems.join(" ")}`);
|
|
39
|
+
lines.push(breadcrumbs.join(" "));
|
|
38
40
|
|
|
39
41
|
if (commandUsage.arguments.length > 0) {
|
|
40
42
|
lines.push("");
|
|
41
|
-
lines.push(typoPrintableString(typoSupport,
|
|
43
|
+
lines.push(typoPrintableString(typoSupport, textCategory("Arguments:")));
|
|
42
44
|
const grid = new Array<GridRow>();
|
|
43
45
|
for (const argumentUsage of commandUsage.arguments) {
|
|
44
46
|
const gridRow = new Array<GridCell>();
|
|
45
|
-
gridRow.push([]);
|
|
46
|
-
gridRow.push([
|
|
47
|
-
gridRow.push([]);
|
|
47
|
+
gridRow.push([textDelimiter()]);
|
|
48
|
+
gridRow.push([textInput(argumentUsage.label)]);
|
|
48
49
|
if (argumentUsage.description) {
|
|
49
|
-
gridRow.push([
|
|
50
|
+
gridRow.push([textDelimiter()]);
|
|
51
|
+
gridRow.push([textDescription(argumentUsage.description)]);
|
|
52
|
+
}
|
|
53
|
+
grid.push(gridRow);
|
|
54
|
+
}
|
|
55
|
+
lines.push(...gridToPrintableLines(grid, typoSupport));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (commandUsage.subcommands.length > 0) {
|
|
59
|
+
lines.push("");
|
|
60
|
+
lines.push(typoPrintableString(typoSupport, textCategory("Subcommands:")));
|
|
61
|
+
const grid = new Array<GridRow>();
|
|
62
|
+
for (const subcommand of commandUsage.subcommands) {
|
|
63
|
+
const gridRow = new Array<GridCell>();
|
|
64
|
+
gridRow.push([textDelimiter()]);
|
|
65
|
+
gridRow.push([textFixed(subcommand.name)]);
|
|
66
|
+
if (subcommand.description) {
|
|
67
|
+
gridRow.push([textDelimiter()]);
|
|
68
|
+
gridRow.push([textDescription(subcommand.description)]);
|
|
50
69
|
}
|
|
51
70
|
grid.push(gridRow);
|
|
52
71
|
}
|
|
@@ -55,72 +74,57 @@ export function usageToPrintableLines(params: {
|
|
|
55
74
|
|
|
56
75
|
if (commandUsage.options.length > 0) {
|
|
57
76
|
lines.push("");
|
|
58
|
-
lines.push(typoPrintableString(typoSupport,
|
|
77
|
+
lines.push(typoPrintableString(typoSupport, textCategory("Options:")));
|
|
59
78
|
const grid = new Array<GridRow>();
|
|
60
79
|
for (const optionUsage of commandUsage.options) {
|
|
61
80
|
const gridRow = new Array<GridCell>();
|
|
62
|
-
gridRow.push([]);
|
|
81
|
+
gridRow.push([textDelimiter()]);
|
|
63
82
|
if (optionUsage.short) {
|
|
64
|
-
gridRow.push([
|
|
83
|
+
gridRow.push([textFixed(`-${optionUsage.short}`), { value: ", " }]);
|
|
65
84
|
} else {
|
|
66
85
|
gridRow.push([]);
|
|
67
86
|
}
|
|
68
87
|
if (optionUsage.label) {
|
|
69
88
|
gridRow.push([
|
|
70
|
-
|
|
71
|
-
|
|
89
|
+
textFixed(`--${optionUsage.long} `),
|
|
90
|
+
textInput(optionUsage.label),
|
|
72
91
|
]);
|
|
73
92
|
} else {
|
|
74
|
-
gridRow.push([
|
|
75
|
-
textName(`--${optionUsage.long}`),
|
|
76
|
-
{ value: "[=yes|no]", color: "grey" },
|
|
77
|
-
]);
|
|
93
|
+
gridRow.push([textFixed(`--${optionUsage.long}`)]);
|
|
78
94
|
}
|
|
79
|
-
gridRow.push([]);
|
|
80
95
|
if (optionUsage.description) {
|
|
81
|
-
gridRow.push([
|
|
96
|
+
gridRow.push([textDelimiter()]);
|
|
97
|
+
gridRow.push([textDescription(optionUsage.description)]);
|
|
82
98
|
}
|
|
83
99
|
grid.push(gridRow);
|
|
84
100
|
}
|
|
85
101
|
lines.push(...gridToPrintableLines(grid, typoSupport));
|
|
86
102
|
}
|
|
87
103
|
|
|
88
|
-
if (commandUsage.subcommands.length > 0) {
|
|
89
|
-
lines.push("");
|
|
90
|
-
lines.push(typoPrintableString(typoSupport, textTitle("Subcommands:")));
|
|
91
|
-
const grid = new Array<GridRow>();
|
|
92
|
-
for (const subcommand of commandUsage.subcommands) {
|
|
93
|
-
const gridRow = new Array<GridCell>();
|
|
94
|
-
gridRow.push([]);
|
|
95
|
-
gridRow.push([textName(subcommand.name)]);
|
|
96
|
-
gridRow.push([]);
|
|
97
|
-
if (subcommand.title) {
|
|
98
|
-
gridRow.push([textDesc(subcommand.title)]);
|
|
99
|
-
}
|
|
100
|
-
grid.push(gridRow);
|
|
101
|
-
}
|
|
102
|
-
lines.push(...gridToPrintableLines(grid, typoSupport));
|
|
103
|
-
}
|
|
104
104
|
lines.push("");
|
|
105
105
|
return lines;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
function
|
|
109
|
-
return { value: text, color: "
|
|
108
|
+
function textCategory(text: string): TypoText {
|
|
109
|
+
return { value: text, color: "brightGreen", bold: true };
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
function
|
|
113
|
-
return { value: text,
|
|
112
|
+
function textDescription(text: string): TypoText {
|
|
113
|
+
return { value: text, bold: true };
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
function
|
|
117
|
-
return { value: text,
|
|
116
|
+
function textDetails(text: string): TypoText {
|
|
117
|
+
return { value: text, color: "brightBlack" };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function textFixed(text: string): TypoText {
|
|
121
|
+
return { value: text, color: "brightCyan", bold: true };
|
|
118
122
|
}
|
|
119
123
|
|
|
120
|
-
function
|
|
121
|
-
return { value: text, color: "
|
|
124
|
+
function textInput(text: string): TypoText {
|
|
125
|
+
return { value: text, color: "brightBlue" };
|
|
122
126
|
}
|
|
123
127
|
|
|
124
|
-
function
|
|
125
|
-
return { value:
|
|
128
|
+
function textDelimiter(): TypoText {
|
|
129
|
+
return { value: " " };
|
|
126
130
|
}
|
|
@@ -3,19 +3,21 @@ import {
|
|
|
3
3
|
argumentOptional,
|
|
4
4
|
argumentRequired,
|
|
5
5
|
argumentVariadics,
|
|
6
|
+
Command,
|
|
6
7
|
command,
|
|
7
8
|
commandWithSubcommands,
|
|
8
9
|
execution,
|
|
9
10
|
optionFlag,
|
|
10
11
|
optionRepeatable,
|
|
11
12
|
optionSingleValue,
|
|
12
|
-
|
|
13
|
+
ReaderTokenizer,
|
|
14
|
+
typeCommaList,
|
|
13
15
|
typeNumber,
|
|
14
16
|
typeString,
|
|
15
17
|
} from "../src";
|
|
16
18
|
|
|
17
|
-
const
|
|
18
|
-
{
|
|
19
|
+
const rootCommand = commandWithSubcommands<string, any, any>(
|
|
20
|
+
{ description: "Root command description" },
|
|
19
21
|
execution(
|
|
20
22
|
{
|
|
21
23
|
options: {
|
|
@@ -27,7 +29,7 @@ const cmd = commandWithSubcommands<string, any, any>(
|
|
|
27
29
|
}),
|
|
28
30
|
numberOption: optionRepeatable({
|
|
29
31
|
long: "number-option",
|
|
30
|
-
type: typeNumber,
|
|
32
|
+
type: typeCommaList(typeNumber),
|
|
31
33
|
}),
|
|
32
34
|
},
|
|
33
35
|
arguments: [
|
|
@@ -41,7 +43,7 @@ const cmd = commandWithSubcommands<string, any, any>(
|
|
|
41
43
|
),
|
|
42
44
|
{
|
|
43
45
|
sub1: command(
|
|
44
|
-
{
|
|
46
|
+
{ description: "Subcommand 1 description" },
|
|
45
47
|
execution(
|
|
46
48
|
{
|
|
47
49
|
options: {},
|
|
@@ -53,7 +55,7 @@ const cmd = commandWithSubcommands<string, any, any>(
|
|
|
53
55
|
),
|
|
54
56
|
),
|
|
55
57
|
sub2: command(
|
|
56
|
-
{
|
|
58
|
+
{ description: "Subcommand 2 description" },
|
|
57
59
|
execution(
|
|
58
60
|
{
|
|
59
61
|
options: {},
|
|
@@ -72,10 +74,10 @@ const cmd = commandWithSubcommands<string, any, any>(
|
|
|
72
74
|
);
|
|
73
75
|
|
|
74
76
|
it("run", async () => {
|
|
75
|
-
const res1 = await
|
|
76
|
-
["
|
|
77
|
+
const res1 = await executeInterpreted(
|
|
78
|
+
["50", "51", "sub1", "final"],
|
|
77
79
|
"Run Context Input",
|
|
78
|
-
|
|
80
|
+
rootCommand,
|
|
79
81
|
);
|
|
80
82
|
expect(res1).toStrictEqual({
|
|
81
83
|
context: {
|
|
@@ -97,25 +99,23 @@ it("run", async () => {
|
|
|
97
99
|
at: "sub1",
|
|
98
100
|
});
|
|
99
101
|
|
|
100
|
-
const res2 = await
|
|
102
|
+
const res2 = await executeInterpreted(
|
|
101
103
|
[
|
|
102
|
-
"node",
|
|
103
|
-
"script",
|
|
104
104
|
"40",
|
|
105
105
|
"41",
|
|
106
106
|
"sub2",
|
|
107
107
|
"--string-option=hello",
|
|
108
108
|
"--number-option",
|
|
109
|
-
"123",
|
|
109
|
+
"123.1,123.2",
|
|
110
110
|
"--number-option",
|
|
111
|
-
"
|
|
111
|
+
"123.3",
|
|
112
112
|
"88.88",
|
|
113
113
|
"a,b",
|
|
114
114
|
"final",
|
|
115
115
|
"--boolean-flag",
|
|
116
116
|
],
|
|
117
117
|
"Run Context Input",
|
|
118
|
-
|
|
118
|
+
rootCommand,
|
|
119
119
|
);
|
|
120
120
|
expect(res2).toStrictEqual({
|
|
121
121
|
context: {
|
|
@@ -124,7 +124,7 @@ it("run", async () => {
|
|
|
124
124
|
options: {
|
|
125
125
|
booleanFlag: true,
|
|
126
126
|
stringOption: "hello",
|
|
127
|
-
numberOption: [123,
|
|
127
|
+
numberOption: [[123.1, 123.2], [123.3]],
|
|
128
128
|
},
|
|
129
129
|
arguments: [40, 41],
|
|
130
130
|
},
|
|
@@ -137,3 +137,13 @@ it("run", async () => {
|
|
|
137
137
|
at: "sub2",
|
|
138
138
|
});
|
|
139
139
|
});
|
|
140
|
+
|
|
141
|
+
async function executeInterpreted<Context, Result>(
|
|
142
|
+
args: Array<string>,
|
|
143
|
+
context: Context,
|
|
144
|
+
command: Command<Context, Result>,
|
|
145
|
+
) {
|
|
146
|
+
const readerTokenizer = new ReaderTokenizer(args);
|
|
147
|
+
const commandInterpreter = command.buildInterpreter(readerTokenizer);
|
|
148
|
+
return await commandInterpreter.execute(context);
|
|
149
|
+
}
|
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
optionRepeatable,
|
|
12
12
|
optionSingleValue,
|
|
13
13
|
ReaderTokenizer,
|
|
14
|
+
typeCommaList,
|
|
15
|
+
typeCommaTuple,
|
|
14
16
|
typeNumber,
|
|
15
17
|
typeString,
|
|
16
18
|
} from "../src";
|
|
@@ -18,11 +20,8 @@ import { usageToPrintableLines } from "../src/lib/Usage";
|
|
|
18
20
|
|
|
19
21
|
const cmd = commandWithSubcommands<string, any, any>(
|
|
20
22
|
{
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"Root command description",
|
|
24
|
-
"Second line of root command description",
|
|
25
|
-
],
|
|
23
|
+
description: "Root command description",
|
|
24
|
+
details: ["Root command details", "Second line of root command details"],
|
|
26
25
|
},
|
|
27
26
|
execution(
|
|
28
27
|
{
|
|
@@ -40,11 +39,10 @@ const cmd = commandWithSubcommands<string, any, any>(
|
|
|
40
39
|
label: "COOL-STUFF",
|
|
41
40
|
description: "Root string-option description",
|
|
42
41
|
}),
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
description: "Root number-option description",
|
|
42
|
+
complexOption: optionRepeatable({
|
|
43
|
+
long: "complex-option",
|
|
44
|
+
type: typeCommaTuple([typeNumber, typeCommaList(typeString)]),
|
|
45
|
+
description: "Root complex-option description",
|
|
48
46
|
}),
|
|
49
47
|
},
|
|
50
48
|
arguments: [
|
|
@@ -67,10 +65,10 @@ const cmd = commandWithSubcommands<string, any, any>(
|
|
|
67
65
|
{
|
|
68
66
|
sub1: command(
|
|
69
67
|
{
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
"Subcommand 1
|
|
73
|
-
"Second line of subcommand 1
|
|
68
|
+
description: "Subcommand 1 description",
|
|
69
|
+
details: [
|
|
70
|
+
"Subcommand 1 details",
|
|
71
|
+
"Second line of subcommand 1 details",
|
|
74
72
|
],
|
|
75
73
|
},
|
|
76
74
|
execution(
|
|
@@ -91,10 +89,10 @@ const cmd = commandWithSubcommands<string, any, any>(
|
|
|
91
89
|
),
|
|
92
90
|
sub2: command(
|
|
93
91
|
{
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
"Subcommand 2
|
|
97
|
-
"Second line of subcommand 2
|
|
92
|
+
description: "Subcommand 2 description",
|
|
93
|
+
details: [
|
|
94
|
+
"Subcommand 2 details",
|
|
95
|
+
"Second line of subcommand 2 details",
|
|
98
96
|
],
|
|
99
97
|
},
|
|
100
98
|
execution(
|
|
@@ -120,7 +118,7 @@ const cmd = commandWithSubcommands<string, any, any>(
|
|
|
120
118
|
default: () => "42",
|
|
121
119
|
}),
|
|
122
120
|
argumentVariadics({
|
|
123
|
-
label: "VARIADIC
|
|
121
|
+
label: "VARIADIC",
|
|
124
122
|
description: "Variadic positional arguments",
|
|
125
123
|
type: typeString,
|
|
126
124
|
}),
|
|
@@ -135,57 +133,58 @@ const cmd = commandWithSubcommands<string, any, any>(
|
|
|
135
133
|
);
|
|
136
134
|
|
|
137
135
|
it("run", async () => {
|
|
138
|
-
const usage1 = getUsage([], cmd);
|
|
136
|
+
const usage1 = await getUsage([], cmd);
|
|
137
|
+
// console.log(usage1.join("\n"));
|
|
139
138
|
expect(usage1).toStrictEqual([
|
|
139
|
+
"{Root command description}+",
|
|
140
|
+
"{Root command details}@brightBlack",
|
|
141
|
+
"{Second line of root command details}@brightBlack",
|
|
140
142
|
"",
|
|
141
|
-
"{
|
|
142
|
-
"{
|
|
143
|
-
"{Second line of root command description}@grey",
|
|
143
|
+
"{Usage:}@brightGreen+",
|
|
144
|
+
" {my-cli}@brightCyan+ {<POS-1>}@brightBlue {<POS-2>}@brightBlue {<SUBCOMMAND>}@brightCyan+",
|
|
144
145
|
"",
|
|
145
|
-
"{
|
|
146
|
+
"{Arguments:}@brightGreen+",
|
|
147
|
+
"{ }{<POS-1>}@brightBlue{ }{First positional argument}+",
|
|
148
|
+
"{ }{<POS-2>}@brightBlue{ }{Second positional argument}+",
|
|
146
149
|
"",
|
|
147
|
-
"{
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
+
"{Subcommands:}@brightGreen+",
|
|
151
|
+
"{ }{sub1}@brightCyan+{ }{Subcommand 1 description}+",
|
|
152
|
+
"{ }{sub2}@brightCyan+{ }{Subcommand 2 description}+",
|
|
150
153
|
"",
|
|
151
|
-
"{Options:}@
|
|
152
|
-
"
|
|
153
|
-
"
|
|
154
|
-
"
|
|
155
|
-
"",
|
|
156
|
-
"{Subcommands:}@green+",
|
|
157
|
-
" {sub1}@cyan+ {Subcommand 1 title}+",
|
|
158
|
-
" {sub2}@cyan+ {Subcommand 2 title}+",
|
|
154
|
+
"{Options:}@brightGreen+",
|
|
155
|
+
"{ }{-b}@brightCyan+{, }{--boolean-flag}@brightCyan+ { }{Root boolean-flag description}+",
|
|
156
|
+
"{ }{-s}@brightCyan+{, }{--string-option }@brightCyan+{<COOL-STUFF>}@brightBlue { }{Root string-option description}+",
|
|
157
|
+
"{ } {--complex-option }@brightCyan+{<NUMBER,STRING[,STRING...]>}@brightBlue{ }{Root complex-option description}+",
|
|
159
158
|
"",
|
|
160
159
|
]);
|
|
161
160
|
|
|
162
|
-
const usage2 = getUsage(["50", "51", "sub1", "final"], cmd);
|
|
161
|
+
const usage2 = await getUsage(["50", "51", "sub1", "final"], cmd);
|
|
163
162
|
expect(usage2).toStrictEqual([
|
|
163
|
+
"{Subcommand 1 description}+",
|
|
164
|
+
"{Subcommand 1 details}@brightBlack",
|
|
165
|
+
"{Second line of subcommand 1 details}@brightBlack",
|
|
164
166
|
"",
|
|
165
|
-
"{
|
|
166
|
-
"{
|
|
167
|
-
"{Second line of subcommand 1 description}@grey",
|
|
168
|
-
"",
|
|
169
|
-
"{Usage:}@green+ {my-cli}@cyan+ {<POS-1>}@cyan {<POS-2>}@cyan {sub1}@cyan+ {<POS-STRING>}@cyan",
|
|
167
|
+
"{Usage:}@brightGreen+",
|
|
168
|
+
" {my-cli}@brightCyan+ {<POS-1>}@brightBlue {<POS-2>}@brightBlue {sub1}@brightCyan+ {<POS-STRING>}@brightBlue",
|
|
170
169
|
"",
|
|
171
|
-
"{Arguments:}@
|
|
172
|
-
"
|
|
173
|
-
"
|
|
174
|
-
"
|
|
170
|
+
"{Arguments:}@brightGreen+",
|
|
171
|
+
"{ }{<POS-1>}@brightBlue { }{First positional argument}+",
|
|
172
|
+
"{ }{<POS-2>}@brightBlue { }{Second positional argument}+",
|
|
173
|
+
"{ }{<POS-STRING>}@brightBlue{ }{Positional string argument}+",
|
|
175
174
|
"",
|
|
176
|
-
"{Options:}@
|
|
177
|
-
"
|
|
178
|
-
"
|
|
179
|
-
"
|
|
175
|
+
"{Options:}@brightGreen+",
|
|
176
|
+
"{ }{-b}@brightCyan+{, }{--boolean-flag}@brightCyan+ { }{Root boolean-flag description}+",
|
|
177
|
+
"{ }{-s}@brightCyan+{, }{--string-option }@brightCyan+{<COOL-STUFF>}@brightBlue { }{Root string-option description}+",
|
|
178
|
+
"{ } {--complex-option }@brightCyan+{<NUMBER,STRING[,STRING...]>}@brightBlue{ }{Root complex-option description}+",
|
|
180
179
|
"",
|
|
181
180
|
]);
|
|
182
181
|
|
|
183
|
-
const usage3 = getUsage(
|
|
182
|
+
const usage3 = await getUsage(
|
|
184
183
|
[
|
|
185
184
|
"40",
|
|
186
185
|
"41",
|
|
187
186
|
"sub2",
|
|
188
|
-
"--
|
|
187
|
+
"--complex-option=42,hello,world",
|
|
189
188
|
"--number-option",
|
|
190
189
|
"123",
|
|
191
190
|
"--number-option",
|
|
@@ -198,37 +197,45 @@ it("run", async () => {
|
|
|
198
197
|
cmd,
|
|
199
198
|
);
|
|
200
199
|
expect(usage3).toStrictEqual([
|
|
201
|
-
"",
|
|
202
|
-
"{Subcommand 2
|
|
203
|
-
"{
|
|
204
|
-
"
|
|
205
|
-
"",
|
|
206
|
-
"{
|
|
207
|
-
"",
|
|
208
|
-
"{Arguments:}@
|
|
209
|
-
"
|
|
210
|
-
"
|
|
211
|
-
"
|
|
212
|
-
"
|
|
213
|
-
"
|
|
214
|
-
"",
|
|
215
|
-
"{Options:}@
|
|
216
|
-
"
|
|
217
|
-
"
|
|
218
|
-
"
|
|
219
|
-
"
|
|
200
|
+
"{Subcommand 2 description}+",
|
|
201
|
+
"{Subcommand 2 details}@brightBlack",
|
|
202
|
+
"{Second line of subcommand 2 details}@brightBlack",
|
|
203
|
+
"",
|
|
204
|
+
"{Usage:}@brightGreen+",
|
|
205
|
+
" {my-cli}@brightCyan+ {<POS-1>}@brightBlue {<POS-2>}@brightBlue {sub2}@brightCyan+ {<POS-NUMBER>}@brightBlue {[OPT-POS]}@brightBlue {[VARIADIC...]}@brightBlue",
|
|
206
|
+
"",
|
|
207
|
+
"{Arguments:}@brightGreen+",
|
|
208
|
+
"{ }{<POS-1>}@brightBlue { }{First positional argument}+",
|
|
209
|
+
"{ }{<POS-2>}@brightBlue { }{Second positional argument}+",
|
|
210
|
+
"{ }{<POS-NUMBER>}@brightBlue { }{Positional number argument}+",
|
|
211
|
+
"{ }{[OPT-POS]}@brightBlue { }{Optional positional argument}+",
|
|
212
|
+
"{ }{[VARIADIC...]}@brightBlue{ }{Variadic positional arguments}+",
|
|
213
|
+
"",
|
|
214
|
+
"{Options:}@brightGreen+",
|
|
215
|
+
"{ }{-b}@brightCyan+{, }{--boolean-flag}@brightCyan+ { }{Root boolean-flag description}+",
|
|
216
|
+
"{ }{-s}@brightCyan+{, }{--string-option }@brightCyan+{<COOL-STUFF>}@brightBlue { }{Root string-option description}+",
|
|
217
|
+
"{ } {--complex-option }@brightCyan+{<NUMBER,STRING[,STRING...]>}@brightBlue{ }{Root complex-option description}+",
|
|
218
|
+
"{ } {--dudu }@brightCyan+{<STRING>}@brightBlue { }{Dudu option description}+",
|
|
220
219
|
"",
|
|
221
220
|
]);
|
|
222
221
|
});
|
|
223
222
|
|
|
224
|
-
function getUsage<Context, Result>(
|
|
225
|
-
|
|
223
|
+
async function getUsage<Context, Result>(
|
|
224
|
+
args: Array<string>,
|
|
226
225
|
command: Command<Context, Result>,
|
|
227
226
|
) {
|
|
228
|
-
const
|
|
227
|
+
const readerTokenizer = new ReaderTokenizer(args);
|
|
228
|
+
const commandInterpreter = command.buildInterpreter(readerTokenizer);
|
|
229
|
+
/*
|
|
230
|
+
try {
|
|
231
|
+
console.log(await commandInterpreter.execute({} as Context));
|
|
232
|
+
} catch (error) {
|
|
233
|
+
console.error("Error during execution:", error);
|
|
234
|
+
}
|
|
235
|
+
*/
|
|
229
236
|
return usageToPrintableLines({
|
|
230
237
|
cliName: "my-cli",
|
|
231
|
-
commandUsage:
|
|
238
|
+
commandUsage: commandInterpreter.computeUsage(),
|
|
232
239
|
typoSupport: "mock",
|
|
233
240
|
});
|
|
234
241
|
}
|