@optique/core 1.3.0-dev.2375 → 1.3.0-dev.2380

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.
@@ -14,6 +14,21 @@ import { createInputTrace } from "../input-trace.js";
14
14
  */
15
15
  const parseLanesKey = Symbol("parseLanes");
16
16
  /**
17
+ * Creates a fresh {@link EffectfulCompletionSession}.
18
+ *
19
+ * @internal
20
+ * @since 1.3.0
21
+ */
22
+ function createEffectfulCompletionSession(policy = "eager") {
23
+ return {
24
+ policy,
25
+ results: /* @__PURE__ */ new Map(),
26
+ demanded: /* @__PURE__ */ new Set(),
27
+ effectfulSources: /* @__PURE__ */ new Set(),
28
+ completedByPath: /* @__PURE__ */ new Map()
29
+ };
30
+ }
31
+ /**
17
32
  * Internal marker for wrappers whose `{ hasCliValue: false }` states should
18
33
  * be treated as unmatched dependency-source states during completion-time
19
34
  * Phase 1.
@@ -21,7 +36,9 @@ const parseLanesKey = Symbol("parseLanes");
21
36
  * Wrappers like `bindEnv()` and `bindConfig()` opt in because their missing
22
37
  * CLI states still carry enough fallback context to pre-complete exactly
23
38
  * once. Wrappers like `prompt()` intentionally do not opt in because
24
- * prompted values are not yet registered as dependency sources.
39
+ * Phase 1 must stay effect-free; prompted values register instead through
40
+ * the `completeSource` capability during the serial effectful completion
41
+ * pass that runs before dependency replay.
25
42
  *
26
43
  * @internal
27
44
  */
@@ -130,7 +147,8 @@ function parseSync(parser, args, options) {
130
147
  dependencyRuntime: runtime,
131
148
  dependencyRegistry: runtime.registry,
132
149
  commandPath: context.exec?.commandPath ?? exec.commandPath,
133
- trace: context.exec?.trace ?? context.trace ?? exec.trace
150
+ trace: context.exec?.trace ?? context.trace ?? exec.trace,
151
+ effectfulCompletionSession: createEffectfulCompletionSession()
134
152
  };
135
153
  const endResult = parser.complete(context.state, completeExec);
136
154
  return endResult.success ? {
@@ -203,7 +221,8 @@ async function parseAsync(parser, args, options) {
203
221
  dependencyRuntime: runtime,
204
222
  dependencyRegistry: runtime.registry,
205
223
  commandPath: context.exec?.commandPath ?? exec.commandPath,
206
- trace: context.exec?.trace ?? context.trace ?? exec.trace
224
+ trace: context.exec?.trace ?? context.trace ?? exec.trace,
225
+ effectfulCompletionSession: createEffectfulCompletionSession()
207
226
  };
208
227
  const endResult = await parser.complete(context.state, completeExec);
209
228
  return endResult.success ? {
@@ -882,4 +901,4 @@ function findNextMatchedCommandArgIndex(args, matchedCommandArgIndices, start) {
882
901
  }
883
902
 
884
903
  //#endregion
885
- export { annotationWrapperRequiresSourceBindingKey, composeWrappedSourceMetadata, createParserContext, defineInheritedAnnotationParser, defineParseLanes, defineSourceBindingOnlyAnnotationCompletionParser, getDelegatingSuggestRuntimeNodes, getDocPage, getDocPageAsync, getDocPageSync, getOwnParseLanes, getParserSuggestRuntimeNodes, inheritParentAnnotationsKey, parse, parseAsync, parseLanesKey, parseSync, suggest, suggestAsync, suggestSync, unmatchedNonCliDependencySourceStateMarker };
904
+ export { annotationWrapperRequiresSourceBindingKey, composeWrappedSourceMetadata, createEffectfulCompletionSession, createParserContext, defineInheritedAnnotationParser, defineParseLanes, defineSourceBindingOnlyAnnotationCompletionParser, getDelegatingSuggestRuntimeNodes, getDocPage, getDocPageAsync, getDocPageSync, getOwnParseLanes, getParserSuggestRuntimeNodes, inheritParentAnnotationsKey, parse, parseAsync, parseLanesKey, parseSync, suggest, suggestAsync, suggestSync, unmatchedNonCliDependencySourceStateMarker };
@@ -1,6 +1,7 @@
1
1
  const require_internal_annotations = require('./internal/annotations.cjs');
2
2
  const require_message = require('./message.cjs');
3
3
  const require_mode_dispatch = require('./internal/mode-dispatch.cjs');
4
+ const require_dependency_runtime = require('./dependency-runtime.cjs');
4
5
  const require_internal_parser = require('./internal/parser.cjs');
5
6
  const require_annotation_state = require('./annotation-state.cjs');
6
7
  const require_execution_context = require('./execution-context.cjs');
@@ -456,8 +457,24 @@ function optional(parser) {
456
457
  }
457
458
  if (parser.dependencyMetadata != null) {
458
459
  const composed = require_dependency_metadata.composeDependencyMetadata(parser.dependencyMetadata, "optional");
459
- if (composed != null) optionalParser.dependencyMetadata = composed;
460
+ if (composed != null) {
461
+ const rebound = composed.source?.completeSource == null ? composed : composed.source.preservesSourceValue === false ? {
462
+ ...composed,
463
+ source: {
464
+ ...composed.source,
465
+ completeSource: void 0
466
+ }
467
+ } : {
468
+ ...composed,
469
+ source: {
470
+ ...composed.source,
471
+ completeSource: (state, exec) => Promise.resolve(optionalParser.complete(state, exec))
472
+ }
473
+ };
474
+ optionalParser.dependencyMetadata = rebound;
475
+ }
460
476
  }
477
+ require_dependency_runtime.defineForwardedEffectfulSchedulingNodes(optionalParser, parser, (state) => Array.isArray(state) && state.length === 1 ? state[0] : state);
461
478
  require_internal_parser.defineParseLanes(optionalParser, adaptOptionalStyleParseLanes(parser));
462
479
  require_internal_parser.defineInheritedAnnotationParser(optionalParser);
463
480
  require_internal_parser.defineSourceBindingOnlyAnnotationCompletionParser(optionalParser);
@@ -691,8 +708,24 @@ function withDefault(parser, defaultValue, options) {
691
708
  value: v
692
709
  };
693
710
  } });
