@optique/core 1.2.8 → 1.2.10

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.
@@ -6,6 +6,7 @@ import { dispatchByMode, dispatchIterableByMode, wrapForMode } from "./internal/
6
6
  import { getDefaultValuesFunction, getDependencyIds, getSnapshottedDefaultDependencyValues, isDerivedValueParser, suggestWithDependency } from "./internal/dependency.js";
7
7
  import { replayDerivedParser, replayDerivedParserAsync } from "./dependency-runtime.js";
8
8
  import { getWrappedChildParseState, getWrappedChildState, isAnnotationWrappedInitialState, normalizeInjectedAnnotationState } from "./annotation-state.js";
9
+ import { defineKnownCompletion, defineOptionMatch, definePassThroughPriority, getOptionMatch, getPassThroughFailure, getPassThroughPriority } from "./internal/passthrough.js";
9
10
  import { hiddenCommandAliasesKey } from "./internal/command-alias.js";
10
11
  import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
11
12
  import { completeOrExtractPhase2Seed, extractPhase2SeedKey } from "./phase2-seed.js";
@@ -145,6 +146,7 @@ function constant(value) {
145
146
  return { fragments: [] };
146
147
  }
147
148
  };
149
+ defineKnownCompletion(result, (state) => normalizeInjectedAnnotationState(state));
148
150
  Object.defineProperty(result, "placeholder", {
149
151
  value,
150
152
  configurable: true,
@@ -584,10 +586,15 @@ function option(...args) {
584
586
  }
585
587
  const invalidOption = context.buffer[0];
586
588
  if (options.errors?.noMatch) {
589
+ if (typeof options.errors.noMatch !== "function") return {
590
+ success: false,
591
+ consumed: 0,
592
+ error: options.errors.noMatch
593
+ };
587
594
  const candidates = /* @__PURE__ */ new Set();
588
595
  for (const name of extractOptionNames(context.usage)) candidates.add(name);
589
596
  const suggestions = findSimilar(invalidOption, candidates, DEFAULT_FIND_SIMILAR_OPTIONS);
590
- const errorMessage = typeof options.errors.noMatch === "function" ? options.errors.noMatch(invalidOption, suggestions) : options.errors.noMatch;
597
+ const errorMessage = options.errors.noMatch(invalidOption, suggestions);
591
598
  return {
592
599
  success: false,
593
600
  consumed: 0,
@@ -872,10 +879,15 @@ function flag(...args) {
872
879
  }
873
880
  const invalidOption = context.buffer[0];
874
881
  if (options.errors?.noMatch) {
882
+ if (typeof options.errors.noMatch !== "function") return {
883
+ success: false,
884
+ consumed: 0,
885
+ error: options.errors.noMatch
886
+ };
875
887
  const candidates = /* @__PURE__ */ new Set();
876
888
  for (const name of extractOptionNames(context.usage)) candidates.add(name);
877
889
  const suggestions = findSimilar(invalidOption, candidates, DEFAULT_FIND_SIMILAR_OPTIONS);
878
- const errorMessage = typeof options.errors.noMatch === "function" ? options.errors.noMatch(invalidOption, suggestions) : options.errors.noMatch;
890
+ const errorMessage = options.errors.noMatch(invalidOption, suggestions);
879
891
  return {
880
892
  success: false,
881
893
  consumed: 0,
@@ -1184,7 +1196,7 @@ function argument(valueParser, options = {}) {
1184
1196
  const syncValueParser = valueParser;
1185
1197
  const dependencyMetadata = extractDependencyMetadata(valueParser);
1186
1198
  const formatInvalidValueError = (error) => options.errors?.invalidValue ? typeof options.errors.invalidValue === "function" ? options.errors.invalidValue(error) : options.errors.invalidValue : message`${metavar(valueParser.metavar)}: ${error}`;
1187
- const optionPattern = /^--?[a-z0-9-]+$/i;
1199
+ const optionPattern = /^(?!--=)(--?[a-z0-9-]+)(?:=|$)/i;
1188
1200
  const term = {
1189
1201
  type: "argument",
1190
1202
  metavar: valueParser.metavar,
@@ -1211,14 +1223,15 @@ function argument(valueParser, options = {}) {
1211
1223
  };
1212
1224
  let i = 0;
1213
1225
  let optionsTerminated = context.optionsTerminated;
1214
- if (!optionsTerminated) {
1215
- if (context.buffer[i] === "--") {
1216
- optionsTerminated = true;
1217
- i++;
1218
- } else if (context.buffer[i].match(optionPattern)) return {
1226
+ if (!optionsTerminated) if (context.buffer[i] === "--") {
1227
+ optionsTerminated = true;
1228
+ i++;
1229
+ } else {
1230
+ const optionMatch = context.buffer[i].match(optionPattern);
1231
+ if (optionMatch != null) return {
1219
1232
  success: false,
1220
1233
  consumed: i,
1221
- error: message`Expected an argument, but got an option: ${optionName(context.buffer[i])}.`
1234
+ error: message`Expected an argument, but got an option: ${optionName(optionMatch[1])}.`
1222
1235
  };
1223
1236
  }
1224
1237
  if (context.buffer.length < i + 1) return {
@@ -1704,6 +1717,22 @@ function command(name, parser, options = {}) {
1704
1717
  configurable: true,
1705
1718
  enumerable: false
1706
1719
  });
1720
+ definePassThroughPriority(result, [parser], (state, token) => {
1721
+ const active = normalizeCommandState(state);
1722
+ if (active == null) return void 0;
1723
+ const childState = active[0] === "matched" ? parser.initialState : active[1];
1724
+ return getPassThroughPriority(parser, getCommandParseChildState(state, childState, parser), token);
1725
+ });
1726
+ defineOptionMatch(result, (state, token) => {
1727
+ const active = normalizeCommandState(state);
1728
+ if (active == null) return void 0;
1729
+ const childState = active[0] === "matched" ? parser.initialState : active[1];
1730
+ const match = getOptionMatch(parser, getCommandParseChildState(state, childState, parser), token);
1731
+ return match == null ? void 0 : {
1732
+ ...match,
1733
+ continuesCommand: true
1734
+ };
1735
+ });
1707
1736
  return fluent(result);
1708
1737
  }
1709
1738
  /**
@@ -1777,6 +1806,8 @@ function passThrough(options = {}) {
1777
1806
  consumed: 0,
1778
1807
  error: message`No input to pass through.`
1779
1808
  };
1809
+ const failure = getPassThroughFailure(context, this?.priority ?? -10);
1810
+ if (failure != null) return failure.failure;
1780
1811
  const token = context.buffer[0];
1781
1812
  if (format === "greedy") {
1782
1813
  const captured = [...context.buffer];
@@ -1888,6 +1919,11 @@ function passThrough(options = {}) {
1888
1919
  return `passThrough(${format})`;
1889
1920
  }
1890
1921
  };
1922
+ definePassThroughPriority(result, [result], (_state, token) => {
1923
+ if (token == null || format === "greedy") return result.priority;
1924
+ const accepts = format === "equalsOnly" ? equalsOptionPattern.test(token) : format === "nextToken" && optionPattern.test(token);
1925
+ return accepts ? result.priority : void 0;
1926
+ });
1891
1927
  return fluent(result);
1892
1928
  }
1893
1929
 
@@ -86,8 +86,10 @@ function findSimilar(input, candidates, options = {}) {
86
86
  const normalizedCandidate = caseSensitive ? candidate : candidate.toLowerCase();
87
87
  if (seen.has(candidate)) continue;
88
88
  seen.add(candidate);
89
+ if (normalizedInput === normalizedCandidate) return [candidate];
90
+ const minimumDistance = Math.abs(normalizedInput.length - normalizedCandidate.length);
91
+ if (minimumDistance > maxDistance || minimumDistance / input.length > maxDistanceRatio) continue;
89
92
  const distance = levenshteinDistance(normalizedInput, normalizedCandidate);
90
- if (distance === 0) return [candidate];
91
93
  const distanceRatio = distance / input.length;
92
94
  if (distance <= maxDistance && distanceRatio <= maxDistanceRatio) matches.push({
93
95
  candidate,
@@ -86,8 +86,10 @@ function findSimilar(input, candidates, options = {}) {
86
86
  const normalizedCandidate = caseSensitive ? candidate : candidate.toLowerCase();
87
87
  if (seen.has(candidate)) continue;
88
88
  seen.add(candidate);
89
+ if (normalizedInput === normalizedCandidate) return [candidate];
90
+ const minimumDistance = Math.abs(normalizedInput.length - normalizedCandidate.length);
91
+ if (minimumDistance > maxDistance || minimumDistance / input.length > maxDistanceRatio) continue;
89
92
  const distance = levenshteinDistance(normalizedInput, normalizedCandidate);
90
- if (distance === 0) return [candidate];
91
93
  const distanceRatio = distance / input.length;
92
94
  if (distance <= maxDistance && distanceRatio <= maxDistanceRatio) matches.push({
93
95
  candidate,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "1.2.8",
3
+ "version": "1.2.10",
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.2.8",
224
+ "@optique/env": "1.2.10",
225
225
  "@types/node": "^24.0.0",
226
226
  "fast-check": "^4.7.0",
227
227
  "tsdown": "^0.13.0",