@optique/core 0.1.0-dev.1 → 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 CHANGED
@@ -1,475 +1,64 @@
1
- Optique: Type-safe combinatorial CLI parser for TypeScript
2
- ==========================================================
1
+ @optique/core
2
+ =============
3
3
 
4
4
  > [!CAUTION]
5
- > Optique is currently in early development for proof of concept purposes,
6
- > and is not yet ready for production use. The API is subject to change,
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
- Optique is a type-safe combinatorial CLI *parser* for TypeScript inspired by
10
- Haskell's [optparse-applicative] and TypeScript's [Zod]. It provides composable
11
- parsers for building command-line interfaces with full type safety and
12
- automatic type inference.
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
-
50
- - *Modifying combinators* transform and combine parsers:
51
- - `optional()` makes parsers optional
52
- - `withDefault()` provides default values for optional parsers
53
- - `multiple()` allows repetition
54
- - `or()` creates alternatives
55
- - `merge()` combines object parsers
56
-
57
- - *Construct combinators* build structured results:
58
-
59
- - `object()` groups parsers into objects
60
- - `tuple()` combines parsers into tuples
61
-
62
- The library automatically infers the result type of your parser composition,
63
- ensuring that your parsed CLI arguments are fully typed without manual type
64
- annotations. When parsing fails, you get detailed error messages that help
65
- users understand what went wrong.
66
-
67
-
68
- Example
69
- -------
70
-
71
- ~~~~ typescript
72
- import { run } from "@optique/core/facade";
73
- import { formatMessage } from "@optique/core/message";
74
- import {
75
- argument,
76
- merge,
77
- multiple,
78
- object,
79
- option,
80
- optional,
81
- or,
82
- withDefault
83
- } from "@optique/core/parser";
84
- import { choice, integer, locale, string, url } from "@optique/core/valueparser";
85
- import process from "node:process";
86
-
87
- // Define a sophisticated CLI with grouped and reusable option sets
88
- const networkOptions = object("Network", {
89
- port: option("-p", "--port", integer({ min: 1, max: 65535 })),
90
- host: withDefault(
91
- option("-h", "--host", string({ metavar: "HOST" })),
92
- "localhost",
93
- ),
94
- });
95
-
96
- const loggingOptions = object("Logging", {
97
- verbose: optional(option("-v", "--verbose")),
98
- logFile: optional(option("--log-file", string({ metavar: "FILE" }))),
99
- });
100
-
101
- const parser = or(
102
- // Server mode: merge network and logging options with server-specific config
103
- merge(
104
- networkOptions,
105
- loggingOptions,
106
- object("Server", {
107
- locales: multiple(option("-l", "--locale", locale())),
108
- config: argument(string({ metavar: "CONFIG_FILE" })),
109
- }),
110
- ),
111
- object("Client mode", {
112
- connect: option(
113
- "-c", "--connect",
114
- url({ allowedProtocols: ["http:", "https:"] }),
115
- ),
116
- headers: multiple(option("-H", "--header", string())),
117
- timeout: withDefault(option("-t", "--timeout", integer({ min: 0 })), 30000),
118
- files: multiple(argument(string({ metavar: "FILE" })), { min: 1, max: 5 }),
119
- }),
120
- );
121
-
122
- const result = run(parser, "myapp", process.argv.slice(2), {
123
- colors: true,
124
- help: "both",
125
- onError: process.exit,
126
- });
127
-
128
- // TypeScript automatically infers the complex union type with optional fields
129
- if ("port" in result) {
130
- const server = result;
131
- console.log(`Starting server on ${server.host}:${server.port}`);
132
- console.log(`Supported locales: ${server.locales.join(", ") || "default"}`);
133
- if (server.verbose) console.log("Verbose mode enabled");
134
- if (server.logFile) console.log(`Logging to: ${server.logFile}`);
135
- } else {
136
- const client = result;
137
- console.log(`Connecting to ${client.connect}`);
138
- console.log(`Processing ${client.files.length} files`);
139
- console.log(`Timeout: ${client.timeout}ms`);
140
- }
141
- ~~~~
142
-
143
- This example demonstrates Optique's powerful combinators:
144
-
145
- - **`merge()`** combines multiple `object()` parsers into a single unified
146
- parser, enabling modular and reusable option groups
147
- - **`optional()`** makes parsers optional, returning `undefined` when not
148
- provided
149
- - **`withDefault()`** provides default values instead of `undefined` for
150
- optional parameters, improving usability
151
- - **`multiple()`** allows repeating options/arguments with configurable
152
- constraints
153
- - **`or()`** creates mutually exclusive alternatives
154
- - **`object()`** groups related options into structured data
155
-
156
- The parser demonstrates modular design by:
157
-
158
- - Separating network options (`--port`, `--host`) for reusability
159
- - Grouping logging configuration (`--verbose`, `--log-file`) separately
160
- - Merging reusable groups with server-specific options using `merge()`
161
- - Supporting complex scenarios like multiple locales: `-l en-US -l fr-FR`
162
-
163
- All with full type safety and automatic inference!
164
-
165
-
166
- Parser combinators
167
- ------------------
168
-
169
- Optique provides several types of parsers and combinators for building sophisticated CLI interfaces:
170
-
171
- ### Primitive parsers
172
-
173
- - **`option()`**: Handles command-line flags and their arguments
174
-
175
- ~~~~ typescript
176
- option("-p", "--port", integer({ min: 1, max: 65535 }))
177
- option("-v", "--verbose") // Boolean flag
178
- ~~~~
179
-
180
- - **`argument()`**: Handles positional arguments
181
-
182
- ~~~~ typescript
183
- argument(string({ metavar: "FILE" }))
184
- ~~~~
185
-
186
- - **`command()`**: Matches subcommands for `git`-like CLI interfaces
187
-
188
- ~~~~ typescript
189
- command("add", object({ file: argument(string()) }))
190
- ~~~~
191
-
192
- ### Modifying combinators
193
-
194
- - **`optional()`**: Makes any parser optional, returning `undefined` if not
195
- matched
196
-
197
- ~~~~ typescript
198
- const parser = object({
199
- name: option("-n", "--name", string()),
200
- verbose: optional(option("-v", "--verbose")), // undefined if not provided
201
- });
202
- ~~~~
203
-
204
- - **`withDefault()`**: Makes any parser provide a default value instead of
205
- `undefined` when not matched
206
-
207
- ~~~~ typescript
208
- const parser = object({
209
- name: option("-n", "--name", string()),
210
- port: withDefault(option("-p", "--port", integer()), 8080), // 8080 if not provided
211
- host: withDefault(option("-h", "--host", string()), "localhost"),
212
- });
213
- ~~~~
214
18
 
