@optique/core 1.3.1 → 1.3.2

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');
@@ -151,6 +152,7 @@ function constant(value) {
151
152
  return { fragments: [] };
152
153
  }
153
154
  };
155
+ require_passthrough.defineKnownCompletion(result, (state) => require_annotation_state.normalizeInjectedAnnotationState(state));
154
156
  Object.defineProperty(result, "placeholder", {
155
157
  value,
156
158
  configurable: true,
@@ -590,10 +592,15 @@ function option(...args) {
590
592
  }
591
593
  const invalidOption = context.buffer[0];
592
594
  if (options.errors?.noMatch) {
595
+ if (typeof options.errors.noMatch !== "function") return {
596
+ success: false,
597
+ consumed: 0,
598
+ error: options.errors.noMatch
599
+ };
593
600
  const candidates = /* @__PURE__ */ new Set();
594
601
  for (const name of require_usage.extractOptionNames(context.usage)) candidates.add(name);
595
602
  const suggestions = require_suggestion.findSimilar(invalidOption, candidates, require_suggestion.DEFAULT_FIND_SIMILAR_OPTIONS);
596
- const errorMessage = typeof options.errors.noMatch === "function" ? options.errors.noMatch(invalidOption, suggestions) : options.errors.noMatch;
603
+ const errorMessage = options.errors.noMatch(invalidOption, suggestions);
597
604
  return {
598
605
  success: false,
599
606
  consumed: 0,
@@ -878,10 +885,15 @@ function flag(...args) {
878
885
  }
879
886
  const invalidOption = context.buffer[0];
880
887
  if (options.errors?.noMatch) {
888
+ if (typeof options.errors.noMatch !== "function") return {
889
+ success: false,
890
+ consumed: 0,
891
+ error: options.errors.noMatch
892
+ };
881
893
  const candidates = /* @__PURE__ */ new Set();
882
894
  for (const name of require_usage.extractOptionNames(context.usage)) candidates.add(name);
883
895
  const suggestions = require_suggestion.findSimilar(invalidOption, candidates, require_suggestion.DEFAULT_FIND_SIMILAR_OPTIONS);
884
- const errorMessage = typeof options.errors.noMatch === "function" ? options.errors.noMatch(invalidOption, suggestions) : options.errors.noMatch;
896
+ const errorMessage = options.errors.noMatch(invalidOption, suggestions);
885
897
  return {
886
898
  success: false,
887
899
  consumed: 0,
@@ -1190,7 +1202,7 @@ function argument(valueParser, options = {}) {
1190
1202
  const syncValueParser = valueParser;
1191
1203
  const dependencyMetadata = require_dependency_metadata.extractDependencyMetadata(valueParser);
1192
1204
  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}`;
1193
- const optionPattern = /^--?[a-z0-9-]+$/i;
1205
+ const optionPattern = /^(?!--=)(--?[a-z0-9-]+)(?:=|$)/i;
1194
1206
  const term = {
1195
1207
  type: "argument",
1196
1208
  metavar: valueParser.metavar,
@@ -1217,14 +1229,15 @@ function argument(valueParser, options = {}) {
1217
1229
  };
1218
1230
  let i = 0;
1219
1231
  let optionsTerminated = context.optionsTerminated;
1220
- if (!optionsTerminated) {
1221
- if (context.buffer[i] === "--") {
1222
- optionsTerminated = true;
1223
- i++;
1224
- } else if (context.buffer[i].match(optionPattern)) return {
1232
+ if (!optionsTerminated) if (context.buffer[i] === "--") {
1233
+ optionsTerminated = true;
1234
+ i++;
1235
+ } else {
1236
+ const optionMatch = context.buffer[i].match(optionPattern);
1237
+ if (optionMatch != null) return {
1225
1238
  success: false,
1226
1239
  consumed: i,
1227
- error: require_message.message`Expected an argument, but got an option: ${require_message.optionName(context.buffer[i])}.`
1240
+ error: require_message.message`Expected an argument, but got an option: ${require_message.optionName(optionMatch[1])}.`
1228
1241
  };
1229
1242
  }
1230
1243
  if (context.buffer.length < i + 1) return {
@@ -1734,6 +1747,22 @@ function command(name, parser, options = {}) {
1734
1747
  configurable: true,
1735
1748
  enumerable: false
1736
1749
  });
1750
+ require_passthrough.definePassThroughPriority(result, [parser], (state, token) => {
1751
+ const active = normalizeCommandState(state);
1752
+ if (active == null) return void 0;
1753
+ const childState = active[0] === "matched" ? parser.initialState : active[1];
1754
+ return require_passthrough.getPassThroughPriority(parser, getCommandParseChildState(state, childState, parser), token);
1755
+ });
1756
+ require_passthrough.defineOptionMatch(result, (state, token) => {
1757
+ const active = normalizeCommandState(state);
1758
+ if (active == null) return void 0;
1759
+ const childState = active[0] === "matched" ? parser.initialState : active[1];
1760
+ const match = require_passthrough.getOptionMatch(parser, getCommandParseChildState(state, childState, parser), token);
1761
+ return match == null ? void 0 : {
1762
+ ...match,
1763
+ continuesCommand: true
1764
+ };
1765
+ });
1737
1766
  return require_modifiers.fluent(result);
1738
1767
  }
1739
1768
  /**
@@ -1807,6 +1836,8 @@ function passThrough(options = {}) {
1807
1836
  consumed: 0,
1808
1837
  error: require_message.message`No input to pass through.`
1809
1838
  };
1839
+ const failure = require_passthrough.getPassThroughFailure(context, this?.priority ?? -10);
1840
+ if (failure != null) return failure.failure;
1810
1841
  const token = context.buffer[0];
1811
1842
  if (format === "greedy") {
1812
1843
  const captured = [...context.buffer];
@@ -1918,6 +1949,11 @@ function passThrough(options = {}) {
1918
1949
  return `passThrough(${format})`;
1919
1950
  }
1920
1951
  };
1952
+ require_passthrough.definePassThroughPriority(result, [result], (_state, token) => {
1953
+ if (token == null || format === "greedy") return result.priority;
1954
+ const accepts = format === "equalsOnly" ? equalsOptionPattern.test(token) : format === "nextToken" && optionPattern.test(token);
1955
+ return accepts ? result.priority : void 0;
1956
+ });
1921
1957
  return require_modifiers.fluent(result);
1922
1958
  }
1923
1959
 
@@ -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 { effectfulSchedulingNodesKey, exclusiveSourceScopeKey, includeSourceFailureChain, recordDerivedRawInput, replayDerivedParser, replayDerivedParserAsync, sourceCollectionExpansionKey } 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";
@@ -151,6 +152,7 @@ function constant(value) {
151
152
  return { fragments: [] };
152
153
  }
153
154
  };
155
+ defineKnownCompletion(result, (state) => normalizeInjectedAnnotationState(state));
154
156
  Object.defineProperty(result, "placeholder", {
155
157
  value,
156
158
  configurable: true,
@@ -590,10 +592,15 @@ function option(...args) {
590
592
  }
591
593
  const invalidOption = context.buffer[0];
592
594
  if (options.errors?.noMatch) {
595
+ if (typeof options.errors.noMatch !== "function") return {
596
+ success: false,
597
+ consumed: 0,
598
+ error: options.errors.noMatch
599
+ };
593
600
  const candidates = /* @__PURE__ */ new Set();
594
601
  for (const name of extractOptionNames(context.usage)) candidates.add(name);
595
602
  const suggestions = findSimilar(invalidOption, candidates, DEFAULT_FIND_SIMILAR_OPTIONS);
596
- const errorMessage = typeof options.errors.noMatch === "function" ? options.errors.noMatch(invalidOption, suggestions) : options.errors.noMatch;
603
+ const errorMessage = options.errors.noMatch(invalidOption, suggestions);
597
604
  return {
598
605
  success: false,
599
606
  consumed: 0,
@@ -878,10 +885,15 @@ function flag(...args) {
878
885
  }
879
886
  const invalidOption = context.buffer[0];
880
887
  if (options.errors?.noMatch) {
888
+ if (typeof options.errors.noMatch !== "function") return {
889
+ success: false,
890
+ consumed: 0,
891
+ error: options.errors.noMatch
892
+ };
881
893
  const candidates = /* @__PURE__ */ new Set();
882
894
  for (const name of extractOptionNames(context.usage)) candidates.add(name);
883
895
  const suggestions = findSimilar(invalidOption, candidates, DEFAULT_FIND_SIMILAR_OPTIONS);
884
- const errorMessage = typeof options.errors.noMatch === "function" ? options.errors.noMatch(invalidOption, suggestions) : options.errors.noMatch;
896
+ const errorMessage = options.errors.noMatch(invalidOption, suggestions);
885
897
  return {
886
898
  success: false,
887
899
  consumed: 0,
@@ -1190,7 +1202,7 @@ function argument(valueParser, options = {}) {
1190
1202
  const syncValueParser = valueParser;
1191
1203
  const dependencyMetadata = extractDependencyMetadata(valueParser);
1192
1204
  const formatInvalidValueError = (error) => options.errors?.invalidValue ? typeof options.errors.invalidValue === "function" ? options.errors.invalidValue(error) : options.errors.invalidValue : message`${metavar(valueParser.metavar)}: ${error}`;
1193
- const optionPattern = /^--?[a-z0-9-]+$/i;
1205
+ const optionPattern = /^(?!--=)(--?[a-z0-9-]+)(?:=|$)/i;
1194
1206
  const term = {
1195
1207
  type: "argument",
1196
1208
  metavar: valueParser.metavar,
@@ -1217,14 +1229,15 @@ function argument(valueParser, options = {}) {
1217
1229
  };
1218
1230
  let i = 0;
1219
1231
  let optionsTerminated = context.optionsTerminated;
1220
- if (!optionsTerminated) {
1221
- if (context.buffer[i] === "--") {
1222
- optionsTerminated = true;
1223
- i++;
1224
- } else if (context.buffer[i].match(optionPattern)) return {
1232
+ if (!optionsTerminated) if (context.buffer[i] === "--") {
1233
+ optionsTerminated = true;
1234
+ i++;
1235
+ } else {
1236
+ const optionMatch = context.buffer[i].match(optionPattern);
1237
+ if (optionMatch != null) return {
1225
1238
  success: false,
1226
1239
  consumed: i,
1227
- error: message`Expected an argument, but got an option: ${optionName(context.buffer[i])}.`
1240
+ error: message`Expected an argument, but got an option: ${optionName(optionMatch[1])}.`
1228
1241
  };
1229
1242
  }
1230
1243
  if (context.buffer.length < i + 1) return {
@@ -1734,6 +1747,22 @@ function command(name, parser, options = {}) {
1734
1747
  configurable: true,
1735
1748
  enumerable: false
1736
1749
  });
1750
+ definePassThroughPriority(result, [parser], (state, token) => {
1751
+ const active = normalizeCommandState(state);
1752
+ if (active == null) return void 0;
1753
+ const childState = active[0] === "matched" ? parser.initialState : active[1];
1754
+ return getPassThroughPriority(parser, getCommandParseChildState(state, childState, parser), token);
1755
+ });
1756
+ defineOptionMatch(result, (state, token) => {
1757
+ const active = normalizeCommandState(state);
1758
+ if (active == null) return void 0;
1759
+ const childState = active[0] === "matched" ? parser.initialState : active[1];
1760
+ const match = getOptionMatch(parser, getCommandParseChildState(state, childState, parser), token);
1761
+ return match == null ? void 0 : {
1762
+ ...match,
1763
+ continuesCommand: true
1764
+ };
1765
+ });
1737
1766
  return fluent(result);
1738
1767
  }
1739
1768
  /**
@@ -1807,6 +1836,8 @@ function passThrough(options = {}) {
1807
1836
  consumed: 0,
1808
1837
  error: message`No input to pass through.`
1809
1838
  };
1839
+ const failure = getPassThroughFailure(context, this?.priority ?? -10);
1840
+ if (failure != null) return failure.failure;
1810
1841
  const token = context.buffer[0];
1811
1842
  if (format === "greedy") {
1812
1843
  const captured = [...context.buffer];
@@ -1918,6 +1949,11 @@ function passThrough(options = {}) {
1918
1949
  return `passThrough(${format})`;
1919
1950
  }
1920
1951
  };
1952
+ definePassThroughPriority(result, [result], (_state, token) => {
1953
+ if (token == null || format === "greedy") return result.priority;
1954
+ const accepts = format === "equalsOnly" ? equalsOptionPattern.test(token) : format === "nextToken" && optionPattern.test(token);
1955
+ return accepts ? result.priority : void 0;
1956
+ });
1921
1957
  return fluent(result);
1922
1958
  }
1923
1959
 
@@ -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.3.1",
3
+ "version": "1.3.2",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",
@@ -237,7 +237,7 @@
237
237
  },
238
238
  "sideEffects": false,
239
239
  "devDependencies": {
240
- "@optique/env": "1.3.1",
240
+ "@optique/env": "1.3.2",
241
241
  "@types/node": "^24.0.0",
242
242
  "fast-check": "^4.7.0",
243
243
  "tsdown": "^0.13.0",