@optique/core 1.0.0-dev.670 → 1.0.0-dev.679

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.
@@ -610,7 +610,7 @@ function longestMatch(...args) {
610
610
  * @internal
611
611
  */
612
612
  function* suggestObjectSync(context, prefix, parserPairs) {
613
- const registry = context.dependencyRegistry instanceof require_dependency.DependencyRegistry ? context.dependencyRegistry : new require_dependency.DependencyRegistry();
613
+ const registry = context.dependencyRegistry ? context.dependencyRegistry.clone() : new require_dependency.DependencyRegistry();
614
614
  if (context.state && typeof context.state === "object") collectDependencies(context.state, registry);
615
615
  const contextWithRegistry = {
616
616
  ...context,
@@ -643,7 +643,7 @@ function* suggestObjectSync(context, prefix, parserPairs) {
643
643
  * @internal
644
644
  */
645
645
  async function* suggestObjectAsync(context, prefix, parserPairs) {
646
- const registry = context.dependencyRegistry instanceof require_dependency.DependencyRegistry ? context.dependencyRegistry : new require_dependency.DependencyRegistry();
646
+ const registry = context.dependencyRegistry ? context.dependencyRegistry.clone() : new require_dependency.DependencyRegistry();
647
647
  if (context.state && typeof context.state === "object") collectDependencies(context.state, registry);
648
648
  const contextWithRegistry = {
649
649
  ...context,
@@ -673,17 +673,9 @@ async function* suggestObjectAsync(context, prefix, parserPairs) {
673
673
  yield* require_suggestion.deduplicateSuggestions(suggestions);
674
674
  }
675
675
  /**
676
- * Resolves deferred parse states in an object's field states.
677
- * This function builds a dependency registry from DependencySourceState fields
678
- * and re-parses DeferredParseState fields using the actual dependency values.
679
- *
680
- * @param fieldStates A record of field names to their state values
681
- * @returns The field states with deferred states resolved to their actual values
682
- * @internal
683
- */
684
- /**
685
676
  * Recursively collects dependency values from DependencySourceState objects
686
677
  * found anywhere in the state tree.
678
+ * @internal
687
679
  */
688
680
  function collectDependencies(state, registry, visited = /* @__PURE__ */ new WeakSet()) {
689
681
  if (state === null || state === void 0) return;
@@ -1687,13 +1679,19 @@ function merge(...args) {
1687
1679
  }
1688
1680
  return p.initialState;
1689
1681
  };
1682
+ const registry = context.dependencyRegistry ? context.dependencyRegistry.clone() : new require_dependency.DependencyRegistry();
1683
+ if (context.state && typeof context.state === "object") collectDependencies(context.state, registry);
1684
+ const contextWithRegistry = {
1685
+ ...context,
1686
+ dependencyRegistry: registry
1687
+ };
1690
1688
  if (isAsync) return async function* () {
1691
1689
  const suggestions = [];
1692
1690
  for (let i = 0; i < parsers.length; i++) {
1693
1691
  const parser = parsers[i];
1694
1692
  const parserState = extractState(parser, i);
1695
1693
  const parserSuggestions = parser.suggest({
1696
- ...context,
1694
+ ...contextWithRegistry,
1697
1695
  state: parserState
1698
1696
  }, prefix);
1699
1697
  if (parser.$mode === "async") for await (const s of parserSuggestions) suggestions.push(s);
@@ -1707,7 +1705,7 @@ function merge(...args) {
1707
1705
  const parser = syncParsers[i];
1708
1706
  const parserState = extractState(parser, i);
1709
1707
  const parserSuggestions = parser.suggest({
1710
- ...context,
1708
+ ...contextWithRegistry,
1711
1709
  state: parserState
1712
1710
  }, prefix);
1713
1711
  suggestions.push(...parserSuggestions);
@@ -1777,6 +1775,118 @@ function merge(...args) {
1777
1775
  }
1778
1776
  };
1779
1777
  }
1778
+ /**
1779
+ * Builds a dependency registry from the pre-parsed context state and returns
1780
+ * the enriched context alongside the state array. Used by both the sync and
1781
+ * async branches of `concat().suggest()`.
1782
+ * @internal
1783
+ */
1784
+ function buildSuggestRegistry(preParsedContext) {
1785
+ const stateArray = preParsedContext.state;
1786
+ const registry = preParsedContext.dependencyRegistry ? preParsedContext.dependencyRegistry.clone() : new require_dependency.DependencyRegistry();
1787
+ if (stateArray && Array.isArray(stateArray)) collectDependencies(stateArray, registry);
1788
+ return {
1789
+ context: {
1790
+ ...preParsedContext,
1791
+ dependencyRegistry: registry
1792
+ },
1793
+ stateArray
1794
+ };
1795
+ }
1796
+ /**
1797
+ * This helper replays child parsers in priority order (mirroring
1798
+ * `concat.parse()`) to accumulate dependency source values for suggestions.
1799
+ * @internal
1800
+ */
1801
+ function preParseSuggestContext(context, parsers) {
1802
+ if (context.buffer.length < 1 || !Array.isArray(context.state)) return context;
1803
+ return preParseSuggestLoop(context, context.state.slice(), parsers);
1804
+ }
1805
+ /**
1806
+ * Async variant of {@link preParseSuggestContext} that awaits async child
1807
+ * parsers so that dependency sources from async sub-parsers are resolved.
1808
+ * @internal
1809
+ */
1810
+ async function preParseSuggestContextAsync(context, parsers) {
1811
+ if (context.buffer.length < 1 || !Array.isArray(context.state)) return context;
1812
+ return await preParseSuggestLoop(context, context.state.slice(), parsers);
1813
+ }
1814
+ /**
1815
+ * Shared loop for sync and async concat suggest pre-parse. When a child
1816
+ * parser returns a Promise its result is awaited; sync results are used
1817
+ * directly. Parsers are tried in priority order, matching `concat.parse()`.
1818
+ * @internal
1819
+ */
1820
+ function preParseSuggestLoop(context, stateArray, parsers, matchedParsers = /* @__PURE__ */ new Set()) {
1821
+ const indexedParsers = parsers.map((parser, index) => [parser, index]);
1822
+ let currentContext = context;
1823
+ let changed = true;
1824
+ while (changed && currentContext.buffer.length > 0) {
1825
+ changed = false;
1826
+ const remaining = indexedParsers.filter(([_, index]) => !matchedParsers.has(index)).sort(([a], [b]) => b.priority - a.priority);
1827
+ const tried = tryParseSuggestList(currentContext, stateArray, parsers, matchedParsers, remaining);
1828
+ if (tried === null) continue;
1829
+ if (typeof tried === "object" && "then" in tried && typeof tried.then === "function") return tried;
1830
+ currentContext = tried;
1831
+ changed = true;
1832
+ }
1833
+ return {
1834
+ ...currentContext,
1835
+ state: stateArray
1836
+ };
1837
+ }
1838
+ /**
1839
+ * Tries each parser in `remaining` once. Returns the updated context if a
1840
+ * parser consumed input (sync), a Promise that resolves to a context if an
1841
+ * async parser was encountered, or `null` if no parser consumed.
1842
+ * @internal
1843
+ */
1844
+ function tryParseSuggestList(context, stateArray, parsers, matchedParsers, remaining) {
1845
+ for (let ri = 0; ri < remaining.length; ri++) {
1846
+ const [parser, index] = remaining[ri];
1847
+ const parserState = index < stateArray.length ? stateArray[index] : parser.initialState;
1848
+ const resultOrPromise = parser.parse({
1849
+ ...context,
1850
+ state: parserState
1851
+ });
1852
+ if (resultOrPromise != null && typeof resultOrPromise === "object" && "then" in resultOrPromise && typeof resultOrPromise.then === "function") {
1853
+ const tail = remaining.slice(ri + 1);
1854
+ return resultOrPromise.then((result$1) => {
1855
+ if (result$1.success && result$1.consumed.length > 0) {
1856
+ stateArray[index] = result$1.next.state;
1857
+ matchedParsers.add(index);
1858
+ return preParseSuggestLoop({
1859
+ ...context,
1860
+ buffer: result$1.next.buffer,
1861
+ optionsTerminated: result$1.next.optionsTerminated,
1862
+ state: stateArray
1863
+ }, stateArray, parsers, matchedParsers);
1864
+ }
1865
+ const next = tryParseSuggestList(context, stateArray, parsers, matchedParsers, tail);
1866
+ if (next === null) return {
1867
+ ...context,
1868
+ state: stateArray
1869
+ };
1870
+ if (typeof next === "object" && "then" in next && typeof next.then === "function") return next.then((ctx) => ctx.buffer.length < context.buffer.length ? preParseSuggestLoop(ctx, stateArray, parsers, matchedParsers) : ctx);
1871
+ const nextCtx = next;
1872
+ if (nextCtx.buffer.length < context.buffer.length) return preParseSuggestLoop(nextCtx, stateArray, parsers, matchedParsers);
1873
+ return nextCtx;
1874
+ });
1875
+ }
1876
+ const result = resultOrPromise;
1877
+ if (result.success && result.consumed.length > 0) {
1878
+ stateArray[index] = result.next.state;
1879
+ matchedParsers.add(index);
1880
+ return {
1881
+ ...context,
1882
+ buffer: result.next.buffer,
1883
+ optionsTerminated: result.next.optionsTerminated,
1884
+ state: stateArray
1885
+ };
1886
+ }
1887
+ }
1888
+ return null;
1889
+ }
1780
1890
  function concat(...parsers) {
1781
1891
  const combinedMode = parsers.some((p) => p.$mode === "async") ? "async" : "sync";
1782
1892
  const isAsync = combinedMode === "async";
@@ -1960,14 +2070,15 @@ function concat(...parsers) {
1960
2070
  return completeSync(state);
1961
2071
  },
1962
2072
  suggest(context, prefix) {
1963
- const stateArray = context.state;
1964
2073
  if (isAsync) return async function* () {
2074
+ const preParsedContext$1 = await preParseSuggestContextAsync(context, parsers);
2075
+ const { context: contextWithRegistry$1, stateArray: stateArray$1 } = buildSuggestRegistry(preParsedContext$1);
1965
2076
  const suggestions = [];
1966
2077
  for (let i = 0; i < parsers.length; i++) {
1967
2078
  const parser = parsers[i];
1968
- const parserState = stateArray && Array.isArray(stateArray) ? stateArray[i] : parser.initialState;
2079
+ const parserState = stateArray$1 && Array.isArray(stateArray$1) ? stateArray$1[i] : parser.initialState;
1969
2080
  const parserSuggestions = parser.suggest({
1970
- ...context,
2081
+ ...contextWithRegistry$1,
1971
2082
  state: parserState
1972
2083
  }, prefix);
1973
2084
  if (parser.$mode === "async") for await (const s of parserSuggestions) suggestions.push(s);
@@ -1975,13 +2086,15 @@ function concat(...parsers) {
1975
2086
  }
1976
2087
  yield* require_suggestion.deduplicateSuggestions(suggestions);
1977
2088
  }();
2089
+ const preParsedContext = preParseSuggestContext(context, syncParsers);
2090
+ const { context: contextWithRegistry, stateArray } = buildSuggestRegistry(preParsedContext);
1978
2091
  return function* () {
1979
2092
  const suggestions = [];
1980
2093
  for (let i = 0; i < syncParsers.length; i++) {
1981
2094
  const parser = syncParsers[i];
1982
2095
  const parserState = stateArray && Array.isArray(stateArray) ? stateArray[i] : parser.initialState;
1983
2096
  const parserSuggestions = parser.suggest({
1984
- ...context,
2097
+ ...contextWithRegistry,
1985
2098
  state: parserState
1986
2099
  }, prefix);
1987
2100
  suggestions.push(...parserSuggestions);
@@ -610,7 +610,7 @@ function longestMatch(...args) {
610
610
  * @internal
611
611
  */
612
612
  function* suggestObjectSync(context, prefix, parserPairs) {
613
- const registry = context.dependencyRegistry instanceof DependencyRegistry ? context.dependencyRegistry : new DependencyRegistry();
613
+ const registry = context.dependencyRegistry ? context.dependencyRegistry.clone() : new DependencyRegistry();
614
614
  if (context.state && typeof context.state === "object") collectDependencies(context.state, registry);
615
615
  const contextWithRegistry = {
616
616
  ...context,
@@ -643,7 +643,7 @@ function* suggestObjectSync(context, prefix, parserPairs) {
643
643
  * @internal
644
644
  */
645
645
  async function* suggestObjectAsync(context, prefix, parserPairs) {
646
- const registry = context.dependencyRegistry instanceof DependencyRegistry ? context.dependencyRegistry : new DependencyRegistry();
646
+ const registry = context.dependencyRegistry ? context.dependencyRegistry.clone() : new DependencyRegistry();
647
647
  if (context.state && typeof context.state === "object") collectDependencies(context.state, registry);
648
648
  const contextWithRegistry = {
649
649
  ...context,
@@ -673,17 +673,9 @@ async function* suggestObjectAsync(context, prefix, parserPairs) {
673
673
  yield* deduplicateSuggestions(suggestions);
674
674
  }
675
675
  /**
676
- * Resolves deferred parse states in an object's field states.
677
- * This function builds a dependency registry from DependencySourceState fields
678
- * and re-parses DeferredParseState fields using the actual dependency values.
679
- *
680
- * @param fieldStates A record of field names to their state values
681
- * @returns The field states with deferred states resolved to their actual values
682
- * @internal
683
- */
684
- /**
685
676
  * Recursively collects dependency values from DependencySourceState objects
686
677
  * found anywhere in the state tree.
678
+ * @internal
687
679
  */
688
680
  function collectDependencies(state, registry, visited = /* @__PURE__ */ new WeakSet()) {
689
681
  if (state === null || state === void 0) return;
@@ -1687,13 +1679,19 @@ function merge(...args) {
1687
1679
  }
1688
1680
  return p.initialState;
1689
1681
  };
1682
+ const registry = context.dependencyRegistry ? context.dependencyRegistry.clone() : new DependencyRegistry();
1683
+ if (context.state && typeof context.state === "object") collectDependencies(context.state, registry);
1684
+ const contextWithRegistry = {
1685
+ ...context,
1686
+ dependencyRegistry: registry
1687
+ };
1690
1688
  if (isAsync) return async function* () {
1691
1689
  const suggestions = [];
1692
1690
  for (let i = 0; i < parsers.length; i++) {
1693
1691
  const parser = parsers[i];
1694
1692
  const parserState = extractState(parser, i);
1695
1693
  const parserSuggestions = parser.suggest({
1696
- ...context,
1694
+ ...contextWithRegistry,
1697
1695
  state: parserState
1698
1696
  }, prefix);
1699
1697
  if (parser.$mode === "async") for await (const s of parserSuggestions) suggestions.push(s);
@@ -1707,7 +1705,7 @@ function merge(...args) {
1707
1705
  const parser = syncParsers[i];
1708
1706
  const parserState = extractState(parser, i);
1709
1707
  const parserSuggestions = parser.suggest({
1710
- ...context,
1708
+ ...contextWithRegistry,
1711
1709
  state: parserState
1712
1710
  }, prefix);
1713
1711
  suggestions.push(...parserSuggestions);
@@ -1777,6 +1775,118 @@ function merge(...args) {
1777
1775
  }
1778
1776
  };
1779
1777
  }
1778
+ /**
1779
+ * Builds a dependency registry from the pre-parsed context state and returns
1780
+ * the enriched context alongside the state array. Used by both the sync and
1781
+ * async branches of `concat().suggest()`.
1782
+ * @internal
1783
+ */
1784
+ function buildSuggestRegistry(preParsedContext) {
1785
+ const stateArray = preParsedContext.state;
1786
+ const registry = preParsedContext.dependencyRegistry ? preParsedContext.dependencyRegistry.clone() : new DependencyRegistry();
1787
+ if (stateArray && Array.isArray(stateArray)) collectDependencies(stateArray, registry);
1788
+ return {
1789
+ context: {
1790
+ ...preParsedContext,
1791
+ dependencyRegistry: registry
1792
+ },
1793
+ stateArray
1794
+ };
1795
+ }
1796
+ /**
1797
+ * This helper replays child parsers in priority order (mirroring
1798
+ * `concat.parse()`) to accumulate dependency source values for suggestions.
1799
+ * @internal
1800
+ */
1801
+ function preParseSuggestContext(context, parsers) {
1802
+ if (context.buffer.length < 1 || !Array.isArray(context.state)) return context;
1803
+ return preParseSuggestLoop(context, context.state.slice(), parsers);
1804
+ }
1805
+ /**
1806
+ * Async variant of {@link preParseSuggestContext} that awaits async child
1807
+ * parsers so that dependency sources from async sub-parsers are resolved.
1808
+ * @internal
1809
+ */
1810
+ async function preParseSuggestContextAsync(context, parsers) {
1811
+ if (context.buffer.length < 1 || !Array.isArray(context.state)) return context;
1812
+ return await preParseSuggestLoop(context, context.state.slice(), parsers);
1813
+ }
1814
+ /**
1815
+ * Shared loop for sync and async concat suggest pre-parse. When a child
1816
+ * parser returns a Promise its result is awaited; sync results are used
1817
+ * directly. Parsers are tried in priority order, matching `concat.parse()`.
1818
+ * @internal
1819
+ */
1820
+ function preParseSuggestLoop(context, stateArray, parsers, matchedParsers = /* @__PURE__ */ new Set()) {
1821
+ const indexedParsers = parsers.map((parser, index) => [parser, index]);
1822
+ let currentContext = context;
1823
+ let changed = true;
1824
+ while (changed && currentContext.buffer.length > 0) {
1825
+ changed = false;
1826
+ const remaining = indexedParsers.filter(([_, index]) => !matchedParsers.has(index)).sort(([a], [b]) => b.priority - a.priority);
1827
+ const tried = tryParseSuggestList(currentContext, stateArray, parsers, matchedParsers, remaining);
1828
+ if (tried === null) continue;
1829
+ if (typeof tried === "object" && "then" in tried && typeof tried.then === "function") return tried;
1830
+ currentContext = tried;
1831
+ changed = true;
1832
+ }
1833
+ return {
1834
+ ...currentContext,
1835
+ state: stateArray
1836
+ };
1837
+ }
1838
+ /**
1839
+ * Tries each parser in `remaining` once. Returns the updated context if a
1840
+ * parser consumed input (sync), a Promise that resolves to a context if an
1841
+ * async parser was encountered, or `null` if no parser consumed.
1842
+ * @internal
1843
+ */
1844
+ function tryParseSuggestList(context, stateArray, parsers, matchedParsers, remaining) {
1845
+ for (let ri = 0; ri < remaining.length; ri++) {
1846
+ const [parser, index] = remaining[ri];
1847
+ const parserState = index < stateArray.length ? stateArray[index] : parser.initialState;
1848
+ const resultOrPromise = parser.parse({
1849
+ ...context,
1850
+ state: parserState
1851
+ });
1852
+ if (resultOrPromise != null && typeof resultOrPromise === "object" && "then" in resultOrPromise && typeof resultOrPromise.then === "function") {
1853
+ const tail = remaining.slice(ri + 1);
1854
+ return resultOrPromise.then((result$1) => {
1855
+ if (result$1.success && result$1.consumed.length > 0) {
1856
+ stateArray[index] = result$1.next.state;
1857
+ matchedParsers.add(index);
1858
+ return preParseSuggestLoop({
1859
+ ...context,
1860
+ buffer: result$1.next.buffer,
1861
+ optionsTerminated: result$1.next.optionsTerminated,
1862
+ state: stateArray
1863
+ }, stateArray, parsers, matchedParsers);
1864
+ }
1865
+ const next = tryParseSuggestList(context, stateArray, parsers, matchedParsers, tail);
1866
+ if (next === null) return {
1867
+ ...context,
1868
+ state: stateArray
1869
+ };
1870
+ if (typeof next === "object" && "then" in next && typeof next.then === "function") return next.then((ctx) => ctx.buffer.length < context.buffer.length ? preParseSuggestLoop(ctx, stateArray, parsers, matchedParsers) : ctx);
1871
+ const nextCtx = next;
1872
+ if (nextCtx.buffer.length < context.buffer.length) return preParseSuggestLoop(nextCtx, stateArray, parsers, matchedParsers);
1873
+ return nextCtx;
1874
+ });
1875
+ }
1876
+ const result = resultOrPromise;
1877
+ if (result.success && result.consumed.length > 0) {
1878
+ stateArray[index] = result.next.state;
1879
+ matchedParsers.add(index);
1880
+ return {
1881
+ ...context,
1882
+ buffer: result.next.buffer,
1883
+ optionsTerminated: result.next.optionsTerminated,
1884
+ state: stateArray
1885
+ };
1886
+ }
1887
+ }
1888
+ return null;
1889
+ }
1780
1890
  function concat(...parsers) {
1781
1891
  const combinedMode = parsers.some((p) => p.$mode === "async") ? "async" : "sync";
1782
1892
  const isAsync = combinedMode === "async";
@@ -1960,14 +2070,15 @@ function concat(...parsers) {
1960
2070
  return completeSync(state);
1961
2071
  },
1962
2072
  suggest(context, prefix) {
1963
- const stateArray = context.state;
1964
2073
  if (isAsync) return async function* () {
2074
+ const preParsedContext$1 = await preParseSuggestContextAsync(context, parsers);
2075
+ const { context: contextWithRegistry$1, stateArray: stateArray$1 } = buildSuggestRegistry(preParsedContext$1);
1965
2076
  const suggestions = [];
1966
2077
  for (let i = 0; i < parsers.length; i++) {
1967
2078
  const parser = parsers[i];
1968
- const parserState = stateArray && Array.isArray(stateArray) ? stateArray[i] : parser.initialState;
2079
+ const parserState = stateArray$1 && Array.isArray(stateArray$1) ? stateArray$1[i] : parser.initialState;
1969
2080
  const parserSuggestions = parser.suggest({
1970
- ...context,
2081
+ ...contextWithRegistry$1,
1971
2082
  state: parserState
1972
2083
  }, prefix);
1973
2084
  if (parser.$mode === "async") for await (const s of parserSuggestions) suggestions.push(s);
@@ -1975,13 +2086,15 @@ function concat(...parsers) {
1975
2086
  }
1976
2087
  yield* deduplicateSuggestions(suggestions);
1977
2088
  }();
2089
+ const preParsedContext = preParseSuggestContext(context, syncParsers);
2090
+ const { context: contextWithRegistry, stateArray } = buildSuggestRegistry(preParsedContext);
1978
2091
  return function* () {
1979
2092
  const suggestions = [];
1980
2093
  for (let i = 0; i < syncParsers.length; i++) {
1981
2094
  const parser = syncParsers[i];
1982
2095
  const parserState = stateArray && Array.isArray(stateArray) ? stateArray[i] : parser.initialState;
1983
2096
  const parserSuggestions = parser.suggest({
1984
- ...context,
2097
+ ...contextWithRegistry,
1985
2098
  state: parserState
1986
2099
  }, prefix);
1987
2100
  suggestions.push(...parserSuggestions);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "1.0.0-dev.670+a142c6c9",
3
+ "version": "1.0.0-dev.679+b8bf2b3d",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",