@optique/core 0.7.2 → 0.7.3

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.
@@ -4,6 +4,27 @@ const require_suggestion = require('./suggestion.cjs');
4
4
 
5
5
  //#region src/constructs.ts
6
6
  /**
7
+ * Checks if the given token is an option name that requires a value
8
+ * (i.e., has a metavar) within the given usage terms.
9
+ * @param usage The usage terms to search through.
10
+ * @param token The token to check.
11
+ * @returns `true` if the token is an option that requires a value, `false` otherwise.
12
+ */
13
+ function isOptionRequiringValue(usage, token) {
14
+ function traverse(terms) {
15
+ if (!terms || !Array.isArray(terms)) return false;
16
+ for (const term of terms) if (term.type === "option") {
17
+ if (term.metavar && term.names.includes(token)) return true;
18
+ } else if (term.type === "optional" || term.type === "multiple") {
19
+ if (traverse(term.terms)) return true;
20
+ } else if (term.type === "exclusive") {
21
+ for (const exclusiveUsage of term.terms) if (traverse(exclusiveUsage)) return true;
22
+ }
23
+ return false;
24
+ }
25
+ return traverse(usage);
26
+ }
27
+ /**
7
28
  * Extracts required (non-optional) usage terms from a usage array.
8
29
  * @param usage The usage to extract required terms from
9
30
  * @returns Usage containing only required (non-optional) terms
@@ -461,6 +482,16 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
461
482
  },
462
483
  suggest(context, prefix) {
463
484
  const suggestions = [];
485
+ if (context.buffer.length > 0) {
486
+ const lastToken = context.buffer[context.buffer.length - 1];
487
+ for (const [field, parser] of parserPairs) if (isOptionRequiringValue(parser.usage, lastToken)) {
488
+ const fieldState = context.state && typeof context.state === "object" && field in context.state ? context.state[field] : parser.initialState;
489
+ return Array.from(parser.suggest({
490
+ ...context,
491
+ state: fieldState
492
+ }, prefix));
493
+ }
494
+ }
464
495
  for (const [field, parser] of parserPairs) {
465
496
  const fieldState = context.state && typeof context.state === "object" && field in context.state ? context.state[field] : parser.initialState;
466
497
  const fieldSuggestions = parser.suggest({
@@ -4,6 +4,27 @@ import { createErrorWithSuggestions } from "./suggestion.js";
4
4
 
5
5
  //#region src/constructs.ts
6
6
  /**
7
+ * Checks if the given token is an option name that requires a value
8
+ * (i.e., has a metavar) within the given usage terms.
9
+ * @param usage The usage terms to search through.
10
+ * @param token The token to check.
11
+ * @returns `true` if the token is an option that requires a value, `false` otherwise.
12
+ */
13
+ function isOptionRequiringValue(usage, token) {
14
+ function traverse(terms) {
15
+ if (!terms || !Array.isArray(terms)) return false;
16
+ for (const term of terms) if (term.type === "option") {
17
+ if (term.metavar && term.names.includes(token)) return true;
18
+ } else if (term.type === "optional" || term.type === "multiple") {
19
+ if (traverse(term.terms)) return true;
20
+ } else if (term.type === "exclusive") {
21
+ for (const exclusiveUsage of term.terms) if (traverse(exclusiveUsage)) return true;
22
+ }
23
+ return false;
24
+ }
25
+ return traverse(usage);
26
+ }
27
+ /**
7
28
  * Extracts required (non-optional) usage terms from a usage array.
8
29
  * @param usage The usage to extract required terms from
9
30
  * @returns Usage containing only required (non-optional) terms
@@ -461,6 +482,16 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
461
482
  },
462
483
  suggest(context, prefix) {
463
484
  const suggestions = [];
485
+ if (context.buffer.length > 0) {
486
+ const lastToken = context.buffer[context.buffer.length - 1];
487
+ for (const [field, parser] of parserPairs) if (isOptionRequiringValue(parser.usage, lastToken)) {
488
+ const fieldState = context.state && typeof context.state === "object" && field in context.state ? context.state[field] : parser.initialState;
489
+ return Array.from(parser.suggest({
490
+ ...context,
491
+ state: fieldState
492
+ }, prefix));
493
+ }
494
+ }
464
495
  for (const [field, parser] of parserPairs) {
465
496
  const fieldState = context.state && typeof context.state === "object" && field in context.state ? context.state[field] : parser.initialState;
466
497
  const fieldSuggestions = parser.suggest({
package/dist/facade.cjs CHANGED
@@ -343,7 +343,7 @@ function classifyResult(result, args) {
343
343
  * Handles shell completion requests.
344
344
  * @since 0.6.0
345
345
  */
