@optique/core 0.1.0-dev.2 → 0.1.0-dev.27
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 +34 -473
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,503 +1,64 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
@optique/core
|
|
2
|
+
=============
|
|
3
3
|
|
|
4
4
|
> [!CAUTION]
|
|
5
|
-
> Optique is currently in early development
|
|
6
|
-
>
|
|
7
|
-
> and there may be bugs or missing features.
|
|
5
|
+
> Optique is currently in early development and may change significantly.
|
|
6
|
+
> Expect breaking changes as we refine the API and features.
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
> [!NOTE]
|
|
15
|
-
> Optique is a parsing library that focuses on extracting and
|
|
16
|
-
> validating command-line arguments. It doesn't dictate your application's
|
|
17
|
-
> structure, handle command execution, or provide scaffolding—it simply
|
|
18
|
-
> transforms command-line input into well-typed data structures that your
|
|
19
|
-
> application can use.
|
|
20
|
-
|
|
21
|
-
Unlike traditional CLI parsers that rely on configuration objects or
|
|
22
|
-
string-based definitions, Optique uses a functional approach where parsers
|
|
23
|
-
are first-class values that can be combined, transformed, and reused.
|
|
24
|
-
This compositional design makes it easy to express complex argument structures
|
|
25
|
-
while maintaining complete type safety throughout your application.
|
|
8
|
+
The core package of Optique which provides the shared types and parser
|
|
9
|
+
combinators. It is designed to be used in universal JavaScript runtimes,
|
|
10
|
+
including Node.js, Deno, Bun, edge functions, and web browsers—although
|
|
11
|
+
you usually won't use it directly in browsers.
|
|
26
12
|
|
|
27
13
|
> [!TIP]
|
|
28
14
|
> *Building CLI apps?* Consider *@optique/run* for automatic `process.argv`
|
|
29
15
|
> handling and `process.exit()` integration. This core package is perfect for
|
|
30
16
|
> libraries, web apps, or when you need full control over argument parsing.
|
|
31
17
|
|
|
32
|
-
[optparse-applicative]: https://github.com/pcapriotti/optparse-applicative
|
|
33
|
-
[Zod]: https://zod.dev/
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
Core concepts
|
|
37
|
-
-------------
|
|
38
|
-
|
|
39
|
-
Optique is built around several key concepts:
|
|
40
|
-
|
|
41
|
-
- *Value parsers* convert strings to typed values
|
|
42
|
-
(`string()`, `integer()`, `url()`, etc.)
|
|
43
|
-
|
|
44
|
-
- *Primitive parsers* handle the basic building blocks:
|
|
45
|
-
|
|
46
|
-
- `option()` for command-line flags and their arguments
|
|
47
|
-
- `argument()` for positional arguments
|
|
48
|
-
- `command()` for subcommands
|
|
49
|
-
- `constant()` for literal values (essential for discriminated unions)
|
|
50
|
-
|
|
51
|
-
- *Modifying combinators* transform and combine parsers:
|
|
52
|
-
- `optional()` makes parsers optional
|
|
53
|
-
- `withDefault()` provides default values for optional parsers
|
|
54
|
-
- `map()` transforms parsed values using mapping functions
|
|
55
|
-
- `multiple()` allows repetition
|
|
56
|
-
- `or()` creates alternatives
|
|
57
|
-
- `merge()` combines object parsers
|
|
58
|
-
|
|
59
|
-
- *Construct combinators* build structured results:
|
|
60
|
-
|
|
61
|
-
- `object()` groups parsers into objects
|
|
62
|
-
- `tuple()` combines parsers into tuples
|
|
63
|
-
|
|
64
|
-
The library automatically infers the result type of your parser composition,
|
|
65
|
-
ensuring that your parsed CLI arguments are fully typed without manual type
|
|
66
|
-
annotations. When parsing fails, you get detailed error messages that help
|
|
67
|
-
users understand what went wrong.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
Example
|
|
71
|
-
-------
|
|
72
|
-
|
|
73
|
-
~~~~ typescript
|
|
74
|
-
import { run } from "@optique/core/facade";
|
|
75
|
-
import { formatMessage } from "@optique/core/message";
|
|
76
|
-
import {
|
|
77
|
-
argument,
|
|
78
|
-
merge,
|
|
79
|
-
multiple,
|
|
80
|
-
object,
|
|
81
|
-
option,
|
|
82
|
-
optional,
|
|
83
|
-
or,
|
|
84
|
-
withDefault
|
|
85
|
-
} from "@optique/core/parser";
|
|
86
|
-
import { choice, integer, locale, string, url } from "@optique/core/valueparser";
|
|
87
|
-
import process from "node:process";
|
|
88
|
-
|
|
89
|
-
// Define a sophisticated CLI with grouped and reusable option sets
|
|
90
|
-
const networkOptions = object("Network", {
|
|
91
|
-
port: option("-p", "--port", integer({ min: 1, max: 65535 })),
|
|
92
|
-
host: withDefault(
|
|
93
|
-
option("-h", "--host", string({ metavar: "HOST" })),
|
|
94
|
-
"localhost",
|
|
95
|
-
),
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
const loggingOptions = object("Logging", {
|
|
99
|
-
verbose: optional(option("-v", "--verbose")),
|
|
100
|
-
logFile: optional(option("--log-file", string({ metavar: "FILE" }))),
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
const parser = or(
|
|
104
|
-
// Server mode: merge network and logging options with server-specific config
|
|
105
|
-
merge(
|
|
106
|
-
networkOptions,
|
|
107
|
-
loggingOptions,
|
|
108
|
-
object("Server", {
|
|
109
|
-
locales: multiple(option("-l", "--locale", locale())),
|
|
110
|
-
config: argument(string({ metavar: "CONFIG_FILE" })),
|
|
111
|
-
}),
|
|
112
|
-
),
|
|
113
|
-
object("Client mode", {
|
|
114
|
-
connect: option(
|
|
115
|
-
"-c", "--connect",
|
|
116
|
-
url({ allowedProtocols: ["http:", "https:"] }),
|
|
117
|
-
),
|
|
118
|
-
headers: multiple(option("-H", "--header", string())),
|
|
119
|
-
timeout: withDefault(option("-t", "--timeout", integer({ min: 0 })), 30000),
|
|
120
|
-
files: multiple(argument(string({ metavar: "FILE" })), { min: 1, max: 5 }),
|
|
121
|
-
}),
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
const result = run(parser, "myapp", process.argv.slice(2), {
|
|
125
|
-
colors: true,
|
|
126
|
-
help: "both",
|
|
127
|
-
onError: process.exit,
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
// TypeScript automatically infers the complex union type with optional fields
|
|
131
|
-
if ("port" in result) {
|
|
132
|
-
const server = result;
|
|
133
|
-
console.log(`Starting server on ${server.host}:${server.port}`);
|
|
134
|
-
console.log(`Supported locales: ${server.locales.join(", ") || "default"}`);
|
|
135
|
-
if (server.verbose) console.log("Verbose mode enabled");
|
|
136
|
-
if (server.logFile) console.log(`Logging to: ${server.logFile}`);
|
|
137
|
-
} else {
|
|
138
|
-
const client = result;
|
|
139
|
-
console.log(`Connecting to ${client.connect}`);
|
|
140
|
-
console.log(`Processing ${client.files.length} files`);
|
|
141
|
-
console.log(`Timeout: ${client.timeout}ms`);
|
|
142
|
-
}
|
|
143
|
-
~~~~
|
|
144
|
-
|
|
145
|
-
This example demonstrates Optique's powerful combinators:
|
|
146
|
-
|
|
147
|
-
- **`merge()`** combines multiple `object()` parsers into a single unified
|
|
148
|
-
parser, enabling modular and reusable option groups
|
|
149
|
-
- **`optional()`** makes parsers optional, returning `undefined` when not
|
|
150
|
-
provided
|
|
151
|
-
- **`withDefault()`** provides default values instead of `undefined` for
|
|
152
|
-
optional parameters, improving usability
|
|
153
|
-
- **`multiple()`** allows repeating options/arguments with configurable
|
|
154
|
-
constraints
|
|
155
|
-
- **`or()`** creates mutually exclusive alternatives
|
|
156
|
-
- **`object()`** groups related options into structured data
|
|
157
|
-
|
|
158
|
-
The parser demonstrates modular design by:
|
|
159
|
-
|
|
160
|
-
- Separating network options (`--port`, `--host`) for reusability
|
|
161
|
-
- Grouping logging configuration (`--verbose`, `--log-file`) separately
|
|
162
|
-
- Merging reusable groups with server-specific options using `merge()`
|
|
163
|
-
- Supporting complex scenarios like multiple locales: `-l en-US -l fr-FR`
|
|
164
|
-
|
|
165
|
-
All with full type safety and automatic inference!
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
Parser combinators
|
|
169
|
-
------------------
|
|
170
|
-
|
|
171
|
-
Optique provides several types of parsers and combinators for building sophisticated CLI interfaces:
|
|
172
|
-
|
|
173
|
-
### Primitive parsers
|
|
174
|
-
|
|
175
|
-
- **`option()`**: Handles command-line flags and their arguments
|
|
176
|
-
|
|
177
|
-
~~~~ typescript
|
|
178
|
-
option("-p", "--port", integer({ min: 1, max: 65535 }))
|
|
179
|
-
option("-v", "--verbose") // Boolean flag
|
|
180
|
-
~~~~
|
|
181
|
-
|
|
182
|
-
- **`argument()`**: Handles positional arguments
|
|
183
|
-
|
|
184
|
-
~~~~ typescript
|
|
185
|
-
argument(string({ metavar: "FILE" }))
|
|
186
|
-
~~~~
|
|
187
|
-
|
|
188
|
-
- **`command()`**: Matches subcommands for `git`-like CLI interfaces
|
|
189
|
-
|
|
190
|
-
~~~~ typescript
|
|
191
|
-
command("add", object({ file: argument(string()) }))
|
|
192
|
-
~~~~
|
|
193
|
-
|
|
194
|
-
- **`constant()`**: Produces a constant value without consuming input, essential for discriminated unions
|
|
195
|
-
|
|
196
|
-
~~~~ typescript
|
|
197
|
-
constant("add") // Always returns "add"
|
|
198
|
-
constant(42) // Always returns 42
|
|
199
|
-
~~~~
|
|
200
|
-
|
|
201
|
-
### Modifying combinators
|
|
202
|
-
|
|
203
|
-
- **`optional()`**: Makes any parser optional, returning `undefined` if not
|
|
204
|
-
matched
|
|
205
|
-
|
|
206
|
-
~~~~ typescript
|
|
207
|
-
const parser = object({
|
|
208
|
-
name: option("-n", "--name", string()),
|
|
209
|
-
verbose: optional(option("-v", "--verbose")), // undefined if not provided
|
|
210
|
-
});
|
|
211
|
-
~~~~
|
|
212
|
-
|
|
213
|
-
- **`withDefault()`**: Makes any parser provide a default value instead of
|
|
214
|
-
`undefined` when not matched
|
|
215
|
-
|
|
216
|
-
~~~~ typescript
|
|
217
|
-
const parser = object({
|
|
218
|
-
name: option("-n", "--name", string()),
|
|
219
|
-
port: withDefault(option("-p", "--port", integer()), 8080), // 8080 if not provided
|
|
220
|
-
host: withDefault(option("-h", "--host", string()), "localhost"),
|
|
221
|
-
});
|
|
222
|
-
~~~~
|
|
223
|
-
|
|
224
|
-
- **`map()`**: Transforms the parsed value using a mapping function while
|
|
225
|
-
preserving the original parsing logic
|
|
226
18
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
// Transform boolean flag to its inverse
|
|
230
|
-
disallow: map(option("--allow"), b => !b),
|
|
231
|
-
// Transform string to uppercase
|
|
232
|
-
upperName: map(option("-n", "--name", string()), s => s.toUpperCase()),
|
|
233
|
-
// Transform number to formatted string
|
|
234
|
-
portDesc: map(option("-p", "--port", integer()), n => `port: ${n}`),
|
|
235
|
-
});
|
|
236
|
-
~~~~
|
|
19
|
+
When to use @optique/core
|
|
20
|
+
------------------------
|
|
237
21
|
|
|
238
|
-
|
|
22
|
+
Use *@optique/core* instead when:
|
|
239
23
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
// 1-3 input files required
|
|
245
|
-
files: multiple(argument(string()), { min: 1, max: 3 }),
|
|
246
|
-
});
|
|
247
|
-
~~~~
|
|
24
|
+
- Building web applications or libraries
|
|
25
|
+
- You need full control over argument sources and error handling
|
|
26
|
+
- Working in environments without `process` (browsers, web workers)
|
|
27
|
+
- Building reusable parser components
|
|
248
28
|
|
|
249
|
-
|
|
250
|
-
(try first, then second, etc.)
|
|
29
|
+
Use *@optique/run* when:
|
|
251
30
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
)
|
|
257
|
-
~~~~
|
|
31
|
+
- Building CLI applications for Node.js, Bun, or Deno
|
|
32
|
+
- You want automatic `process.argv` parsing and `process.exit()` handling
|
|
33
|
+
- You need automatic terminal capability detection (colors, width)
|
|
34
|
+
- You prefer a simple, batteries-included approach
|
|
258
35
|
|
|
259
|
-
- **`merge()`**: Merges multiple `object()` parsers into a single parser,
|
|
260
|
-
enabling modular composition of option groups
|
|
261
36
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
~~~~
|
|
265
|
-
|
|
266
|
-
### Construct combinators
|
|
267
|
-
|
|
268
|
-
- **`object()`**: Combines multiple parsers into a structured object
|
|
269
|
-
|
|
270
|
-
~~~~ typescript
|
|
271
|
-
object("Server", {
|
|
272
|
-
port: option("-p", "--port", integer()),
|
|
273
|
-
host: option("-h", "--host", string()),
|
|
274
|
-
})
|
|
275
|
-
~~~~
|
|
276
|
-
|
|
277
|
-
- **`tuple()`**: Combines multiple parsers into a tuple with preserved order
|
|
278
|
-
|
|
279
|
-
~~~~ typescript
|
|
280
|
-
tuple(
|
|
281
|
-
option("-u", "--user", string()),
|
|
282
|
-
option("-p", "--port", integer())
|
|
283
|
-
)
|
|
284
|
-
~~~~
|
|
285
|
-
|
|
286
|
-
### Advanced patterns
|
|
287
|
-
|
|
288
|
-
The `merge()` combinator enables powerful modular designs by separating concerns
|
|
289
|
-
into reusable option groups:
|
|
290
|
-
|
|
291
|
-
~~~~ typescript
|
|
292
|
-
// Define reusable option groups
|
|
293
|
-
const databaseOptions = object("Database", {
|
|
294
|
-
dbHost: option("--db-host", string()),
|
|
295
|
-
dbPort: option("--db-port", integer({ min: 1, max: 65535 })),
|
|
296
|
-
dbName: option("--db-name", string()),
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
const authOptions = object("Authentication", {
|
|
300
|
-
username: option("-u", "--user", string()),
|
|
301
|
-
password: optional(option("-p", "--password", string())),
|
|
302
|
-
token: optional(option("-t", "--token", string())),
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
const loggingOptions = object("Logging", {
|
|
306
|
-
logLevel: option("--log-level", choice(["debug", "info", "warn", "error"])),
|
|
307
|
-
logFile: optional(option("--log-file", string())),
|
|
308
|
-
});
|
|
309
|
-
|
|
310
|
-
// Combine groups differently for different modes
|
|
311
|
-
const parser = or(
|
|
312
|
-
// Development: all options available
|
|
313
|
-
merge(
|
|
314
|
-
object("Dev", { dev: option("--dev") }),
|
|
315
|
-
databaseOptions,
|
|
316
|
-
authOptions,
|
|
317
|
-
loggingOptions
|
|
318
|
-
),
|
|
319
|
-
// Production: database and auth required, enhanced logging
|
|
320
|
-
merge(
|
|
321
|
-
object("Prod", { config: option("-c", "--config", string()) }),
|
|
322
|
-
databaseOptions,
|
|
323
|
-
authOptions,
|
|
324
|
-
loggingOptions,
|
|
325
|
-
object("Production", {
|
|
326
|
-
workers: multiple(option("-w", "--worker", integer({ min: 1 }))),
|
|
327
|
-
})
|
|
328
|
-
),
|
|
329
|
-
);
|
|
330
|
-
~~~~
|
|
331
|
-
|
|
332
|
-
This approach promotes:
|
|
333
|
-
|
|
334
|
-
- *Reusability*: Option groups can be shared across different command modes
|
|
335
|
-
- *Maintainability*: Changes to option groups automatically propagate
|
|
336
|
-
- *Modularity*: Each concern is separated into its own focused parser
|
|
337
|
-
- *Flexibility*: Different combinations for different use cases
|
|
338
|
-
|
|
339
|
-
The `multiple()` combinator is especially powerful when combined with `object()`
|
|
340
|
-
parsers, as it provides empty arrays as defaults when no matches are found,
|
|
341
|
-
allowing for clean optional repeated arguments.
|
|
342
|
-
|
|
343
|
-
### Quick subcommand example
|
|
344
|
-
|
|
345
|
-
For a quick introduction to subcommands, here's a simple `git`-like interface:
|
|
37
|
+
Quick example
|
|
38
|
+
-------------
|
|
346
39
|
|
|
347
40
|
~~~~ typescript
|
|
348
41
|
import { run } from "@optique/core/facade";
|
|
349
|
-
import {
|
|
350
|
-
import { string } from "@optique/core/valueparser";
|
|
42
|
+
import { object, option, argument } from "@optique/core/parser";
|
|
43
|
+
import { string, integer } from "@optique/core/valueparser";
|
|
351
44
|
import process from "node:process";
|
|
352
45
|
|
|
353
|
-
const parser =
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
file: argument(string()),
|
|
358
|
-
})),
|
|
359
|
-
command("commit", object({
|
|
360
|
-
type: constant("commit"),
|
|
361
|
-
message: option("-m", "--message", string()),
|
|
362
|
-
amend: option("--amend"),
|
|
363
|
-
})),
|
|
364
|
-
);
|
|
365
|
-
|
|
366
|
-
const result = run(parser, "git", ["commit", "-m", "Fix parser bug"], {
|
|
367
|
-
help: "both",
|
|
368
|
-
onError: process.exit,
|
|
46
|
+
const parser = object({
|
|
47
|
+
name: argument(string()),
|
|
48
|
+
age: option("-a", "--age", integer()),
|
|
49
|
+
verbose: option("-v", "--verbose"),
|
|
369
50
|
});
|
|
370
|
-
// result.type === "commit"
|
|
371
|
-
// result.message === "Fix parser bug"
|
|
372
|
-
// result.amend === false
|
|
373
|
-
~~~~
|
|
374
|
-
|
|
375
|
-
### Subcommands
|
|
376
|
-
|
|
377
|
-
The `command()` combinator enables building git-like CLI interfaces with
|
|
378
|
-
subcommands. Each subcommand can have its own set of options and arguments:
|
|
379
|
-
|
|
380
|
-
~~~~ typescript
|
|
381
|
-
import { run } from "@optique/core/facade";
|
|
382
|
-
import {
|
|
383
|
-
argument,
|
|
384
|
-
command,
|
|
385
|
-
constant,
|
|
386
|
-
multiple,
|
|
387
|
-
object,
|
|
388
|
-
option,
|
|
389
|
-
optional,
|
|
390
|
-
or,
|
|
391
|
-
} from "@optique/core/parser";
|
|
392
|
-
import { string } from "@optique/core/valueparser";
|
|
393
|
-
import process from "node:process";
|
|
394
51
|
|
|
395
|
-
const
|
|
396
|
-
command("show", object({
|
|
397
|
-
type: constant("show"),
|
|
398
|
-
progress: option("-p", "--progress"),
|
|
399
|
-
verbose: optional(option("-v", "--verbose")),
|
|
400
|
-
id: argument(string({ metavar: "ITEM_ID" })),
|
|
401
|
-
})),
|
|
402
|
-
command("edit", object({
|
|
403
|
-
type: constant("edit"),
|
|
404
|
-
editor: optional(option("-e", "--editor", string({ metavar: "EDITOR" }))),
|
|
405
|
-
backup: option("-b", "--backup"),
|
|
406
|
-
id: argument(string({ metavar: "ITEM_ID" })),
|
|
407
|
-
})),
|
|
408
|
-
command("delete", object({
|
|
409
|
-
type: constant("delete"),
|
|
410
|
-
force: option("-f", "--force"),
|
|
411
|
-
recursive: optional(option("-r", "--recursive")),
|
|
412
|
-
items: multiple(argument(string({ metavar: "ITEM_ID" })), { min: 1 }),
|
|
413
|
-
})),
|
|
414
|
-
);
|
|
415
|
-
|
|
416
|
-
const result = run(parser, "myapp", process.argv.slice(2), {
|
|
417
|
-
colors: true,
|
|
52
|
+
const config = run(parser, "myapp", process.argv.slice(2), {
|
|
418
53
|
help: "both",
|
|
419
54
|
onError: process.exit,
|
|
420
55
|
});
|
|
421
56
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
console.log(`Showing item: ${result.id}`);
|
|
426
|
-
if (result.progress) console.log("Progress enabled");
|
|
427
|
-
if (result.verbose) console.log("Verbose mode enabled");
|
|
428
|
-
break;
|
|
429
|
-
case "edit":
|
|
430
|
-
console.log(`Editing item: ${result.id}`);
|
|
431
|
-
if (result.editor) console.log(`Using editor: ${result.editor}`);
|
|
432
|
-
if (result.backup) console.log("Backup enabled");
|
|
433
|
-
break;
|
|
434
|
-
case "delete":
|
|
435
|
-
console.log(`Deleting items: ${result.items.join(", ")}`);
|
|
436
|
-
if (result.force) console.log("Force delete enabled");
|
|
437
|
-
if (result.recursive) console.log("Recursive delete enabled");
|
|
438
|
-
break;
|
|
439
|
-
}
|
|
440
|
-
~~~~
|
|
441
|
-
|
|
442
|
-
This example demonstrates:
|
|
443
|
-
|
|
444
|
-
- *Subcommand routing*: `command("show", ...)` matches the first argument
|
|
445
|
-
and applies the inner parser to remaining arguments
|
|
446
|
-
- *Type discrimination*: Using `constant()` with unique values enables
|
|
447
|
-
TypeScript to discriminate between subcommand types in the result union
|
|
448
|
-
- *Per-subcommand options*: Each subcommand can have its own unique set
|
|
449
|
-
of options and arguments
|
|
450
|
-
- *Complex arguments*: The `delete` command shows multiple required arguments
|
|
451
|
-
|
|
452
|
-
The `constant()` parser is crucial here—it adds a literal value to each
|
|
453
|
-
subcommand's result object without consuming any input. This creates
|
|
454
|
-
a discriminated union type that TypeScript can use for type narrowing in
|
|
455
|
-
`switch` statements or type guards.
|
|
456
|
-
|
|
457
|
-
Example usage:
|
|
458
|
-
|
|
459
|
-
~~~~ bash
|
|
460
|
-
# Show command with options
|
|
461
|
-
$ myapp show --progress --verbose item123
|
|
462
|
-
|
|
463
|
-
# Edit command with optional editor
|
|
464
|
-
$ myapp edit --editor vim --backup item456
|
|
465
|
-
|
|
466
|
-
# Delete command with multiple items
|
|
467
|
-
$ myapp delete --force item1 item2 item3
|
|
57
|
+
console.log(`Hello ${config.name}!`);
|
|
58
|
+
if (config.age) console.log(`You are ${config.age} years old.`);
|
|
59
|
+
if (config.verbose) console.log("Verbose mode enabled.");
|
|
468
60
|
~~~~
|
|
469
61
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
You can also combine subcommands with global options using `object()`:
|
|
473
|
-
|
|
474
|
-
~~~~ typescript
|
|
475
|
-
const parser = object({
|
|
476
|
-
// Global options available to all subcommands
|
|
477
|
-
debug: optional(option("--debug")),
|
|
478
|
-
config: optional(option("-c", "--config", string())),
|
|
479
|
-
|
|
480
|
-
// Subcommand with its own options
|
|
481
|
-
command: or(
|
|
482
|
-
command("server", object({
|
|
483
|
-
type: constant("server" as const),
|
|
484
|
-
port: option("-p", "--port", integer({ min: 1, max: 65535 })),
|
|
485
|
-
daemon: option("-d", "--daemon"),
|
|
486
|
-
})),
|
|
487
|
-
command("client", object({
|
|
488
|
-
type: constant("client" as const),
|
|
489
|
-
connect: option("--connect", url()),
|
|
490
|
-
timeout: optional(option("-t", "--timeout", integer())),
|
|
491
|
-
})),
|
|
492
|
-
),
|
|
493
|
-
});
|
|
494
|
-
~~~~
|
|
495
|
-
|
|
496
|
-
This allows for commands like:
|
|
497
|
-
|
|
498
|
-
~~~~ bash
|
|
499
|
-
$ myapp --debug --config app.json server --port 8080 --daemon
|
|
500
|
-
$ myapp client --connect http://localhost:8080 --timeout 5000
|
|
501
|
-
~~~~
|
|
62
|
+
For more resources, see the [docs] and the [*examples/*](/examples/) directory.
|
|
502
63
|
|
|
503
|
-
|
|
64
|
+
[docs]: https://optique.dev/
|