@optique/core 1.0.0-dev.1252 → 1.0.0-dev.1265

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.
@@ -9,6 +9,13 @@ const require_usage_internals = require('./usage-internals.cjs');
9
9
  //#region src/constructs.ts
10
10
  const inheritParentAnnotationsKey = Symbol.for("@optique/core/inheritParentAnnotations");
11
11
  /**
12
+ * Internal symbol for exposing field-level parser pairs from `object()`
13
+ * and `merge()` parsers. This allows `merge()` to pre-complete dependency
14
+ * source fields from child parsers before resolving deferred states.
15
+ * @internal
16
+ */
17
+ const fieldParsersKey = Symbol("fieldParsers");
18
+ /**
12
19
  * Returns the field state with parent annotations inherited, respecting
13
20
  * the parser's {@link inheritParentAnnotationsKey} flag. This is the
14
21
  * same logic as {@link createFieldStateGetter} inside `object()` but
@@ -777,6 +784,64 @@ async function completeDependencySourceDefaultsAsync(context, parserPairs, regis
777
784
  }
778
785
  }
779
786
  /**
787
+ * Collects field-level parser pairs from child parsers that expose them
788
+ * via {@link fieldParsersKey}. Used by `merge()` to gather field→parser
789
+ * mappings from its child `object()` (or nested `merge()`) parsers.
790
+ * @internal
791
+ */
792
+ function collectChildFieldParsers(parsers) {
793
+ const pairs = [];
794
+ for (const parser of parsers) if (fieldParsersKey in parser) pairs.push(...parser[fieldParsersKey]);
795
+ return pairs;
796
+ }
797
+ /**
798
+ * Pre-completes dependency source fields and registers their values in
799
+ * the given registry. Unlike `completeDependencySourceDefaults()` (used
800
+ * by suggest), this function handles all four Phase 1 cases — including
801
+ * PendingDependencySourceState in arrays and wrappedDependencySourceMarker.
802
+ *
803
+ * The original state is NOT modified; only the registry is populated.
804
+ * @internal
805
+ */
806
+ function preCompleteAndRegisterDependencies(state, fieldParserPairs, registry) {
807
+ for (const [field, fieldParser] of fieldParserPairs) {
808
+ const fieldState = state[field];
809
+ let completed;
810
+ if (Array.isArray(fieldState) && fieldState.length === 1 && require_dependency.isPendingDependencySourceState(fieldState[0])) completed = fieldParser.complete(fieldState);
811
+ else if (fieldState === void 0 && require_dependency.isPendingDependencySourceState(fieldParser.initialState)) completed = fieldParser.complete([fieldParser.initialState]);
812
+ else if (fieldState === void 0 && require_dependency.isWrappedDependencySource(fieldParser)) {
813
+ const pendingState = fieldParser[require_dependency.wrappedDependencySourceMarker];
814
+ completed = fieldParser.complete([pendingState]);
815
+ } else if (fieldState != null && !Array.isArray(fieldState) && !require_dependency.isDependencySourceState(fieldState) && (require_dependency.isWrappedDependencySource(fieldParser) || require_dependency.isPendingDependencySourceState(fieldParser.initialState))) {
816
+ const annotatedFieldState = getAnnotatedFieldState(state, field, fieldParser);
817
+ completed = fieldParser.complete(annotatedFieldState);
818
+ } else continue;
819
+ const depState = wrapAsDependencySourceState(completed, fieldParser);
820
+ if (depState) registerCompletedDependency(depState, registry);
821
+ }
822
+ }
823
+ /**
824
+ * Async version of {@link preCompleteAndRegisterDependencies}.
825
+ * @internal
826
+ */
827
+ async function preCompleteAndRegisterDependenciesAsync(state, fieldParserPairs, registry) {
828
+ for (const [field, fieldParser] of fieldParserPairs) {
829
+ const fieldState = state[field];
830
+ let completed;
831
+ if (Array.isArray(fieldState) && fieldState.length === 1 && require_dependency.isPendingDependencySourceState(fieldState[0])) completed = await fieldParser.complete(fieldState);
832
+ else if (fieldState === void 0 && require_dependency.isPendingDependencySourceState(fieldParser.initialState)) completed = await fieldParser.complete([fieldParser.initialState]);
833
+ else if (fieldState === void 0 && require_dependency.isWrappedDependencySource(fieldParser)) {
834
+ const pendingState = fieldParser[require_dependency.wrappedDependencySourceMarker];
835
+ completed = await fieldParser.complete([pendingState]);
836
+ } else if (fieldState != null && !Array.isArray(fieldState) && !require_dependency.isDependencySourceState(fieldState) && (require_dependency.isWrappedDependencySource(fieldParser) || require_dependency.isPendingDependencySourceState(fieldParser.initialState))) {
837
+ const annotatedFieldState = getAnnotatedFieldState(state, field, fieldParser);
838
+ completed = await fieldParser.complete(annotatedFieldState);
839
+ } else continue;
840
+ const depState = wrapAsDependencySourceState(completed, fieldParser);
841
+ if (depState) registerCompletedDependency(depState, registry);
842
+ }
843
+ }
844
+ /**
780
845
  * Recursively collects dependency values from DependencySourceState objects
781
846
  * found anywhere in the state tree.
782
847
  * @internal
@@ -869,8 +934,8 @@ function resolveDeferred(state, registry, visited = /* @__PURE__ */ new WeakSet(
869
934
  }
870
935
  return state;
871
936
  }