346
- function handleCompletion(completionArgs, programName, parser, completionParser, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionMode) {
346
+ function handleCompletion(completionArgs, programName, parser, completionParser, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionMode, completionName) {
347
347
  const shellName = completionArgs[0] || "";
348
348
  const args = completionArgs.slice(1);
349
349
  if (!shellName) {
@@ -375,7 +375,8 @@ function handleCompletion(completionArgs, programName, parser, completionParser,
375
375
  return onError(1);
376
376
  }
377
377
  if (args.length === 0) {
378
- const completionArg = completionMode === "option" ? "--completion" : "completion";
378
+ const usePlural = completionName === "plural";
379
+ const completionArg = completionMode === "option" ? usePlural ? "--completions" : "--completion" : usePlural ? "completions" : "completion";
379
380
  const script = shell.generateScript(programName, [completionArg, shellName]);
380
381
  stdout(script);
381
382
  } else {
@@ -457,7 +458,7 @@ function run(parser, programName, args, options = {}) {
457
458
  } : createCompletionParser(completion, programName, availableShells, completionName);
458
459
  if (options.completion) {
459
460
  const hasHelpOption = args.includes("--help");
460
- if ((completionMode === "command" || completionMode === "both") && args.length >= 1 && ((completionName === "singular" || completionName === "both" ? args[0] === "completion" : false) || (completionName === "plural" || completionName === "both" ? args[0] === "completions" : false)) && !hasHelpOption) return handleCompletion(args.slice(1), programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionMode);
461
+ if ((completionMode === "command" || completionMode === "both") && args.length >= 1 && ((completionName === "singular" || completionName === "both" ? args[0] === "completion" : false) || (completionName === "plural" || completionName === "both" ? args[0] === "completions" : false)) && !hasHelpOption) return handleCompletion(args.slice(1), programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionMode, completionName);
461
462
  if (completionMode === "option" || completionMode === "both") for (let i = 0; i < args.length; i++) {
462
463
  const arg = args[i];
463
464
  const singularMatch = completionName === "singular" || completionName === "both" ? arg.startsWith("--completion=") : false;
@@ -465,14 +466,14 @@ function run(parser, programName, args, options = {}) {
465
466
  if (singularMatch || pluralMatch) {
466
467
  const shell = arg.slice(arg.indexOf("=") + 1);
467
468
  const completionArgs = args.slice(i + 1);
468
- return handleCompletion([shell, ...completionArgs], programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionMode);
469
+ return handleCompletion([shell, ...completionArgs], programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionMode, completionName);
469
470
  } else {
470
471
  const singularMatchExact = completionName === "singular" || completionName === "both" ? arg === "--completion" : false;
471
472
  const pluralMatchExact = completionName === "plural" || completionName === "both" ? arg === "--completions" : false;
472
473
  if ((singularMatchExact || pluralMatchExact) && i + 1 < args.length) {
473
474
  const shell = args[i + 1];
474
475
  const completionArgs = args.slice(i + 2);
475
- return handleCompletion([shell, ...completionArgs], programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionMode);
476
+ return handleCompletion([shell, ...completionArgs], programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionMode, completionName);
476
477
  }
477
478
  }
478
479
  }
package/dist/facade.js CHANGED
@@ -343,7 +343,7 @@ function classifyResult(result, args) {
343
343
  * Handles shell completion requests.
344
344
  * @since 0.6.0
345
345
  */
346
- function handleCompletion(completionArgs, programName, parser, completionParser, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionMode) {
346
+ function handleCompletion(completionArgs, programName, parser, completionParser, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionMode, completionName) {
347
347
  const shellName = completionArgs[0] || "";
348
348
  const args = completionArgs.slice(1);
349
349
  if (!shellName) {
@@ -375,7 +375,8 @@ function handleCompletion(completionArgs, programName, parser, completionParser,
375
375
  return onError(1);
376
376
  }
377
377
  if (args.length === 0) {
378
- const completionArg = completionMode === "option" ? "--completion" : "completion";
378
+ const usePlural = completionName === "plural";
379
+ const completionArg = completionMode === "option" ? usePlural ? "--completions" : "--completion" : usePlural ? "completions" : "completion";
379
380
  const script = shell.generateScript(programName, [completionArg, shellName]);
380
381
  stdout(script);
381
382
  } else {
@@ -457,7 +458,7 @@ function run(parser, programName, args, options = {}) {
457
458
  } : createCompletionParser(completion, programName, availableShells, completionName);
458
459
  if (options.completion) {
459
460
  const hasHelpOption = args.includes("--help");
460
- if ((completionMode === "command" || completionMode === "both") && args.length >= 1 && ((completionName === "singular" || completionName === "both" ? args[0] === "completion" : false) || (completionName === "plural" || completionName === "both" ? args[0] === "completions" : false)) && !hasHelpOption) return handleCompletion(args.slice(1), programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionMode);
461
+ if ((completionMode === "command" || completionMode === "both") && args.length >= 1 && ((completionName === "singular" || completionName === "both" ? args[0] === "completion" : false) || (completionName === "plural" || completionName === "both" ? args[0] === "completions" : false)) && !hasHelpOption) return handleCompletion(args.slice(1), programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionMode, completionName);
461
462
  if (completionMode === "option" || completionMode === "both") for (let i = 0; i < args.length; i++) {
462
463
  const arg = args[i];
463
464
  const singularMatch = completionName === "singular" || completionName === "both" ? arg.startsWith("--completion=") : false;
@@ -465,14 +466,14 @@ function run(parser, programName, args, options = {}) {
465
466
  if (singularMatch || pluralMatch) {
466
467
  const shell = arg.slice(arg.indexOf("=") + 1);
467
468
  const completionArgs = args.slice(i + 1);
468
- return handleCompletion([shell, ...completionArgs], programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionMode);
469
+ return handleCompletion([shell, ...completionArgs], programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionMode, completionName);
469
470
  } else {
470
471
  const singularMatchExact = completionName === "singular" || completionName === "both" ? arg === "--completion" : false;
471
472
  const pluralMatchExact = completionName === "plural" || completionName === "both" ? arg === "--completions" : false;
472
473
  if ((singularMatchExact || pluralMatchExact) && i + 1 < args.length) {
473
474
  const shell = args[i + 1];
474
475
  const completionArgs = args.slice(i + 2);
475
- return handleCompletion([shell, ...completionArgs], programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionMode);
476
+ return handleCompletion([shell, ...completionArgs], programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionMode, completionName);
476
477
  }
477
478
  }
478
479
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",