694
- if (composed != null) withDefaultParser.dependencyMetadata = composed;
711
+ if (composed != null) {
712
+ const rebound = composed.source?.completeSource == null ? composed : composed.source.preservesSourceValue === false ? {
713
+ ...composed,
714
+ source: {
715
+ ...composed.source,
716
+ completeSource: void 0
717
+ }
718
+ } : {
719
+ ...composed,
720
+ source: {
721
+ ...composed.source,
722
+ completeSource: (state, exec) => Promise.resolve(withDefaultParser.complete(state, exec))
723
+ }
724
+ };
725
+ withDefaultParser.dependencyMetadata = rebound;
726
+ }
695
727
  }
728
+ require_dependency_runtime.defineForwardedEffectfulSchedulingNodes(withDefaultParser, parser, (state) => Array.isArray(state) && state.length === 1 ? state[0] : state);
696
729
  require_internal_parser.defineParseLanes(withDefaultParser, adaptOptionalStyleParseLanes(parser));
697
730
  require_internal_parser.defineInheritedAnnotationParser(withDefaultParser);
698
731
  require_internal_parser.defineSourceBindingOnlyAnnotationCompletionParser(withDefaultParser);
@@ -884,6 +917,7 @@ function map(parser, transform) {
884
917
  }
885
918
  if (composed != null) mappedParser.dependencyMetadata = composed;
886
919
  }
920
+ require_dependency_runtime.defineForwardedEffectfulSchedulingNodes(mappedParser, parser);
887
921
  return fluent(mappedParser);
888
922
  }
889
923
  const deferredValueBrand = Symbol.for("@optique/core/deferredValue");
@@ -1660,6 +1694,7 @@ function multiple(parser, options = {}) {
1660
1694
  source: {
1661
1695
  ...innerSource,
1662
1696
  preservesSourceValue: false,
1697
+ completeSource: void 0,
1663
1698
  extractSourceValue: (state) => {
1664
1699
  if (!Array.isArray(state)) return innerSource.extractSourceValue(state);
1665
1700
  const scan = (index) => {
@@ -1785,6 +1820,11 @@ function nonEmpty(parser) {
1785
1820
  return lane.parse(context);
1786
1821
  }
1787
1822
  })));
1823
+ if (parser.dependencyMetadata != null) Object.defineProperty(nonEmptyParser, "dependencyMetadata", {
1824
+ value: parser.dependencyMetadata,
1825
+ configurable: true,
1826
+ enumerable: false
1827
+ });
1788
1828
  if ("placeholder" in parser) Object.defineProperty(nonEmptyParser, "placeholder", {
1789
1829
  get() {
1790
1830
  return parser.placeholder;
@@ -1809,6 +1849,7 @@ function nonEmpty(parser) {
1809
1849
  configurable: true,
1810
1850
  enumerable: false
1811
1851
  });
1852
+ require_dependency_runtime.defineForwardedEffectfulSchedulingNodes(nonEmptyParser, parser);
1812
1853
  return fluent(nonEmptyParser);
1813
1854
  }
1814
1855
  const fluentParserMarker = Symbol.for("@optique/core/fluent");
package/dist/modifiers.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { annotateFreshArray, annotationKey, getAnnotations, inheritAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper } from "./internal/annotations.js";
2
2
  import { formatMessage, message, text } from "./message.js";
3
3
  import { dispatchByMode, dispatchIterableByMode, mapModeValue, wrapForMode } from "./internal/mode-dispatch.js";
4
+ import { defineForwardedEffectfulSchedulingNodes } from "./dependency-runtime.js";
4
5
  import { defineInheritedAnnotationParser, defineParseLanes, defineSourceBindingOnlyAnnotationCompletionParser, getOwnParseLanes, unmatchedNonCliDependencySourceStateMarker } from "./internal/parser.js";
5
6
  import { getDelegatedAnnotationState, hasDelegatedAnnotationCarrier, isAnnotationWrappedInitialState, normalizeDelegatedAnnotationState, normalizeNestedDelegatedAnnotationState } from "./annotation-state.js";
6
7
  import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
@@ -456,8 +457,24 @@ function optional(parser) {
456
457
  }
457
458
  if (parser.dependencyMetadata != null) {
458
459
  const composed = composeDependencyMetadata(parser.dependencyMetadata, "optional");
459
- if (composed != null) optionalParser.dependencyMetadata = composed;
460
+ if (composed != null) {
461
+ const rebound = composed.source?.completeSource == null ? composed : composed.source.preservesSourceValue === false ? {
462
+ ...composed,
463
+ source: {
464
+ ...composed.source,
465
+ completeSource: void 0
466
+ }
467
+ } : {
468
+ ...composed,
469
+ source: {
470
+ ...composed.source,
471
+ completeSource: (state, exec) => Promise.resolve(optionalParser.complete(state, exec))
472
+ }
473
+ };
474
+ optionalParser.dependencyMetadata = rebound;
475
+ }
460
476
  }
477
+ defineForwardedEffectfulSchedulingNodes(optionalParser, parser, (state) => Array.isArray(state) && state.length === 1 ? state[0] : state);
461
478
  defineParseLanes(optionalParser, adaptOptionalStyleParseLanes(parser));
462
479
  defineInheritedAnnotationParser(optionalParser);
463
480
  defineSourceBindingOnlyAnnotationCompletionParser(optionalParser);
@@ -691,8 +708,24 @@ function withDefault(parser, defaultValue, options) {
691
708
  value: v
692
709
  };
693
710
  } });
