@optique/core 0.9.0-dev.201 → 0.9.0-dev.202

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/dist/facade.cjs CHANGED
@@ -89,6 +89,11 @@ function createCompletionParser(mode, programName, availableShells, name = "both
89
89
  { description: require_message.message`Generate shell completion script.` }
90
90
  ];
91
91
  const completionOption = require_primitives.option(...completionOptionArgs);
92
+ const argsParser = require_modifiers.withDefault(require_modifiers.multiple(require_primitives.argument(require_valueparser.string({ metavar: "ARG" }), { description: require_message.message`Command line arguments for completion suggestions (used by shell integration; you usually don't need to provide this).` })), []);
93
+ const optionParser = require_constructs.object({
94
+ shell: completionOption,
95
+ args: argsParser
96
+ });
92
97
  switch (mode) {
93
98
  case "command": return {
94
99
  completionCommand,
@@ -96,17 +101,11 @@ function createCompletionParser(mode, programName, availableShells, name = "both
96
101
  };
97
102
  case "option": return {
98
103
  completionCommand: null,
99
- completionOption: require_constructs.object({
100
- shell: completionOption,
101
- args: require_modifiers.withDefault(require_modifiers.multiple(require_primitives.argument(require_valueparser.string({ metavar: "ARG" }), { description: require_message.message`Command line arguments for completion suggestions (used by shell integration; you usually don't need to provide this).` })), [])
102
- })
104
+ completionOption: optionParser
103
105
  };
104
106
  case "both": return {
105
107
  completionCommand,
106
- completionOption: require_constructs.object({
107
- shell: completionOption,
108
- args: require_modifiers.withDefault(require_modifiers.multiple(require_primitives.argument(require_valueparser.string({ metavar: "ARG" }), { description: require_message.message`Command line arguments for completion suggestions (used by shell integration; you usually don't need to provide this).` })), [])
109
- })
108
+ completionOption: optionParser
110
109
  };
111
110
  }
112
111
  }