215
- - **`multiple()`**: Allows repeating a parser multiple times with constraints
19
+ When to use @optique/core
20
+ ------------------------
216
21
 
217
- ~~~~ typescript
218
- const parser = object({
219
- // Multiple locales: -l en -l fr
220
- locales: multiple(option("-l", "--locale", locale())),
221
- // 1-3 input files required
222
- files: multiple(argument(string()), { min: 1, max: 3 }),
223
- });
224
- ~~~~
22
+ Use *@optique/core* instead when:
225
23
 
226
- - **`or()`**: Creates mutually exclusive alternatives
227
- (try first, then second, etc.)
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
228
28
 
229
- ~~~~ typescript
230
- or(
231
- command("add", addParser),
232
- command("remove", removeParser)
233
- )
234
- ~~~~
29
+ Use *@optique/run* when:
235
30
 
236
- - **`merge()`**: Merges multiple `object()` parsers into a single parser,
237
- enabling modular composition of option groups
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
238
35
 
239
- ~~~~ typescript
240
- merge(networkOptions, loggingOptions, serverOptions)
241
- ~~~~
242
36
 
243
- ### Construct combinators
244
-
245
- - **`object()`**: Combines multiple parsers into a structured object
246
-
247
- ~~~~ typescript
248
- object("Server", {
249
- port: option("-p", "--port", integer()),
250
- host: option("-h", "--host", string()),
251
- })
252
- ~~~~
253
-
254
- - **`tuple()`**: Combines multiple parsers into a tuple with preserved order
255
-
256
- ~~~~ typescript
257
- tuple(
258
- option("-u", "--user", string()),
259
- option("-p", "--port", integer())
260
- )
261
- ~~~~
262
-
263
- ### Advanced patterns
264
-
265
- The `merge()` combinator enables powerful modular designs by separating concerns
266
- into reusable option groups:
267
-
268
- ~~~~ typescript
269
- // Define reusable option groups
270
- const databaseOptions = object("Database", {
271
- dbHost: option("--db-host", string()),
272
- dbPort: option("--db-port", integer({ min: 1, max: 65535 })),
273
- dbName: option("--db-name", string()),
274
- });
275
-
276
- const authOptions = object("Authentication", {
277
- username: option("-u", "--user", string()),
278
- password: optional(option("-p", "--password", string())),
279
- token: optional(option("-t", "--token", string())),
280
- });
281
-
282
- const loggingOptions = object("Logging", {
283
- logLevel: option("--log-level", choice(["debug", "info", "warn", "error"])),
284
- logFile: optional(option("--log-file", string())),
285
- });
286
-
287
- // Combine groups differently for different modes
288
- const parser = or(
289
- // Development: all options available
290
- merge(
291
- object("Dev", { dev: option("--dev") }),
292
- databaseOptions,
293
- authOptions,
294
- loggingOptions
295
- ),
296
- // Production: database and auth required, enhanced logging
297
- merge(
298
- object("Prod", { config: option("-c", "--config", string()) }),
299
- databaseOptions,
300
- authOptions,
301
- loggingOptions,
302
- object("Production", {
303
- workers: multiple(option("-w", "--worker", integer({ min: 1 }))),
304
- })
305
- ),
306
- );
307
- ~~~~
308
-
309
- This approach promotes:
310
-
311
- - *Reusability*: Option groups can be shared across different command modes
312
- - *Maintainability*: Changes to option groups automatically propagate
313
- - *Modularity*: Each concern is separated into its own focused parser
314
- - *Flexibility*: Different combinations for different use cases
315
-
316
- The `multiple()` combinator is especially powerful when combined with `object()`
317
- parsers, as it provides empty arrays as defaults when no matches are found,
318
- allowing for clean optional repeated arguments.
319
-
320
- ### Quick subcommand example
321
-
322
- For a quick introduction to subcommands, here's a simple `git`-like interface:
37
+ Quick example
38
+ -------------
323
39
 