872
- function resolveDeferredParseStates(fieldStates) {
873
- const registry = new require_dependency.DependencyRegistry();
937
+ function resolveDeferredParseStates(fieldStates, initialRegistry) {
938
+ const registry = initialRegistry ?? new require_dependency.DependencyRegistry();
874
939
  collectDependencies(fieldStates, registry);
875
940
  return resolveDeferred(fieldStates, registry);
876
941
  }
@@ -916,8 +981,8 @@ async function resolveDeferredAsync(state, registry, visited = /* @__PURE__ */ n
916
981
  * Async version of resolveDeferredParseStates for async parsers.
917
982
  * @internal
918
983
  */
919
- async function resolveDeferredParseStatesAsync(fieldStates) {
920
- const registry = new require_dependency.DependencyRegistry();
984
+ async function resolveDeferredParseStatesAsync(fieldStates, initialRegistry) {
985
+ const registry = initialRegistry ?? new require_dependency.DependencyRegistry();
921
986
  collectDependencies(fieldStates, registry);
922
987
  return await resolveDeferredAsync(fieldStates, registry);
923
988
  }
@@ -1102,6 +1167,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1102
1167
  $mode: combinedMode,
1103
1168
  $valueType: [],
1104
1169
  $stateType: [],
1170
+ [fieldParsersKey]: parserPairs,
1105
1171
  priority: Math.max(...parserKeys.map((k) => parsers[k].priority)),
1106
1172
  usage: applyHiddenToUsage(parserPairs.flatMap(([_, p]) => p.usage), options.hidden),
1107
1173
  get initialState() {
@@ -1724,10 +1790,12 @@ function merge(...args) {
1724
1790
  error: require_message.message`No matching option or argument found.`
1725
1791
  };
1726
1792
  };
1793
+ const mergedFieldParsers = collectChildFieldParsers(parsers);
1727
1794
  return {
1728
1795
  $mode: combinedMode,
1729
1796
  $valueType: [],
1730
1797
  $stateType: [],
1798
+ [fieldParsersKey]: mergedFieldParsers,
1731
1799
  priority: Math.max(...parsers.map((p) => p.priority)),
1732
1800
  usage: applyHiddenToUsage(parsers.flatMap((p) => p.usage), options.hidden),
1733
1801
  initialState,
@@ -1745,6 +1813,8 @@ function merge(...args) {
1745
1813
  if (resolvedState && typeof resolvedState === "object") {
1746
1814
  const extractedState = {};
1747
1815
  for (const field in parser.initialState) extractedState[field] = field in resolvedState ? resolvedState[field] : parser.initialState[field];
1816
+ const annotations = require_annotations.getAnnotations(resolvedState);
1817
+ if (annotations !== void 0) return require_annotations.inheritAnnotations(resolvedState, extractedState);
1748
1818
  return extractedState;
1749
1819
  }
1750
1820
  return parser.initialState;
@@ -1752,7 +1822,10 @@ function merge(...args) {
1752
1822
  return parser.initialState;
1753
1823
  };
1754
1824
  if (!isAsync) {
1755
- const resolvedState = resolveDeferredParseStates(state);
1825
+ const childFieldPairs = collectChildFieldParsers(syncParsers);
1826
+ const registry = new require_dependency.DependencyRegistry();
1827
+ preCompleteAndRegisterDependencies(state, childFieldPairs, registry);
1828
+ const resolvedState = resolveDeferredParseStates(state, registry);
1756
1829
  const object$1 = {};
1757
1830
  for (let i = 0; i < syncParsers.length; i++) {
1758
1831
  const parser = syncParsers[i];
@@ -1767,7 +1840,10 @@ function merge(...args) {
1767
1840
  };
1768
1841
  }
1769
1842
  return (async () => {
1770
- const resolvedState = await resolveDeferredParseStatesAsync(state);
1843
+ const childFieldPairs = collectChildFieldParsers(parsers);
1844
+ const registry = new require_dependency.DependencyRegistry();
1845
+ await preCompleteAndRegisterDependenciesAsync(state, childFieldPairs, registry);
1846
+ const resolvedState = await resolveDeferredParseStatesAsync(state, registry);
1771
1847
  const object$1 = {};
1772
1848
  for (let i = 0; i < parsers.length; i++) {
1773
1849
  const parser = parsers[i];
@@ -1799,19 +1875,23 @@ function merge(...args) {
1799
1875
  }
1800
1876
  return p.initialState;
1801
1877
  };
1802
- const registry = context.dependencyRegistry ? context.dependencyRegistry.clone() : new require_dependency.DependencyRegistry();
1803
- if (context.state && typeof context.state === "object") collectDependencies(context.state, registry);
1804
- const contextWithRegistry = {
1805
- ...context,
1806
- dependencyRegistry: registry
1807
- };
1808
1878
  if (isAsync) return async function* () {
1879
+ const registry$1 = context.dependencyRegistry ? context.dependencyRegistry.clone() : new require_dependency.DependencyRegistry();
1880
+ const childFieldPairs$1 = collectChildFieldParsers(parsers);
1881
+ if (context.state && typeof context.state === "object") {
1882
+ await preCompleteAndRegisterDependenciesAsync(context.state, childFieldPairs$1, registry$1);
1883
+ collectDependencies(context.state, registry$1);
1884
+ } else await completeDependencySourceDefaultsAsync(context, childFieldPairs$1, registry$1);
1885
+ const contextWithRegistry$1 = {
1886
+ ...context,
1887
+ dependencyRegistry: registry$1
1888
+ };
1809
1889
  const suggestions = [];
1810
1890
  for (let i = 0; i < parsers.length; i++) {
1811
1891
  const parser = parsers[i];
1812
1892
  const parserState = extractState(parser, i);
1813
1893
  const parserSuggestions = parser.suggest({
1814
- ...contextWithRegistry,
1894
+ ...contextWithRegistry$1,
1815
1895
  state: parserState
1816
1896
  }, prefix);
1817
1897
  if (parser.$mode === "async") for await (const s of parserSuggestions) suggestions.push(s);
@@ -1819,6 +1899,16 @@ function merge(...args) {
1819
1899
  }
1820
1900
  yield* require_suggestion.deduplicateSuggestions(suggestions);
1821
1901
  }();
1902
+ const registry = context.dependencyRegistry ? context.dependencyRegistry.clone() : new require_dependency.DependencyRegistry();
1903
+ const childFieldPairs = collectChildFieldParsers(syncParsers);
1904
+ if (context.state && typeof context.state === "object") {
1905
+ preCompleteAndRegisterDependencies(context.state, childFieldPairs, registry);
1906
+ collectDependencies(context.state, registry);
1907
+ } else completeDependencySourceDefaults(context, childFieldPairs, registry);
1908
+ const contextWithRegistry = {
1909
+ ...context,
1910
+ dependencyRegistry: registry
1911
+ };
1822
1912
  return function* () {
1823
1913
  const suggestions = [];
1824
1914
  for (let i = 0; i < syncParsers.length; i++) {
@@ -2257,6 +2347,7 @@ function group(label, parser, options = {}) {
2257
2347
  priority: parser.priority,
2258
2348
  usage: applyHiddenToUsage(parser.usage, options.hidden),
2259
2349
  initialState: parser.initialState,
2350
+ ...fieldParsersKey in parser ? { [fieldParsersKey]: parser[fieldParsersKey] } : {},
2260
2351
  ...typeof parser.shouldDeferCompletion === "function" ? { shouldDeferCompletion: parser.shouldDeferCompletion.bind(parser) } : {},
2261
2352
  parse: (context) => parser.parse(context),
2262
2353
  complete: (state) => parser.complete(state),
@@ -9,6 +9,13 @@ import { collectLeadingCandidates } from "./usage-internals.js";
9
9
  //#region src/constructs.ts
10
10
  const inheritParentAnnotationsKey = Symbol.for("@optique/core/inheritParentAnnotations");
11
11
  /**
12
+ * Internal symbol for exposing field-level parser pairs from `object()`
13
+ * and `merge()` parsers. This allows `merge()` to pre-complete dependency
14
+ * source fields from child parsers before resolving deferred states.
15
+ * @internal
16
+ */
17
+ const fieldParsersKey = Symbol("fieldParsers");
18
+ /**
12
19
  * Returns the field state with parent annotations inherited, respecting
13
20
  * the parser's {@link inheritParentAnnotationsKey} flag. This is the
14
21
  * same logic as {@link createFieldStateGetter} inside `object()` but
@@ -777,6 +784,64 @@ async function completeDependencySourceDefaultsAsync(context, parserPairs, regis
777
784
  }
778
785
  }
779
786
  /**
787
+ * Collects field-level parser pairs from child parsers that expose them
788
+ * via {@link fieldParsersKey}. Used by `merge()` to gather field→parser
789
+ * mappings from its child `object()` (or nested `merge()`) parsers.
790
+ * @internal
791
+ */
792
+ function collectChildFieldParsers(parsers) {
793
+ const pairs = [];
794
+ for (const parser of parsers) if (fieldParsersKey in parser) pairs.push(...parser[fieldParsersKey]);
795
+ return pairs;
796
+ }
797
+ /**
798
+ * Pre-completes dependency source fields and registers their values in
799
+ * the given registry. Unlike `completeDependencySourceDefaults()` (used
800
+ * by suggest), this function handles all four Phase 1 cases — including
801
+ * PendingDependencySourceState in arrays and wrappedDependencySourceMarker.
802
+ *
803
+ * The original state is NOT modified; only the registry is populated.
804
+ * @internal
805
+ */
806
+ function preCompleteAndRegisterDependencies(state, fieldParserPairs, registry) {
807
+ for (const [field, fieldParser] of fieldParserPairs) {
808
+ const fieldState = state[field];
809
+ let completed;
810
+ if (Array.isArray(fieldState) && fieldState.length === 1 && isPendingDependencySourceState(fieldState[0])) completed = fieldParser.complete(fieldState);
811
+ else if (fieldState === void 0 && isPendingDependencySourceState(fieldParser.initialState)) completed = fieldParser.complete([fieldParser.initialState]);
812
+ else if (fieldState === void 0 && isWrappedDependencySource(fieldParser)) {
813
+ const pendingState = fieldParser[wrappedDependencySourceMarker];
814
+ completed = fieldParser.complete([pendingState]);
815
+ } else if (fieldState != null && !Array.isArray(fieldState) && !isDependencySourceState(fieldState) && (isWrappedDependencySource(fieldParser) || isPendingDependencySourceState(fieldParser.initialState))) {
816
+ const annotatedFieldState = getAnnotatedFieldState(state, field, fieldParser);
817
+ completed = fieldParser.complete(annotatedFieldState);
818
+ } else continue;
819
+ const depState = wrapAsDependencySourceState(completed, fieldParser);
820
+ if (depState) registerCompletedDependency(depState, registry);
821
+ }
822
+ }
823
+ /**
824
+ * Async version of {@link preCompleteAndRegisterDependencies}.
825
+ * @internal
826
+ */
827
+ async function preCompleteAndRegisterDependenciesAsync(state, fieldParserPairs, registry) {
828
+ for (const [field, fieldParser] of fieldParserPairs) {
829
+ const fieldState = state[field];
830
+ let completed;
831
+ if (Array.isArray(fieldState) && fieldState.length === 1 && isPendingDependencySourceState(fieldState[0])) completed = await fieldParser.complete(fieldState);
832
+ else if (fieldState === void 0 && isPendingDependencySourceState(fieldParser.initialState)) completed = await fieldParser.complete([fieldParser.initialState]);
833
+ else if (fieldState === void 0 && isWrappedDependencySource(fieldParser)) {
834
+ const pendingState = fieldParser[wrappedDependencySourceMarker];
835
+ completed = await fieldParser.complete([pendingState]);
836
+ } else if (fieldState != null && !Array.isArray(fieldState) && !isDependencySourceState(fieldState) && (isWrappedDependencySource(fieldParser) || isPendingDependencySourceState(fieldParser.initialState))) {
837
+ const annotatedFieldState = getAnnotatedFieldState(state, field, fieldParser);
838
+ completed = await fieldParser.complete(annotatedFieldState);
839
+ } else continue;
840
+ const depState = wrapAsDependencySourceState(completed, fieldParser);
841
+ if (depState) registerCompletedDependency(depState, registry);
842
+ }
843
+ }
844
+ /**
780
845
  * Recursively collects dependency values from DependencySourceState objects
781
846
  * found anywhere in the state tree.
782
847
  * @internal
@@ -869,8 +934,8 @@ function resolveDeferred(state, registry, visited = /* @__PURE__ */ new WeakSet(
869
934
  }
870
935
  return state;
871
936
  }
872
- function resolveDeferredParseStates(fieldStates) {
873
- const registry = new DependencyRegistry();
937
+ function resolveDeferredParseStates(fieldStates, initialRegistry) {
938
+ const registry = initialRegistry ?? new DependencyRegistry();
874
939
  collectDependencies(fieldStates, registry);
875
940
  return resolveDeferred(fieldStates, registry);
876
941
  }
@@ -916,8 +981,8 @@ async function resolveDeferredAsync(state, registry, visited = /* @__PURE__ */ n
916
981
  * Async version of resolveDeferredParseStates for async parsers.
917
982
  * @internal
918
983
  */
919
- async function resolveDeferredParseStatesAsync(fieldStates) {
920
- const registry = new DependencyRegistry();
984
+ async function resolveDeferredParseStatesAsync(fieldStates, initialRegistry) {
985
+ const registry = initialRegistry ?? new DependencyRegistry();
921
986
  collectDependencies(fieldStates, registry);
922
987
  return await resolveDeferredAsync(fieldStates, registry);
923
988
  }
@@ -1102,6 +1167,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1102
1167
  $mode: combinedMode,
1103
1168
  $valueType: [],
1104
1169
  $stateType: [],
1170
+ [fieldParsersKey]: parserPairs,
1105
1171
  priority: Math.max(...parserKeys.map((k) => parsers[k].priority)),
1106
1172
  usage: applyHiddenToUsage(parserPairs.flatMap(([_, p]) => p.usage), options.hidden),
1107
1173
  get initialState() {
@@ -1724,10 +1790,12 @@ function merge(...args) {
1724
1790
  error: message`No matching option or argument found.`
1725
1791
  };
1726
1792
  };
1793
+ const mergedFieldParsers = collectChildFieldParsers(parsers);
1727
1794
  return {
1728
1795
  $mode: combinedMode,
1729
1796
  $valueType: [],
1730
1797
  $stateType: [],
1798
+ [fieldParsersKey]: mergedFieldParsers,
1731
1799
  priority: Math.max(...parsers.map((p) => p.priority)),
1732
1800
  usage: applyHiddenToUsage(parsers.flatMap((p) => p.usage), options.hidden),
1733
1801
  initialState,
@@ -1745,6 +1813,8 @@ function merge(...args) {
1745
1813
  if (resolvedState && typeof resolvedState === "object") {
1746
1814
  const extractedState = {};
1747
1815
  for (const field in parser.initialState) extractedState[field] = field in resolvedState ? resolvedState[field] : parser.initialState[field];
1816
+ const annotations = getAnnotations(resolvedState);
1817
+ if (annotations !== void 0) return inheritAnnotations(resolvedState, extractedState);
1748
1818
  return extractedState;
1749
1819
  }
1750
1820
  return parser.initialState;
@@ -1752,7 +1822,10 @@ function merge(...args) {
1752
1822
  return parser.initialState;
1753
1823
  };
1754
1824
  if (!isAsync) {
1755
- const resolvedState = resolveDeferredParseStates(state);
1825
+ const childFieldPairs = collectChildFieldParsers(syncParsers);
1826
+ const registry = new DependencyRegistry();
1827
+ preCompleteAndRegisterDependencies(state, childFieldPairs, registry);
1828
+ const resolvedState = resolveDeferredParseStates(state, registry);
1756
1829
  const object$1 = {};
1757
1830
  for (let i = 0; i < syncParsers.length; i++) {
1758
1831
  const parser = syncParsers[i];
@@ -1767,7 +1840,10 @@ function merge(...args) {
1767
1840
  };
1768
1841
  }
1769
1842
  return (async () => {
1770
- const resolvedState = await resolveDeferredParseStatesAsync(state);
1843
+ const childFieldPairs = collectChildFieldParsers(parsers);
1844
+ const registry = new DependencyRegistry();
1845
+ await preCompleteAndRegisterDependenciesAsync(state, childFieldPairs, registry);
1846
+ const resolvedState = await resolveDeferredParseStatesAsync(state, registry);
1771
1847
  const object$1 = {};
1772
1848
  for (let i = 0; i < parsers.length; i++) {
1773
1849
  const parser = parsers[i];
@@ -1799,19 +1875,23 @@ function merge(...args) {
1799
1875
  }
1800
1876
  return p.initialState;
1801
1877
  };
1802
- const registry = context.dependencyRegistry ? context.dependencyRegistry.clone() : new DependencyRegistry();
1803
- if (context.state && typeof context.state === "object") collectDependencies(context.state, registry);
1804
- const contextWithRegistry = {
1805
- ...context,
1806
- dependencyRegistry: registry
1807
- };
1808
1878
  if (isAsync) return async function* () {
1879
+ const registry$1 = context.dependencyRegistry ? context.dependencyRegistry.clone() : new DependencyRegistry();
1880
+ const childFieldPairs$1 = collectChildFieldParsers(parsers);
1881
+ if (context.state && typeof context.state === "object") {
1882
+ await preCompleteAndRegisterDependenciesAsync(context.state, childFieldPairs$1, registry$1);
1883
+ collectDependencies(context.state, registry$1);
1884
+ } else await completeDependencySourceDefaultsAsync(context, childFieldPairs$1, registry$1);
1885
+ const contextWithRegistry$1 = {
1886
+ ...context,
1887
+ dependencyRegistry: registry$1
1888
+ };
1809
1889
  const suggestions = [];
1810
1890
  for (let i = 0; i < parsers.length; i++) {
1811
1891
  const parser = parsers[i];
1812
1892
  const parserState = extractState(parser, i);
1813
1893
  const parserSuggestions = parser.suggest({
1814
- ...contextWithRegistry,
1894
+ ...contextWithRegistry$1,
1815
1895
  state: parserState
1816
1896
  }, prefix);
1817
1897
  if (parser.$mode === "async") for await (const s of parserSuggestions) suggestions.push(s);
@@ -1819,6 +1899,16 @@ function merge(...args) {
1819
1899
  }
1820
1900
  yield* deduplicateSuggestions(suggestions);
1821
1901
  }();
1902
+ const registry = context.dependencyRegistry ? context.dependencyRegistry.clone() : new DependencyRegistry();
1903
+ const childFieldPairs = collectChildFieldParsers(syncParsers);
1904
+ if (context.state && typeof context.state === "object") {
1905
+ preCompleteAndRegisterDependencies(context.state, childFieldPairs, registry);
1906
+ collectDependencies(context.state, registry);
1907
+ } else completeDependencySourceDefaults(context, childFieldPairs, registry);
1908
+ const contextWithRegistry = {
1909
+ ...context,
1910
+ dependencyRegistry: registry
1911
+ };
1822
1912
  return function* () {
1823
1913
  const suggestions = [];
1824
1914
  for (let i = 0; i < syncParsers.length; i++) {
@@ -2257,6 +2347,7 @@ function group(label, parser, options = {}) {
2257
2347
  priority: parser.priority,
2258
2348
  usage: applyHiddenToUsage(parser.usage, options.hidden),
2259
2349
  initialState: parser.initialState,
2350
+ ...fieldParsersKey in parser ? { [fieldParsersKey]: parser[fieldParsersKey] } : {},
2260
2351
  ...typeof parser.shouldDeferCompletion === "function" ? { shouldDeferCompletion: parser.shouldDeferCompletion.bind(parser) } : {},
2261
2352
  parse: (context) => parser.parse(context),
2262
2353
  complete: (state) => parser.complete(state),
@@ -499,6 +499,7 @@ function url(options = {}) {
499
499
  originalProtocolsList.push(protocol);
500
500
  normalizedProtocolsList.push(normalized);
501
501
  }
502
+ if (originalProtocolsList.length === 0) throw new TypeError("allowedProtocols must not be empty.");
502
503
  }
503
504
  const originalProtocols = options.allowedProtocols != null ? Object.freeze(originalProtocolsList) : void 0;
504
505
  const allowedProtocols = options.allowedProtocols != null ? Object.freeze(normalizedProtocolsList) : void 0;
@@ -517,7 +518,25 @@ function url(options = {}) {
517
518
  const url$1 = new URL(input);
518
519
  if (allowedProtocols != null && !allowedProtocols.includes(url$1.protocol)) return {
519
520
  success: false,
520
- error: disallowedProtocol ? typeof disallowedProtocol === "function" ? disallowedProtocol(url$1.protocol, originalProtocols) : disallowedProtocol : require_message.message`URL protocol ${url$1.protocol} is not allowed. Allowed protocols: ${allowedProtocols.join(", ")}.`
521
+ error: disallowedProtocol ? typeof disallowedProtocol === "function" ? disallowedProtocol(url$1.protocol, originalProtocols) : disallowedProtocol : [
522
+ {
523
+ type: "text",
524
+ text: "URL protocol "
525
+ },
526
+ {
527
+ type: "value",
528
+ value: url$1.protocol
529
+ },
530
+ {
531
+ type: "text",
532
+ text: " is not allowed. Allowed protocols: "
533
+ },
534
+ ...require_message.valueSet(originalProtocols, { locale: "en-US" }),
535
+ {
536
+ type: "text",
537
+ text: "."
538
+ }
539
+ ]
521
540
  };
522
541
  return {
523
542
  success: true,
@@ -1364,16 +1383,19 @@ function email(options) {
1364
1383
  const allowDisplayName = options?.allowDisplayName ?? false;
1365
1384
  const lowercase = options?.lowercase ?? false;
1366
1385
  const allowedDomains = options?.allowedDomains != null ? Object.freeze([...options.allowedDomains]) : void 0;
1367
- if (allowedDomains != null) for (let i = 0; i < allowedDomains.length; i++) {
1368
- const entry = allowedDomains[i];
1369
- if (typeof entry !== "string") throw new TypeError(`allowedDomains[${i}] must be a string, got ${typeof entry}.`);
1370
- if (entry !== entry.trim()) throw new TypeError(`allowedDomains[${i}] must not have leading or trailing whitespace: ${JSON.stringify(entry)}`);
1371
- if (entry.startsWith("@")) throw new TypeError(`allowedDomains[${i}] must not start with "@": ${JSON.stringify(entry)}`);
1372
- if (entry === "" || !entry.includes(".")) throw new TypeError(`allowedDomains[${i}] is not a valid domain: ${JSON.stringify(entry)}`);
1373
- if (entry.startsWith(".") || entry.endsWith(".") || entry.startsWith("-") || entry.endsWith("-")) throw new TypeError(`allowedDomains[${i}] is not a valid domain: ${JSON.stringify(entry)}`);
1374
- const labels = entry.split(".");
1375
- for (const label of labels) if (label.length === 0 || label.length > 63 || label.startsWith("-") || label.endsWith("-") || !/^[a-zA-Z0-9-]+$/.test(label)) throw new TypeError(`allowedDomains[${i}] is not a valid domain: ${JSON.stringify(entry)}`);
1376
- if (labels.length === 4 && labels.every((label) => /^[0-9]+$/.test(label))) throw new TypeError(`allowedDomains[${i}] is not a valid domain: ${JSON.stringify(entry)}`);
1386
+ if (allowedDomains != null) {
1387
+ if (allowedDomains.length === 0) throw new TypeError("allowedDomains must not be empty.");
1388
+ for (let i = 0; i < allowedDomains.length; i++) {
1389
+ const entry = allowedDomains[i];
1390
+ if (typeof entry !== "string") throw new TypeError(`allowedDomains[${i}] must be a string, got ${typeof entry}.`);
1391
+ if (entry !== entry.trim()) throw new TypeError(`allowedDomains[${i}] must not have leading or trailing whitespace: ${JSON.stringify(entry)}`);
1392
+ if (entry.startsWith("@")) throw new TypeError(`allowedDomains[${i}] must not start with "@": ${JSON.stringify(entry)}`);
1393
+ if (entry === "" || !entry.includes(".")) throw new TypeError(`allowedDomains[${i}] is not a valid domain: ${JSON.stringify(entry)}`);
1394
+ if (entry.startsWith(".") || entry.endsWith(".") || entry.startsWith("-") || entry.endsWith("-")) throw new TypeError(`allowedDomains[${i}] is not a valid domain: ${JSON.stringify(entry)}`);
1395
+ const labels = entry.split(".");
1396
+ for (const label of labels) if (label.length === 0 || label.length > 63 || label.startsWith("-") || label.endsWith("-") || !/^[a-zA-Z0-9-]+$/.test(label)) throw new TypeError(`allowedDomains[${i}] is not a valid domain: ${JSON.stringify(entry)}`);
1397
+ if (labels.length === 4 && labels.every((label) => /^[0-9]+$/.test(label))) throw new TypeError(`allowedDomains[${i}] is not a valid domain: ${JSON.stringify(entry)}`);
1398
+ }
1377
1399
  }
1378
1400
  const invalidEmail = options?.errors?.invalidEmail;
1379
1401
  const domainNotAllowed = options?.errors?.domainNotAllowed;
@@ -1489,7 +1511,12 @@ function email(options) {
1489
1511
  },
1490
1512
  {
1491
1513
  type: "text",
1492
- text: ` is not allowed. Allowed domains: ${allowedDomains.join(", ")}.`
1514
+ text: " is not allowed. Allowed domains: "
1515
+ },
1516
+ ...require_message.valueSet(allowedDomains, { locale: "en-US" }),
1517
+ {
1518
+ type: "text",
1519
+ text: "."
1493
1520
  }
1494
1521
  ];
1495
1522
  return {
@@ -1535,7 +1562,12 @@ function email(options) {
1535
1562
  },
1536
1563
  {
1537
1564
  type: "text",
1538
- text: ` is not allowed. Allowed domains: ${allowedDomains.join(", ")}.`
1565
+ text: " is not allowed. Allowed domains: "
1566
+ },
1567
+ ...require_message.valueSet(allowedDomains, { locale: "en-US" }),
1568
+ {
1569
+ type: "text",
1570
+ text: "."
1539
1571
  }
1540
1572
  ];
1541
1573
  return {
@@ -1849,8 +1881,8 @@ function macAddress(options) {
1849
1881
  const caseOption = options?.case ?? "preserve";
1850
1882
  const outputSeparator = options?.outputSeparator;
1851
1883
  const metavar = options?.metavar ?? "MAC";
1852
- const colonRegex = /^([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2})$/;
1853
- const hyphenRegex = /^([0-9a-fA-F]{1,2})-([0-9a-fA-F]{1,2})-([0-9a-fA-F]{1,2})-([0-9a-fA-F]{1,2})-([0-9a-fA-F]{1,2})-([0-9a-fA-F]{1,2})$/;
1884
+ const colonRegex = /^([0-9a-fA-F]{2}):([0-9a-fA-F]{2}):([0-9a-fA-F]{2}):([0-9a-fA-F]{2}):([0-9a-fA-F]{2}):([0-9a-fA-F]{2})$/;
1885
+ const hyphenRegex = /^([0-9a-fA-F]{2})-([0-9a-fA-F]{2})-([0-9a-fA-F]{2})-([0-9a-fA-F]{2})-([0-9a-fA-F]{2})-([0-9a-fA-F]{2})$/;
1854
1886
  const dotRegex = /^([0-9a-fA-F]{4})\.([0-9a-fA-F]{4})\.([0-9a-fA-F]{4})$/;
1855
1887
  const noneRegex = /^([0-9a-fA-F]{12})$/;
1856
1888
  return {
@@ -1983,15 +2015,18 @@ function domain(options) {
1983
2015
  const allowSubdomains = options?.allowSubdomains ?? true;
1984
2016
  const allowedTlds = options?.allowedTlds != null ? Object.freeze([...options.allowedTlds]) : void 0;
1985
2017
  const labelRegex = /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/;
1986
- if (allowedTlds !== void 0) for (const [i, tld] of allowedTlds.entries()) {
1987
- if (typeof tld !== "string") {
1988
- const actualType = Array.isArray(tld) ? "array" : typeof tld;
1989
- throw new TypeError(`allowedTlds[${i}] must be a string, but got ${actualType}.`);
2018
+ if (allowedTlds !== void 0) {
2019
+ if (allowedTlds.length === 0) throw new TypeError("allowedTlds must not be empty.");
2020
+ for (const [i, tld] of allowedTlds.entries()) {
2021
+ if (typeof tld !== "string") {
2022
+ const actualType = Array.isArray(tld) ? "array" : typeof tld;
2023
+ throw new TypeError(`allowedTlds[${i}] must be a string, but got ${actualType}.`);
2024
+ }
2025
+ if (tld.length === 0) throw new TypeError(`allowedTlds[${i}] must not be an empty string.`);
2026
+ if (tld.includes(".")) throw new TypeError(`allowedTlds[${i}] must not contain dots: ${JSON.stringify(tld)}.`);
2027
+ if (tld !== tld.trim()) throw new TypeError(`allowedTlds[${i}] must not have leading or trailing whitespace: ${JSON.stringify(tld)}.`);
2028
+ if (!labelRegex.test(tld)) throw new TypeError(`allowedTlds[${i}] is not a valid DNS label: ${JSON.stringify(tld)}.`);
1990
2029
  }
1991
- if (tld.length === 0) throw new TypeError(`allowedTlds[${i}] must not be an empty string.`);
1992
- if (tld.includes(".")) throw new TypeError(`allowedTlds[${i}] must not contain dots: ${JSON.stringify(tld)}.`);
1993
- if (tld !== tld.trim()) throw new TypeError(`allowedTlds[${i}] must not have leading or trailing whitespace: ${JSON.stringify(tld)}.`);
1994
- if (!labelRegex.test(tld)) throw new TypeError(`allowedTlds[${i}] is not a valid DNS label: ${JSON.stringify(tld)}.`);
1995
2030
  }
1996
2031
  const allowedTldsLower = allowedTlds != null ? Object.freeze(allowedTlds.map((t) => t.toLowerCase())) : void 0;
1997
2032
  const minLabels = options?.minLabels ?? 2;
@@ -2188,7 +2223,12 @@ function domain(options) {
2188
2223
  },
2189
2224
  {
2190
2225
  type: "text",
2191
- text: ` is not allowed. Allowed TLDs: ${allowedTlds.join(", ")}.`
2226
+ text: " is not allowed. Allowed TLDs: "
2227
+ },
2228
+ ...require_message.valueSet(allowedTlds, { locale: "en-US" }),
2229
+ {
2230
+ type: "text",
2231
+ text: "."
2192
2232
  }
2193
2233
  ];
2194
2234
  return {
@@ -499,6 +499,7 @@ function url(options = {}) {
499
499
  originalProtocolsList.push(protocol);
500
500
  normalizedProtocolsList.push(normalized);
501
501
  }
502
+ if (originalProtocolsList.length === 0) throw new TypeError("allowedProtocols must not be empty.");
502
503
  }
503
504
  const originalProtocols = options.allowedProtocols != null ? Object.freeze(originalProtocolsList) : void 0;
504
505
  const allowedProtocols = options.allowedProtocols != null ? Object.freeze(normalizedProtocolsList) : void 0;
@@ -517,7 +518,25 @@ function url(options = {}) {
517
518
  const url$1 = new URL(input);
518
519
  if (allowedProtocols != null && !allowedProtocols.includes(url$1.protocol)) return {
519
520
  success: false,
520
- error: disallowedProtocol ? typeof disallowedProtocol === "function" ? disallowedProtocol(url$1.protocol, originalProtocols) : disallowedProtocol : message`URL protocol ${url$1.protocol} is not allowed. Allowed protocols: ${allowedProtocols.join(", ")}.`
521
+ error: disallowedProtocol ? typeof disallowedProtocol === "function" ? disallowedProtocol(url$1.protocol, originalProtocols) : disallowedProtocol : [
522
+ {
523
+ type: "text",
524
+ text: "URL protocol "
525
+ },
526
+ {
527
+ type: "value",
528
+ value: url$1.protocol
529
+ },
530
+ {
531
+ type: "text",
532
+ text: " is not allowed. Allowed protocols: "
533
+ },
534
+ ...valueSet(originalProtocols, { locale: "en-US" }),
535
+ {
536
+ type: "text",
537
+ text: "."
538
+ }
539
+ ]
521
540
  };
522
541
  return {
523
542
  success: true,
@@ -1364,16 +1383,19 @@ function email(options) {
1364
1383
  const allowDisplayName = options?.allowDisplayName ?? false;
1365
1384
  const lowercase = options?.lowercase ?? false;
1366
1385
  const allowedDomains = options?.allowedDomains != null ? Object.freeze([...options.allowedDomains]) : void 0;
1367
- if (allowedDomains != null) for (let i = 0; i < allowedDomains.length; i++) {
1368
- const entry = allowedDomains[i];
1369
- if (typeof entry !== "string") throw new TypeError(`allowedDomains[${i}] must be a string, got ${typeof entry}.`);
1370
- if (entry !== entry.trim()) throw new TypeError(`allowedDomains[${i}] must not have leading or trailing whitespace: ${JSON.stringify(entry)}`);
1371
- if (entry.startsWith("@")) throw new TypeError(`allowedDomains[${i}] must not start with "@": ${JSON.stringify(entry)}`);
1372
- if (entry === "" || !entry.includes(".")) throw new TypeError(`allowedDomains[${i}] is not a valid domain: ${JSON.stringify(entry)}`);
1373
- if (entry.startsWith(".") || entry.endsWith(".") || entry.startsWith("-") || entry.endsWith("-")) throw new TypeError(`allowedDomains[${i}] is not a valid domain: ${JSON.stringify(entry)}`);
1374
- const labels = entry.split(".");
1375
- for (const label of labels) if (label.length === 0 || label.length > 63 || label.startsWith("-") || label.endsWith("-") || !/^[a-zA-Z0-9-]+$/.test(label)) throw new TypeError(`allowedDomains[${i}] is not a valid domain: ${JSON.stringify(entry)}`);
1376
- if (labels.length === 4 && labels.every((label) => /^[0-9]+$/.test(label))) throw new TypeError(`allowedDomains[${i}] is not a valid domain: ${JSON.stringify(entry)}`);
1386
+ if (allowedDomains != null) {
1387
+ if (allowedDomains.length === 0) throw new TypeError("allowedDomains must not be empty.");
1388
+ for (let i = 0; i < allowedDomains.length; i++) {
1389
+ const entry = allowedDomains[i];
1390
+ if (typeof entry !== "string") throw new TypeError(`allowedDomains[${i}] must be a string, got ${typeof entry}.`);
1391
+ if (entry !== entry.trim()) throw new TypeError(`allowedDomains[${i}] must not have leading or trailing whitespace: ${JSON.stringify(entry)}`);
1392
+ if (entry.startsWith("@")) throw new TypeError(`allowedDomains[${i}] must not start with "@": ${JSON.stringify(entry)}`);
1393
+ if (entry === "" || !entry.includes(".")) throw new TypeError(`allowedDomains[${i}] is not a valid domain: ${JSON.stringify(entry)}`);
1394
+ if (entry.startsWith(".") || entry.endsWith(".") || entry.startsWith("-") || entry.endsWith("-")) throw new TypeError(`allowedDomains[${i}] is not a valid domain: ${JSON.stringify(entry)}`);
1395
+ const labels = entry.split(".");
1396
+ for (const label of labels) if (label.length === 0 || label.length > 63 || label.startsWith("-") || label.endsWith("-") || !/^[a-zA-Z0-9-]+$/.test(label)) throw new TypeError(`allowedDomains[${i}] is not a valid domain: ${JSON.stringify(entry)}`);
1397
+ if (labels.length === 4 && labels.every((label) => /^[0-9]+$/.test(label))) throw new TypeError(`allowedDomains[${i}] is not a valid domain: ${JSON.stringify(entry)}`);
1398
+ }
1377
1399
  }
1378
1400
  const invalidEmail = options?.errors?.invalidEmail;
1379
1401
  const domainNotAllowed = options?.errors?.domainNotAllowed;
@@ -1489,7 +1511,12 @@ function email(options) {
1489
1511
  },
1490
1512
  {
1491
1513
  type: "text",
1492
- text: ` is not allowed. Allowed domains: ${allowedDomains.join(", ")}.`
1514
+ text: " is not allowed. Allowed domains: "
1515
+ },
1516
+ ...valueSet(allowedDomains, { locale: "en-US" }),
1517
+ {
1518
+ type: "text",
1519
+ text: "."
1493
1520
  }
1494
1521
  ];
1495
1522
  return {
@@ -1535,7 +1562,12 @@ function email(options) {
1535
1562
  },
1536
1563
  {
1537
1564
  type: "text",
1538
- text: ` is not allowed. Allowed domains: ${allowedDomains.join(", ")}.`
1565
+ text: " is not allowed. Allowed domains: "
1566
+ },
1567
+ ...valueSet(allowedDomains, { locale: "en-US" }),
1568
+ {
1569
+ type: "text",
1570
+ text: "."
1539
1571
  }
1540
1572
  ];
1541
1573
  return {
@@ -1849,8 +1881,8 @@ function macAddress(options) {
1849
1881
  const caseOption = options?.case ?? "preserve";
1850
1882
  const outputSeparator = options?.outputSeparator;
1851
1883
  const metavar = options?.metavar ?? "MAC";
1852
- const colonRegex = /^([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2})$/;
1853
- const hyphenRegex = /^([0-9a-fA-F]{1,2})-([0-9a-fA-F]{1,2})-([0-9a-fA-F]{1,2})-([0-9a-fA-F]{1,2})-([0-9a-fA-F]{1,2})-([0-9a-fA-F]{1,2})$/;
1884
+ const colonRegex = /^([0-9a-fA-F]{2}):([0-9a-fA-F]{2}):([0-9a-fA-F]{2}):([0-9a-fA-F]{2}):([0-9a-fA-F]{2}):([0-9a-fA-F]{2})$/;
1885
+ const hyphenRegex = /^([0-9a-fA-F]{2})-([0-9a-fA-F]{2})-([0-9a-fA-F]{2})-([0-9a-fA-F]{2})-([0-9a-fA-F]{2})-([0-9a-fA-F]{2})$/;
1854
1886
  const dotRegex = /^([0-9a-fA-F]{4})\.([0-9a-fA-F]{4})\.([0-9a-fA-F]{4})$/;
1855
1887
  const noneRegex = /^([0-9a-fA-F]{12})$/;
1856
1888
  return {
@@ -1983,15 +2015,18 @@ function domain(options) {
1983
2015
  const allowSubdomains = options?.allowSubdomains ?? true;
1984
2016
  const allowedTlds = options?.allowedTlds != null ? Object.freeze([...options.allowedTlds]) : void 0;
1985
2017
  const labelRegex = /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/;
1986
- if (allowedTlds !== void 0) for (const [i, tld] of allowedTlds.entries()) {
1987
- if (typeof tld !== "string") {
1988
- const actualType = Array.isArray(tld) ? "array" : typeof tld;
1989
- throw new TypeError(`allowedTlds[${i}] must be a string, but got ${actualType}.`);
2018
+ if (allowedTlds !== void 0) {
2019
+ if (allowedTlds.length === 0) throw new TypeError("allowedTlds must not be empty.");
2020
+ for (const [i, tld] of allowedTlds.entries()) {
2021
+ if (typeof tld !== "string") {
2022
+ const actualType = Array.isArray(tld) ? "array" : typeof tld;
2023
+ throw new TypeError(`allowedTlds[${i}] must be a string, but got ${actualType}.`);
2024
+ }
2025
+ if (tld.length === 0) throw new TypeError(`allowedTlds[${i}] must not be an empty string.`);
2026
+ if (tld.includes(".")) throw new TypeError(`allowedTlds[${i}] must not contain dots: ${JSON.stringify(tld)}.`);
2027
+ if (tld !== tld.trim()) throw new TypeError(`allowedTlds[${i}] must not have leading or trailing whitespace: ${JSON.stringify(tld)}.`);
2028
+ if (!labelRegex.test(tld)) throw new TypeError(`allowedTlds[${i}] is not a valid DNS label: ${JSON.stringify(tld)}.`);
1990
2029
  }
1991
- if (tld.length === 0) throw new TypeError(`allowedTlds[${i}] must not be an empty string.`);
1992
- if (tld.includes(".")) throw new TypeError(`allowedTlds[${i}] must not contain dots: ${JSON.stringify(tld)}.`);
1993
- if (tld !== tld.trim()) throw new TypeError(`allowedTlds[${i}] must not have leading or trailing whitespace: ${JSON.stringify(tld)}.`);
1994
- if (!labelRegex.test(tld)) throw new TypeError(`allowedTlds[${i}] is not a valid DNS label: ${JSON.stringify(tld)}.`);
1995
2030
  }
1996
2031
  const allowedTldsLower = allowedTlds != null ? Object.freeze(allowedTlds.map((t) => t.toLowerCase())) : void 0;
1997
2032
  const minLabels = options?.minLabels ?? 2;
@@ -2188,7 +2223,12 @@ function domain(options) {
2188
2223
  },
2189
2224
  {
2190
2225
  type: "text",
2191
- text: ` is not allowed. Allowed TLDs: ${allowedTlds.join(", ")}.`
2226
+ text: " is not allowed. Allowed TLDs: "
2227
+ },
2228
+ ...valueSet(allowedTlds, { locale: "en-US" }),
2229
+ {
2230
+ type: "text",
2231
+ text: "."
2192
2232
  }
2193
2233
  ];
2194
2234
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "1.0.0-dev.1252+eebac476",
3
+ "version": "1.0.0-dev.1265+4c1a69a0",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",