@@ -117,6 +116,7 @@ function combineWithHelpVersion(originalParser, helpParsers, versionParsers, com
117
116
  const parsers = [];
118
117
  if (helpParsers.helpOption) {
119
118
  const lenientHelpParser = {
119
+ $mode: "sync",
120
120
  $valueType: [],
121
121
  $stateType: [],
122
122
  priority: 200,
@@ -178,12 +178,11 @@ function combineWithHelpVersion(originalParser, helpParsers, versionParsers, com
178
178
  value: state
179
179
  };
180
180
  },
181
- suggest(_context, prefix) {
182
- if ("--help".startsWith(prefix)) return [{
181
+ *suggest(_context, prefix) {
182
+ if ("--help".startsWith(prefix)) yield {
183
183
  kind: "literal",
184
184
  text: "--help"
185
- }];
186
- return [];
185
+ };
187
186
  },
188
187
  getDocFragments(state) {
189
188
  return helpParsers.helpOption?.getDocFragments(state) ?? { fragments: [] };
@@ -193,6 +192,7 @@ function combineWithHelpVersion(originalParser, helpParsers, versionParsers, com
193
192
  }
194
193
  if (versionParsers.versionOption) {
195
194
  const lenientVersionParser = {
195
+ $mode: "sync",
196
196
  $valueType: [],
197
197
  $stateType: [],
198
198
  priority: 200,
@@ -246,12 +246,11 @@ function combineWithHelpVersion(originalParser, helpParsers, versionParsers, com
246
246
  value: state
247
247
  };
248
248
  },
249
- suggest(_context, prefix) {
250
- if ("--version".startsWith(prefix)) return [{
249
+ *suggest(_context, prefix) {
250
+ if ("--version".startsWith(prefix)) yield {
251
251
  kind: "literal",
252
252
  text: "--version"
253
- }];
254
- return [];
253
+ };
255
254
  },
256
255
  getDocFragments(state) {
257
256
  return versionParsers.versionOption?.getDocFragments(state) ?? { fragments: [] };
@@ -346,6 +345,20 @@ function classifyResult(result, args) {
346
345
  function handleCompletion(completionArgs, programName, parser, completionParser, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionMode, completionName) {
347
346
  const shellName = completionArgs[0] || "";
348
347
  const args = completionArgs.slice(1);
348
+ const callOnError = (code) => {
349
+ try {
350
+ return onError(code);
351
+ } catch {
352
+ return onError();
353
+ }
354
+ };
355
+ const callOnCompletion = (code) => {
356
+ try {
357
+ return onCompletion(code);
358
+ } catch {
359
+ return onCompletion();
360
+ }
361
+ };
349
362
  if (!shellName) {
350
363
  stderr("Error: Missing shell name for completion.\n");
351
364
  if (completionParser) {
@@ -355,70 +368,41 @@ function handleCompletion(completionArgs, programName, parser, completionParser,
355
368
  maxWidth
356
369
  }));
357
370
  }
358
- try {
359
- return onError(1);
360
- } catch {
361
- return onError();
362
- }
371
+ if (parser.$mode === "async") return Promise.resolve(callOnError(1));
372
+ return callOnError(1);
363
373
  }
364
374
  const shell = availableShells[shellName];
365
375
  if (!shell) {
366
376
  const available = [];
367
- for (const shell$1 in availableShells) {
377
+ for (const name in availableShells) {
368
378
  if (available.length > 0) available.push(require_message.text(", "));
369
- available.push(require_message.value(shell$1));
379
+ available.push(require_message.value(name));
370
380
  }
371
381
  stderr(require_message.formatMessage(require_message.message`Error: Unsupported shell ${shellName}. Available shells: ${available}.`, {
372
382
  colors,
373
383
  quotes: !colors
374
384
  }));
375
- return onError(1);
385
+ if (parser.$mode === "async") return Promise.resolve(callOnError(1));
386
+ return callOnError(1);
376
387
  }
377
388
  if (args.length === 0) {
378
389
  const usePlural = completionName === "plural";
379
390
  const completionArg = completionMode === "option" ? usePlural ? "--completions" : "--completion" : usePlural ? "completions" : "completion";
380
391
  const script = shell.generateScript(programName, [completionArg, shellName]);
381
392
  stdout(script);
382
- } else {
383
- const suggestions = require_parser.suggest(parser, args);
384
- for (const chunk of shell.encodeSuggestions(suggestions)) stdout(chunk);
385
- }
386
- try {
387
- return onCompletion(0);
388
- } catch {
389
- return onCompletion();
393
+ if (parser.$mode === "async") return Promise.resolve(callOnCompletion(0));
394
+ return callOnCompletion(0);
390
395
  }
396
+ if (parser.$mode === "async") return (async () => {
397
+ const suggestions$1 = await require_parser.suggestAsync(parser, args);
398
+ for (const chunk of shell.encodeSuggestions(suggestions$1)) stdout(chunk);
399
+ return callOnCompletion(0);
400
+ })();
401
+ const syncParser = parser;
402
+ const suggestions = require_parser.suggest(syncParser, args);
403
+ for (const chunk of shell.encodeSuggestions(suggestions)) stdout(chunk);
404
+ return callOnCompletion(0);
391
405
  }
392
- /**
393
- * Runs a parser against command-line arguments with built-in help and error
394
- * handling.
395
- *
396
- * This function provides a complete CLI interface by automatically handling
397
- * help commands/options and displaying formatted error messages with usage
398
- * information when parsing fails. It augments the provided parser with help
399
- * functionality based on the configuration options.
400
- *
401
- * The function will:
402
- *
403
- * 1. Add help command/option support (unless disabled)
404
- * 2. Parse the provided arguments
405
- * 3. Display help if requested
406
- * 4. Show formatted error messages with usage/help info on parse failures
407
- * 5. Return the parsed result or invoke the appropriate callback
408
- *
409
- * @template TParser The parser type being run.
410
- * @template THelp Return type when help is shown (defaults to `void`).
411
- * @template TError Return type when an error occurs (defaults to `never`).
412
- * @param parser The parser to run against the command-line arguments.
413
- * @param programName Name of the program used in usage and help output.
414
- * @param args Command-line arguments to parse (typically from
415
- * `process.argv.slice(2)` on Node.js or `Deno.args` on Deno).
416
- * @param options Configuration options for output formatting and callbacks.
417
- * @returns The parsed result value, or the return value of `onHelp`/`onError`
418
- * callbacks.
419
- * @throws {RunParserError} When parsing fails and no `onError` callback is
420
- * provided.
421
- */
422
406
  function runParser(parser, programName, args, options = {}) {
423
407
  let { colors, maxWidth, showDefault, aboveError = "usage", onError = () => {
424
408
  throw new RunParserError("Failed to parse command line arguments.");
@@ -480,94 +464,100 @@ function runParser(parser, programName, args, options = {}) {
480
464
  }
481
465
  }
482
466
  const augmentedParser = help === "none" && version === "none" && completion === "none" ? parser : combineWithHelpVersion(parser, helpParsers, versionParsers, completionParsers);
483
- const result = require_parser.parse(augmentedParser, args);
484
- const classified = classifyResult(result, args);
485
- switch (classified.type) {
486
- case "success": return classified.value;
487
- case "version":
488
- stdout(versionValue);
489
- try {
490
- return onVersion(0);
491
- } catch {
492
- return onVersion();
493
- }
494
- case "completion": throw new RunParserError("Completion should be handled by early return");
495
- case "help": {
496
- let helpGeneratorParser;
497
- const helpAsCommand = help === "command" || help === "both";
498
- const versionAsCommand = version === "command" || version === "both";
499
- const completionAsCommand = completion === "command" || completion === "both";
500
- const requestedCommand = classified.commands[0];
501
- if ((requestedCommand === "completion" || requestedCommand === "completions") && completionAsCommand && completionParsers.completionCommand) helpGeneratorParser = completionParsers.completionCommand;
502
- else if (requestedCommand === "help" && helpAsCommand && helpParsers.helpCommand) helpGeneratorParser = helpParsers.helpCommand;
503
- else if (requestedCommand === "version" && versionAsCommand && versionParsers.versionCommand) helpGeneratorParser = versionParsers.versionCommand;
504
- else {
505
- const commandParsers = [parser];
506
- if (helpAsCommand) {
507
- if (helpParsers.helpCommand) commandParsers.push(helpParsers.helpCommand);
508
- }
509
- if (versionAsCommand) {
510
- if (versionParsers.versionCommand) commandParsers.push(versionParsers.versionCommand);
467
+ const handleResult = (result) => {
468
+ const classified = classifyResult(result, args);
469
+ switch (classified.type) {
470
+ case "success": return classified.value;
471
+ case "version":
472
+ stdout(versionValue);
473
+ try {
474
+ return onVersion(0);
475
+ } catch {
476
+ return onVersion();
511
477
  }
512
- if (completionAsCommand) {
513
- if (completionParsers.completionCommand) commandParsers.push(completionParsers.completionCommand);
514
- }
515
- if (commandParsers.length === 1) helpGeneratorParser = commandParsers[0];
516
- else if (commandParsers.length === 2) helpGeneratorParser = require_constructs.longestMatch(commandParsers[0], commandParsers[1]);
517
- else helpGeneratorParser = require_constructs.longestMatch(...commandParsers);
518
- }
519
- const doc = require_parser.getDocPage(helpGeneratorParser, classified.commands);
520
- if (doc != null) {
521
- const isMetaCommandHelp = (completionName === "singular" || completionName === "both" ? requestedCommand === "completion" : false) || (completionName === "plural" || completionName === "both" ? requestedCommand === "completions" : false) || requestedCommand === "help" || requestedCommand === "version";
522
- const augmentedDoc = {
523
- ...doc,
524
- brief: !isMetaCommandHelp ? brief ?? doc.brief : doc.brief,
525
- description: !isMetaCommandHelp ? description ?? doc.description : doc.description,
526
- footer: !isMetaCommandHelp ? footer ?? doc.footer : doc.footer
527
- };
528
- stdout(require_doc.formatDocPage(programName, augmentedDoc, {
529
- colors,
530
- maxWidth,
531
- showDefault
532
- }));
533
- }
534
- try {
535
- return onHelp(0);
536
- } catch {
537
- return onHelp();
538
- }
539
- }
540
- case "error": {
541
- if (aboveError === "help") {
542
- const doc = require_parser.getDocPage(args.length < 1 ? augmentedParser : parser, args);
543
- if (doc == null) aboveError = "usage";
478
+ case "completion": throw new RunParserError("Completion should be handled by early return");
479
+ case "help": {
480
+ let helpGeneratorParser;
481
+ const helpAsCommand = help === "command" || help === "both";
482
+ const versionAsCommand = version === "command" || version === "both";
483
+ const completionAsCommand = completion === "command" || completion === "both";
484
+ const requestedCommand = classified.commands[0];
485
+ if ((requestedCommand === "completion" || requestedCommand === "completions") && completionAsCommand && completionParsers.completionCommand) helpGeneratorParser = completionParsers.completionCommand;
486
+ else if (requestedCommand === "help" && helpAsCommand && helpParsers.helpCommand) helpGeneratorParser = helpParsers.helpCommand;
487
+ else if (requestedCommand === "version" && versionAsCommand && versionParsers.versionCommand) helpGeneratorParser = versionParsers.versionCommand;
544
488
  else {
489
+ const commandParsers = [parser];
490
+ if (helpAsCommand) {
491
+ if (helpParsers.helpCommand) commandParsers.push(helpParsers.helpCommand);
492
+ }
493
+ if (versionAsCommand) {
494
+ if (versionParsers.versionCommand) commandParsers.push(versionParsers.versionCommand);
495
+ }
496
+ if (completionAsCommand) {
497
+ if (completionParsers.completionCommand) commandParsers.push(completionParsers.completionCommand);
498
+ }
499
+ if (commandParsers.length === 1) helpGeneratorParser = commandParsers[0];
500
+ else if (commandParsers.length === 2) helpGeneratorParser = require_constructs.longestMatch(commandParsers[0], commandParsers[1]);
501
+ else helpGeneratorParser = require_constructs.longestMatch(...commandParsers);
502
+ }
503
+ const doc = require_parser.getDocPage(helpGeneratorParser, classified.commands);
504
+ if (doc != null) {
505
+ const isMetaCommandHelp = (completionName === "singular" || completionName === "both" ? requestedCommand === "completion" : false) || (completionName === "plural" || completionName === "both" ? requestedCommand === "completions" : false) || requestedCommand === "help" || requestedCommand === "version";
545
506
  const augmentedDoc = {
546
507
  ...doc,
547
- brief: brief ?? doc.brief,
548
- description: description ?? doc.description,
549
- footer: footer ?? doc.footer
508
+ brief: !isMetaCommandHelp ? brief ?? doc.brief : doc.brief,
509
+ description: !isMetaCommandHelp ? description ?? doc.description : doc.description,
510
+ footer: !isMetaCommandHelp ? footer ?? doc.footer : doc.footer
550
511
  };
551
- stderr(require_doc.formatDocPage(programName, augmentedDoc, {
512
+ stdout(require_doc.formatDocPage(programName, augmentedDoc, {
552
513
  colors,
553
514
  maxWidth,
554
515
  showDefault
555
516
  }));
556
517
  }
518
+ try {
519
+ return onHelp(0);
520
+ } catch {
521
+ return onHelp();
522
+ }
557
523
  }
558
- if (aboveError === "usage") stderr(`Usage: ${indentLines(require_usage.formatUsage(programName, augmentedParser.usage, {
559
- colors,
560
- maxWidth: maxWidth == null ? void 0 : maxWidth - 7,
561
- expandCommands: true
562
- }), 7)}`);
563
- const errorMessage = require_message.formatMessage(classified.error, {
564
- colors,
565
- quotes: !colors
566
- });
567
- stderr(`Error: ${errorMessage}`);
568
- return onError(1);
524
+ case "error": {
525
+ if (aboveError === "help") {
526
+ const doc = require_parser.getDocPage(args.length < 1 ? augmentedParser : parser, args);
527
+ if (doc == null) aboveError = "usage";
528
+ else {
529
+ const augmentedDoc = {
530
+ ...doc,
531
+ brief: brief ?? doc.brief,
532
+ description: description ?? doc.description,
533
+ footer: footer ?? doc.footer
534
+ };
535
+ stderr(require_doc.formatDocPage(programName, augmentedDoc, {
536
+ colors,
537
+ maxWidth,
538
+ showDefault
539
+ }));
540
+ }
541
+ }
542
+ if (aboveError === "usage") stderr(`Usage: ${indentLines(require_usage.formatUsage(programName, augmentedParser.usage, {
543
+ colors,
544
+ maxWidth: maxWidth == null ? void 0 : maxWidth - 7,
545
+ expandCommands: true
546
+ }), 7)}`);
547
+ const errorMessage = require_message.formatMessage(classified.error, {
548
+ colors,
549
+ quotes: !colors
550
+ });
551
+ stderr(`Error: ${errorMessage}`);
552
+ return onError(1);
553
+ }
554
+ default: throw new RunParserError("Unexpected parse result type");
569
555
  }
570
- default: throw new RunParserError("Unexpected parse result type");
556
+ };
557
+ if (parser.$mode === "async") return require_parser.parseAsync(augmentedParser, args).then(handleResult);
558
+ else {
559
+ const result = require_parser.parseSync(augmentedParser, args);
560
+ return handleResult(result);
571
561
  }
572
562
  }
573
563
  /**
package/dist/facade.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Message } from "./message.cjs";
2
2
  import { ShowDefaultOptions } from "./doc.cjs";
3
- import { InferValue, Parser } from "./parser.cjs";
3
+ import { InferMode, InferValue, Mode, ModeValue, Parser } from "./parser.cjs";
4
4
  import { ShellCompletion } from "./completion.cjs";
5
5
 
6
6
  //#region src/facade.d.ts
@@ -214,7 +214,9 @@ interface RunOptions<THelp, TError> {
214
214
  * @throws {RunParserError} When parsing fails and no `onError` callback is
215
215
  * provided.
216
216
  */
217
- declare function runParser<TParser extends Parser<unknown, unknown>, THelp = void, TError = never>(parser: TParser, programName: string, args: readonly string[], options?: RunOptions<THelp, TError>): InferValue<TParser>;
217
+ declare function runParser<TParser extends Parser<"sync", unknown, unknown>, THelp = void, TError = never>(parser: TParser, programName: string, args: readonly string[], options?: RunOptions<THelp, TError>): InferValue<TParser>;
218
+ declare function runParser<TParser extends Parser<"async", unknown, unknown>, THelp = void, TError = never>(parser: TParser, programName: string, args: readonly string[], options?: RunOptions<THelp, TError>): Promise<InferValue<TParser>>;
219
+ declare function runParser<TParser extends Parser<Mode, unknown, unknown>, THelp = void, TError = never>(parser: TParser, programName: string, args: readonly string[], options?: RunOptions<THelp, TError>): ModeValue<InferMode<TParser>, InferValue<TParser>>;
218
220
  /**
219
221
  * @deprecated Use `runParser()` instead. This export will be removed in
220
222
  * a future major version. The name `run` conflicts with
package/dist/facade.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Message } from "./message.js";
2
2
  import { ShowDefaultOptions } from "./doc.js";
3
- import { InferValue, Parser } from "./parser.js";
3
+ import { InferMode, InferValue, Mode, ModeValue, Parser } from "./parser.js";
4
4
  import { ShellCompletion } from "./completion.js";
5
5
 
6
6
  //#region src/facade.d.ts
@@ -214,7 +214,9 @@ interface RunOptions<THelp, TError> {
214
214
  * @throws {RunParserError} When parsing fails and no `onError` callback is
215
215
  * provided.
216
216
  */
217
- declare function runParser<TParser extends Parser<unknown, unknown>, THelp = void, TError = never>(parser: TParser, programName: string, args: readonly string[], options?: RunOptions<THelp, TError>): InferValue<TParser>;
217
+ declare function runParser<TParser extends Parser<"sync", unknown, unknown>, THelp = void, TError = never>(parser: TParser, programName: string, args: readonly string[], options?: RunOptions<THelp, TError>): InferValue<TParser>;
218
+ declare function runParser<TParser extends Parser<"async", unknown, unknown>, THelp = void, TError = never>(parser: TParser, programName: string, args: readonly string[], options?: RunOptions<THelp, TError>): Promise<InferValue<TParser>>;
219
+ declare function runParser<TParser extends Parser<Mode, unknown, unknown>, THelp = void, TError = never>(parser: TParser, programName: string, args: readonly string[], options?: RunOptions<THelp, TError>): ModeValue<InferMode<TParser>, InferValue<TParser>>;
218
220
  /**
219
221
  * @deprecated Use `runParser()` instead. This export will be removed in
220
222
  * a future major version. The name `run` conflicts with