694
- if (composed != null) withDefaultParser.dependencyMetadata = composed;
711
+ if (composed != null) {
712
+ const rebound = composed.source?.completeSource == null ? composed : composed.source.preservesSourceValue === false ? {
713
+ ...composed,
714
+ source: {
715
+ ...composed.source,
716
+ completeSource: void 0
717
+ }
718
+ } : {
719
+ ...composed,
720
+ source: {
721
+ ...composed.source,
722
+ completeSource: (state, exec) => Promise.resolve(withDefaultParser.complete(state, exec))
723
+ }
724
+ };
725
+ withDefaultParser.dependencyMetadata = rebound;
726
+ }
695
727
  }
728
+ defineForwardedEffectfulSchedulingNodes(withDefaultParser, parser, (state) => Array.isArray(state) && state.length === 1 ? state[0] : state);
696
729
  defineParseLanes(withDefaultParser, adaptOptionalStyleParseLanes(parser));
697
730
  defineInheritedAnnotationParser(withDefaultParser);
698
731
  defineSourceBindingOnlyAnnotationCompletionParser(withDefaultParser);
@@ -884,6 +917,7 @@ function map(parser, transform) {
884
917
  }
885
918
  if (composed != null) mappedParser.dependencyMetadata = composed;
886
919
  }
920
+ defineForwardedEffectfulSchedulingNodes(mappedParser, parser);
887
921
  return fluent(mappedParser);
888
922
  }
889
923
  const deferredValueBrand = Symbol.for("@optique/core/deferredValue");
@@ -1660,6 +1694,7 @@ function multiple(parser, options = {}) {
1660
1694
  source: {
1661
1695
  ...innerSource,
1662
1696
  preservesSourceValue: false,
1697
+ completeSource: void 0,
1663
1698
  extractSourceValue: (state) => {
1664
1699
  if (!Array.isArray(state)) return innerSource.extractSourceValue(state);
1665
1700
  const scan = (index) => {
@@ -1785,6 +1820,11 @@ function nonEmpty(parser) {
1785
1820
  return lane.parse(context);
1786
1821
  }
1787
1822
  })));
