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.
@@ -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" },
@@ -0,0 +1,4 @@
1
+ import DefaultTheme from "vitepress/theme";
2
+ import "./style.css";
3
+
4
+ export default DefaultTheme;
@@ -0,0 +1,4 @@
1
+ :root {
2
+ --vp-home-hero-image-background-image: linear-gradient( -50deg, #ff003cff 0%, #00000000 50%, #459900ff 100% );
3
+ --vp-home-hero-image-filter: blur(150px);
4
+ }
@@ -8,10 +8,10 @@ npm install cli-kiss
8
8
 
9
9
  ## Your first CLI
10
10
 
11
- Minimal "greet" CLI with:
11
+ Example minimal "greet" CLI with:
12
12
 
13
- - a required `NAME` positional
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
- typeString,
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: typeString,
36
- label: "NAME",
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 (_ctx, { options: { loud }, positionals: [name] }) => {
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), undefined, greetCommand, {
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 <NAME>
79
+ Usage: greet <name>
81
80
 
82
81
  Greet someone
83
82
 
84
83
  Positionals:
85
- <NAME> The name to greet
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: typeString, label: "NAME" })],
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 <SUBCOMMAND>
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 type — must be lowercase strings.
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: typeString,
88
+ type: type("secret"),
130
89
  description: "API token",
131
- default: () => {
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
+ ```
@@ -1,14 +1,13 @@
1
1
  # Options
2
2
 
3
- Named `--` arguments (or `-` for short forms). Declared in the `options` map of [`operation`](/guide/02_commands).
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=yes` / `--flag=no`.
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` | `Lowercase<string>` | Long flag name (without `--`) |
26
- | `short` | `string?` | Short flag name (without `-`) |
27
- | `description` | `string?` | Help text |
28
- | `hint` | `string?` | Short note in parentheses |
29
- | `default` | `() => boolean` | Default when absent (default: `() => false`) |
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: typeString,
49
- label: "PATH",
45
+ type: typePath(),
50
46
  description: "Output directory",
51
- default: () => "dist/",
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 | Type | Description |
60
- | ------------- | --------------------- | ----------------------------------------------------------- |
61
- | `long` | `Lowercase<string>` | Long option name |
62
- | `short` | `string?` | Short option name |
63
- | `type` | `Type<Value>` | Decoder for the value |
64
- | `label` | `Uppercase<string>?` | Placeholder in help (defaults to uppercased type content) |
65
- | `description` | `string?` | Help text |
66
- | `hint` | `string?` | Short note in parentheses |
67
- | `default` | `() => Value` | Default when absent **throw** to make the option required |
68
- | `aliases` | `{ longs?, shorts? }` | Additional names |
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: typeString,
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` | `Lowercase<string>` | Long option name |
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` array of [`operation`](/guide/02_commands).
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: typeString,
14
- label: "NAME",
15
- description: "The name to greet",
12
+ type: type("person"),
13
+ description: "The name of the person to greet",
16
14
  });
17
- // my-cli Alice → "Alice"
18
- // my-cli Error: <NAME>: Is required, but was not provided
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 | Description |
22
- | ------------- | -------------------- | --------------------------------------------------------- |
23
- | `type` | `Type<Value>` | Decoder for the raw string token |
24
- | `label` | `Uppercase<string>?` | Placeholder in help (defaults to uppercased type content) |
25
- | `description` | `string?` | Help text |
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: typeString,
37
- label: "GREETING",
38
- description: "Custom greeting (default: Hello)",
32
+ type: type("greeting"),
33
+ description: "Custom greeting",
34
+ hint: "default to 'Hello'",
39
35
  default: () => "Hello",
40
36
  });
41
- // my-cli → "Hello"
42
- // my-cli Howdy → "Howdy"
37
+ // Usage:
38
+ // my-cli → "Hello"
39
+ //. my-cli Howdy → "Howdy"
43
40
  ```
44
41
 
45
- | Parameter | Type | Description |
46
- | ------------- | -------------------- | ------------------------------------------------- |
47
- | `type` | `Type<Value>` | Decoder for the raw string token |
48
- | `label` | `Uppercase<string>?` | Placeholder in help |
49
- | `description` | `string?` | Help text |
50
- | `hint` | `string?` | Short note in parentheses |
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: typeString,
62
- label: "FILE",
55
+ type: typePath(),
63
56
  description: "Files to process",
64
57
  });
65
- // my-cli a.ts b.ts c.ts → ["a.ts", "b.ts", "c.ts"]
66
- // my-cli → []
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: typeString,
76
- label: "ARG",
69
+ type: type("argument"),
77
70
  endDelimiter: "STOP",
78
71
  description: "Arguments (end with STOP)",
79
72
  });
80
- // my-cli foo bar STOP → ["foo", "bar"]
73
+ // Usage:
74
+ // my-cli foo bar STOP → ["foo", "bar"]
81
75
  ```
82
76
 
83
- | Parameter | Type | Description |
84
- | -------------- | -------------------- | ------------------------------------ |
85
- | `type` | `Type<Value>` | Decoder applied to each token |
86
- | `label` | `Uppercase<string>?` | Placeholder in help |
87
- | `description` | `string?` | Help text |
88
- | `hint` | `string?` | Short note in parentheses |
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: typeString, label: "SOURCE" }),
101
- positionalRequired({ type: typeString, label: "DEST" }),
102
- positionalOptional({
103
- type: typeString,
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: [source, dest, tag, extras] }) => {
99
+ async function (_ctx, { positionals: [src, dst, tag, extras] }) {
111
100
  /* ... */
112
101
  },
113
102
  );
114
- // my-cli src/ dst/ → source="src/", dest="dst/", tag="latest", extras=[]
115
- // my-cli src/ dst/ v2 a b c source="src/", dest="dst/", tag="v2", extras=["a","b","c"]
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
  ```