@optique/core 0.9.2 → 0.9.4

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.
@@ -314,7 +314,9 @@ function or(...args) {
314
314
  },
315
315
  suggest: createExclusiveSuggest(parsers, isAsync),
316
316
  getDocFragments(state, _defaultValue) {
317
+ let brief;
317
318
  let description;
319
+ let footer;
318
320
  let fragments;
319
321
  if (state.kind === "unavailable" || state.state == null) fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }, void 0).fragments);
320
322
  else {
@@ -324,7 +326,9 @@ function or(...args) {
324
326
  state: parserResult.next.state
325
327
  } : { kind: "unavailable" };
326
328
  const docFragments = parsers[index].getDocFragments(innerState, void 0);
329
+ brief = docFragments.brief;
327
330
  description = docFragments.description;
331
+ footer = docFragments.footer;
328
332
  fragments = docFragments.fragments;
329
333
  }
330
334
  const entries = fragments.filter((f) => f.type === "entry");
@@ -335,7 +339,9 @@ function or(...args) {
335
339
  else sections.push(fragment);
336
340
  }
337
341
  return {
342
+ brief,
338
343
  description,
344
+ footer,
339
345
  fragments: [...sections.map((s) => ({
340
346
  ...s,
341
347
  type: "section"
@@ -452,6 +458,7 @@ function longestMatch(...args) {
452
458
  },
453
459
  suggest: createExclusiveSuggest(parsers, isAsync),
454
460
  getDocFragments(state, _defaultValue) {
461
+ let brief;
455
462
  let description;
456
463
  let footer;
457
464
  let fragments;
@@ -463,12 +470,14 @@ function longestMatch(...args) {
463
470
  kind: "available",
464
471
  state: result.next.state
465
472
  });
473
+ brief = docResult.brief;
466
474
  description = docResult.description;
467
475
  footer = docResult.footer;
468
476
  fragments = docResult.fragments;
469
477
  } else fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }).fragments);
470
478
  }
471
479
  return {
480
+ brief,
472
481
  description,
473
482
  fragments,
474
483
  footer
@@ -314,7 +314,9 @@ function or(...args) {
314
314
  },
315
315
  suggest: createExclusiveSuggest(parsers, isAsync),
316
316
  getDocFragments(state, _defaultValue) {
317
+ let brief;
317
318
  let description;
319
+ let footer;
318
320
  let fragments;
319
321
  if (state.kind === "unavailable" || state.state == null) fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }, void 0).fragments);
320
322
  else {
@@ -324,7 +326,9 @@ function or(...args) {
324
326
  state: parserResult.next.state
325
327
  } : { kind: "unavailable" };
326
328
  const docFragments = parsers[index].getDocFragments(innerState, void 0);
329
+ brief = docFragments.brief;
327
330
  description = docFragments.description;
331
+ footer = docFragments.footer;
328
332
  fragments = docFragments.fragments;
329
333
  }
330
334
  const entries = fragments.filter((f) => f.type === "entry");
@@ -335,7 +339,9 @@ function or(...args) {
335
339
  else sections.push(fragment);
336
340
  }
337
341
  return {
342
+ brief,
338
343
  description,
344
+ footer,
339
345
  fragments: [...sections.map((s) => ({
340
346
  ...s,
341
347
  type: "section"
@@ -452,6 +458,7 @@ function longestMatch(...args) {
452
458
  },
453
459
  suggest: createExclusiveSuggest(parsers, isAsync),
454
460
  getDocFragments(state, _defaultValue) {
461
+ let brief;
455
462
  let description;
456
463
  let footer;
457
464
  let fragments;
@@ -463,12 +470,14 @@ function longestMatch(...args) {
463
470
  kind: "available",
464
471
  state: result.next.state
465
472
  });
473
+ brief = docResult.brief;
466
474
  description = docResult.description;
467
475
  footer = docResult.footer;
468
476
  fragments = docResult.fragments;
469
477
  } else fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }).fragments);
470
478
  }