1823
+ if (parser.dependencyMetadata != null) Object.defineProperty(nonEmptyParser, "dependencyMetadata", {
1824
+ value: parser.dependencyMetadata,
1825
+ configurable: true,
1826
+ enumerable: false
1827
+ });
1788
1828
  if ("placeholder" in parser) Object.defineProperty(nonEmptyParser, "placeholder", {
1789
1829
  get() {
1790
1830
  return parser.placeholder;
@@ -1809,6 +1849,7 @@ function nonEmpty(parser) {
1809
1849
  configurable: true,
1810
1850
  enumerable: false
1811
1851
  });
1852
+ defineForwardedEffectfulSchedulingNodes(nonEmptyParser, parser);
1812
1853
  return fluent(nonEmptyParser);
1813
1854
  }
1814
1855
  const fluentParserMarker = Symbol.for("@optique/core/fluent");
package/dist/parser.d.cts CHANGED
@@ -1,3 +1,3 @@
1
1
  import { ParseOptions } from "./internal/annotations.cjs";
2
- import { CombineModes, DocState, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, Parser, ParserContext, ParserResult, Result, Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync } from "./internal/parser.cjs";
3
- export { type CombineModes, type DocState, type ExecutionContext, type ExecutionPhase, type InferMode, type InferValue, type Mode, type ModeIterable, type ModeValue, type ParseFrame, type ParseOptions, type Parser, type ParserContext, type ParserResult, type Result, type Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync };
2
+ import { CombineModes, DocState, EffectfulCompletionSession, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, Parser, ParserContext, ParserResult, Result, Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync } from "./internal/parser.cjs";
3
+ export { type CombineModes, type DocState, type EffectfulCompletionSession, type ExecutionContext, type ExecutionPhase, type InferMode, type InferValue, type Mode, type ModeIterable, type ModeValue, type ParseFrame, type ParseOptions, type Parser, type ParserContext, type ParserResult, type Result, type Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync };
package/dist/parser.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import { ParseOptions } from "./internal/annotations.js";
2
- import { CombineModes, DocState, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, Parser, ParserContext, ParserResult, Result, Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync } from "./internal/parser.js";
3
- export { type CombineModes, type DocState, type ExecutionContext, type ExecutionPhase, type InferMode, type InferValue, type Mode, type ModeIterable, type ModeValue, type ParseFrame, type ParseOptions, type Parser, type ParserContext, type ParserResult, type Result, type Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync };
2
+ import { CombineModes, DocState, EffectfulCompletionSession, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, Parser, ParserContext, ParserResult, Result, Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync } from "./internal/parser.js";
3
+ export { type CombineModes, type DocState, type EffectfulCompletionSession, type ExecutionContext, type ExecutionPhase, type InferMode, type InferValue, type Mode, type ModeIterable, type ModeValue, type ParseFrame, type ParseOptions, type Parser, type ParserContext, type ParserResult, type Result, type Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync };
@@ -1706,6 +1706,20 @@ function command(name, parser, options = {}) {
1706
1706
  configurable: true,
1707
1707
  enumerable: false
1708
1708
  });
1709
+ Object.defineProperty(result, require_dependency_runtime.effectfulSchedulingNodesKey, {
1710
+ value: ((state, parentPath) => {
1711
+ const normalizedState = normalizeCommandState(state);
1712
+ if (normalizedState == null) return [];
1713
+ const innerState = normalizedState[0] === "parsing" ? normalizedState[1] : parser.initialState;
1714
+ return [{
1715
+ path: [...parentPath ?? [], name],
1716
+ parser,
1717
+ state: getCommandChildState(state, innerState, parser)
1718
+ }];
1719
+ }),
1720
+ configurable: true,
1721
+ enumerable: false
1722
+ });
1709
1723
  return require_modifiers.fluent(result);
1710
1724
  }