324
40
  ~~~~ typescript
325
41
  import { run } from "@optique/core/facade";
326
- import { argument, command, constant, object, option, or } from "@optique/core/parser";
327
- import { string } from "@optique/core/valueparser";
42
+ import { object, option, argument } from "@optique/core/parser";
43
+ import { string, integer } from "@optique/core/valueparser";
328
44
  import process from "node:process";
329
45
 
330
- const parser = or(
331
- command("add", object({
332
- type: constant("add"),
333
- all: option("-A", "--all"),
334
- file: argument(string()),
335
- })),
336
- command("commit", object({
337
- type: constant("commit"),
338
- message: option("-m", "--message", string()),
339
- amend: option("--amend"),
340
- })),
341
- );
342
-
343
- const result = run(parser, "git", ["commit", "-m", "Fix parser bug"], {
344
- help: "both",
345
- onError: process.exit,
46
+ const parser = object({
47
+ name: argument(string()),
48
+ age: option("-a", "--age", integer()),
49
+ verbose: option("-v", "--verbose"),
346
50
  });
347
- // result.type === "commit"
348
- // result.message === "Fix parser bug"
349
- // result.amend === false
350
- ~~~~
351
-
352
- ### Subcommands
353
-
354
- The `command()` combinator enables building git-like CLI interfaces with
355
- subcommands. Each subcommand can have its own set of options and arguments:
356
-
357
- ~~~~ typescript
358
- import { run } from "@optique/core/facade";
359
- import {
360
- argument,
361
- command,
362
- constant,
363
- multiple,
364
- object,
365
- option,
366
- optional,
367
- or,
368
- } from "@optique/core/parser";
369
- import { string } from "@optique/core/valueparser";
370
- import process from "node:process";
371
51
 
372
- const parser = or(
373
- command("show", object({
374
- type: constant("show"),
375
- progress: option("-p", "--progress"),
376
- verbose: optional(option("-v", "--verbose")),
377
- id: argument(string({ metavar: "ITEM_ID" })),
378
- })),
379
- command("edit", object({
380
- type: constant("edit"),
381
- editor: optional(option("-e", "--editor", string({ metavar: "EDITOR" }))),
382
- backup: option("-b", "--backup"),
383
- id: argument(string({ metavar: "ITEM_ID" })),
384
- })),
385
- command("delete", object({
386
- type: constant("delete"),
387
- force: option("-f", "--force"),
388
- recursive: optional(option("-r", "--recursive")),
389
- items: multiple(argument(string({ metavar: "ITEM_ID" })), { min: 1 }),
390
- })),
391
- );
392
-
393
- const result = run(parser, "myapp", process.argv.slice(2), {
394
- colors: true,
52
+ const config = run(parser, "myapp", process.argv.slice(2), {
395
53
  help: "both",
396
54
  onError: process.exit,
397
55
  });
398
56
 
399
- // TypeScript infers a union type with discriminated subcommands
400
- switch (result.type) {
401
- case "show":
402
- console.log(`Showing item: ${result.id}`);
403
- if (result.progress) console.log("Progress enabled");
404
- if (result.verbose) console.log("Verbose mode enabled");
405
- break;
406
- case "edit":
407
- console.log(`Editing item: ${result.id}`);
408
- if (result.editor) console.log(`Using editor: ${result.editor}`);
409
- if (result.backup) console.log("Backup enabled");
410
- break;
411
- case "delete":
412
- console.log(`Deleting items: ${result.items.join(", ")}`);
413
- if (result.force) console.log("Force delete enabled");
414
- if (result.recursive) console.log("Recursive delete enabled");
415
- break;
416
- }
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.");
417
60
  ~~~~
418
61
 
419
- This example demonstrates:
420
-
421
- - *Subcommand routing*: `command("show", ...)` matches the first argument
422
- and applies the inner parser to remaining arguments
423
- - *Type discrimination*: Using `constant()` with unique values enables
424
- TypeScript to discriminate between subcommand types
425
- - *Per-subcommand options*: Each subcommand can have its own unique set
426
- of options and arguments
427
- - *Complex arguments*: The `delete` command shows multiple required arguments
428
-
429
- Example usage:
430
-
431
- ~~~~ bash
432
- # Show command with options
433
- $ myapp show --progress --verbose item123
434
-
435
- # Edit command with optional editor
436
- $ myapp edit --editor vim --backup item456
437
-
438
- # Delete command with multiple items
439
- $ myapp delete --force item1 item2 item3
440
- ~~~~
441
-
442
- ### Advanced subcommand patterns
443
-
444
- You can also combine subcommands with global options using `object()`:
445
-
446
- ~~~~ typescript
447
- const parser = object({
448
- // Global options available to all subcommands
449
- debug: optional(option("--debug")),
450
- config: optional(option("-c", "--config", string())),
451
-
452
- // Subcommand with its own options
453
- command: or(
454
- command("server", object({
455
- type: constant("server" as const),
456
- port: option("-p", "--port", integer({ min: 1, max: 65535 })),
457
- daemon: option("-d", "--daemon"),
458
- })),
459
- command("client", object({
460
- type: constant("client" as const),
461
- connect: option("--connect", url()),
462
- timeout: optional(option("-t", "--timeout", integer())),
463
- })),
464
- ),
465
- });
466
- ~~~~
467
-
468
- This allows for commands like:
469
-
470
- ~~~~ bash
471
- $ myapp --debug --config app.json server --port 8080 --daemon
472
- $ myapp client --connect http://localhost:8080 --timeout 5000
473
- ~~~~
62
+ For more resources, see the [docs] and the [*examples/*](/examples/) directory.
474
63
 
475
- <!-- cSpell: ignore optparse myapp -->
64
+ [docs]: https://optique.dev/
package/dist/index.cjs CHANGED
@@ -19,6 +19,7 @@ exports.getDocPage = require_parser.getDocPage;
19
19
  exports.integer = require_valueparser.integer;
20
20
  exports.isValueParser = require_valueparser.isValueParser;
21
21
  exports.locale = require_valueparser.locale;
22
+ exports.map = require_parser.map;
22
23
  exports.merge = require_parser.merge;
23
24
  exports.message = require_message.message;
24
25
  exports.metavar = require_message.metavar;
package/dist/index.d.cts CHANGED
@@ -2,6 +2,6 @@ import { Message, MessageFormatOptions, MessageTerm, formatMessage, message, met
2
2
  import { OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, formatUsage, formatUsageTerm, normalizeUsage } from "./usage.cjs";
3
3
  import { DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, formatDocPage } from "./doc.cjs";
4
4
  import { ChoiceOptions, FloatOptions, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, StringOptions, UrlOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, choice, float, integer, isValueParser, locale, string, url, uuid } from "./valueparser.cjs";
5
- import { ArgumentOptions, CommandOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, argument, command, constant, getDocPage, merge, multiple, object, option, optional, or, parse, tuple, withDefault } from "./parser.cjs";
5
+ import { ArgumentOptions, CommandOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, argument, command, constant, getDocPage, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault } from "./parser.cjs";
6
6
  import { RunError, RunOptions, run } from "./facade.cjs";
7
- export { ArgumentOptions, ChoiceOptions, CommandOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, Message, MessageFormatOptions, MessageTerm, MultipleOptions, OptionName, OptionOptions, Parser, ParserContext, ParserResult, Result, RunError, RunOptions, StringOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, argument, choice, command, constant, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, integer, isValueParser, locale, merge, message, metavar, multiple, normalizeUsage, object, option, optionName, optionNames, optional, or, parse, run, string, text, tuple, url, uuid, value, values, withDefault };
7
+ export { ArgumentOptions, ChoiceOptions, CommandOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, Message, MessageFormatOptions, MessageTerm, MultipleOptions, OptionName, OptionOptions, Parser, ParserContext, ParserResult, Result, RunError, RunOptions, StringOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, argument, choice, command, constant, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, integer, isValueParser, locale, map, merge, message, metavar, multiple, normalizeUsage, object, option, optionName, optionNames, optional, or, parse, run, string, text, tuple, url, uuid, value, values, withDefault };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,6 @@ import { Message, MessageFormatOptions, MessageTerm, formatMessage, message, met
2
2
  import { OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, formatUsage, formatUsageTerm, normalizeUsage } from "./usage.js";
3
3
  import { DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, formatDocPage } from "./doc.js";
4
4
  import { ChoiceOptions, FloatOptions, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, StringOptions, UrlOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, choice, float, integer, isValueParser, locale, string, url, uuid } from "./valueparser.js";
5
- import { ArgumentOptions, CommandOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, argument, command, constant, getDocPage, merge, multiple, object, option, optional, or, parse, tuple, withDefault } from "./parser.js";
5
+ import { ArgumentOptions, CommandOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, argument, command, constant, getDocPage, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault } from "./parser.js";
6
6
  import { RunError, RunOptions, run } from "./facade.js";
7
- export { ArgumentOptions, ChoiceOptions, CommandOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, Message, MessageFormatOptions, MessageTerm, MultipleOptions, OptionName, OptionOptions, Parser, ParserContext, ParserResult, Result, RunError, RunOptions, StringOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, argument, choice, command, constant, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, integer, isValueParser, locale, merge, message, metavar, multiple, normalizeUsage, object, option, optionName, optionNames, optional, or, parse, run, string, text, tuple, url, uuid, value, values, withDefault };
7
+ export { ArgumentOptions, ChoiceOptions, CommandOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, Message, MessageFormatOptions, MessageTerm, MultipleOptions, OptionName, OptionOptions, Parser, ParserContext, ParserResult, Result, RunError, RunOptions, StringOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, argument, choice, command, constant, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, integer, isValueParser, locale, map, merge, message, metavar, multiple, normalizeUsage, object, option, optionName, optionNames, optional, or, parse, run, string, text, tuple, url, uuid, value, values, withDefault };
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import { formatMessage, message, metavar, optionName, optionNames, text, value,
2
2
  import { formatUsage, formatUsageTerm, normalizeUsage } from "./usage.js";
3
3
  import { formatDocPage } from "./doc.js";
4
4
  import { choice, float, integer, isValueParser, locale, string, url, uuid } from "./valueparser.js";
5
- import { argument, command, constant, getDocPage, merge, multiple, object, option, optional, or, parse, tuple, withDefault } from "./parser.js";
5
+ import { argument, command, constant, getDocPage, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault } from "./parser.js";
6
6
  import { RunError, run } from "./facade.js";
7
7
 
8
- export { RunError, argument, choice, command, constant, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, integer, isValueParser, locale, merge, message, metavar, multiple, normalizeUsage, object, option, optionName, optionNames, optional, or, parse, run, string, text, tuple, url, uuid, value, values, withDefault };
8
+ export { RunError, argument, choice, command, constant, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, integer, isValueParser, locale, map, merge, message, metavar, multiple, normalizeUsage, object, option, optionName, optionNames, optional, or, parse, run, string, text, tuple, url, uuid, value, values, withDefault };
package/dist/parser.cjs CHANGED
@@ -413,6 +413,60 @@ function withDefault(parser, defaultValue) {
413
413
  };
414
414
  }
415
415
  /**
416
+ * Creates a parser that transforms the result value of another parser using
417
+ * a mapping function. This enables value transformation while preserving
418
+ * the original parser's parsing logic and state management.
419
+ *
420
+ * The `map()` function is useful for:
421
+ * - Converting parsed values to different types
422
+ * - Applying transformations like string formatting or boolean inversion
423
+ * - Computing derived values from parsed input
424
+ * - Creating reusable transformations that can be applied to any parser
425
+ *
426
+ * @template T The type of the value produced by the original parser.
427
+ * @template U The type of the value produced by the mapping function.
428
+ * @template TState The type of the state used by the original parser.
429
+ * @param parser The {@link Parser} whose result will be transformed.
430
+ * @param transform A function that transforms the parsed value from type T to type U.
431
+ * @returns A {@link Parser} that produces the transformed value of type U
432
+ * while preserving the original parser's state type and parsing behavior.
433
+ *
434
+ * @example
435
+ * ```typescript
436
+ * // Transform boolean flag to its inverse
437
+ * const parser = object({
438
+ * disallow: map(option("--allow"), b => !b)
439
+ * });
440
+ *
441
+ * // Transform string to uppercase
442
+ * const upperParser = map(argument(string()), s => s.toUpperCase());
443
+ *
444
+ * // Transform number to formatted string
445
+ * const prefixedParser = map(option("-n", integer()), n => `value: ${n}`);
446
+ * ```
447
+ */
448
+ function map(parser, transform) {
449
+ return {
450
+ $valueType: [],
451
+ $stateType: parser.$stateType,
452
+ priority: parser.priority,
453
+ usage: parser.usage,
454
+ initialState: parser.initialState,
455
+ parse: parser.parse.bind(parser),
456
+ complete(state) {
457
+ const result = parser.complete(state);
458
+ if (result.success) return {
459
+ success: true,
460
+ value: transform(result.value)
461
+ };
462
+ return result;
463
+ },
464
+ getDocFragments(state, _defaultValue) {
465
+ return parser.getDocFragments(state, void 0);
466
+ }
467
+ };
468
+ }
469
+ /**
416
470
  * Creates a parser that allows multiple occurrences of a given parser.
417
471
  * This parser can be used to parse multiple values of the same type,
418
472
  * such as multiple command-line arguments or options.
@@ -1054,6 +1108,7 @@ exports.argument = argument;
1054
1108
  exports.command = command;
1055
1109
  exports.constant = constant;
1056
1110
  exports.getDocPage = getDocPage;
1111
+ exports.map = map;
1057
1112
  exports.merge = merge;
1058
1113
  exports.multiple = multiple;
1059
1114
  exports.object = object;
package/dist/parser.d.cts CHANGED
@@ -238,6 +238,40 @@ declare function optional<TValue, TState>(parser: Parser<TValue, TState>): Parse
238
238
  * or the default value if the wrapped parser fails to match.
239
239
  */
240
240
  declare function withDefault<TValue, TState>(parser: Parser<TValue, TState>, defaultValue: TValue | (() => TValue)): Parser<TValue, [TState] | undefined>;
241
+ /**
242
+ * Creates a parser that transforms the result value of another parser using
243
+ * a mapping function. This enables value transformation while preserving
244
+ * the original parser's parsing logic and state management.
245
+ *
246
+ * The `map()` function is useful for:
247
+ * - Converting parsed values to different types
248
+ * - Applying transformations like string formatting or boolean inversion
249
+ * - Computing derived values from parsed input
250
+ * - Creating reusable transformations that can be applied to any parser
251
+ *
252
+ * @template T The type of the value produced by the original parser.
253
+ * @template U The type of the value produced by the mapping function.
254
+ * @template TState The type of the state used by the original parser.
255
+ * @param parser The {@link Parser} whose result will be transformed.
256
+ * @param transform A function that transforms the parsed value from type T to type U.
257
+ * @returns A {@link Parser} that produces the transformed value of type U
258
+ * while preserving the original parser's state type and parsing behavior.
259
+ *
260
+ * @example
261
+ * ```typescript
262
+ * // Transform boolean flag to its inverse
263
+ * const parser = object({
264
+ * disallow: map(option("--allow"), b => !b)
265
+ * });
266
+ *
267
+ * // Transform string to uppercase
268
+ * const upperParser = map(argument(string()), s => s.toUpperCase());
269
+ *
270
+ * // Transform number to formatted string
271
+ * const prefixedParser = map(option("-n", integer()), n => `value: ${n}`);
272
+ * ```
273
+ */
274
+ declare function map<T, U, TState>(parser: Parser<T, TState>, transform: (value: T) => U): Parser<U, TState>;
241
275
  /**
242
276
  * Options for the {@link multiple} parser.
243
277
  */
@@ -577,4 +611,4 @@ declare function parse<T>(parser: Parser<T, unknown>, args: readonly string[]):
577
611
  */
578
612
  declare function getDocPage(parser: Parser<unknown, unknown>, args?: readonly string[]): DocPage | undefined;
579
613
  //#endregion
580
- export { ArgumentOptions, CommandOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, argument, command, constant, getDocPage, merge, multiple, object, option, optional, or, parse, tuple, withDefault };
614
+ export { ArgumentOptions, CommandOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, argument, command, constant, getDocPage, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault };
package/dist/parser.d.ts CHANGED
@@ -238,6 +238,40 @@ declare function optional<TValue, TState>(parser: Parser<TValue, TState>): Parse
238
238
  * or the default value if the wrapped parser fails to match.
239
239
  */
240
240
  declare function withDefault<TValue, TState>(parser: Parser<TValue, TState>, defaultValue: TValue | (() => TValue)): Parser<TValue, [TState] | undefined>;
241
+ /**
242
+ * Creates a parser that transforms the result value of another parser using
243
+ * a mapping function. This enables value transformation while preserving
244
+ * the original parser's parsing logic and state management.
245
+ *
246
+ * The `map()` function is useful for:
247
+ * - Converting parsed values to different types
248
+ * - Applying transformations like string formatting or boolean inversion
249
+ * - Computing derived values from parsed input
250
+ * - Creating reusable transformations that can be applied to any parser
251
+ *
252
+ * @template T The type of the value produced by the original parser.
253
+ * @template U The type of the value produced by the mapping function.
254
+ * @template TState The type of the state used by the original parser.
255
+ * @param parser The {@link Parser} whose result will be transformed.
256
+ * @param transform A function that transforms the parsed value from type T to type U.
257
+ * @returns A {@link Parser} that produces the transformed value of type U
258
+ * while preserving the original parser's state type and parsing behavior.
259
+ *
260
+ * @example
261
+ * ```typescript
262
+ * // Transform boolean flag to its inverse
263
+ * const parser = object({
264
+ * disallow: map(option("--allow"), b => !b)
265
+ * });
266
+ *
267
+ * // Transform string to uppercase
268
+ * const upperParser = map(argument(string()), s => s.toUpperCase());
269
+ *
270
+ * // Transform number to formatted string
271
+ * const prefixedParser = map(option("-n", integer()), n => `value: ${n}`);
272
+ * ```
273
+ */
274
+ declare function map<T, U, TState>(parser: Parser<T, TState>, transform: (value: T) => U): Parser<U, TState>;
241
275
  /**
242
276
  * Options for the {@link multiple} parser.
243
277
  */
@@ -577,4 +611,4 @@ declare function parse<T>(parser: Parser<T, unknown>, args: readonly string[]):
577
611
  */
578
612
  declare function getDocPage(parser: Parser<unknown, unknown>, args?: readonly string[]): DocPage | undefined;
579
613
  //#endregion
580
- export { ArgumentOptions, CommandOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, argument, command, constant, getDocPage, merge, multiple, object, option, optional, or, parse, tuple, withDefault };
614
+ export { ArgumentOptions, CommandOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, argument, command, constant, getDocPage, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault };
package/dist/parser.js CHANGED
@@ -413,6 +413,60 @@ function withDefault(parser, defaultValue) {
413
413
  };
414
414
  }
415
415
  /**
416
+ * Creates a parser that transforms the result value of another parser using
417
+ * a mapping function. This enables value transformation while preserving
418
+ * the original parser's parsing logic and state management.
419
+ *
420
+ * The `map()` function is useful for:
421
+ * - Converting parsed values to different types
422
+ * - Applying transformations like string formatting or boolean inversion
423
+ * - Computing derived values from parsed input
424
+ * - Creating reusable transformations that can be applied to any parser
425
+ *
426
+ * @template T The type of the value produced by the original parser.
427
+ * @template U The type of the value produced by the mapping function.
428
+ * @template TState The type of the state used by the original parser.
429
+ * @param parser The {@link Parser} whose result will be transformed.
430
+ * @param transform A function that transforms the parsed value from type T to type U.
431
+ * @returns A {@link Parser} that produces the transformed value of type U
432
+ * while preserving the original parser's state type and parsing behavior.
433
+ *
434
+ * @example
435
+ * ```typescript
436
+ * // Transform boolean flag to its inverse
437
+ * const parser = object({
438
+ * disallow: map(option("--allow"), b => !b)
439
+ * });
440
+ *
441
+ * // Transform string to uppercase
442
+ * const upperParser = map(argument(string()), s => s.toUpperCase());
443
+ *
444
+ * // Transform number to formatted string
445
+ * const prefixedParser = map(option("-n", integer()), n => `value: ${n}`);
446
+ * ```
447
+ */
448
+ function map(parser, transform) {
449
+ return {
450
+ $valueType: [],
451
+ $stateType: parser.$stateType,
452
+ priority: parser.priority,
453
+ usage: parser.usage,
454
+ initialState: parser.initialState,
455
+ parse: parser.parse.bind(parser),
456
+ complete(state) {
457
+ const result = parser.complete(state);
458
+ if (result.success) return {
459
+ success: true,
460
+ value: transform(result.value)
461
+ };
462
+ return result;
463
+ },
464
+ getDocFragments(state, _defaultValue) {
465
+ return parser.getDocFragments(state, void 0);
466
+ }
467
+ };
468
+ }
469
+ /**
416
470
  * Creates a parser that allows multiple occurrences of a given parser.
417
471
  * This parser can be used to parse multiple values of the same type,
418
472
  * such as multiple command-line arguments or options.
@@ -1050,4 +1104,4 @@ function getDocPage(parser, args = []) {
1050
1104
  }
1051
1105
 
1052
1106
  //#endregion
1053
- export { argument, command, constant, getDocPage, merge, multiple, object, option, optional, or, parse, tuple, withDefault };
1107
+ export { argument, command, constant, getDocPage, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "0.1.0-dev.1+4d43eddd",
3
+ "version": "0.1.0-dev.27+836bb5a6",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",