471
479
  return {
480
+ brief,
472
481
  description,
473
482
  fragments,
474
483
  footer
package/dist/doc.d.cts CHANGED
@@ -60,6 +60,12 @@ type DocFragment = {
60
60
  * a final document page.
61
61
  */
62
62
  interface DocFragments {
63
+ /**
64
+ * An optional brief that provides a short summary for the collection
65
+ * of fragments.
66
+ * @since 0.7.12
67
+ */
68
+ readonly brief?: Message;
63
69
  /**
64
70
  * An optional description that applies to the entire collection of fragments.
65
71
  */
package/dist/doc.d.ts CHANGED
@@ -60,6 +60,12 @@ type DocFragment = {
60
60
  * a final document page.
61
61
  */
62
62
  interface DocFragments {
63
+ /**
64
+ * An optional brief that provides a short summary for the collection
65
+ * of fragments.
66
+ * @since 0.7.12
67
+ */
68
+ readonly brief?: Message;
63
69
  /**
64
70
  * An optional description that applies to the entire collection of fragments.
65
71
  */
package/dist/facade.cjs CHANGED
@@ -500,14 +500,69 @@ function runParser(parser, programName, args, options = {}) {
500
500
  else if (commandParsers.length === 2) helpGeneratorParser = require_constructs.longestMatch(commandParsers[0], commandParsers[1]);
501
501
  else helpGeneratorParser = require_constructs.longestMatch(...commandParsers);
502
502
  }
503
+ const reportInvalidHelpCommand = (validationError) => {
504
+ stderr(`Usage: ${indentLines(require_usage.formatUsage(programName, augmentedParser.usage, {
505
+ colors,
506
+ maxWidth: maxWidth == null ? void 0 : maxWidth - 7,
507
+ expandCommands: true
508
+ }), 7)}`);
509
+ const errorMessage = require_message.formatMessage(validationError, {
510
+ colors,
511
+ quotes: !colors
512
+ });
513
+ stderr(`Error: ${errorMessage}`);
514
+ return onError(1);
515
+ };
516
+ if (classified.commands.length > 0) {
517
+ let validationContext = {
518
+ buffer: [...classified.commands],
519
+ optionsTerminated: false,
520
+ state: helpGeneratorParser.initialState,
521
+ usage: helpGeneratorParser.usage
522
+ };
523
+ const processStep = (stepResult) => {
524
+ if (!stepResult.success) return stepResult.error;
525
+ if (stepResult.consumed.length < 1) return require_message.message`Unexpected option or subcommand: ${require_message.optionName(validationContext.buffer[0])}.`;
526
+ validationContext = {
527
+ ...validationContext,
528
+ buffer: stepResult.next.buffer,
529
+ optionsTerminated: stepResult.next.optionsTerminated,
530
+ state: stepResult.next.state,
531
+ usage: stepResult.next.usage ?? validationContext.usage
532
+ };
533
+ return validationContext.buffer.length > 0 ? "continue" : null;
534
+ };
535
+ let validationResult = "continue";
536
+ while (validationResult === "continue") {
537
+ const stepResult = helpGeneratorParser.parse(validationContext);
538
+ if (stepResult instanceof Promise) {
539
+ const asyncValidate = async (result$1) => {
540
+ let res = processStep(result$1);
541
+ while (res === "continue") {
542
+ const next = helpGeneratorParser.parse(validationContext);
543
+ const resolved = next instanceof Promise ? await next : next;
544
+ res = processStep(resolved);
545
+ }
546
+ if (res != null) return reportInvalidHelpCommand(res);
547
+ const docOrPromise$1 = require_parser.getDocPage(helpGeneratorParser, classified.commands);
548
+ return docOrPromise$1 instanceof Promise ? docOrPromise$1.then(displayHelp) : displayHelp(docOrPromise$1);
549
+ };
550
+ return stepResult.then(asyncValidate);
551
+ }
552
+ validationResult = processStep(stepResult);
553
+ }
554
+ if (validationResult != null) return reportInvalidHelpCommand(validationResult);
555
+ }
503
556
  const displayHelp = (doc) => {
504
557
  if (doc != null) {
505
558
  const isMetaCommandHelp = (completionName === "singular" || completionName === "both" ? requestedCommand === "completion" : false) || (completionName === "plural" || completionName === "both" ? requestedCommand === "completions" : false) || requestedCommand === "help" || requestedCommand === "version";
559
+ const isSubcommandHelp = classified.commands.length > 0;
560
+ const shouldOverride = !isMetaCommandHelp && !isSubcommandHelp;
506
561
  const augmentedDoc = {
507
562
  ...doc,
508
- brief: !isMetaCommandHelp ? brief ?? doc.brief : doc.brief,
509
- description: !isMetaCommandHelp ? description ?? doc.description : doc.description,
510
- footer: !isMetaCommandHelp ? footer ?? doc.footer : doc.footer
563
+ brief: shouldOverride ? brief ?? doc.brief : doc.brief ?? brief,
564
+ description: shouldOverride ? description ?? doc.description : doc.description ?? description,
565
+ footer: shouldOverride ? footer ?? doc.footer : doc.footer ?? footer
511
566
  };
512
567
  stdout(require_doc.formatDocPage(programName, augmentedDoc, {
513
568
  colors,
package/dist/facade.js CHANGED
@@ -500,14 +500,69 @@ function runParser(parser, programName, args, options = {}) {
500
500
  else if (commandParsers.length === 2) helpGeneratorParser = longestMatch(commandParsers[0], commandParsers[1]);
501
501
  else helpGeneratorParser = longestMatch(...commandParsers);
502
502
  }
503
+ const reportInvalidHelpCommand = (validationError) => {
504
+ stderr(`Usage: ${indentLines(formatUsage(programName, augmentedParser.usage, {
505
+ colors,
506
+ maxWidth: maxWidth == null ? void 0 : maxWidth - 7,
507
+ expandCommands: true
508
+ }), 7)}`);
509
+ const errorMessage = formatMessage(validationError, {
510
+ colors,
511
+ quotes: !colors
512
+ });
513
+ stderr(`Error: ${errorMessage}`);
514
+ return onError(1);
515
+ };
516
+ if (classified.commands.length > 0) {
517
+ let validationContext = {
518
+ buffer: [...classified.commands],
519
+ optionsTerminated: false,
520
+ state: helpGeneratorParser.initialState,
521
+ usage: helpGeneratorParser.usage
522
+ };
523
+ const processStep = (stepResult) => {
524
+ if (!stepResult.success) return stepResult.error;
525
+ if (stepResult.consumed.length < 1) return message`Unexpected option or subcommand: ${optionName(validationContext.buffer[0])}.`;
526
+ validationContext = {
527
+ ...validationContext,
528
+ buffer: stepResult.next.buffer,
529
+ optionsTerminated: stepResult.next.optionsTerminated,
530
+ state: stepResult.next.state,
531
+ usage: stepResult.next.usage ?? validationContext.usage
532
+ };
533
+ return validationContext.buffer.length > 0 ? "continue" : null;
534
+ };
535
+ let validationResult = "continue";
536
+ while (validationResult === "continue") {
537
+ const stepResult = helpGeneratorParser.parse(validationContext);
538
+ if (stepResult instanceof Promise) {
539
+ const asyncValidate = async (result$1) => {
540
+ let res = processStep(result$1);
541
+ while (res === "continue") {
542
+ const next = helpGeneratorParser.parse(validationContext);
543
+ const resolved = next instanceof Promise ? await next : next;
544
+ res = processStep(resolved);
545
+ }
546
+ if (res != null) return reportInvalidHelpCommand(res);
547
+ const docOrPromise$1 = getDocPage(helpGeneratorParser, classified.commands);
548
+ return docOrPromise$1 instanceof Promise ? docOrPromise$1.then(displayHelp) : displayHelp(docOrPromise$1);
549
+ };
550
+ return stepResult.then(asyncValidate);
551
+ }
552
+ validationResult = processStep(stepResult);
553
+ }
554
+ if (validationResult != null) return reportInvalidHelpCommand(validationResult);
555
+ }
503
556
  const displayHelp = (doc) => {
504
557
  if (doc != null) {
505
558
  const isMetaCommandHelp = (completionName === "singular" || completionName === "both" ? requestedCommand === "completion" : false) || (completionName === "plural" || completionName === "both" ? requestedCommand === "completions" : false) || requestedCommand === "help" || requestedCommand === "version";
559
+ const isSubcommandHelp = classified.commands.length > 0;
560
+ const shouldOverride = !isMetaCommandHelp && !isSubcommandHelp;
506
561
  const augmentedDoc = {
507
562
  ...doc,
508
- brief: !isMetaCommandHelp ? brief ?? doc.brief : doc.brief,
509
- description: !isMetaCommandHelp ? description ?? doc.description : doc.description,
510
- footer: !isMetaCommandHelp ? footer ?? doc.footer : doc.footer
563
+ brief: shouldOverride ? brief ?? doc.brief : doc.brief ?? brief,
564
+ description: shouldOverride ? description ?? doc.description : doc.description ?? description,
565
+ footer: shouldOverride ? footer ?? doc.footer : doc.footer ?? footer
511
566
  };
512
567
  stdout(formatDocPage(programName, augmentedDoc, {
513
568
  colors,
package/dist/parser.cjs CHANGED
@@ -337,7 +337,7 @@ async function getDocPageAsyncImpl(parser, args) {
337
337
  * Shared by both sync and async implementations.
338
338
  */
339
339
  function buildDocPage(parser, context, args) {
340
- const { description, fragments, footer } = parser.getDocFragments({
340
+ const { brief, description, fragments, footer } = parser.getDocFragments({
341
341
  kind: "available",
342
342
  state: context.state
343
343
  }, void 0);
@@ -356,15 +356,14 @@ function buildDocPage(parser, context, args) {
356
356
  const term = usage[i];
357
357
  if (term.type === "exclusive") {
358
358
  const found = findCommandInExclusive(term, arg);
359
- if (found) {
360
- usage.splice(i, 1, ...found);
361
- i += found.length;
362
- } else i++;
363
- } else i++;
359
+ if (found) usage.splice(i, 1, ...found);
360
+ }
361
+ i++;
364
362
  }
365
363
  return {
366
364
  usage,
367
365
  sections,
366
+ ...brief != null && { brief },
368
367
  ...description != null && { description },
369
368
  ...footer != null && { footer }
370
369
  };
package/dist/parser.js CHANGED
@@ -337,7 +337,7 @@ async function getDocPageAsyncImpl(parser, args) {
337
337
  * Shared by both sync and async implementations.
338
338
  */
339
339
  function buildDocPage(parser, context, args) {
340
- const { description, fragments, footer } = parser.getDocFragments({
340
+ const { brief, description, fragments, footer } = parser.getDocFragments({
341
341
  kind: "available",
342
342
  state: context.state
343
343
  }, void 0);
@@ -356,15 +356,14 @@ function buildDocPage(parser, context, args) {
356
356
  const term = usage[i];
357
357
  if (term.type === "exclusive") {
358
358
  const found = findCommandInExclusive(term, arg);
359
- if (found) {
360
- usage.splice(i, 1, ...found);
361
- i += found.length;
362
- } else i++;
363
- } else i++;
359
+ if (found) usage.splice(i, 1, ...found);
360
+ }
361
+ i++;
364
362
  }
365
363
  return {
366
364
  usage,
367
365
  sections,
366
+ ...brief != null && { brief },
368
367
  ...description != null && { description },
369
368
  ...footer != null && { footer }
370
369
  };
@@ -867,6 +867,7 @@ function command(name, parser, options = {}) {
867
867
  const innerFragments = parser.getDocFragments(innerState, defaultValue);
868
868
  return {
869
869
  ...innerFragments,
870
+ brief: innerFragments.brief ?? options.brief,
870
871
  description: innerFragments.description ?? options.description,
871
872
  footer: innerFragments.footer ?? options.footer
872
873
  };
@@ -867,6 +867,7 @@ function command(name, parser, options = {}) {
867
867
  const innerFragments = parser.getDocFragments(innerState, defaultValue);
868
868
  return {
869
869
  ...innerFragments,
870
+ brief: innerFragments.brief ?? options.brief,
870
871
  description: innerFragments.description ?? options.description,
871
872
  footer: innerFragments.footer ?? options.footer
872
873
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",