1711
1725
  /**
@@ -4,7 +4,7 @@ import { validateCommandNames, validateOptionNames } from "./validate.js";
4
4
  import { extractOptionNames, isDocHidden, isSuggestionHidden } from "./usage.js";
5
5
  import { dispatchByMode, dispatchIterableByMode, wrapForMode } from "./internal/mode-dispatch.js";
6
6
  import { getDefaultValuesFunction, getDependencyIds, getSnapshottedDefaultDependencyValues, isDerivedValueParser, suggestWithDependency } from "./internal/dependency.js";
7
- import { replayDerivedParser, replayDerivedParserAsync } from "./dependency-runtime.js";
7
+ import { effectfulSchedulingNodesKey, replayDerivedParser, replayDerivedParserAsync } from "./dependency-runtime.js";
8
8
  import { getWrappedChildParseState, getWrappedChildState, isAnnotationWrappedInitialState, normalizeInjectedAnnotationState } from "./annotation-state.js";
9
9
  import { hiddenCommandAliasesKey } from "./internal/command-alias.js";
10
10
  import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
@@ -1706,6 +1706,20 @@ function command(name, parser, options = {}) {
1706
1706
  configurable: true,
1707
1707
  enumerable: false
1708
1708
  });
1709
+ Object.defineProperty(result, effectfulSchedulingNodesKey, {
1710
+ value: ((state, parentPath) => {
1711
+ const normalizedState = normalizeCommandState(state);
1712
+ if (normalizedState == null) return [];
1713
+ const innerState = normalizedState[0] === "parsing" ? normalizedState[1] : parser.initialState;
1714
+ return [{
1715
+ path: [...parentPath ?? [], name],
1716
+ parser,
1717
+ state: getCommandChildState(state, innerState, parser)
1718
+ }];
1719
+ }),
1720
+ configurable: true,
1721
+ enumerable: false
1722
+ });
1709
1723
  return fluent(result);
1710
1724
  }
1711
1725
  /**
@@ -620,71 +620,6 @@ function string(options = {}) {
620
620
  }
621
621
  };
622
622
  }
623
- /**
624
- * Creates a {@link ValueParser} that compiles regular expression sources.
625
- *
626
- * The entire input is treated as the source. Slash-delimited notation such
627
- * as `/pattern/flags` is not interpreted; use {@link RegExpOptions.flags} to
628
- * configure fixed flags for the parser.
629
- *
630
- * **Security note**: Compiling a source does not establish that it is safe to
631
- * execute. Patterns from untrusted input can cause Regular Expression Denial
632
- * of Service (ReDoS) when matched. Limit pattern and subject lengths, execute
633
- * matches in an environment that can be terminated, or use a linear-time
634
- * regular expression engine when accepting untrusted patterns.
635
- *
636
- * @param options Configuration options for the regular expression parser.
637
- * @returns A sync value parser producing JavaScript {@link RegExp} objects.
638
- * @throws {TypeError} If `options.metavar` is an empty string or
639
- * `options.flags` is not a string.
640
- * @throws {SyntaxError} If `options.flags` contains invalid, duplicate, or
641
- * incompatible regular expression flags.
642
- * @since 1.3.0
643
- */
644
- function regExp(options = {}) {
645
- const metavar$1 = options.metavar ?? "REGEXP";
646
- require_nonempty.ensureNonEmptyString(metavar$1);
647
- if (options.flags !== void 0 && typeof options.flags !== "string") throw new TypeError(`Expected flags to be a string, but got ${typeof options.flags}: ${String(options.flags)}.`);
648
- const flags = new RegExp("", options.flags ?? "").flags;
649
- const invalidRegExp = options.errors?.invalidRegExp;
650
- const parseRegExp = (input) => {
651
- try {
652
- return {
653
- success: true,
654
- value: new RegExp(input, flags)
655
- };
656
- } catch (error) {
657
- if (!(error instanceof SyntaxError)) throw error;
658
- return {
659
- success: false,
660
- error: invalidRegExp ? typeof invalidRegExp === "function" ? invalidRegExp(input) : invalidRegExp : require_message.message`Invalid regular expression: ${input}.`
661
- };
662
- }
663
- };
664
- return {
665
- mode: "sync",
666
- metavar: metavar$1,
667
- get placeholder() {
668
- return new RegExp("", flags);
669
- },
670
- parse: parseRegExp,
671
- validate(value) {
672
- if (!(value instanceof RegExp)) return {
673
- success: false,
674
- error: require_message.message`Expected a RegExp value.`
675
- };
676
- return parseRegExp(value.source);
677
- },
678
- normalize(value) {
679
- if (!(value instanceof RegExp)) return value;
680
- const result = parseRegExp(value.source);
681
- return result.success ? result.value : value;
682
- },
683
- format(value) {
684
- return value.source;
685
- }
686
- };
687
- }
688
623
  function keyValue(options = {}) {
689
624
  const separator = options.separator ?? "=";
690
625
  if (typeof separator !== "string") throw new TypeError(`Expected separator to be a string, but got ${typeof separator}: ${String(separator)}.`);
@@ -6693,7 +6628,6 @@ exports.locale = locale;
6693
6628
  exports.macAddress = macAddress;
6694
6629
  exports.port = port;
6695
6630
  exports.portRange = portRange;
6696
- exports.regExp = regExp;
6697
6631
  exports.semVer = semVer;
6698
6632
  exports.socketAddress = socketAddress;
6699
6633
  exports.string = string;
@@ -498,64 +498,6 @@ declare function checkEnumOption<T extends object>(options: T | undefined, key:
498
498
  * `RegExp` instance.
499
499
  */
500
500
  declare function string(options?: StringOptions): ValueParser<"sync", string>;
501
- /**
502
- * Options for creating a {@link regExp} value parser.
503
- *
504
- * @since 1.3.0
505
- */
506
- interface RegExpOptions {
507
- /**
508
- * The metavariable name for this parser. This is used in help messages to
509
- * indicate what kind of value this parser expects.
510
- * @default `"REGEXP"`
511
- * @since 1.3.0
512
- */
513
- readonly metavar?: NonEmptyString;
514
- /**
515
- * Fixed flags used to compile every input source.
516
- * @default `""`
517
- * @since 1.3.0
518
- */
519
- readonly flags?: string;
520
- /**
521
- * Custom error messages for regular expression parsing failures.
522
- * @since 1.3.0
523
- */
524
- readonly errors?: {
525
- /**
526
- * Custom error message when the input is not a valid regular expression
527
- * source. Can be a static message or a function that receives the input.
528
- *
529
- * **Security note**: Successful compilation does not guarantee safe
530
- * execution. Vulnerable patterns can cause catastrophic backtracking when
531
- * later matched against untrusted data.
532
- * @since 1.3.0
533
- */
534
- readonly invalidRegExp?: Message | ((input: string) => Message);
535
- };
536
- }
537
- /**
538
- * Creates a {@link ValueParser} that compiles regular expression sources.
539
- *
540
- * The entire input is treated as the source. Slash-delimited notation such
541
- * as `/pattern/flags` is not interpreted; use {@link RegExpOptions.flags} to
542
- * configure fixed flags for the parser.
543
- *
544
- * **Security note**: Compiling a source does not establish that it is safe to
545
- * execute. Patterns from untrusted input can cause Regular Expression Denial
546
- * of Service (ReDoS) when matched. Limit pattern and subject lengths, execute
547
- * matches in an environment that can be terminated, or use a linear-time
548
- * regular expression engine when accepting untrusted patterns.
549
- *
550
- * @param options Configuration options for the regular expression parser.
551
- * @returns A sync value parser producing JavaScript {@link RegExp} objects.
552
- * @throws {TypeError} If `options.metavar` is an empty string or
553
- * `options.flags` is not a string.
554
- * @throws {SyntaxError} If `options.flags` contains invalid, duplicate, or
555
- * incompatible regular expression flags.
556
- * @since 1.3.0
557
- */
558
- declare function regExp(options?: RegExpOptions): ValueParser<"sync", RegExp>;
559
501
  interface KeyValueOptionsBase {
560
502
  /**
561
503
  * The metavariable name for this parser. Used in help messages to
@@ -3337,4 +3279,4 @@ declare function firstOf<const TParsers extends readonly [ValueParser<"sync", un
3337
3279
  */
3338
3280
  declare function firstOf<const TParsers extends readonly ValueParser<"sync", unknown>[]>(parsers: TParsers, options?: FirstOfOptions): ValueParser<"sync", ValueParserValue<TParsers[number]>>;
3339
3281
  //#endregion
3340
- export { ChoiceOptions, ChoiceOptionsBase, ChoiceOptionsNumber, ChoiceOptionsString, CidrOptions, CidrValue, Color, ColorFormat, ColorOptions, CronExpression, CronExpressionForOptions, CronOptions, DeferredMap, DomainOptions, EmailOptions, FileSizeOptions, FileSizeOptionsBigInt, FileSizeOptionsNumber, FileSizeUnit, FirstOfOptions, FloatOptions, HostnameOptions, IntegerOptionsBigInt, IntegerOptionsNumber, IpOptions, Ipv4Options, Ipv6Options, Json, JsonOptions, KeyValueOptions, LocaleOptions, MacAddressOptions, type Mode, type ModeIterable, type ModeValue, type NonEmptyString, PortOptionsBigInt, PortOptionsNumber, PortRangeOptionsBigInt, PortRangeOptionsNumber, PortRangeValueBigInt, PortRangeValueNumber, RegExpOptions, SemVer, SemVerOptionsObject, SemVerOptionsString, SemVerString, SocketAddressOptions, SocketAddressValue, StringOptions, TransformMapping, UrlOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, biject, checkBooleanOption, checkEnumOption, choice, cidr, color, cron, domain, email, ensureNonEmptyString, fileSize, firstOf, float, hostname, integer, ip, ipv4, ipv6, isNonEmptyString, isValueParser, json, keyValue, locale, macAddress, port, portRange, regExp, semVer, socketAddress, string, transform, url, uuid };
3282
+ export { ChoiceOptions, ChoiceOptionsBase, ChoiceOptionsNumber, ChoiceOptionsString, CidrOptions, CidrValue, Color, ColorFormat, ColorOptions, CronExpression, CronExpressionForOptions, CronOptions, DeferredMap, DomainOptions, EmailOptions, FileSizeOptions, FileSizeOptionsBigInt, FileSizeOptionsNumber, FileSizeUnit, FirstOfOptions, FloatOptions, HostnameOptions, IntegerOptionsBigInt, IntegerOptionsNumber, IpOptions, Ipv4Options, Ipv6Options, Json, JsonOptions, KeyValueOptions, LocaleOptions, MacAddressOptions, type Mode, type ModeIterable, type ModeValue, type NonEmptyString, PortOptionsBigInt, PortOptionsNumber, PortRangeOptionsBigInt, PortRangeOptionsNumber, PortRangeValueBigInt, PortRangeValueNumber, SemVer, SemVerOptionsObject, SemVerOptionsString, SemVerString, SocketAddressOptions, SocketAddressValue, StringOptions, TransformMapping, UrlOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, biject, checkBooleanOption, checkEnumOption, choice, cidr, color, cron, domain, email, ensureNonEmptyString, fileSize, firstOf, float, hostname, integer, ip, ipv4, ipv6, isNonEmptyString, isValueParser, json, keyValue, locale, macAddress, port, portRange, semVer, socketAddress, string, transform, url, uuid };
@@ -498,64 +498,6 @@ declare function checkEnumOption<T extends object>(options: T | undefined, key:
498
498
  * `RegExp` instance.
499
499
  */
500
500
  declare function string(options?: StringOptions): ValueParser<"sync", string>;
501
- /**
502
- * Options for creating a {@link regExp} value parser.
503
- *
504
- * @since 1.3.0
505
- */
506
- interface RegExpOptions {
507
- /**
508
- * The metavariable name for this parser. This is used in help messages to
509
- * indicate what kind of value this parser expects.
510
- * @default `"REGEXP"`
511
- * @since 1.3.0
512
- */
513
- readonly metavar?: NonEmptyString;
514
- /**
515
- * Fixed flags used to compile every input source.
516
- * @default `""`
517
- * @since 1.3.0
518
- */
519
- readonly flags?: string;
520
- /**
521
- * Custom error messages for regular expression parsing failures.
522
- * @since 1.3.0
523
- */
524
- readonly errors?: {
525
- /**
526
- * Custom error message when the input is not a valid regular expression
527
- * source. Can be a static message or a function that receives the input.
528
- *
529
- * **Security note**: Successful compilation does not guarantee safe
530
- * execution. Vulnerable patterns can cause catastrophic backtracking when
531
- * later matched against untrusted data.
532
- * @since 1.3.0
533
- */
534
- readonly invalidRegExp?: Message | ((input: string) => Message);
535
- };
536
- }
537
- /**
538
- * Creates a {@link ValueParser} that compiles regular expression sources.
539
- *
540
- * The entire input is treated as the source. Slash-delimited notation such
541
- * as `/pattern/flags` is not interpreted; use {@link RegExpOptions.flags} to
542
- * configure fixed flags for the parser.
543
- *
544
- * **Security note**: Compiling a source does not establish that it is safe to
545
- * execute. Patterns from untrusted input can cause Regular Expression Denial
546
- * of Service (ReDoS) when matched. Limit pattern and subject lengths, execute
547
- * matches in an environment that can be terminated, or use a linear-time
548
- * regular expression engine when accepting untrusted patterns.
549
- *
550
- * @param options Configuration options for the regular expression parser.
551
- * @returns A sync value parser producing JavaScript {@link RegExp} objects.
552
- * @throws {TypeError} If `options.metavar` is an empty string or
553
- * `options.flags` is not a string.
554
- * @throws {SyntaxError} If `options.flags` contains invalid, duplicate, or
555
- * incompatible regular expression flags.
556
- * @since 1.3.0
557
- */
558
- declare function regExp(options?: RegExpOptions): ValueParser<"sync", RegExp>;
559
501
  interface KeyValueOptionsBase {
560
502
  /**
561
503
  * The metavariable name for this parser. Used in help messages to
@@ -3337,4 +3279,4 @@ declare function firstOf<const TParsers extends readonly [ValueParser<"sync", un
3337
3279
  */
3338
3280
  declare function firstOf<const TParsers extends readonly ValueParser<"sync", unknown>[]>(parsers: TParsers, options?: FirstOfOptions): ValueParser<"sync", ValueParserValue<TParsers[number]>>;
3339
3281
  //#endregion
3340
- export { ChoiceOptions, ChoiceOptionsBase, ChoiceOptionsNumber, ChoiceOptionsString, CidrOptions, CidrValue, Color, ColorFormat, ColorOptions, CronExpression, CronExpressionForOptions, CronOptions, DeferredMap, DomainOptions, EmailOptions, FileSizeOptions, FileSizeOptionsBigInt, FileSizeOptionsNumber, FileSizeUnit, FirstOfOptions, FloatOptions, HostnameOptions, IntegerOptionsBigInt, IntegerOptionsNumber, IpOptions, Ipv4Options, Ipv6Options, Json, JsonOptions, KeyValueOptions, LocaleOptions, MacAddressOptions, type Mode, type ModeIterable, type ModeValue, type NonEmptyString, PortOptionsBigInt, PortOptionsNumber, PortRangeOptionsBigInt, PortRangeOptionsNumber, PortRangeValueBigInt, PortRangeValueNumber, RegExpOptions, SemVer, SemVerOptionsObject, SemVerOptionsString, SemVerString, SocketAddressOptions, SocketAddressValue, StringOptions, TransformMapping, UrlOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, biject, checkBooleanOption, checkEnumOption, choice, cidr, color, cron, domain, email, ensureNonEmptyString, fileSize, firstOf, float, hostname, integer, ip, ipv4, ipv6, isNonEmptyString, isValueParser, json, keyValue, locale, macAddress, port, portRange, regExp, semVer, socketAddress, string, transform, url, uuid };
3282
+ export { ChoiceOptions, ChoiceOptionsBase, ChoiceOptionsNumber, ChoiceOptionsString, CidrOptions, CidrValue, Color, ColorFormat, ColorOptions, CronExpression, CronExpressionForOptions, CronOptions, DeferredMap, DomainOptions, EmailOptions, FileSizeOptions, FileSizeOptionsBigInt, FileSizeOptionsNumber, FileSizeUnit, FirstOfOptions, FloatOptions, HostnameOptions, IntegerOptionsBigInt, IntegerOptionsNumber, IpOptions, Ipv4Options, Ipv6Options, Json, JsonOptions, KeyValueOptions, LocaleOptions, MacAddressOptions, type Mode, type ModeIterable, type ModeValue, type NonEmptyString, PortOptionsBigInt, PortOptionsNumber, PortRangeOptionsBigInt, PortRangeOptionsNumber, PortRangeValueBigInt, PortRangeValueNumber, SemVer, SemVerOptionsObject, SemVerOptionsString, SemVerString, SocketAddressOptions, SocketAddressValue, StringOptions, TransformMapping, UrlOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, biject, checkBooleanOption, checkEnumOption, choice, cidr, color, cron, domain, email, ensureNonEmptyString, fileSize, firstOf, float, hostname, integer, ip, ipv4, ipv6, isNonEmptyString, isValueParser, json, keyValue, locale, macAddress, port, portRange, semVer, socketAddress, string, transform, url, uuid };
@@ -620,71 +620,6 @@ function string(options = {}) {
620
620
  }
621
621
  };
622
622
  }
623
- /**
624
- * Creates a {@link ValueParser} that compiles regular expression sources.
625
- *
626
- * The entire input is treated as the source. Slash-delimited notation such
627
- * as `/pattern/flags` is not interpreted; use {@link RegExpOptions.flags} to
628
- * configure fixed flags for the parser.
629
- *
630
- * **Security note**: Compiling a source does not establish that it is safe to
631
- * execute. Patterns from untrusted input can cause Regular Expression Denial
632
- * of Service (ReDoS) when matched. Limit pattern and subject lengths, execute
633
- * matches in an environment that can be terminated, or use a linear-time
634
- * regular expression engine when accepting untrusted patterns.
635
- *
636
- * @param options Configuration options for the regular expression parser.
637
- * @returns A sync value parser producing JavaScript {@link RegExp} objects.
638
- * @throws {TypeError} If `options.metavar` is an empty string or
639
- * `options.flags` is not a string.
640
- * @throws {SyntaxError} If `options.flags` contains invalid, duplicate, or
641
- * incompatible regular expression flags.
642
- * @since 1.3.0
643
- */
644
- function regExp(options = {}) {
645
- const metavar$1 = options.metavar ?? "REGEXP";
646
- ensureNonEmptyString(metavar$1);
647
- if (options.flags !== void 0 && typeof options.flags !== "string") throw new TypeError(`Expected flags to be a string, but got ${typeof options.flags}: ${String(options.flags)}.`);
648
- const flags = new RegExp("", options.flags ?? "").flags;
649
- const invalidRegExp = options.errors?.invalidRegExp;
650
- const parseRegExp = (input) => {
651
- try {
652
- return {
653
- success: true,
654
- value: new RegExp(input, flags)
655
- };
656
- } catch (error) {
657
- if (!(error instanceof SyntaxError)) throw error;
658
- return {
659
- success: false,
660
- error: invalidRegExp ? typeof invalidRegExp === "function" ? invalidRegExp(input) : invalidRegExp : message`Invalid regular expression: ${input}.`
661
- };
662
- }
663
- };
664
- return {
665
- mode: "sync",
666
- metavar: metavar$1,
667
- get placeholder() {
668
- return new RegExp("", flags);
669
- },
670
- parse: parseRegExp,
671
- validate(value) {
672
- if (!(value instanceof RegExp)) return {
673
- success: false,
674
- error: message`Expected a RegExp value.`
675
- };
676
- return parseRegExp(value.source);
677
- },
678
- normalize(value) {
679
- if (!(value instanceof RegExp)) return value;
680
- const result = parseRegExp(value.source);
681
- return result.success ? result.value : value;
682
- },
683
- format(value) {
684
- return value.source;
685
- }
686
- };
687
- }
688
623
  function keyValue(options = {}) {
689
624
  const separator = options.separator ?? "=";
690
625
  if (typeof separator !== "string") throw new TypeError(`Expected separator to be a string, but got ${typeof separator}: ${String(separator)}.`);
@@ -6667,4 +6602,4 @@ function plainObjectsEqual(a, b) {
6667
6602
  }
6668
6603
 
6669
6604
  //#endregion
6670
- export { biject, checkBooleanOption, checkEnumOption, choice, cidr, color, cron, domain, email, ensureNonEmptyString, fileSize, firstOf, float, hostname, integer, ip, ipv4, ipv6, isNonEmptyString, isValueParser, json, keyValue, locale, macAddress, port, portRange, regExp, semVer, socketAddress, string, transform, url, uuid };
6605
+ export { biject, checkBooleanOption, checkEnumOption, choice, cidr, color, cron, domain, email, ensureNonEmptyString, fileSize, firstOf, float, hostname, integer, ip, ipv4, ipv6, isNonEmptyString, isValueParser, json, keyValue, locale, macAddress, port, portRange, semVer, socketAddress, string, transform, url, uuid };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "1.3.0-dev.2375",
3
+ "version": "1.3.0-dev.2380",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",
@@ -221,7 +221,7 @@
221
221
  },
222
222
  "sideEffects": false,
223
223
  "devDependencies": {
224
- "@optique/env": "1.3.0-dev.2375+820d01c0",
224
+ "@optique/env": "1.3.0-dev.2380+4bce39a7",
225
225
  "@types/node": "^24.0.0",
226
226
  "fast-check": "^4.7.0",
227
227
  "tsdown": "^0.13.0",
@@ -40,12 +40,11 @@ Core rules
40
40
  - Use `message` from *@optique/core/message* for descriptions, help text, and
41
41
  custom errors. Prefer semantic message helpers such as `optionName()` and
42
42
  `metavar()` over string concatenation when naming CLI elements.
43
- - Use value parsers such as `integer()`, `choice()`, `biject()`, `regExp()`,
44
- `url()`, and `uuid()` instead of validating raw strings after parsing. Use
45
- `regExp({ flags })` for user-supplied regular expression sources,
46
- `biject()` for one-to-one string-to-value choices, and `transform()` when
47
- an existing value parser describes the accepted CLI spelling but your app
48
- needs a different result type. Use `path()` from
43
+ - Use value parsers such as `integer()`, `choice()`, `biject()`, `url()`,
44
+ and `uuid()` instead of validating raw strings after parsing. Use
45
+ `biject()` for one-to-one string-to-value choices, and use `transform()`
46
+ when an existing value parser describes the accepted CLI spelling but your
47
+ app needs a different result type. Use `path()` from
49
48
  `@optique/run/valueparser` for file-system paths. Write a custom
50
49
  `{ mode, metavar, parse, format }` value parser only when the catalog does
51
50
  not cover the domain.