cli-kiss 0.2.4 → 0.2.6

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.
@@ -1,132 +0,0 @@
1
- # Types
2
-
3
- A `Type<Value>` converts a raw CLI string into a typed value: a `content` label paired with a `decoder`.
4
-
5
- ## Built-in types
6
-
7
- | Export | TypeScript type | Accepts |
8
- | ------------- | --------------- | ---------------------------------------------------------- |
9
- | `typeString` | `string` | Any string |
10
- | `typeBoolean` | `boolean` | `true/yes/on/1/y/t` → true, `false/no/off/0/n/f` → false (case-insensitive) |
11
- | `typeNumber` | `number` | Integers, floats, scientific notation |
12
- | `typeInteger` | `bigint` | Integer strings only |
13
- | `typeDate` | `Date` | Any format accepted by `Date.parse` (ISO 8601 recommended) |
14
- | `typeUrl` | `URL` | Absolute URLs |
15
-
16
- ```ts
17
- import {
18
- typeBoolean,
19
- typeDate,
20
- typeInteger,
21
- typeNumber,
22
- typeString,
23
- typeUrl,
24
- } from "cli-kiss";
25
-
26
- typeString.decoder("hello"); // → "hello"
27
- typeBoolean.decoder("yes"); // → true
28
- typeNumber.decoder("3.14"); // → 3.14
29
- typeInteger.decoder("9007199254740993"); // → 9007199254740993n
30
- typeDate.decoder("2024-01-15"); // → Date object
31
- typeUrl.decoder("https://example.com/path"); // → URL object
32
- ```
33
-
34
- ## `typeOneOf` — string enum
35
-
36
- Accepts only a fixed set of strings:
37
-
38
- ```ts
39
- import { typeOneOf } from "cli-kiss";
40
-
41
- const typeEnv = typeOneOf("Environment", ["dev", "staging", "prod"]);
42
-
43
- typeEnv.decoder("prod"); // → "prod"
44
- typeEnv.decoder("unknown");
45
- // Error: Invalid value: "unknown" (expected one of: "dev" | "staging" | "prod")
46
- ```
47
-
48
- ## `typeMapped` — transform an existing type
49
-
50
- Chain a `before` type with an `after` transformation:
51
-
52
- ```ts
53
- import { typeMapped, typeNumber } from "cli-kiss";
54
-
55
- const typePort = typeMapped(typeNumber, {
56
- content: "Port",
57
- decoder: (n) => {
58
- if (n < 1 || n > 65535) throw new Error("Out of range");
59
- return n;
60
- },
61
- });
62
- // "--port 8080" → 8080
63
- // "--port 99999" → Error: --port: <PORT>: Port: Out of range
64
- ```
65
-
66
- Errors from the `before` decoder are prefixed with `from: <content>`.
67
-
68
- ## `typeTuple` — fixed-length delimited value
69
-
70
- Splits a string into a fixed-length typed tuple:
71
-
72
- ```ts
73
- import { typeTuple, typeNumber } from "cli-kiss";
74
-
75
- const typePoint = typeTuple([typeNumber, typeNumber]);
76
-
77
- typePoint.decoder("3.14,2.71"); // → [3.14, 2.71]
78
- typePoint.decoder("x,2"); // → Error: at 0: Number: Unable to parse: "x"
79
- ```
80
-
81
- The default separator is `","`. Pass a second argument to change it:
82
-
83
- ```ts
84
- typeTuple([typeString, typeNumber], ":");
85
- // "foo:42" → ["foo", 42]
86
- ```
87
-
88
- ## `typeList` — variable-length delimited value
89
-
90
- Splits a string into an array of typed values:
91
-
92
- ```ts
93
- import { typeList, typeNumber } from "cli-kiss";
94
-
95
- const typeNumbers = typeList(typeNumber);
96
-
97
- typeNumbers.decoder("1,2,3"); // → [1, 2, 3]
98
- typeNumbers.decoder("1,x,3"); // → Error: at 1: Number: Unable to parse: "x"
99
- ```
100
-
101
- Custom separator:
102
-
103
- ```ts
104
- const typePaths = typeList(typeString, ":");
105
- typePaths.decoder("/usr/bin:/usr/local/bin"); // → ["/usr/bin", "/usr/local/bin"]
106
- ```
107
-
108
- ::: tip Prefer
109
- [`optionRepeatable`](/guide/03_options#optionrepeatable-collect-multiple-values)
110
- over `typeList` when users should pass multiple values as separate flags
111
- (`--file a --file b` rather than `--files a,b`).
112
-
113
- :::
114
-
115
- ## Custom types
116
-
117
- Implement the `Type<Value>` interface directly:
118
-
119
- ```ts
120
- import type { Type } from "cli-kiss";
121
-
122
- const typeHexColor: Type<string> = {
123
- content: "HexColor",
124
- decoder(value) {
125
- if (/^#[0-9a-fA-F]{6}$/.test(value)) return value;
126
- throw new Error(`Not a valid value: "${value}"`);
127
- },
128
- };
129
-
130
- // "--color #ff0000" → "#ff0000"
131
- // "--color red" → Error: --color: <HEXCOLOR>: HexColor: Not a valid value: "red"
132
- ```
@@ -1,160 +0,0 @@
1
- # Running your CLI
2
-
3
- ## `runAndExit`
4
-
5
- `runAndExit` parses arguments, runs the matched command, and exits.
6
-
7
- ```ts
8
- await runAndExit(cliName, cliArgs, context, command, options?);
9
- ```
10
-
11
- | Parameter | Type | Description |
12
- | --------- | ---------------------------------- | ------------------------------------------------- |
13
- | `cliName` | `Lowercase<string>` | Program name used in help and `--version` output |
14
- | `cliArgs` | `ReadonlyArray<string>` | Raw arguments — typically `process.argv.slice(2)` |
15
- | `context` | `Context` | Value forwarded to every command handler |
16
- | `command` | `Command<Context, void>` | The root command |
17
- | `options` | `object?` | See below |
18
-
19
- ### Options
20
-
21
- | Option | Type | Default | Description |
22
- | -------------- | -------------------------- | -------------- | ----------------------------------------------------------- |
23
- | `buildVersion` | `string?` | — | Enables `--version` flag; prints `<cliName> <buildVersion>` |
24
- | `usageOnHelp` | `boolean?` | `true` | Enables `--help` flag |
25
- | `usageOnError` | `boolean?` | `true` | Prints usage to stderr when parsing fails |
26
- | `useTtyColors` | `boolean \| "mock"?` | auto | Controls ANSI color output |
27
- | `onError` | `(error: unknown) => void` | — | Custom handler for parse and execution errors |
28
- | `onExit` | `(code: number) => never` | `process.exit` | Override for testing |
29
-
30
- ### Exit codes
31
-
32
- | Code | Reason |
33
- | ---- | --------------------------------------- |
34
- | `0` | Success, `--help`, or `--version` |
35
- | `1` | Parse error or uncaught execution error |
36
-
37
- ## Full example
38
-
39
- ```ts
40
- import {
41
- command,
42
- commandWithSubcommands,
43
- operation,
44
- optionFlag,
45
- optionSingleValue,
46
- positionalRequired,
47
- runAndExit,
48
- typeString,
49
- typeUrl,
50
- } from "cli-kiss";
51
-
52
- type Ctx = { db: string };
53
-
54
- const deployCmd = command(
55
- { description: "Deploy to production" },
56
- operation(
57
- {
58
- options: {
59
- dryRun: optionFlag({ long: "dry-run", description: "Simulate only" }),
60
- },
61
- positionals: [],
62
- },
63
- async ({ db }, { options: { dryRun } }) => {
64
- if (dryRun) {
65
- console.log(`[dry-run] would deploy with DB: ${db}`);
66
- } else {
67
- console.log(`Deploying with DB: ${db}`);
68
- }
69
- },
70
- ),
71
- );
72
-
73
- const rootCmd = commandWithSubcommands(
74
- { description: "My deployment CLI" },
75
- operation(
76
- {
77
- options: {
78
- dbUrl: optionSingleValue({
79
- long: "db",
80
- type: typeUrl,
81
- description: "Database URL",
82
- default: () => new URL("postgres://localhost/mydb"),
83
- }),
84
- },
85
- positionals: [],
86
- },
87
- async (_ctx, { options: { dbUrl } }): Promise<Ctx> => ({
88
- db: dbUrl.toString(),
89
- }),
90
- ),
91
- { deploy: deployCmd },
92
- );
93
-
94
- await runAndExit("my-cli", process.argv.slice(2), undefined, rootCmd, {
95
- buildVersion: "2.0.0",
96
- });
97
- ```
98
-
99
- Check it
100
-
101
- ```sh
102
- my-cli --help
103
- ```
104
-
105
- ```text
106
- Usage: my-cli <SUBCOMMAND>
107
-
108
- My deployment CLI
109
-
110
- Subcommands:
111
- deploy Deploy to production
112
-
113
- Options:
114
- --db <URL> Database URL
115
- ```
116
-
117
- Try it
118
-
119
- ```sh
120
- my-cli deploy --dry-run
121
- ```
122
-
123
- ```text
124
- [dry-run] would deploy with DB: postgres://localhost/mydb
125
- ```
126
-
127
- ## Color control
128
-
129
- Colors are auto-detected. Override:
130
-
131
- ```ts
132
- // Force colors on
133
- await runAndExit("my-cli", args, ctx, cmd, { useTtyColors: true });
134
-
135
- // Force colors off (useful in CI)
136
- await runAndExit("my-cli", args, ctx, cmd, { useTtyColors: false });
137
-
138
- // Deterministic mock output (useful in snapshot tests)
139
- await runAndExit("my-cli", args, ctx, cmd, { useTtyColors: "mock" });
140
- ```
141
-
142
- ## Testing your CLI
143
-
144
- Override `onExit` to prevent process exit during tests:
145
-
146
- ```ts
147
- import { runAndExit } from "cli-kiss";
148
-
149
- const exitCodes: number[] = [];
150
-
151
- await runAndExit("my-cli", ["--help"], undefined, myCommand, {
152
- useTtyColors: false,
153
- onExit: (code) => {
154
- exitCodes.push(code);
155
- return undefined as never;
156
- },
157
- });
158
-
159
- console.assert(exitCodes[0] === 0, "expected exit 0 for --help");
160
- ```