@optique/core 1.1.8 → 1.1.9

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 @@ const require_mode_dispatch = require('./internal/mode-dispatch.cjs');
6
6
  const require_internal_dependency = require('./internal/dependency.cjs');
7
7
  const require_dependency_runtime = require('./dependency-runtime.cjs');
8
8
  const require_annotation_state = require('./annotation-state.cjs');
9
+ const require_passthrough = require('./internal/passthrough.cjs');
9
10
  const require_command_alias = require('./internal/command-alias.cjs');
10
11
  const require_execution_context = require('./execution-context.cjs');
11
12
  const require_phase2_seed = require('./phase2-seed.cjs');
@@ -144,6 +145,7 @@ function constant(value) {
144
145
  return { fragments: [] };
145
146
  }
146
147
  };
148
+ require_passthrough.defineKnownCompletion(result, (state) => require_annotation_state.normalizeInjectedAnnotationState(state));
147
149
  Object.defineProperty(result, "placeholder", {
148
150
  value,
149
151
  configurable: true,
@@ -583,10 +585,15 @@ function option(...args) {
583
585
  }
584
586
  const invalidOption = context.buffer[0];
585
587
  if (options.errors?.noMatch) {
588
+ if (typeof options.errors.noMatch !== "function") return {
589
+ success: false,
590
+ consumed: 0,
591
+ error: options.errors.noMatch
592
+ };
586
593
  const candidates = /* @__PURE__ */ new Set();
587
594
  for (const name of require_usage.extractOptionNames(context.usage)) candidates.add(name);
588
595
  const suggestions = require_suggestion.findSimilar(invalidOption, candidates, require_suggestion.DEFAULT_FIND_SIMILAR_OPTIONS);
589
- const errorMessage = typeof options.errors.noMatch === "function" ? options.errors.noMatch(invalidOption, suggestions) : options.errors.noMatch;
596
+ const errorMessage = options.errors.noMatch(invalidOption, suggestions);
590
597
  return {
591
598
  success: false,
592
599
  consumed: 0,
@@ -871,10 +878,15 @@ function flag(...args) {
871
878
  }
872
879
  const invalidOption = context.buffer[0];
873
880
  if (options.errors?.noMatch) {
881
+ if (typeof options.errors.noMatch !== "function") return {
882
+ success: false,
883
+ consumed: 0,
884
+ error: options.errors.noMatch
885
+ };
874
886
  const candidates = /* @__PURE__ */ new Set();
875
887
  for (const name of require_usage.extractOptionNames(context.usage)) candidates.add(name);
876
888
  const suggestions = require_suggestion.findSimilar(invalidOption, candidates, require_suggestion.DEFAULT_FIND_SIMILAR_OPTIONS);
877
- const errorMessage = typeof options.errors.noMatch === "function" ? options.errors.noMatch(invalidOption, suggestions) : options.errors.noMatch;
889
+ const errorMessage = options.errors.noMatch(invalidOption, suggestions);
878
890
  return {
879
891
  success: false,
880
892
  consumed: 0,
@@ -1183,7 +1195,7 @@ function argument(valueParser, options = {}) {
1183
1195
  const syncValueParser = valueParser;
1184
1196
  const dependencyMetadata = require_dependency_metadata.extractDependencyMetadata(valueParser);
1185
1197
  const formatInvalidValueError = (error) => options.errors?.invalidValue ? typeof options.errors.invalidValue === "function" ? options.errors.invalidValue(error) : options.errors.invalidValue : require_message.message`${require_message.metavar(valueParser.metavar)}: ${error}`;
1186
- const optionPattern = /^--?[a-z0-9-]+$/i;
1198
+ const optionPattern = /^(?!--=)(--?[a-z0-9-]+)(?:=|$)/i;
1187
1199
  const term = {
1188
1200
  type: "argument",
1189
1201
  metavar: valueParser.metavar,
@@ -1210,14 +1222,15 @@ function argument(valueParser, options = {}) {
1210
1222
  };
1211
1223
  let i = 0;
1212
1224
  let optionsTerminated = context.optionsTerminated;
1213
- if (!optionsTerminated) {
1214
- if (context.buffer[i] === "--") {
1215
- optionsTerminated = true;
1216
- i++;
1217
- } else if (context.buffer[i].match(optionPattern)) return {
1225
+ if (!optionsTerminated) if (context.buffer[i] === "--") {
1226
+ optionsTerminated = true;
1227
+ i++;
1228
+ } else {
1229
+ const optionMatch = context.buffer[i].match(optionPattern);
1230
+ if (optionMatch != null) return {
1218
1231
  success: false,
1219
1232
  consumed: i,
1220
- error: require_message.message`Expected an argument, but got an option: ${require_message.optionName(context.buffer[i])}.`
1233
+ error: require_message.message`Expected an argument, but got an option: ${require_message.optionName(optionMatch[1])}.`
1221
1234
  };
1222
1235
  }
1223
1236
  if (context.buffer.length < i + 1) return {
@@ -1703,6 +1716,22 @@ function command(name, parser, options = {}) {
1703
1716
  configurable: true,
1704
1717
  enumerable: false
1705
1718
  });
1719
+ require_passthrough.definePassThroughPriority(result, [parser], (state, token) => {
1720
+ const active = normalizeCommandState(state);
1721
+ if (active == null) return void 0;
1722
+ const childState = active[0] === "matched" ? parser.initialState : active[1];
1723
+ return require_passthrough.getPassThroughPriority(parser, getCommandParseChildState(state, childState, parser), token);
1724
+ });
1725
+ require_passthrough.defineOptionMatch(result, (state, token) => {
1726
+ const active = normalizeCommandState(state);
1727
+ if (active == null) return void 0;
1728
+ const childState = active[0] === "matched" ? parser.initialState : active[1];
1729
+ const match = require_passthrough.getOptionMatch(parser, getCommandParseChildState(state, childState, parser), token);
1730
+ return match == null ? void 0 : {
1731
+ ...match,
1732
+ continuesCommand: true
1733
+ };
1734
+ });
1706
1735
  return result;
1707
1736
  }
1708
1737
  /**
@@ -1755,7 +1784,7 @@ function passThrough(options = {}) {
1755
1784
  const format = options.format ?? "equalsOnly";
1756
1785
  const optionPattern = /^-[a-z0-9-]|^--[a-z0-9-]+/i;
1757
1786
  const equalsOptionPattern = /^--[a-z0-9-]+=/i;
1758
- return {
1787
+ const result = {
1759
1788
  $valueType: [],
1760
1789
  $stateType: [],
1761
1790
  mode: "sync",
@@ -1776,6 +1805,8 @@ function passThrough(options = {}) {
1776
1805
  consumed: 0,
1777
1806
  error: require_message.message`No input to pass through.`
1778
1807
  };
1808
+ const failure = require_passthrough.getPassThroughFailure(context, this?.priority ?? -10);
1809
+ if (failure != null) return failure.failure;
1779
1810
  const token = context.buffer[0];
1780
1811
  if (format === "greedy") {
1781
1812
  const captured = [...context.buffer];
@@ -1887,6 +1918,12 @@ function passThrough(options = {}) {
1887
1918
  return `passThrough(${format})`;
1888
1919
  }
1889
1920
  };
1921
+ require_passthrough.definePassThroughPriority(result, [result], (_state, token) => {
1922
+ if (token == null || format === "greedy") return result.priority;
1923
+ const accepts = format === "equalsOnly" ? equalsOptionPattern.test(token) : format === "nextToken" && optionPattern.test(token);
1924
+ return accepts ? result.priority : void 0;
1925
+ });
1926
+ return result;
1890
1927
  }
1891
1928
 
1892
1929
  //#endregion
@@ -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";
@@ -144,6 +145,7 @@ function constant(value) {
144
145
  return { fragments: [] };
145
146
  }
146
147
  };
148
+ defineKnownCompletion(result, (state) => normalizeInjectedAnnotationState(state));
147
149
  Object.defineProperty(result, "placeholder", {
148
150
  value,
149
151
  configurable: true,
@@ -583,10 +585,15 @@ function option(...args) {
583
585
  }
584
586
  const invalidOption = context.buffer[0];
585
587
  if (options.errors?.noMatch) {
588
+ if (typeof options.errors.noMatch !== "function") return {
589
+ success: false,
590
+ consumed: 0,
591
+ error: options.errors.noMatch
592
+ };
586
593
  const candidates = /* @__PURE__ */ new Set();
587
594
  for (const name of extractOptionNames(context.usage)) candidates.add(name);
588
595
  const suggestions = findSimilar(invalidOption, candidates, DEFAULT_FIND_SIMILAR_OPTIONS);
589
- const errorMessage = typeof options.errors.noMatch === "function" ? options.errors.noMatch(invalidOption, suggestions) : options.errors.noMatch;
596
+ const errorMessage = options.errors.noMatch(invalidOption, suggestions);
590
597
  return {
591
598
  success: false,
592
599
  consumed: 0,
@@ -871,10 +878,15 @@ function flag(...args) {
871
878
  }
872
879
  const invalidOption = context.buffer[0];
873
880
  if (options.errors?.noMatch) {
881
+ if (typeof options.errors.noMatch !== "function") return {
882
+ success: false,
883
+ consumed: 0,
884
+ error: options.errors.noMatch
885
+ };
874
886
  const candidates = /* @__PURE__ */ new Set();
875
887
  for (const name of extractOptionNames(context.usage)) candidates.add(name);
876
888
  const suggestions = findSimilar(invalidOption, candidates, DEFAULT_FIND_SIMILAR_OPTIONS);
877
- const errorMessage = typeof options.errors.noMatch === "function" ? options.errors.noMatch(invalidOption, suggestions) : options.errors.noMatch;
889
+ const errorMessage = options.errors.noMatch(invalidOption, suggestions);
878
890
  return {
879
891
  success: false,
880
892
  consumed: 0,
@@ -1183,7 +1195,7 @@ function argument(valueParser, options = {}) {
1183
1195
  const syncValueParser = valueParser;
1184
1196
  const dependencyMetadata = extractDependencyMetadata(valueParser);
1185
1197
  const formatInvalidValueError = (error) => options.errors?.invalidValue ? typeof options.errors.invalidValue === "function" ? options.errors.invalidValue(error) : options.errors.invalidValue : message`${metavar(valueParser.metavar)}: ${error}`;
1186
- const optionPattern = /^--?[a-z0-9-]+$/i;
1198
+ const optionPattern = /^(?!--=)(--?[a-z0-9-]+)(?:=|$)/i;
1187
1199
  const term = {
1188
1200
  type: "argument",
1189
1201
  metavar: valueParser.metavar,
@@ -1210,14 +1222,15 @@ function argument(valueParser, options = {}) {
1210
1222
  };
1211
1223
  let i = 0;
1212
1224
  let optionsTerminated = context.optionsTerminated;
1213
- if (!optionsTerminated) {
1214
- if (context.buffer[i] === "--") {
1215
- optionsTerminated = true;
1216
- i++;
1217
- } else if (context.buffer[i].match(optionPattern)) return {
1225
+ if (!optionsTerminated) if (context.buffer[i] === "--") {
1226
+ optionsTerminated = true;
1227
+ i++;
1228
+ } else {
1229
+ const optionMatch = context.buffer[i].match(optionPattern);
1230
+ if (optionMatch != null) return {
1218
1231
  success: false,
1219
1232
  consumed: i,
1220
- error: message`Expected an argument, but got an option: ${optionName(context.buffer[i])}.`
1233
+ error: message`Expected an argument, but got an option: ${optionName(optionMatch[1])}.`
1221
1234
  };
1222
1235
  }
1223
1236
  if (context.buffer.length < i + 1) return {
@@ -1703,6 +1716,22 @@ function command(name, parser, options = {}) {
1703
1716
  configurable: true,
1704
1717
  enumerable: false
1705
1718
  });
1719
+ definePassThroughPriority(result, [parser], (state, token) => {
1720
+ const active = normalizeCommandState(state);
1721
+ if (active == null) return void 0;
1722
+ const childState = active[0] === "matched" ? parser.initialState : active[1];
1723
+ return getPassThroughPriority(parser, getCommandParseChildState(state, childState, parser), token);
1724
+ });
1725
+ defineOptionMatch(result, (state, token) => {
1726
+ const active = normalizeCommandState(state);
1727
+ if (active == null) return void 0;
1728
+ const childState = active[0] === "matched" ? parser.initialState : active[1];
1729
+ const match = getOptionMatch(parser, getCommandParseChildState(state, childState, parser), token);
1730
+ return match == null ? void 0 : {
1731
+ ...match,
1732
+ continuesCommand: true
1733
+ };
1734
+ });
1706
1735
  return result;
1707
1736
  }
1708
1737
  /**
@@ -1755,7 +1784,7 @@ function passThrough(options = {}) {
1755
1784
  const format = options.format ?? "equalsOnly";
1756
1785
  const optionPattern = /^-[a-z0-9-]|^--[a-z0-9-]+/i;
1757
1786
  const equalsOptionPattern = /^--[a-z0-9-]+=/i;
1758
- return {
1787
+ const result = {
1759
1788
  $valueType: [],
1760
1789
  $stateType: [],
1761
1790
  mode: "sync",
@@ -1776,6 +1805,8 @@ function passThrough(options = {}) {
1776
1805
  consumed: 0,
1777
1806
  error: message`No input to pass through.`
1778
1807
  };
1808
+ const failure = getPassThroughFailure(context, this?.priority ?? -10);
1809
+ if (failure != null) return failure.failure;
1779
1810
  const token = context.buffer[0];
1780
1811
  if (format === "greedy") {
1781
1812
  const captured = [...context.buffer];
@@ -1887,6 +1918,12 @@ function passThrough(options = {}) {
1887
1918
  return `passThrough(${format})`;
1888
1919
  }
1889
1920
  };
1921
+ definePassThroughPriority(result, [result], (_state, token) => {
1922
+ if (token == null || format === "greedy") return result.priority;
1923
+ const accepts = format === "equalsOnly" ? equalsOptionPattern.test(token) : format === "nextToken" && optionPattern.test(token);
1924
+ return accepts ? result.priority : void 0;
1925
+ });
1926
+ return result;
1890
1927
  }
1891
1928
 
1892
1929
  //#endregion
@@ -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.1.8",
3
+ "version": "1.1.9",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",
@@ -196,7 +196,7 @@
196
196
  },
197
197
  "sideEffects": false,
198
198
  "devDependencies": {
199
- "@optique/env": "1.1.8",
199
+ "@optique/env": "1.1.9",
200
200
  "@types/node": "^24.0.0",
201
201
  "fast-check": "^4.7.0",
202
202
  "tsdown": "^0.13.0",