@optique/core 0.7.12 → 0.7.13-dev.361
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 +48 -2
- package/dist/constructs.js +50 -4
- package/dist/suggestion.cjs +1 -0
- package/dist/suggestion.js +1 -1
- package/package.json +1 -1
package/dist/constructs.cjs
CHANGED
|
@@ -24,6 +24,52 @@ function isOptionRequiringValue(usage, token) {
|
|
|
24
24
|
}
|
|
25
25
|
return traverse(usage);
|
|
26
26
|
}
|
|
27
|
+
function collectLeadingCandidates(terms, optionNames, commandNames) {
|
|
28
|
+
if (!terms || !Array.isArray(terms)) return true;
|
|
29
|
+
for (const term of terms) {
|
|
30
|
+
if (term.type === "option") {
|
|
31
|
+
for (const name of term.names) optionNames.add(name);
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
if (term.type === "command") {
|
|
35
|
+
commandNames.add(term.name);
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
if (term.type === "argument") return false;
|
|
39
|
+
if (term.type === "optional") {
|
|
40
|
+
collectLeadingCandidates(term.terms, optionNames, commandNames);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (term.type === "multiple") {
|
|
44
|
+
collectLeadingCandidates(term.terms, optionNames, commandNames);
|
|
45
|
+
if (term.min === 0) continue;
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
if (term.type === "exclusive") {
|
|
49
|
+
let allAlternativesSkippable = true;
|
|
50
|
+
for (const exclusiveUsage of term.terms) {
|
|
51
|
+
const alternativeSkippable = collectLeadingCandidates(exclusiveUsage, optionNames, commandNames);
|
|
52
|
+
allAlternativesSkippable = allAlternativesSkippable && alternativeSkippable;
|
|
53
|
+
}
|
|
54
|
+
if (allAlternativesSkippable) continue;
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
function createUnexpectedInputErrorWithScopedSuggestions(baseError, invalidInput, parsers, customFormatter) {
|
|
61
|
+
const options = /* @__PURE__ */ new Set();
|
|
62
|
+
const commands = /* @__PURE__ */ new Set();
|
|
63
|
+
for (const parser of parsers) collectLeadingCandidates(parser.usage, options, commands);
|
|
64
|
+
const candidates = new Set([...options, ...commands]);
|
|
65
|
+
const suggestions = require_suggestion.findSimilar(invalidInput, candidates, require_suggestion.DEFAULT_FIND_SIMILAR_OPTIONS);
|
|
66
|
+
const suggestionMsg = customFormatter ? customFormatter(suggestions) : require_suggestion.createSuggestionMessage(suggestions);
|
|
67
|
+
return suggestionMsg.length > 0 ? [
|
|
68
|
+
...baseError,
|
|
69
|
+
require_message.text("\n\n"),
|
|
70
|
+
...suggestionMsg
|
|
71
|
+
] : baseError;
|
|
72
|
+
}
|
|
27
73
|
/**
|
|
28
74
|
* Extracts required (non-optional) usage terms from a usage array.
|
|
29
75
|
* @param usage The usage to extract required terms from
|
|
@@ -132,7 +178,7 @@ function or(...args) {
|
|
|
132
178
|
const token = context.buffer[0];
|
|
133
179
|
const defaultMsg = require_message.message`Unexpected option or subcommand: ${require_message.optionName(token)}.`;
|
|
134
180
|
if (options?.errors?.unexpectedInput != null) return typeof options.errors.unexpectedInput === "function" ? options.errors.unexpectedInput(token) : options.errors.unexpectedInput;
|
|
135
|
-
return
|
|
181
|
+
return createUnexpectedInputErrorWithScopedSuggestions(defaultMsg, token, parsers, options?.errors?.suggestions);
|
|
136
182
|
})()
|
|
137
183
|
};
|
|
138
184
|
const orderedParsers = parsers.map((p, i) => [p, i]);
|
|
@@ -282,7 +328,7 @@ function longestMatch(...args) {
|
|
|
282
328
|
const token = context.buffer[0];
|
|
283
329
|
const defaultMsg = require_message.message`Unexpected option or subcommand: ${require_message.optionName(token)}.`;
|
|
284
330
|
if (options?.errors?.unexpectedInput != null) return typeof options.errors.unexpectedInput === "function" ? options.errors.unexpectedInput(token) : options.errors.unexpectedInput;
|
|
285
|
-
return
|
|
331
|
+
return createUnexpectedInputErrorWithScopedSuggestions(defaultMsg, token, parsers, options?.errors?.suggestions);
|
|
286
332
|
})()
|
|
287
333
|
};
|
|
288
334
|
for (let i = 0; i < parsers.length; i++) {
|
package/dist/constructs.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { message, optionName, values } from "./message.js";
|
|
1
|
+
import { message, optionName, text, values } from "./message.js";
|
|
2
2
|
import { extractArgumentMetavars, extractCommandNames, extractOptionNames } from "./usage.js";
|
|
3
|
-
import { createErrorWithSuggestions } from "./suggestion.js";
|
|
3
|
+
import { DEFAULT_FIND_SIMILAR_OPTIONS, createErrorWithSuggestions, createSuggestionMessage, findSimilar } from "./suggestion.js";
|
|
4
4
|
|
|
5
5
|
//#region src/constructs.ts
|
|
6
6
|
/**
|
|
@@ -24,6 +24,52 @@ function isOptionRequiringValue(usage, token) {
|
|
|
24
24
|
}
|
|
25
25
|
return traverse(usage);
|
|
26
26
|
}
|
|
27
|
+
function collectLeadingCandidates(terms, optionNames, commandNames) {
|
|
28
|
+
if (!terms || !Array.isArray(terms)) return true;
|
|
29
|
+
for (const term of terms) {
|
|
30
|
+
if (term.type === "option") {
|
|
31
|
+
for (const name of term.names) optionNames.add(name);
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
if (term.type === "command") {
|
|
35
|
+
commandNames.add(term.name);
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
if (term.type === "argument") return false;
|
|
39
|
+
if (term.type === "optional") {
|
|
40
|
+
collectLeadingCandidates(term.terms, optionNames, commandNames);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (term.type === "multiple") {
|
|
44
|
+
collectLeadingCandidates(term.terms, optionNames, commandNames);
|
|
45
|
+
if (term.min === 0) continue;
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
if (term.type === "exclusive") {
|
|
49
|
+
let allAlternativesSkippable = true;
|
|
50
|
+
for (const exclusiveUsage of term.terms) {
|
|
51
|
+
const alternativeSkippable = collectLeadingCandidates(exclusiveUsage, optionNames, commandNames);
|
|
52
|
+
allAlternativesSkippable = allAlternativesSkippable && alternativeSkippable;
|
|
53
|
+
}
|
|
54
|
+
if (allAlternativesSkippable) continue;
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
function createUnexpectedInputErrorWithScopedSuggestions(baseError, invalidInput, parsers, customFormatter) {
|
|
61
|
+
const options = /* @__PURE__ */ new Set();
|
|
62
|
+
const commands = /* @__PURE__ */ new Set();
|
|
63
|
+
for (const parser of parsers) collectLeadingCandidates(parser.usage, options, commands);
|
|
64
|
+
const candidates = new Set([...options, ...commands]);
|
|
65
|
+
const suggestions = findSimilar(invalidInput, candidates, DEFAULT_FIND_SIMILAR_OPTIONS);
|
|
66
|
+
const suggestionMsg = customFormatter ? customFormatter(suggestions) : createSuggestionMessage(suggestions);
|
|
67
|
+
return suggestionMsg.length > 0 ? [
|
|
68
|
+
...baseError,
|
|
69
|
+
text("\n\n"),
|
|
70
|
+
...suggestionMsg
|
|
71
|
+
] : baseError;
|
|
72
|
+
}
|
|
27
73
|
/**
|
|
28
74
|
* Extracts required (non-optional) usage terms from a usage array.
|
|
29
75
|
* @param usage The usage to extract required terms from
|
|
@@ -132,7 +178,7 @@ function or(...args) {
|
|
|
132
178
|
const token = context.buffer[0];
|
|
133
179
|
const defaultMsg = message`Unexpected option or subcommand: ${optionName(token)}.`;
|
|
134
180
|
if (options?.errors?.unexpectedInput != null) return typeof options.errors.unexpectedInput === "function" ? options.errors.unexpectedInput(token) : options.errors.unexpectedInput;
|
|
135
|
-
return
|
|
181
|
+
return createUnexpectedInputErrorWithScopedSuggestions(defaultMsg, token, parsers, options?.errors?.suggestions);
|
|
136
182
|
})()
|
|
137
183
|
};
|
|
138
184
|
const orderedParsers = parsers.map((p, i) => [p, i]);
|
|
@@ -282,7 +328,7 @@ function longestMatch(...args) {
|
|
|
282
328
|
const token = context.buffer[0];
|
|
283
329
|
const defaultMsg = message`Unexpected option or subcommand: ${optionName(token)}.`;
|
|
284
330
|
if (options?.errors?.unexpectedInput != null) return typeof options.errors.unexpectedInput === "function" ? options.errors.unexpectedInput(token) : options.errors.unexpectedInput;
|
|
285
|
-
return
|
|
331
|
+
return createUnexpectedInputErrorWithScopedSuggestions(defaultMsg, token, parsers, options?.errors?.suggestions);
|
|
286
332
|
})()
|
|
287
333
|
};
|
|
288
334
|
for (let i = 0; i < parsers.length; i++) {
|
package/dist/suggestion.cjs
CHANGED
|
@@ -183,4 +183,5 @@ function createErrorWithSuggestions(baseError, invalidInput, usage, type = "both
|
|
|
183
183
|
//#endregion
|
|
184
184
|
exports.DEFAULT_FIND_SIMILAR_OPTIONS = DEFAULT_FIND_SIMILAR_OPTIONS;
|
|
185
185
|
exports.createErrorWithSuggestions = createErrorWithSuggestions;
|
|
186
|
+
exports.createSuggestionMessage = createSuggestionMessage;
|
|
186
187
|
exports.findSimilar = findSimilar;
|
package/dist/suggestion.js
CHANGED
|
@@ -181,4 +181,4 @@ function createErrorWithSuggestions(baseError, invalidInput, usage, type = "both
|
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
//#endregion
|
|
184
|
-
export { DEFAULT_FIND_SIMILAR_OPTIONS, createErrorWithSuggestions, findSimilar };
|
|
184
|
+
export { DEFAULT_FIND_SIMILAR_OPTIONS, createErrorWithSuggestions, createSuggestionMessage, findSimilar };
|