@optique/core 1.4.0-dev.2662 → 1.4.0-dev.2665
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.
- package/dist/constructs.cjs +105 -109
- package/dist/constructs.d.cts +8 -0
- package/dist/constructs.d.ts +8 -0
- package/dist/constructs.js +105 -109
- package/dist/internal/failure.cjs +68 -0
- package/dist/internal/failure.js +66 -0
- package/dist/primitives.cjs +35 -82
- package/dist/primitives.d.cts +7 -0
- package/dist/primitives.d.ts +7 -0
- package/dist/primitives.js +35 -82
- package/package.json +2 -2
- package/skills/optique/SKILL.md +4 -4
package/dist/primitives.cjs
CHANGED
|
@@ -11,6 +11,7 @@ const require_usage_internals = require('./usage-internals.cjs');
|
|
|
11
11
|
const require_short_option = require('./short-option.cjs');
|
|
12
12
|
const require_passthrough = require('./internal/passthrough.cjs');
|
|
13
13
|
const require_command_alias = require('./internal/command-alias.cjs');
|
|
14
|
+
const require_failure = require('./internal/failure.cjs');
|
|
14
15
|
const require_phase2_seed = require('./phase2-seed.cjs');
|
|
15
16
|
const require_dependency_metadata = require('./dependency-metadata.cjs');
|
|
16
17
|
const require_modifiers = require('./modifiers.cjs');
|
|
@@ -115,6 +116,22 @@ async function resolveDerivedCompletionAsync(derivedMetadata, state, exec) {
|
|
|
115
116
|
}, traceEntry.rawInput, exec.dependencyRuntime);
|
|
116
117
|
return replayed ?? traceEntry.preliminaryResult ?? state;
|
|
117
118
|
}
|
|
119
|
+
/** Defers option/flag typo work until a failure's message is requested. */
|
|
120
|
+
function unmatchedOptionFailure(invalidOption, usage, errors) {
|
|
121
|
+
const noMatch = errors?.noMatch;
|
|
122
|
+
if (noMatch != null && typeof noMatch !== "function") return {
|
|
123
|
+
success: false,
|
|
124
|
+
consumed: 0,
|
|
125
|
+
error: noMatch
|
|
126
|
+
};
|
|
127
|
+
return require_failure.createDeferredFailure(0, () => {
|
|
128
|
+
if (noMatch != null) {
|
|
129
|
+
const candidates = new Set(require_usage.extractOptionNames(usage));
|
|
130
|
+
return noMatch.call(errors, invalidOption, require_suggestion.findSimilar(invalidOption, candidates, require_suggestion.DEFAULT_FIND_SIMILAR_OPTIONS));
|
|
131
|
+
}
|
|
132
|
+
return require_suggestion.createErrorWithSuggestions(require_message.message`No matched option for ${require_message.optionName(invalidOption)}.`, invalidOption, usage, "option");
|
|
133
|
+
});
|
|
134
|
+
}
|
|
118
135
|
/**
|
|
119
136
|
* Creates a parser that always succeeds without consuming any input and
|
|
120
137
|
* produces a constant value of the type {@link T}.
|
|
@@ -634,28 +651,7 @@ function option(...args) {
|
|
|
634
651
|
}
|
|
635
652
|
}
|
|
636
653
|
const invalidOption = context.buffer[0];
|
|
637
|
-
|
|
638
|
-
if (typeof options.errors.noMatch !== "function") return {
|
|
639
|
-
success: false,
|
|
640
|
-
consumed: 0,
|
|
641
|
-
error: options.errors.noMatch
|
|
642
|
-
};
|
|
643
|
-
const candidates = /* @__PURE__ */ new Set();
|
|
644
|
-
for (const name of require_usage.extractOptionNames(context.usage)) candidates.add(name);
|
|
645
|
-
const suggestions = require_suggestion.findSimilar(invalidOption, candidates, require_suggestion.DEFAULT_FIND_SIMILAR_OPTIONS);
|
|
646
|
-
const errorMessage = options.errors.noMatch(invalidOption, suggestions);
|
|
647
|
-
return {
|
|
648
|
-
success: false,
|
|
649
|
-
consumed: 0,
|
|
650
|
-
error: errorMessage
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
const baseError = require_message.message`No matched option for ${require_message.optionName(invalidOption)}.`;
|
|
654
|
-
return {
|
|
655
|
-
success: false,
|
|
656
|
-
consumed: 0,
|
|
657
|
-
error: require_suggestion.createErrorWithSuggestions(baseError, invalidOption, context.usage, "option")
|
|
658
|
-
};
|
|
654
|
+
return unmatchedOptionFailure(invalidOption, context.usage, options.errors);
|
|
659
655
|
},
|
|
660
656
|
complete(state, exec) {
|
|
661
657
|
const missing = valueParser == null ? {
|
|
@@ -928,28 +924,7 @@ function flag(...args) {
|
|
|
928
924
|
};
|
|
929
925
|
}
|
|
930
926
|
const invalidOption = context.buffer[0];
|
|
931
|
-
|
|
932
|
-
if (typeof options.errors.noMatch !== "function") return {
|
|
933
|
-
success: false,
|
|
934
|
-
consumed: 0,
|
|
935
|
-
error: options.errors.noMatch
|
|
936
|
-
};
|
|
937
|
-
const candidates = /* @__PURE__ */ new Set();
|
|
938
|
-
for (const name of require_usage.extractOptionNames(context.usage)) candidates.add(name);
|
|
939
|
-
const suggestions = require_suggestion.findSimilar(invalidOption, candidates, require_suggestion.DEFAULT_FIND_SIMILAR_OPTIONS);
|
|
940
|
-
const errorMessage = options.errors.noMatch(invalidOption, suggestions);
|
|
941
|
-
return {
|
|
942
|
-
success: false,
|
|
943
|
-
consumed: 0,
|
|
944
|
-
error: errorMessage
|
|
945
|
-
};
|
|
946
|
-
}
|
|
947
|
-
const baseError = require_message.message`No matched option for ${require_message.optionName(invalidOption)}.`;
|
|
948
|
-
return {
|
|
949
|
-
success: false,
|
|
950
|
-
consumed: 0,
|
|
951
|
-
error: require_suggestion.createErrorWithSuggestions(baseError, invalidOption, context.usage, "option")
|
|
952
|
-
};
|
|
927
|
+
return unmatchedOptionFailure(invalidOption, context.usage, options.errors);
|
|
953
928
|
},
|
|
954
929
|
complete(state, _exec) {
|
|
955
930
|
if (state == null) return {
|
|
@@ -1137,23 +1112,7 @@ function negatableFlag(names, options = {}) {
|
|
|
1137
1112
|
if (!context.buffer[0].startsWith(shortOption) || require_short_option.fullNameOwnsToken(context, context.buffer[0])) continue;
|
|
1138
1113
|
return parseMatchedNegatableFlag(context, shortOption, valueByName.get(shortOption), [context.buffer[0].slice(0, shortOption.length)], 1, [`-${context.buffer[0].slice(shortOption.length)}`, ...context.buffer.slice(1)], options);
|
|
1139
1114
|
}
|
|
1140
|
-
|
|
1141
|
-
if (options.errors?.noMatch) {
|
|
1142
|
-
const candidates = /* @__PURE__ */ new Set();
|
|
1143
|
-
for (const name of require_usage.extractOptionNames(context.usage)) candidates.add(name);
|
|
1144
|
-
const suggestions = require_suggestion.findSimilar(invalidOption, candidates, require_suggestion.DEFAULT_FIND_SIMILAR_OPTIONS);
|
|
1145
|
-
return {
|
|
1146
|
-
success: false,
|
|
1147
|
-
consumed: 0,
|
|
1148
|
-
error: typeof options.errors.noMatch === "function" ? options.errors.noMatch(invalidOption, suggestions) : options.errors.noMatch
|
|
1149
|
-
};
|
|
1150
|
-
}
|
|
1151
|
-
const baseError = require_message.message`No matched option for ${require_message.optionName(invalidOption)}.`;
|
|
1152
|
-
return {
|
|
1153
|
-
success: false,
|
|
1154
|
-
consumed: 0,
|
|
1155
|
-
error: require_suggestion.createErrorWithSuggestions(baseError, invalidOption, context.usage, "option")
|
|
1156
|
-
};
|
|
1115
|
+
return unmatchedOptionFailure(context.buffer[0], context.usage, options.errors);
|
|
1157
1116
|
},
|
|
1158
1117
|
complete(state, _exec) {
|
|
1159
1118
|
if (state == null) return {
|
|
@@ -1594,33 +1553,27 @@ function command(name, parser, options = {}) {
|
|
|
1594
1553
|
if (state === void 0) {
|
|
1595
1554
|
if (context.buffer.length < 1 || !commandNames.includes(context.buffer[0])) {
|
|
1596
1555
|
const actual = context.buffer.length > 0 ? context.buffer[0] : null;
|
|
1597
|
-
const
|
|
1598
|
-
|
|
1599
|
-
const suggestions = require_suggestion.expandCommandAliasSuggestions(context.usage, rawSuggestions);
|
|
1600
|
-
if (options.errors?.notMatched) {
|
|
1601
|
-
const errorMessage = options.errors.notMatched;
|
|
1602
|
-
return {
|
|
1603
|
-
success: false,
|
|
1604
|
-
consumed: 0,
|
|
1605
|
-
error: typeof errorMessage === "function" ? errorMessage(name, actual, suggestions) : errorMessage
|
|
1606
|
-
};
|
|
1607
|
-
}
|
|
1608
|
-
if (actual == null) return {
|
|
1556
|
+
const notMatched = options.errors?.notMatched;
|
|
1557
|
+
if (notMatched != null && typeof notMatched !== "function") return {
|
|
1609
1558
|
success: false,
|
|
1610
1559
|
consumed: 0,
|
|
1611
|
-
error:
|
|
1560
|
+
error: notMatched
|
|
1612
1561
|
};
|
|
1613
|
-
const
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1562
|
+
const usage = context.usage;
|
|
1563
|
+
return require_failure.createDeferredFailure(0, () => {
|
|
1564
|
+
const leadingCmds = require_usage_internals.extractLeadingCommandNames(usage);
|
|
1565
|
+
const rawSuggestions = actual ? require_suggestion.findSimilar(actual, leadingCmds, require_suggestion.DEFAULT_FIND_SIMILAR_OPTIONS) : [];
|
|
1566
|
+
const suggestions = require_suggestion.expandCommandAliasSuggestions(usage, rawSuggestions);
|
|
1567
|
+
if (notMatched != null) return notMatched(name, actual, suggestions);
|
|
1568
|
+
if (actual == null) return require_message.message`Expected command ${require_message.optionName(name)}, but got end of input.`;
|
|
1569
|
+
const baseError = require_message.message`Expected command ${require_message.optionName(name)}, but got ${actual}.`;
|
|
1570
|
+
const suggestionMsg = require_suggestion.createSuggestionMessage(suggestions);
|
|
1571
|
+
return suggestionMsg.length > 0 ? [
|
|
1619
1572
|
...baseError,
|
|
1620
1573
|
require_message.text("\n\n"),
|
|
1621
1574
|
...suggestionMsg
|
|
1622
|
-
] : baseError
|
|
1623
|
-
};
|
|
1575
|
+
] : baseError;
|
|
1576
|
+
});
|
|
1624
1577
|
}
|
|
1625
1578
|
commandScope.select(context, enteredScope);
|
|
1626
1579
|
return {
|
package/dist/primitives.d.cts
CHANGED
|
@@ -96,6 +96,8 @@ interface OptionErrorOptions {
|
|
|
96
96
|
* Can be a static message or a function that receives:
|
|
97
97
|
* - invalidOption: The invalid option name that was provided
|
|
98
98
|
* - suggestions: Array of similar valid option names (can be empty)
|
|
99
|
+
* The callback runs when a retained failure's error is read, and may be
|
|
100
|
+
* skipped for discarded failures. It should not have side effects.
|
|
99
101
|
*
|
|
100
102
|
* @since 0.7.0
|
|
101
103
|
*/
|
|
@@ -209,6 +211,8 @@ interface FlagErrorOptions {
|
|
|
209
211
|
* Can be a static message or a function that receives:
|
|
210
212
|
* - invalidOption: The invalid option name that was provided
|
|
211
213
|
* - suggestions: Array of similar valid option names (can be empty)
|
|
214
|
+
* The callback runs when a retained failure's error is read, and may be
|
|
215
|
+
* skipped for discarded failures. It should not have side effects.
|
|
212
216
|
*
|
|
213
217
|
* @since 0.7.0
|
|
214
218
|
*/
|
|
@@ -321,6 +325,7 @@ interface NegatableFlagErrorOptions {
|
|
|
321
325
|
readonly unexpectedValue?: Message | ((optionName: string, value: string) => Message);
|
|
322
326
|
/**
|
|
323
327
|
* Custom error message when no matching flag is found.
|
|
328
|
+
* Callbacks may be skipped when a mismatch is discarded.
|
|
324
329
|
*/
|
|
325
330
|
readonly noMatch?: Message | ((invalidOption: string, suggestions: readonly string[]) => Message);
|
|
326
331
|
}
|
|
@@ -484,6 +489,8 @@ interface CommandErrorOptions {
|
|
|
484
489
|
* - expected: The expected command name
|
|
485
490
|
* - actual: The actual input (or null if no input)
|
|
486
491
|
* - suggestions: Array of similar valid command names (can be empty)
|
|
492
|
+
* The callback runs when a retained failure's error is read, and may be
|
|
493
|
+
* skipped for discarded failures. It should not have side effects.
|
|
487
494
|
*/
|
|
488
495
|
readonly notMatched?: Message | ((expected: string, actual: string | null, suggestions?: readonly string[]) => Message);
|
|
489
496
|
/**
|
package/dist/primitives.d.ts
CHANGED
|
@@ -96,6 +96,8 @@ interface OptionErrorOptions {
|
|
|
96
96
|
* Can be a static message or a function that receives:
|
|
97
97
|
* - invalidOption: The invalid option name that was provided
|
|
98
98
|
* - suggestions: Array of similar valid option names (can be empty)
|
|
99
|
+
* The callback runs when a retained failure's error is read, and may be
|
|
100
|
+
* skipped for discarded failures. It should not have side effects.
|
|
99
101
|
*
|
|
100
102
|
* @since 0.7.0
|
|
101
103
|
*/
|
|
@@ -209,6 +211,8 @@ interface FlagErrorOptions {
|
|
|
209
211
|
* Can be a static message or a function that receives:
|
|
210
212
|
* - invalidOption: The invalid option name that was provided
|
|
211
213
|
* - suggestions: Array of similar valid option names (can be empty)
|
|
214
|
+
* The callback runs when a retained failure's error is read, and may be
|
|
215
|
+
* skipped for discarded failures. It should not have side effects.
|
|
212
216
|
*
|
|
213
217
|
* @since 0.7.0
|
|
214
218
|
*/
|
|
@@ -321,6 +325,7 @@ interface NegatableFlagErrorOptions {
|
|
|
321
325
|
readonly unexpectedValue?: Message | ((optionName: string, value: string) => Message);
|
|
322
326
|
/**
|
|
323
327
|
* Custom error message when no matching flag is found.
|
|
328
|
+
* Callbacks may be skipped when a mismatch is discarded.
|
|
324
329
|
*/
|
|
325
330
|
readonly noMatch?: Message | ((invalidOption: string, suggestions: readonly string[]) => Message);
|
|
326
331
|
}
|
|
@@ -484,6 +489,8 @@ interface CommandErrorOptions {
|
|
|
484
489
|
* - expected: The expected command name
|
|
485
490
|
* - actual: The actual input (or null if no input)
|
|
486
491
|
* - suggestions: Array of similar valid command names (can be empty)
|
|
492
|
+
* The callback runs when a retained failure's error is read, and may be
|
|
493
|
+
* skipped for discarded failures. It should not have side effects.
|
|
487
494
|
*/
|
|
488
495
|
readonly notMatched?: Message | ((expected: string, actual: string | null, suggestions?: readonly string[]) => Message);
|
|
489
496
|
/**
|
package/dist/primitives.js
CHANGED
|
@@ -11,6 +11,7 @@ import { extractLeadingCommandNames } from "./usage-internals.js";
|
|
|
11
11
|
import { attachedValuePrefix, combinedOptionScope, fullNameOwnsToken, prefixSuggestion, scopeParser, selectableOptionScope } from "./short-option.js";
|
|
12
12
|
import { defineKnownCompletion, definePassThroughPriority, defineReachableChildren, getPassThroughFailure } from "./internal/passthrough.js";
|
|
13
13
|
import { hiddenCommandAliasesKey } from "./internal/command-alias.js";
|
|
14
|
+
import { createDeferredFailure } from "./internal/failure.js";
|
|
14
15
|
import { completeOrExtractPhase2Seed, extractPhase2SeedKey } from "./phase2-seed.js";
|
|
15
16
|
import { extractDependencyMetadata } from "./dependency-metadata.js";
|
|
16
17
|
import { fluent } from "./modifiers.js";
|
|
@@ -115,6 +116,22 @@ async function resolveDerivedCompletionAsync(derivedMetadata, state, exec) {
|
|
|
115
116
|
}, traceEntry.rawInput, exec.dependencyRuntime);
|
|
116
117
|
return replayed ?? traceEntry.preliminaryResult ?? state;
|
|
117
118
|
}
|
|
119
|
+
/** Defers option/flag typo work until a failure's message is requested. */
|
|
120
|
+
function unmatchedOptionFailure(invalidOption, usage, errors) {
|
|
121
|
+
const noMatch = errors?.noMatch;
|
|
122
|
+
if (noMatch != null && typeof noMatch !== "function") return {
|
|
123
|
+
success: false,
|
|
124
|
+
consumed: 0,
|
|
125
|
+
error: noMatch
|
|
126
|
+
};
|
|
127
|
+
return createDeferredFailure(0, () => {
|
|
128
|
+
if (noMatch != null) {
|
|
129
|
+
const candidates = new Set(extractOptionNames(usage));
|
|
130
|
+
return noMatch.call(errors, invalidOption, findSimilar(invalidOption, candidates, DEFAULT_FIND_SIMILAR_OPTIONS));
|
|
131
|
+
}
|
|
132
|
+
return createErrorWithSuggestions(message`No matched option for ${optionName(invalidOption)}.`, invalidOption, usage, "option");
|
|
133
|
+
});
|
|
134
|
+
}
|
|
118
135
|
/**
|
|
119
136
|
* Creates a parser that always succeeds without consuming any input and
|
|
120
137
|
* produces a constant value of the type {@link T}.
|
|
@@ -634,28 +651,7 @@ function option(...args) {
|
|
|
634
651
|
}
|
|
635
652
|
}
|
|
636
653
|
const invalidOption = context.buffer[0];
|
|
637
|
-
|
|
638
|
-
if (typeof options.errors.noMatch !== "function") return {
|
|
639
|
-
success: false,
|
|
640
|
-
consumed: 0,
|
|
641
|
-
error: options.errors.noMatch
|
|
642
|
-
};
|
|
643
|
-
const candidates = /* @__PURE__ */ new Set();
|
|
644
|
-
for (const name of extractOptionNames(context.usage)) candidates.add(name);
|
|
645
|
-
const suggestions = findSimilar(invalidOption, candidates, DEFAULT_FIND_SIMILAR_OPTIONS);
|
|
646
|
-
const errorMessage = options.errors.noMatch(invalidOption, suggestions);
|
|
647
|
-
return {
|
|
648
|
-
success: false,
|
|
649
|
-
consumed: 0,
|
|
650
|
-
error: errorMessage
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
const baseError = message`No matched option for ${optionName(invalidOption)}.`;
|
|
654
|
-
return {
|
|
655
|
-
success: false,
|
|
656
|
-
consumed: 0,
|
|
657
|
-
error: createErrorWithSuggestions(baseError, invalidOption, context.usage, "option")
|
|
658
|
-
};
|
|
654
|
+
return unmatchedOptionFailure(invalidOption, context.usage, options.errors);
|
|
659
655
|
},
|
|
660
656
|
complete(state, exec) {
|
|
661
657
|
const missing = valueParser == null ? {
|
|
@@ -928,28 +924,7 @@ function flag(...args) {
|
|
|
928
924
|
};
|
|
929
925
|
}
|
|
930
926
|
const invalidOption = context.buffer[0];
|
|
931
|
-
|
|
932
|
-
if (typeof options.errors.noMatch !== "function") return {
|
|
933
|
-
success: false,
|
|
934
|
-
consumed: 0,
|
|
935
|
-
error: options.errors.noMatch
|
|
936
|
-
};
|
|
937
|
-
const candidates = /* @__PURE__ */ new Set();
|
|
938
|
-
for (const name of extractOptionNames(context.usage)) candidates.add(name);
|
|
939
|
-
const suggestions = findSimilar(invalidOption, candidates, DEFAULT_FIND_SIMILAR_OPTIONS);
|
|
940
|
-
const errorMessage = options.errors.noMatch(invalidOption, suggestions);
|
|
941
|
-
return {
|
|
942
|
-
success: false,
|
|
943
|
-
consumed: 0,
|
|
944
|
-
error: errorMessage
|
|
945
|
-
};
|
|
946
|
-
}
|
|
947
|
-
const baseError = message`No matched option for ${optionName(invalidOption)}.`;
|
|
948
|
-
return {
|
|
949
|
-
success: false,
|
|
950
|
-
consumed: 0,
|
|
951
|
-
error: createErrorWithSuggestions(baseError, invalidOption, context.usage, "option")
|
|
952
|
-
};
|
|
927
|
+
return unmatchedOptionFailure(invalidOption, context.usage, options.errors);
|
|
953
928
|
},
|
|
954
929
|
complete(state, _exec) {
|
|
955
930
|
if (state == null) return {
|
|
@@ -1137,23 +1112,7 @@ function negatableFlag(names, options = {}) {
|
|
|
1137
1112
|
if (!context.buffer[0].startsWith(shortOption) || fullNameOwnsToken(context, context.buffer[0])) continue;
|
|
1138
1113
|
return parseMatchedNegatableFlag(context, shortOption, valueByName.get(shortOption), [context.buffer[0].slice(0, shortOption.length)], 1, [`-${context.buffer[0].slice(shortOption.length)}`, ...context.buffer.slice(1)], options);
|
|
1139
1114
|
}
|
|
1140
|
-
|
|
1141
|
-
if (options.errors?.noMatch) {
|
|
1142
|
-
const candidates = /* @__PURE__ */ new Set();
|
|
1143
|
-
for (const name of extractOptionNames(context.usage)) candidates.add(name);
|
|
1144
|
-
const suggestions = findSimilar(invalidOption, candidates, DEFAULT_FIND_SIMILAR_OPTIONS);
|
|
1145
|
-
return {
|
|
1146
|
-
success: false,
|
|
1147
|
-
consumed: 0,
|
|
1148
|
-
error: typeof options.errors.noMatch === "function" ? options.errors.noMatch(invalidOption, suggestions) : options.errors.noMatch
|
|
1149
|
-
};
|
|
1150
|
-
}
|
|
1151
|
-
const baseError = message`No matched option for ${optionName(invalidOption)}.`;
|
|
1152
|
-
return {
|
|
1153
|
-
success: false,
|
|
1154
|
-
consumed: 0,
|
|
1155
|
-
error: createErrorWithSuggestions(baseError, invalidOption, context.usage, "option")
|
|
1156
|
-
};
|
|
1115
|
+
return unmatchedOptionFailure(context.buffer[0], context.usage, options.errors);
|
|
1157
1116
|
},
|
|
1158
1117
|
complete(state, _exec) {
|
|
1159
1118
|
if (state == null) return {
|
|
@@ -1594,33 +1553,27 @@ function command(name, parser, options = {}) {
|
|
|
1594
1553
|
if (state === void 0) {
|
|
1595
1554
|
if (context.buffer.length < 1 || !commandNames.includes(context.buffer[0])) {
|
|
1596
1555
|
const actual = context.buffer.length > 0 ? context.buffer[0] : null;
|
|
1597
|
-
const
|
|
1598
|
-
|
|
1599
|
-
const suggestions = expandCommandAliasSuggestions(context.usage, rawSuggestions);
|
|
1600
|
-
if (options.errors?.notMatched) {
|
|
1601
|
-
const errorMessage = options.errors.notMatched;
|
|
1602
|
-
return {
|
|
1603
|
-
success: false,
|
|
1604
|
-
consumed: 0,
|
|
1605
|
-
error: typeof errorMessage === "function" ? errorMessage(name, actual, suggestions) : errorMessage
|
|
1606
|
-
};
|
|
1607
|
-
}
|
|
1608
|
-
if (actual == null) return {
|
|
1556
|
+
const notMatched = options.errors?.notMatched;
|
|
1557
|
+
if (notMatched != null && typeof notMatched !== "function") return {
|
|
1609
1558
|
success: false,
|
|
1610
1559
|
consumed: 0,
|
|
1611
|
-
error:
|
|
1560
|
+
error: notMatched
|
|
1612
1561
|
};
|
|
1613
|
-
const
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1562
|
+
const usage = context.usage;
|
|
1563
|
+
return createDeferredFailure(0, () => {
|
|
1564
|
+
const leadingCmds = extractLeadingCommandNames(usage);
|
|
1565
|
+
const rawSuggestions = actual ? findSimilar(actual, leadingCmds, DEFAULT_FIND_SIMILAR_OPTIONS) : [];
|
|
1566
|
+
const suggestions = expandCommandAliasSuggestions(usage, rawSuggestions);
|
|
1567
|
+
if (notMatched != null) return notMatched(name, actual, suggestions);
|
|
1568
|
+
if (actual == null) return message`Expected command ${optionName(name)}, but got end of input.`;
|
|
1569
|
+
const baseError = message`Expected command ${optionName(name)}, but got ${actual}.`;
|
|
1570
|
+
const suggestionMsg = createSuggestionMessage(suggestions);
|
|
1571
|
+
return suggestionMsg.length > 0 ? [
|
|
1619
1572
|
...baseError,
|
|
1620
1573
|
text("\n\n"),
|
|
1621
1574
|
...suggestionMsg
|
|
1622
|
-
] : baseError
|
|
1623
|
-
};
|
|
1575
|
+
] : baseError;
|
|
1576
|
+
});
|
|
1624
1577
|
}
|
|
1625
1578
|
commandScope.select(context, enteredScope);
|
|
1626
1579
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optique/core",
|
|
3
|
-
"version": "1.4.0-dev.
|
|
3
|
+
"version": "1.4.0-dev.2665",
|
|
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.4.0-dev.
|
|
240
|
+
"@optique/env": "1.4.0-dev.2665+868a9d77",
|
|
241
241
|
"@types/node": "^24.0.0",
|
|
242
242
|
"fast-check": "^4.7.0",
|
|
243
243
|
"tsdown": "^0.13.0",
|
package/skills/optique/SKILL.md
CHANGED
|
@@ -36,10 +36,10 @@ Core rules
|
|
|
36
36
|
- Let TypeScript infer results unless another API needs a separate interface.
|
|
37
37
|
- Parsers usually require input. `optional(p)` yields `undefined`; use
|
|
38
38
|
`withDefault(p, value)` or `withDefault(flag("-v"), false)` for fallbacks.
|
|
39
|
-
- Use semantic `message` helpers
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
- Use semantic `message` helpers; keep canonical errors unthemed. Since
|
|
40
|
+
1.3.0, `theme`/`messageFormatter` should preserve `initialWidth`, quoting,
|
|
41
|
+
and width options. `flag()` has static/callback `errors.unexpectedValue`
|
|
42
|
+
since 1.4.0. Mismatch callbacks may be skipped; avoid side effects.
|
|
43
43
|
- Use value parsers such as `integer()`, `choice()`, `biject()`, `regExp()`,
|
|
44
44
|
`url()`, `origin()`, and `uuid()` instead of validating raw strings after
|
|
45
45
|
parsing. Use `regExp({ flags })` for user-supplied sources, `biject()` for
|