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
|
@@ -5,6 +5,7 @@ export default defineConfig({
|
|
|
5
5
|
title: "cli-kiss 💋",
|
|
6
6
|
base: "/cli-kiss/",
|
|
7
7
|
head: [
|
|
8
|
+
["link", { rel: "icon", href: "/cli-kiss/favicon.ico" }],
|
|
8
9
|
[
|
|
9
10
|
"style",
|
|
10
11
|
{},
|
|
@@ -14,9 +15,7 @@ export default defineConfig({
|
|
|
14
15
|
],
|
|
15
16
|
],
|
|
16
17
|
themeConfig: {
|
|
17
|
-
search: {
|
|
18
|
-
provider: "local",
|
|
19
|
-
},
|
|
18
|
+
search: { provider: "local", options: { detailedView: true } },
|
|
20
19
|
nav: [
|
|
21
20
|
{ text: "Guide", link: "/guide/01_getting_started" },
|
|
22
21
|
{ text: "npm", link: "https://www.npmjs.com/package/cli-kiss" },
|
|
@@ -8,10 +8,10 @@ npm install cli-kiss
|
|
|
8
8
|
|
|
9
9
|
## Your first CLI
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Example minimal "greet" CLI with:
|
|
12
12
|
|
|
13
|
-
- a required `
|
|
14
|
-
- optional `--loud` flag
|
|
13
|
+
- a required `name` positional argument
|
|
14
|
+
- optional `--loud` boolean flag
|
|
15
15
|
|
|
16
16
|
```ts
|
|
17
17
|
import {
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
optionFlag,
|
|
21
21
|
positionalRequired,
|
|
22
22
|
runAndExit,
|
|
23
|
-
|
|
23
|
+
type,
|
|
24
24
|
} from "cli-kiss";
|
|
25
25
|
|
|
26
26
|
const greetCommand = command(
|
|
@@ -32,20 +32,19 @@ const greetCommand = command(
|
|
|
32
32
|
},
|
|
33
33
|
positionals: [
|
|
34
34
|
positionalRequired({
|
|
35
|
-
type:
|
|
36
|
-
|
|
37
|
-
description: "The name to greet",
|
|
35
|
+
type: type("name"),
|
|
36
|
+
description: "The name of the person to greet",
|
|
38
37
|
}),
|
|
39
38
|
],
|
|
40
39
|
},
|
|
41
|
-
async (
|
|
40
|
+
async (_context, { options: { loud }, positionals: [name] }) => {
|
|
42
41
|
const message = `Hello, ${name}!`;
|
|
43
42
|
console.log(loud ? message.toUpperCase() : message);
|
|
44
43
|
},
|
|
45
44
|
),
|
|
46
45
|
);
|
|
47
46
|
|
|
48
|
-
await runAndExit("greet", process.argv.slice(2),
|
|
47
|
+
await runAndExit("greet", process.argv.slice(2), {}, greetCommand, {
|
|
49
48
|
buildVersion: "1.0.0",
|
|
50
49
|
});
|
|
51
50
|
```
|
|
@@ -70,19 +69,19 @@ greet --loud Alice
|
|
|
70
69
|
HELLO, ALICE!
|
|
71
70
|
```
|
|
72
71
|
|
|
73
|
-
Help (built-in):
|
|
72
|
+
Help and color (built-in):
|
|
74
73
|
|
|
75
74
|
```sh
|
|
76
|
-
greet --help
|
|
75
|
+
greet --help --color
|
|
77
76
|
```
|
|
78
77
|
|
|
79
78
|
```text
|
|
80
|
-
Usage: greet <
|
|
79
|
+
Usage: greet <name>
|
|
81
80
|
|
|
82
81
|
Greet someone
|
|
83
82
|
|
|
84
83
|
Positionals:
|
|
85
|
-
<
|
|
84
|
+
<name> The name of the person to greet
|
|
86
85
|
|
|
87
86
|
Options:
|
|
88
87
|
--loud[=no] Print in uppercase
|
|
@@ -7,75 +7,42 @@ Three factory functions cover every use-case.
|
|
|
7
7
|
No subcommands — directly runs an operation.
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
|
-
import { command, operation, positionalRequired, typeString } from "cli-kiss";
|
|
11
|
-
|
|
12
10
|
const greet = command(
|
|
13
11
|
{ description: "Greet a user" },
|
|
14
12
|
operation(
|
|
15
13
|
{
|
|
16
14
|
options: {},
|
|
17
|
-
positionals: [positionalRequired({ type:
|
|
15
|
+
positionals: [positionalRequired({ type: type("name") })],
|
|
18
16
|
},
|
|
19
|
-
async (_ctx, { positionals: [name] })
|
|
17
|
+
async function (_ctx, { positionals: [name] }) {
|
|
20
18
|
console.log(`Hello, ${name}!`);
|
|
21
19
|
},
|
|
22
20
|
),
|
|
23
21
|
);
|
|
24
22
|
```
|
|
25
23
|
|
|
26
|
-
### `CommandInformation`
|
|
27
|
-
|
|
28
|
-
Every command accepts a metadata object:
|
|
29
|
-
|
|
30
|
-
| Field | Type | Description |
|
|
31
|
-
| ------------- | ----------- | ------------------------------------------------- |
|
|
32
|
-
| `description` | `string` | Short description shown in help output |
|
|
33
|
-
| `hint` | `string?` | Note shown in parentheses next to the description |
|
|
34
|
-
| `details` | `string[]?` | Extra lines printed below the description |
|
|
35
|
-
|
|
36
|
-
```ts
|
|
37
|
-
command(
|
|
38
|
-
{
|
|
39
|
-
description: "Deploy the application",
|
|
40
|
-
hint: "experimental",
|
|
41
|
-
details: [
|
|
42
|
-
"Pushes to the configured remote.",
|
|
43
|
-
"Runs migrations after push.",
|
|
44
|
-
],
|
|
45
|
-
},
|
|
46
|
-
deployOperation,
|
|
47
|
-
);
|
|
48
|
-
```
|
|
49
|
-
|
|
50
24
|
## `commandWithSubcommands` — dispatch to a subcommand
|
|
51
25
|
|
|
52
26
|
User must pick one of several sub-actions.
|
|
53
27
|
|
|
54
28
|
```ts
|
|
55
|
-
import {
|
|
56
|
-
command,
|
|
57
|
-
commandWithSubcommands,
|
|
58
|
-
operation,
|
|
59
|
-
runAndExit,
|
|
60
|
-
} from "cli-kiss";
|
|
61
|
-
|
|
62
29
|
const rootCmd = commandWithSubcommands(
|
|
63
30
|
{ description: "My deployment CLI" },
|
|
64
31
|
// This operation runs before the subcommand is selected.
|
|
65
32
|
// Its return value becomes the subcommand's context.
|
|
66
|
-
operation({ options: {}, positionals: [] }, async (_ctx)
|
|
67
|
-
db: "postgres://localhost/mydb"
|
|
68
|
-
})
|
|
33
|
+
operation({ options: {}, positionals: [] }, async function (_ctx) {
|
|
34
|
+
return { db: "postgres://localhost/mydb" };
|
|
35
|
+
}),
|
|
69
36
|
{
|
|
70
37
|
deploy: command(
|
|
71
38
|
{ description: "Deploy the latest build" },
|
|
72
|
-
operation({ options: {}, positionals: [] }, async (ctx)
|
|
39
|
+
operation({ options: {}, positionals: [] }, async function (ctx) {
|
|
73
40
|
console.log(`Deploying with DB: ${ctx.db}`);
|
|
74
41
|
}),
|
|
75
42
|
),
|
|
76
43
|
rollback: command(
|
|
77
44
|
{ description: "Rollback to the previous release" },
|
|
78
|
-
operation({ options: {}, positionals: [] }, async (ctx)
|
|
45
|
+
operation({ options: {}, positionals: [] }, async function (ctx) {
|
|
79
46
|
console.log(`Rolling back, DB: ${ctx.db}`);
|
|
80
47
|
}),
|
|
81
48
|
),
|
|
@@ -92,7 +59,7 @@ deploy-cli --help
|
|
|
92
59
|
```
|
|
93
60
|
|
|
94
61
|
```text
|
|
95
|
-
Usage: deploy-cli <
|
|
62
|
+
Usage: deploy-cli <subcommand>
|
|
96
63
|
|
|
97
64
|
My deployment CLI
|
|
98
65
|
|
|
@@ -103,21 +70,13 @@ Subcommands:
|
|
|
103
70
|
|
|
104
71
|
### Subcommand names
|
|
105
72
|
|
|
106
|
-
Keys are the tokens users
|
|
73
|
+
Keys are the tokens users must type.
|
|
107
74
|
|
|
108
75
|
## `commandChained` — sequential stages
|
|
109
76
|
|
|
110
77
|
Splits a command into reusable steps with no extra user-visible token.
|
|
111
78
|
|
|
112
79
|
```ts
|
|
113
|
-
import {
|
|
114
|
-
command,
|
|
115
|
-
commandChained,
|
|
116
|
-
operation,
|
|
117
|
-
optionSingleValue,
|
|
118
|
-
typeString,
|
|
119
|
-
} from "cli-kiss";
|
|
120
|
-
|
|
121
80
|
const authenticatedDeploy = commandChained(
|
|
122
81
|
{ description: "Authenticate then deploy" },
|
|
123
82
|
// Stage 1: parse a --token option and forward the token as context
|
|
@@ -126,9 +85,9 @@ const authenticatedDeploy = commandChained(
|
|
|
126
85
|
options: {
|
|
127
86
|
token: optionSingleValue({
|
|
128
87
|
long: "token",
|
|
129
|
-
type:
|
|
88
|
+
type: type("secret"),
|
|
130
89
|
description: "API token",
|
|
131
|
-
|
|
90
|
+
defaultWhenNotDefined: function () {
|
|
132
91
|
const t = process.env.API_TOKEN;
|
|
133
92
|
if (!t) throw new Error("API_TOKEN env var is required");
|
|
134
93
|
return t;
|
|
@@ -150,3 +109,63 @@ const authenticatedDeploy = commandChained(
|
|
|
150
109
|
```
|
|
151
110
|
|
|
152
111
|
All stages share a single flat usage — users see one combined command.
|
|
112
|
+
|
|
113
|
+
## `CommandInformation`
|
|
114
|
+
|
|
115
|
+
Every command accepts a metadata object:
|
|
116
|
+
|
|
117
|
+
| Field | Type | Description |
|
|
118
|
+
| ------------- | ------------ | ------------------------------------------------- |
|
|
119
|
+
| `description` | `string` | Short description shown in help output |
|
|
120
|
+
| `hint` | `string?` | Note shown in parentheses next to the description |
|
|
121
|
+
| `details` | `string[]?` | Extra lines printed below the description |
|
|
122
|
+
| `examples` | `Example[]?` | Usage examples shown in the `Examples:` section |
|
|
123
|
+
|
|
124
|
+
Each `Example` entry has:
|
|
125
|
+
|
|
126
|
+
| Field | Type | Description |
|
|
127
|
+
| ------------- | -------------- | ------------------------------------------------------- |
|
|
128
|
+
| `explanation` | `string` | Comment line shown above the example command |
|
|
129
|
+
| `commandArgs` | `CommandArg[]` | Ordered list of arguments to render on the command line |
|
|
130
|
+
|
|
131
|
+
Each `CommandArg` is one of:
|
|
132
|
+
|
|
133
|
+
| Shape | Renders as |
|
|
134
|
+
| ----------------------------------------------------------------------- | --------------------- |
|
|
135
|
+
| `string` | literal text |
|
|
136
|
+
| `{ positional: string }` | positional label |
|
|
137
|
+
| `{ subcommand: string }` | subcommand name |
|
|
138
|
+
| `{ option: { long: string; inlined?: string; separated?: string[] } }` | `--long[=val] [args]` |
|
|
139
|
+
| `{ option: { short: string; inlined?: string; separated?: string[] } }` | `-s[=val] [args]` |
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
command(
|
|
143
|
+
{
|
|
144
|
+
description: "Deploy the application",
|
|
145
|
+
hint: "experimental",
|
|
146
|
+
details: [
|
|
147
|
+
"Pushes to the configured remote.",
|
|
148
|
+
"Runs migrations after push.",
|
|
149
|
+
],
|
|
150
|
+
examples: [
|
|
151
|
+
{
|
|
152
|
+
explanation: "Deploy with a specific tag",
|
|
153
|
+
commandArgs: [
|
|
154
|
+
{ positional: "v1.2.3" },
|
|
155
|
+
{ option: { long: "dry-run" } },
|
|
156
|
+
],
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
},
|
|
160
|
+
deployOperation,
|
|
161
|
+
);
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The `Examples:` section in `--help` output renders each entry as a comment
|
|
165
|
+
followed by the reconstructed command line:
|
|
166
|
+
|
|
167
|
+
```text
|
|
168
|
+
Examples:
|
|
169
|
+
# Deploy with a specific tag
|
|
170
|
+
deploy v1.2.3 --dry-run
|
|
171
|
+
```
|
package/docs/guide/03_options.md
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
# Options
|
|
2
2
|
|
|
3
|
-
Named `--` arguments (or `-` for short forms). Declared in the `options` map of
|
|
3
|
+
Named `--` arguments (or `-` for short forms). Declared in the `options` map of
|
|
4
|
+
[`operation`](/guide/02_commands).
|
|
4
5
|
|
|
5
6
|
## `optionFlag` — boolean toggle
|
|
6
7
|
|
|
7
|
-
Present or absent. Also accepts `--flag=
|
|
8
|
+
Present or absent. Also accepts `--flag=true` / `--flag=no`.
|
|
8
9
|
|
|
9
10
|
```ts
|
|
10
|
-
import { optionFlag } from "cli-kiss";
|
|
11
|
-
|
|
12
11
|
const verbose = optionFlag({
|
|
13
12
|
long: "verbose",
|
|
14
13
|
short: "v",
|
|
@@ -20,14 +19,14 @@ const verbose = optionFlag({
|
|
|
20
19
|
// (absent) → false
|
|
21
20
|
```
|
|
22
21
|
|
|
23
|
-
| Parameter | Type | Description
|
|
24
|
-
| ------------- | --------------------- |
|
|
25
|
-
| `long` | `
|
|
26
|
-
| `short` | `string?` | Short flag name (without `-`)
|
|
27
|
-
| `description` | `string?` | Help text
|
|
28
|
-
| `hint` | `string?` | Short note in parentheses
|
|
29
|
-
| `default` | `
|
|
30
|
-
| `aliases` | `{ longs?, shorts? }` | Additional names for the flag
|
|
22
|
+
| Parameter | Type | Description |
|
|
23
|
+
| ------------- | --------------------- | ------------------------------------ |
|
|
24
|
+
| `long` | `string` | Long flag name (without `--`) |
|
|
25
|
+
| `short` | `string?` | Short flag name (without `-`) |
|
|
26
|
+
| `description` | `string?` | Help text |
|
|
27
|
+
| `hint` | `string?` | Short note in parentheses |
|
|
28
|
+
| `default` | `boolean? ` | Value when absent (default: `false`) |
|
|
29
|
+
| `aliases` | `{ longs?, shorts? }` | Additional names for the flag |
|
|
31
30
|
|
|
32
31
|
::: tip A flag specified more than once triggers a parse error. Use
|
|
33
32
|
[`optionRepeatable`](#optionrepeatable-collect-multiple-values) if you need
|
|
@@ -40,15 +39,12 @@ multiple values.
|
|
|
40
39
|
Exactly one typed value.
|
|
41
40
|
|
|
42
41
|
```ts
|
|
43
|
-
import { optionSingleValue, typeString } from "cli-kiss";
|
|
44
|
-
|
|
45
42
|
const output = optionSingleValue({
|
|
46
43
|
long: "output",
|
|
47
44
|
short: "o",
|
|
48
|
-
type:
|
|
49
|
-
label: "PATH",
|
|
45
|
+
type: typePath(),
|
|
50
46
|
description: "Output directory",
|
|
51
|
-
|
|
47
|
+
defaultWhenNotDefined: () => "dist/",
|
|
52
48
|
});
|
|
53
49
|
// --output dist/ → "dist/"
|
|
54
50
|
// --output=dist/ → "dist/"
|
|
@@ -56,29 +52,26 @@ const output = optionSingleValue({
|
|
|
56
52
|
// (absent) → "dist/"
|
|
57
53
|
```
|
|
58
54
|
|
|
59
|
-
| Parameter
|
|
60
|
-
|
|
|
61
|
-
| `long`
|
|
62
|
-
| `short`
|
|
63
|
-
| `type`
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
68
|
-
| `aliases`
|
|
55
|
+
| Parameter | Type | Description |
|
|
56
|
+
| ----------------------- | --------------------- | ---------------------------------------------------------------------------- |
|
|
57
|
+
| `long` | `string` | Long option name |
|
|
58
|
+
| `short` | `string?` | Short option name |
|
|
59
|
+
| `type` | `Type<Value>` | Decoder for the value |
|
|
60
|
+
| `description` | `string?` | Help text |
|
|
61
|
+
| `hint` | `string?` | Short note in parentheses |
|
|
62
|
+
| `defaultWhenNotDefined` | `() => Value` | Value when option is absent — **throw** to make it required |
|
|
63
|
+
| `defaultWhenNotInlined` | `() => Value?` | Value when option is present but has no inline value (e.g. `--output` alone) |
|
|
64
|
+
| `aliases` | `{ longs?, shorts? }` | Additional names |
|
|
69
65
|
|
|
70
66
|
## `optionRepeatable` — collect multiple values
|
|
71
67
|
|
|
72
68
|
Collects every occurrence into an array.
|
|
73
69
|
|
|
74
70
|
```ts
|
|
75
|
-
import { optionRepeatable, typeString } from "cli-kiss";
|
|
76
|
-
|
|
77
71
|
const files = optionRepeatable({
|
|
78
72
|
long: "file",
|
|
79
73
|
short: "f",
|
|
80
|
-
type:
|
|
81
|
-
label: "PATH",
|
|
74
|
+
type: typePath("FILE_PATH"),
|
|
82
75
|
description: "Input file (may be repeated)",
|
|
83
76
|
});
|
|
84
77
|
// --file a.ts --file b.ts → ["a.ts", "b.ts"]
|
|
@@ -87,10 +80,9 @@ const files = optionRepeatable({
|
|
|
87
80
|
|
|
88
81
|
| Parameter | Type | Description |
|
|
89
82
|
| ------------- | --------------------- | ---------------------------------- |
|
|
90
|
-
| `long` | `
|
|
83
|
+
| `long` | `string` | Long option name |
|
|
91
84
|
| `short` | `string?` | Short option name |
|
|
92
85
|
| `type` | `Type<Value>` | Decoder applied to each occurrence |
|
|
93
|
-
| `label` | `Uppercase<string>?` | Placeholder in help |
|
|
94
86
|
| `description` | `string?` | Help text |
|
|
95
87
|
| `hint` | `string?` | Short note in parentheses |
|
|
96
88
|
| `aliases` | `{ longs?, shorts? }` | Additional names |
|
|
@@ -1,69 +1,63 @@
|
|
|
1
1
|
# Positionals
|
|
2
2
|
|
|
3
|
-
Bare (non-`--`) arguments, consumed in order. Declared in the `positionals`
|
|
3
|
+
Bare (non-`--`) arguments, consumed in order. Declared in the `positionals`
|
|
4
|
+
array of [`operation`](/guide/02_commands).
|
|
4
5
|
|
|
5
6
|
## `positionalRequired` — must be present
|
|
6
7
|
|
|
7
8
|
Fails if missing.
|
|
8
9
|
|
|
9
10
|
```ts
|
|
10
|
-
import { positionalRequired, typeString } from "cli-kiss";
|
|
11
|
-
|
|
12
11
|
const name = positionalRequired({
|
|
13
|
-
type:
|
|
14
|
-
|
|
15
|
-
description: "The name to greet",
|
|
12
|
+
type: type("person"),
|
|
13
|
+
description: "The name of the person to greet",
|
|
16
14
|
});
|
|
17
|
-
//
|
|
18
|
-
//
|
|
15
|
+
// Usage:
|
|
16
|
+
// my-cli Alice → "Alice"
|
|
17
|
+
// my-cli → Error: <person>: Is required, but was not provided
|
|
19
18
|
```
|
|
20
19
|
|
|
21
|
-
| Parameter | Type
|
|
22
|
-
| ------------- |
|
|
23
|
-
| `type` | `Type<Value>`
|
|
24
|
-
| `
|
|
25
|
-
| `
|
|
26
|
-
| `hint` | `string?` | Short note in parentheses |
|
|
20
|
+
| Parameter | Type | Description |
|
|
21
|
+
| ------------- | ------------- | -------------------------------- |
|
|
22
|
+
| `type` | `Type<Value>` | Decoder for the raw string token |
|
|
23
|
+
| `description` | `string?` | Help text |
|
|
24
|
+
| `hint` | `string?` | Short note in parentheses |
|
|
27
25
|
|
|
28
26
|
## `positionalOptional` — may be absent
|
|
29
27
|
|
|
30
28
|
Falls back to a default when absent.
|
|
31
29
|
|
|
32
30
|
```ts
|
|
33
|
-
import { positionalOptional, typeString } from "cli-kiss";
|
|
34
|
-
|
|
35
31
|
const greeting = positionalOptional({
|
|
36
|
-
type:
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
type: type("greeting"),
|
|
33
|
+
description: "Custom greeting",
|
|
34
|
+
hint: "default to 'Hello'",
|
|
39
35
|
default: () => "Hello",
|
|
40
36
|
});
|
|
41
|
-
//
|
|
42
|
-
//
|
|
37
|
+
// Usage:
|
|
38
|
+
// my-cli → "Hello"
|
|
39
|
+
//. my-cli Howdy → "Howdy"
|
|
43
40
|
```
|
|
44
41
|
|
|
45
|
-
| Parameter | Type
|
|
46
|
-
| ------------- |
|
|
47
|
-
| `type` | `Type<Value>`
|
|
48
|
-
| `
|
|
49
|
-
| `
|
|
50
|
-
| `
|
|
51
|
-
| `default` | `() => Value` | Value when absent — **throw** to make it required |
|
|
42
|
+
| Parameter | Type | Description |
|
|
43
|
+
| ------------- | ------------- | ------------------------------------------------- |
|
|
44
|
+
| `type` | `Type<Value>` | Decoder for the raw string token |
|
|
45
|
+
| `description` | `string?` | Help text |
|
|
46
|
+
| `hint` | `string?` | Short note in parentheses |
|
|
47
|
+
| `default` | `() => Value` | Value when absent — **throw** to make it required |
|
|
52
48
|
|
|
53
49
|
## `positionalVariadics` — zero or more
|
|
54
50
|
|
|
55
51
|
Consumes all remaining tokens into an array.
|
|
56
52
|
|
|
57
53
|
```ts
|
|
58
|
-
import { positionalVariadics, typeString } from "cli-kiss";
|
|
59
|
-
|
|
60
54
|
const files = positionalVariadics({
|
|
61
|
-
type:
|
|
62
|
-
label: "FILE",
|
|
55
|
+
type: typePath(),
|
|
63
56
|
description: "Files to process",
|
|
64
57
|
});
|
|
65
|
-
//
|
|
66
|
-
//
|
|
58
|
+
// Usage:
|
|
59
|
+
// my-cli a.ts b.ts c.ts → ["a.ts", "b.ts", "c.ts"]
|
|
60
|
+
// my-cli → []
|
|
67
61
|
```
|
|
68
62
|
|
|
69
63
|
### End delimiter
|
|
@@ -72,21 +66,20 @@ Optionally stop collecting at a specific sentinel token:
|
|
|
72
66
|
|
|
73
67
|
```ts
|
|
74
68
|
const args = positionalVariadics({
|
|
75
|
-
type:
|
|
76
|
-
label: "ARG",
|
|
69
|
+
type: type("argument"),
|
|
77
70
|
endDelimiter: "STOP",
|
|
78
71
|
description: "Arguments (end with STOP)",
|
|
79
72
|
});
|
|
80
|
-
//
|
|
73
|
+
// Usage:
|
|
74
|
+
// my-cli foo bar STOP → ["foo", "bar"]
|
|
81
75
|
```
|
|
82
76
|
|
|
83
|
-
| Parameter | Type
|
|
84
|
-
| -------------- |
|
|
85
|
-
| `type` | `Type<Value>`
|
|
86
|
-
| `
|
|
87
|
-
| `
|
|
88
|
-
| `
|
|
89
|
-
| `endDelimiter` | `string?` | Sentinel token that stops collection |
|
|
77
|
+
| Parameter | Type | Description |
|
|
78
|
+
| -------------- | ------------- | ------------------------------------ |
|
|
79
|
+
| `type` | `Type<Value>` | Decoder applied to each token |
|
|
80
|
+
| `description` | `string?` | Help text |
|
|
81
|
+
| `hint` | `string?` | Short note in parentheses |
|
|
82
|
+
| `endDelimiter` | `string?` | Sentinel token that stops collection |
|
|
90
83
|
|
|
91
84
|
## Ordering rules
|
|
92
85
|
|
|
@@ -97,20 +90,17 @@ operation(
|
|
|
97
90
|
{
|
|
98
91
|
options: {},
|
|
99
92
|
positionals: [
|
|
100
|
-
positionalRequired({ type:
|
|
101
|
-
positionalRequired({ type:
|
|
102
|
-
positionalOptional({
|
|
103
|
-
|
|
104
|
-
label: "TAG",
|
|
105
|
-
default: () => "latest",
|
|
106
|
-
}),
|
|
107
|
-
positionalVariadics({ type: typeString, label: "EXTRA" }),
|
|
93
|
+
positionalRequired({ type: type("src") }),
|
|
94
|
+
positionalRequired({ type: type("dst") }),
|
|
95
|
+
positionalOptional({ type: type("tag"), default: () => "latest" }),
|
|
96
|
+
positionalVariadics({ type: type("extra") }),
|
|
108
97
|
],
|
|
109
98
|
},
|
|
110
|
-
async (_ctx, { positionals: [
|
|
99
|
+
async function (_ctx, { positionals: [src, dst, tag, extras] }) {
|
|
111
100
|
/* ... */
|
|
112
101
|
},
|
|
113
102
|
);
|
|
114
|
-
//
|
|
115
|
-
//
|
|
103
|
+
// Usage:
|
|
104
|
+
// my-cli in out → src="in", src="out", tag="latest", extras=[]
|
|
105
|
+
// my-cli in out v2 a b c → src="in", src="out", tag="v2", extras=["a","b","c"]
|
|
116
106
|
```
|