cli-kiss 0.2.3 → 0.2.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/README.md +1 -1
- package/dist/index.d.ts +696 -734
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/docs/.vitepress/config.mts +2 -3
- package/docs/.vitepress/theme/index.ts +4 -0
- package/docs/.vitepress/theme/style.css +4 -0
- package/docs/guide/01_getting_started.md +12 -13
- package/docs/guide/02_commands.md +71 -52
- package/docs/guide/03_options.md +25 -33
- package/docs/guide/04_positionals.md +45 -55
- package/docs/guide/05_types.md +66 -66
- package/docs/guide/06_run.md +28 -40
- package/docs/index.md +8 -3
- package/docs/public/favicon.ico +0 -0
- package/docs/public/hero.png +0 -0
- package/package.json +1 -1
- package/src/index.ts +0 -2
- package/src/lib/Command.ts +45 -123
- package/src/lib/Operation.ts +23 -32
- package/src/lib/Option.ts +150 -170
- package/src/lib/Positional.ts +44 -94
- package/src/lib/Reader.ts +123 -99
- package/src/lib/Run.ts +86 -45
- package/src/lib/Type.ts +246 -156
- package/src/lib/Typo.ts +98 -107
- package/src/lib/Usage.ts +163 -82
- package/tests/unit.Reader.aliases.ts +31 -15
- package/tests/unit.Reader.commons.ts +99 -43
- package/tests/unit.Reader.parsings.ts +50 -0
- package/tests/unit.Reader.shortBig.ts +75 -31
- package/tests/unit.command.execute.ts +86 -43
- package/tests/unit.command.usage.ts +88 -82
- package/tests/unit.runner.colors.ts +197 -0
- package/tests/unit.runner.cycle.ts +77 -63
- package/tests/unit.runner.errors.ts +23 -15
package/src/lib/Run.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Command, CommandDecoder } from "./Command";
|
|
2
|
+
import { optionFlag, optionSingleValue } from "./Option";
|
|
2
3
|
import { ReaderArgs } from "./Reader";
|
|
4
|
+
import { typeChoice } from "./Type";
|
|
3
5
|
import { TypoSupport } from "./Typo";
|
|
4
6
|
import { usageToStyledLines } from "./Usage";
|
|
5
7
|
|
|
@@ -7,17 +9,17 @@ import { usageToStyledLines } from "./Usage";
|
|
|
7
9
|
* Main entry point: parses CLI arguments, executes the matched command, and exits.
|
|
8
10
|
* Handles `--help`, `--version`, usage-on-error, and exit codes.
|
|
9
11
|
*
|
|
10
|
-
* Exit codes:
|
|
12
|
+
* Exit codes:
|
|
13
|
+
* - `0` on success / `--help` / `--version`
|
|
14
|
+
* - `1` on parse error or execution error.
|
|
11
15
|
*
|
|
12
|
-
* @typeParam Context -
|
|
16
|
+
* @typeParam Context - Forwarded unchanged to the handler.
|
|
13
17
|
*
|
|
14
18
|
* @param cliName - Program name used in usage and `--version` output.
|
|
15
19
|
* @param cliArgs - Raw arguments, typically `process.argv.slice(2)`.
|
|
16
|
-
* @param context - Forwarded to the
|
|
20
|
+
* @param context - Forwarded to the handler.
|
|
17
21
|
* @param command - Root {@link Command}.
|
|
18
|
-
* @param options -
|
|
19
|
-
* @param options.useTtyColors - Color mode: `true` (always), `false` (never),
|
|
20
|
-
* `"mock"` (snapshot-friendly), `undefined` (auto-detect from env).
|
|
22
|
+
* @param options.colorSetup - Configures color support; enables `--color` flag if set to `"flag"`.
|
|
21
23
|
* @param options.usageOnHelp - Enables `--help` flag (default `true`).
|
|
22
24
|
* @param options.usageOnError - Prints usage to stderr on parse error (default `true`).
|
|
23
25
|
* @param options.buildVersion - Enables `--version`; prints `<cliName> <buildVersion>`.
|
|
@@ -28,13 +30,13 @@ import { usageToStyledLines } from "./Usage";
|
|
|
28
30
|
*
|
|
29
31
|
* @example
|
|
30
32
|
* ```ts
|
|
31
|
-
* import { runAndExit, command, operation, positionalRequired,
|
|
33
|
+
* import { runAndExit, command, operation, positionalRequired, type } from "cli-kiss";
|
|
32
34
|
*
|
|
33
35
|
* const greetCommand = command(
|
|
34
36
|
* { description: "Greet someone" },
|
|
35
37
|
* operation(
|
|
36
|
-
* { options: {}, positionals: [positionalRequired({ type:
|
|
37
|
-
* async (_ctx, { positionals: [name] })
|
|
38
|
+
* { options: {}, positionals: [positionalRequired({ type: type("name") })] },
|
|
39
|
+
* async function (_ctx, { positionals: [name] }) {
|
|
38
40
|
* console.log(`Hello, ${name}!`);
|
|
39
41
|
* },
|
|
40
42
|
* ),
|
|
@@ -46,12 +48,12 @@ import { usageToStyledLines } from "./Usage";
|
|
|
46
48
|
* ```
|
|
47
49
|
*/
|
|
48
50
|
export async function runAndExit<Context>(
|
|
49
|
-
cliName:
|
|
51
|
+
cliName: string,
|
|
50
52
|
cliArgs: ReadonlyArray<string>,
|
|
51
53
|
context: Context,
|
|
52
54
|
command: Command<Context, void>,
|
|
53
55
|
options?: {
|
|
54
|
-
|
|
56
|
+
colorSetup?: "flag" | "env" | "always" | "never" | "mock" | undefined;
|
|
55
57
|
usageOnHelp?: boolean | undefined;
|
|
56
58
|
usageOnError?: boolean | undefined;
|
|
57
59
|
buildVersion?: string | undefined;
|
|
@@ -60,20 +62,58 @@ export async function runAndExit<Context>(
|
|
|
60
62
|
},
|
|
61
63
|
): Promise<never> {
|
|
62
64
|
const readerArgs = new ReaderArgs(cliArgs);
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
const preprocessors = new Array<
|
|
66
|
+
(commandDecoder: CommandDecoder<Context, void>) => undefined | number
|
|
67
|
+
>();
|
|
68
|
+
let typoSupport = TypoSupport.none();
|
|
69
|
+
const colorSetup = options?.colorSetup ?? "flag";
|
|
70
|
+
if (colorSetup === "flag") {
|
|
71
|
+
const colorOption = optionSingleValue<"auto" | "always" | "never" | "mock">(
|
|
72
|
+
{
|
|
73
|
+
long: "color",
|
|
74
|
+
type: typeChoice("color-mode", ["auto", "always", "never", "mock"]),
|
|
75
|
+
defaultWhenNotDefined: () => "auto",
|
|
76
|
+
defaultWhenNotInlined: () => "always",
|
|
77
|
+
},
|
|
78
|
+
).registerAndMakeDecoder(readerArgs);
|
|
79
|
+
preprocessors.push(() => {
|
|
80
|
+
try {
|
|
81
|
+
typoSupport = computeTypoSupport(colorOption.getAndDecodeValue());
|
|
82
|
+
} catch (error) {
|
|
83
|
+
typoSupport = TypoSupport.inferFromEnv();
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
return undefined;
|
|
87
|
+
});
|
|
88
|
+
} else {
|
|
89
|
+
if (colorSetup === "env") {
|
|
90
|
+
typoSupport = TypoSupport.inferFromEnv();
|
|
91
|
+
} else {
|
|
92
|
+
typoSupport = computeTypoSupport(colorSetup);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (options?.usageOnHelp ?? true) {
|
|
96
|
+
const helpOption = optionFlag({ long: "help" }).registerAndMakeDecoder(
|
|
97
|
+
readerArgs,
|
|
98
|
+
);
|
|
99
|
+
preprocessors.push((commandDecoder) => {
|
|
100
|
+
if (!helpOption.getAndDecodeValue()) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
console.log(computeUsageString(cliName, commandDecoder, typoSupport));
|
|
104
|
+
return 0;
|
|
69
105
|
});
|
|
70
106
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
107
|
+
if (options?.buildVersion) {
|
|
108
|
+
const versionOption = optionFlag({
|
|
109
|
+
long: "version",
|
|
110
|
+
}).registerAndMakeDecoder(readerArgs);
|
|
111
|
+
preprocessors.push(() => {
|
|
112
|
+
if (!versionOption.getAndDecodeValue()) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
console.log([cliName, options.buildVersion].join(" "));
|
|
116
|
+
return 0;
|
|
77
117
|
});
|
|
78
118
|
}
|
|
79
119
|
/*
|
|
@@ -94,27 +134,13 @@ export async function runAndExit<Context>(
|
|
|
94
134
|
} catch (_) {}
|
|
95
135
|
}
|
|
96
136
|
const onExit = options?.onExit ?? process.exit;
|
|
97
|
-
const typoSupport =
|
|
98
|
-
options?.useTtyColors === undefined
|
|
99
|
-
? TypoSupport.inferFromProcess()
|
|
100
|
-
: options.useTtyColors === "mock"
|
|
101
|
-
? TypoSupport.mock()
|
|
102
|
-
: options.useTtyColors
|
|
103
|
-
? TypoSupport.tty()
|
|
104
|
-
: TypoSupport.none();
|
|
105
|
-
if (usageOnHelp) {
|
|
106
|
-
if (readerArgs.getOptionValues("--help" as any).length > 0) {
|
|
107
|
-
console.log(computeUsageString(cliName, commandDecoder, typoSupport));
|
|
108
|
-
return onExit(0);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
if (buildVersion) {
|
|
112
|
-
if (readerArgs.getOptionValues("--version" as any).length > 0) {
|
|
113
|
-
console.log([cliName, buildVersion].join(" "));
|
|
114
|
-
return onExit(0);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
137
|
try {
|
|
138
|
+
for (const preprocessor of preprocessors) {
|
|
139
|
+
const preprocessorResult = preprocessor(commandDecoder);
|
|
140
|
+
if (preprocessorResult !== undefined) {
|
|
141
|
+
return onExit(preprocessorResult);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
118
144
|
const commandInterpreter = commandDecoder.decodeAndMakeInterpreter();
|
|
119
145
|
try {
|
|
120
146
|
await commandInterpreter.executeWithContext(context);
|
|
@@ -145,13 +171,28 @@ function handleError(
|
|
|
145
171
|
}
|
|
146
172
|
|
|
147
173
|
function computeUsageString<Context, Result>(
|
|
148
|
-
cliName:
|
|
174
|
+
cliName: string,
|
|
149
175
|
commandDecoder: CommandDecoder<Context, Result>,
|
|
150
176
|
typoSupport: TypoSupport,
|
|
151
177
|
) {
|
|
152
178
|
return usageToStyledLines({
|
|
153
179
|
cliName,
|
|
154
|
-
|
|
180
|
+
usage: commandDecoder.generateUsage(),
|
|
155
181
|
typoSupport,
|
|
156
182
|
}).join("\n");
|
|
157
183
|
}
|
|
184
|
+
|
|
185
|
+
function computeTypoSupport(
|
|
186
|
+
colorMode: "auto" | "always" | "never" | "mock",
|
|
187
|
+
): TypoSupport {
|
|
188
|
+
switch (colorMode) {
|
|
189
|
+
case "auto":
|
|
190
|
+
return TypoSupport.inferFromEnv();
|
|
191
|
+
case "always":
|
|
192
|
+
return TypoSupport.tty();
|
|
193
|
+
case "never":
|
|
194
|
+
return TypoSupport.none();
|
|
195
|
+
case "mock":
|
|
196
|
+
return TypoSupport.mock();
|
|
197
|
+
}
|
|
198
|
+
}
|