@optique/core 1.3.4 → 1.3.6
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/completion.cjs +1709 -230
- package/dist/completion.js +1709 -230
- package/dist/constructs.cjs +7 -1
- package/dist/constructs.d.cts +2 -0
- package/dist/constructs.d.ts +2 -0
- package/dist/constructs.js +7 -1
- package/dist/internal/joined-file-suggestion.cjs +73 -0
- package/dist/internal/joined-file-suggestion.js +70 -0
- package/dist/internal/parser.d.cts +8 -0
- package/dist/internal/parser.d.ts +8 -0
- package/dist/modifiers.cjs +14 -8
- package/dist/modifiers.js +14 -8
- package/dist/primitives.cjs +23 -26
- package/dist/primitives.js +23 -26
- package/dist/suggestion.cjs +12 -5
- package/dist/suggestion.d.cts +1 -1
- package/dist/suggestion.d.ts +1 -1
- package/dist/suggestion.js +12 -5
- package/dist/valueparser.cjs +2 -1
- package/dist/valueparser.js +2 -1
- package/package.json +2 -2
package/dist/constructs.cjs
CHANGED
|
@@ -1019,12 +1019,16 @@ function analyzeNoMatchContext(parsers) {
|
|
|
1019
1019
|
* construction. This is a programmer error, not a user error.
|
|
1020
1020
|
*/
|
|
1021
1021
|
var DuplicateOptionError = class extends Error {
|
|
1022
|
+
/** The option name shared by multiple fields. */
|
|
1023
|
+
optionName;
|
|
1024
|
+
/** The fields declaring the option. */
|
|
1025
|
+
sources;
|
|
1022
1026
|
constructor(optionName$1, sources) {
|
|
1023
1027
|
const sourceNames = sources.map((s) => typeof s === "symbol" ? s.description ?? s.toString() : s);
|
|
1024
1028
|
super(`Duplicate option name "${optionName$1}" found in fields: ${sourceNames.join(", ")}. Each option name must be unique within a parser combinator.`);
|
|
1029
|
+
this.name = "DuplicateOptionError";
|
|
1025
1030
|
this.optionName = optionName$1;
|
|
1026
1031
|
this.sources = sources;
|
|
1027
|
-
this.name = "DuplicateOptionError";
|
|
1028
1032
|
}
|
|
1029
1033
|
};
|
|
1030
1034
|
/**
|
|
@@ -1032,6 +1036,8 @@ var DuplicateOptionError = class extends Error {
|
|
|
1032
1036
|
* during parser construction. This is a programmer error, not a user error.
|
|
1033
1037
|
*/
|
|
1034
1038
|
var DuplicateCommandNameError = class extends TypeError {
|
|
1039
|
+
commandName;
|
|
1040
|
+
sources;
|
|
1035
1041
|
constructor(commandName, sources) {
|
|
1036
1042
|
const sourceNames = sources.map((s) => typeof s === "symbol" ? s.description ?? s.toString() : s);
|
|
1037
1043
|
super(`Duplicate command name "${commandName}" found in parsers: ${sourceNames.join(", ")}. Each command name or alias must be unique within active parser alternatives.`);
|
package/dist/constructs.d.cts
CHANGED
|
@@ -103,7 +103,9 @@ interface OrErrorOptions {
|
|
|
103
103
|
* construction. This is a programmer error, not a user error.
|
|
104
104
|
*/
|
|
105
105
|
declare class DuplicateOptionError extends Error {
|
|
106
|
+
/** The option name shared by multiple fields. */
|
|
106
107
|
readonly optionName: string;
|
|
108
|
+
/** The fields declaring the option. */
|
|
107
109
|
readonly sources: readonly (string | symbol)[];
|
|
108
110
|
constructor(optionName: string, sources: readonly (string | symbol)[]);
|
|
109
111
|
}
|
package/dist/constructs.d.ts
CHANGED
|
@@ -103,7 +103,9 @@ interface OrErrorOptions {
|
|
|
103
103
|
* construction. This is a programmer error, not a user error.
|
|
104
104
|
*/
|
|
105
105
|
declare class DuplicateOptionError extends Error {
|
|
106
|
+
/** The option name shared by multiple fields. */
|
|
106
107
|
readonly optionName: string;
|
|
108
|
+
/** The fields declaring the option. */
|
|
107
109
|
readonly sources: readonly (string | symbol)[];
|
|
108
110
|
constructor(optionName: string, sources: readonly (string | symbol)[]);
|
|
109
111
|
}
|
package/dist/constructs.js
CHANGED
|
@@ -1019,12 +1019,16 @@ function analyzeNoMatchContext(parsers) {
|
|
|
1019
1019
|
* construction. This is a programmer error, not a user error.
|
|
1020
1020
|
*/
|
|
1021
1021
|
var DuplicateOptionError = class extends Error {
|
|
1022
|
+
/** The option name shared by multiple fields. */
|
|
1023
|
+
optionName;
|
|
1024
|
+
/** The fields declaring the option. */
|
|
1025
|
+
sources;
|
|
1022
1026
|
constructor(optionName$1, sources) {
|
|
1023
1027
|
const sourceNames = sources.map((s) => typeof s === "symbol" ? s.description ?? s.toString() : s);
|
|
1024
1028
|
super(`Duplicate option name "${optionName$1}" found in fields: ${sourceNames.join(", ")}. Each option name must be unique within a parser combinator.`);
|
|
1029
|
+
this.name = "DuplicateOptionError";
|
|
1025
1030
|
this.optionName = optionName$1;
|
|
1026
1031
|
this.sources = sources;
|
|
1027
|
-
this.name = "DuplicateOptionError";
|
|
1028
1032
|
}
|
|
1029
1033
|
};
|
|
1030
1034
|
/**
|
|
@@ -1032,6 +1036,8 @@ var DuplicateOptionError = class extends Error {
|
|
|
1032
1036
|
* during parser construction. This is a programmer error, not a user error.
|
|
1033
1037
|
*/
|
|
1034
1038
|
var DuplicateCommandNameError = class extends TypeError {
|
|
1039
|
+
commandName;
|
|
1040
|
+
sources;
|
|
1035
1041
|
constructor(commandName, sources) {
|
|
1036
1042
|
const sourceNames = sources.map((s) => typeof s === "symbol" ? s.description ?? s.toString() : s);
|
|
1037
1043
|
super(`Duplicate command name "${commandName}" found in parsers: ${sourceNames.join(", ")}. Each command name or alias must be unique within active parser alternatives.`);
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/internal/joined-file-suggestion.ts
|
|
3
|
+
const joinedFiles = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
/**
|
|
5
|
+
* Keeps a joined file fallback's origin available to the Bash encoder.
|
|
6
|
+
* Other shells retain the existing literal representation.
|
|
7
|
+
* @param prefix The option name and delimiter.
|
|
8
|
+
* @param file The original file suggestion.
|
|
9
|
+
* @param value The value prefix being completed.
|
|
10
|
+
* @returns The literal fallback with private file metadata.
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
function joinedFileSuggestion(prefix, file, value) {
|
|
14
|
+
const literal = {
|
|
15
|
+
kind: "literal",
|
|
16
|
+
text: prefix + (file.pattern ?? ""),
|
|
17
|
+
description: file.description
|
|
18
|
+
};
|
|
19
|
+
joinedFiles.set(literal, {
|
|
20
|
+
files: [{
|
|
21
|
+
prefix,
|
|
22
|
+
file: file.pattern === value && !/[?*]/.test(value) && !(file.prefix != null && file.prefix !== "" && value.startsWith(file.prefix)) ? {
|
|
23
|
+
...file,
|
|
24
|
+
pattern: void 0
|
|
25
|
+
} : file
|
|
26
|
+
}],
|
|
27
|
+
literal: false
|
|
28
|
+
});
|
|
29
|
+
return literal;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Retrieves the originating file suggestion for a joined literal fallback.
|
|
33
|
+
* @param suggestion The suggestion to inspect.
|
|
34
|
+
* @returns Its private file metadata, if present.
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
function getJoinedFileSuggestion(suggestion) {
|
|
38
|
+
return joinedFiles.get(suggestion);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Preserves file origins when equal literal fallbacks are deduplicated.
|
|
42
|
+
* @param target The retained suggestion.
|
|
43
|
+
* @param source The duplicate suggestion.
|
|
44
|
+
* @internal
|
|
45
|
+
*/
|
|
46
|
+
function mergeJoinedFileSuggestions(target, source) {
|
|
47
|
+
const a = joinedFiles.get(target);
|
|
48
|
+
const b = joinedFiles.get(source);
|
|
49
|
+
if (a === void 0 && b === void 0) return;
|
|
50
|
+
const files = [...a?.files ?? [], ...b?.files ?? []];
|
|
51
|
+
const seen = /* @__PURE__ */ new Set();
|
|
52
|
+
joinedFiles.set(target, {
|
|
53
|
+
literal: (a?.literal ?? true) || (b?.literal ?? true),
|
|
54
|
+
files: files.filter(({ prefix, file }) => {
|
|
55
|
+
const key = JSON.stringify([
|
|
56
|
+
prefix,
|
|
57
|
+
file.type,
|
|
58
|
+
file.pattern,
|
|
59
|
+
file.prefix,
|
|
60
|
+
file.includeHidden === true,
|
|
61
|
+
file.extensions?.toSorted()
|
|
62
|
+
]);
|
|
63
|
+
if (seen.has(key)) return false;
|
|
64
|
+
seen.add(key);
|
|
65
|
+
return true;
|
|
66
|
+
})
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
exports.getJoinedFileSuggestion = getJoinedFileSuggestion;
|
|
72
|
+
exports.joinedFileSuggestion = joinedFileSuggestion;
|
|
73
|
+
exports.mergeJoinedFileSuggestions = mergeJoinedFileSuggestions;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
//#region src/internal/joined-file-suggestion.ts
|
|
2
|
+
const joinedFiles = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
/**
|
|
4
|
+
* Keeps a joined file fallback's origin available to the Bash encoder.
|
|
5
|
+
* Other shells retain the existing literal representation.
|
|
6
|
+
* @param prefix The option name and delimiter.
|
|
7
|
+
* @param file The original file suggestion.
|
|
8
|
+
* @param value The value prefix being completed.
|
|
9
|
+
* @returns The literal fallback with private file metadata.
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
function joinedFileSuggestion(prefix, file, value) {
|
|
13
|
+
const literal = {
|
|
14
|
+
kind: "literal",
|
|
15
|
+
text: prefix + (file.pattern ?? ""),
|
|
16
|
+
description: file.description
|
|
17
|
+
};
|
|
18
|
+
joinedFiles.set(literal, {
|
|
19
|
+
files: [{
|
|
20
|
+
prefix,
|
|
21
|
+
file: file.pattern === value && !/[?*]/.test(value) && !(file.prefix != null && file.prefix !== "" && value.startsWith(file.prefix)) ? {
|
|
22
|
+
...file,
|
|
23
|
+
pattern: void 0
|
|
24
|
+
} : file
|
|
25
|
+
}],
|
|
26
|
+
literal: false
|
|
27
|
+
});
|
|
28
|
+
return literal;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Retrieves the originating file suggestion for a joined literal fallback.
|
|
32
|
+
* @param suggestion The suggestion to inspect.
|
|
33
|
+
* @returns Its private file metadata, if present.
|
|
34
|
+
* @internal
|
|
35
|
+
*/
|
|
36
|
+
function getJoinedFileSuggestion(suggestion) {
|
|
37
|
+
return joinedFiles.get(suggestion);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Preserves file origins when equal literal fallbacks are deduplicated.
|
|
41
|
+
* @param target The retained suggestion.
|
|
42
|
+
* @param source The duplicate suggestion.
|
|
43
|
+
* @internal
|
|
44
|
+
*/
|
|
45
|
+
function mergeJoinedFileSuggestions(target, source) {
|
|
46
|
+
const a = joinedFiles.get(target);
|
|
47
|
+
const b = joinedFiles.get(source);
|
|
48
|
+
if (a === void 0 && b === void 0) return;
|
|
49
|
+
const files = [...a?.files ?? [], ...b?.files ?? []];
|
|
50
|
+
const seen = /* @__PURE__ */ new Set();
|
|
51
|
+
joinedFiles.set(target, {
|
|
52
|
+
literal: (a?.literal ?? true) || (b?.literal ?? true),
|
|
53
|
+
files: files.filter(({ prefix, file }) => {
|
|
54
|
+
const key = JSON.stringify([
|
|
55
|
+
prefix,
|
|
56
|
+
file.type,
|
|
57
|
+
file.pattern,
|
|
58
|
+
file.prefix,
|
|
59
|
+
file.includeHidden === true,
|
|
60
|
+
file.extensions?.toSorted()
|
|
61
|
+
]);
|
|
62
|
+
if (seen.has(key)) return false;
|
|
63
|
+
seen.add(key);
|
|
64
|
+
return true;
|
|
65
|
+
})
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
//#endregion
|
|
70
|
+
export { getJoinedFileSuggestion, joinedFileSuggestion, mergeJoinedFileSuggestions };
|
|
@@ -758,6 +758,14 @@ type Suggestion = {
|
|
|
758
758
|
* The current prefix/pattern for fallback when native completion is unavailable.
|
|
759
759
|
*/
|
|
760
760
|
readonly pattern?: string;
|
|
761
|
+
/**
|
|
762
|
+
* Literal text at the start of `pattern` that is preserved on insertion
|
|
763
|
+
* but excluded from native filesystem matching, such as `output=`.
|
|
764
|
+
* Shell adapters ignore it if it does not lead both the pattern and
|
|
765
|
+
* the current word. Regenerate installed scripts to use this field.
|
|
766
|
+
* @since 1.1.13
|
|
767
|
+
*/
|
|
768
|
+
readonly prefix?: string;
|
|
761
769
|
/**
|
|
762
770
|
* The type of file system entries to complete.
|
|
763
771
|
*/
|
|
@@ -758,6 +758,14 @@ type Suggestion = {
|
|
|
758
758
|
* The current prefix/pattern for fallback when native completion is unavailable.
|
|
759
759
|
*/
|
|
760
760
|
readonly pattern?: string;
|
|
761
|
+
/**
|
|
762
|
+
* Literal text at the start of `pattern` that is preserved on insertion
|
|
763
|
+
* but excluded from native filesystem matching, such as `output=`.
|
|
764
|
+
* Shell adapters ignore it if it does not lead both the pattern and
|
|
765
|
+
* the current word. Regenerate installed scripts to use this field.
|
|
766
|
+
* @since 1.1.13
|
|
767
|
+
*/
|
|
768
|
+
readonly prefix?: string;
|
|
761
769
|
/**
|
|
762
770
|
* The type of file system entries to complete.
|
|
763
771
|
*/
|
package/dist/modifiers.cjs
CHANGED
|
@@ -4,6 +4,7 @@ const require_mode_dispatch = require('./internal/mode-dispatch.cjs');
|
|
|
4
4
|
const require_dependency_runtime = require('./dependency-runtime.cjs');
|
|
5
5
|
const require_internal_parser = require('./internal/parser.cjs');
|
|
6
6
|
const require_annotation_state = require('./annotation-state.cjs');
|
|
7
|
+
const require_joined_file_suggestion = require('./internal/joined-file-suggestion.cjs');
|
|
7
8
|
const require_command_doc_metadata = require('./internal/command-doc-metadata.cjs');
|
|
8
9
|
const require_passthrough = require('./internal/passthrough.cjs');
|
|
9
10
|
const require_execution_context = require('./execution-context.cjs');
|
|
@@ -1516,6 +1517,7 @@ function multiple(parser, options = {}) {
|
|
|
1516
1517
|
"file",
|
|
1517
1518
|
suggestion.type,
|
|
1518
1519
|
suggestion.pattern ?? "",
|
|
1520
|
+
suggestion.prefix ?? "",
|
|
1519
1521
|
suggestion.includeHidden === true,
|
|
1520
1522
|
suggestion.extensions == null ? "" : suggestion.extensions.toSorted().join("\0"),
|
|
1521
1523
|
description
|
|
@@ -1523,14 +1525,16 @@ function multiple(parser, options = {}) {
|
|
|
1523
1525
|
};
|
|
1524
1526
|
return require_mode_dispatch.dispatchIterableByMode(parser.mode, function* () {
|
|
1525
1527
|
const selectedValues = collectSelectedValuesSync();
|
|
1526
|
-
const emitted = /* @__PURE__ */ new
|
|
1528
|
+
const emitted = /* @__PURE__ */ new Map();
|
|
1527
1529
|
const yieldUnique = function* (suggestions) {
|
|
1528
1530
|
for (const s of suggestions) {
|
|
1529
1531
|
const key = suggestionKey(s);
|
|
1530
|
-
if (shouldInclude(selectedValues, s)
|
|
1531
|
-
|
|
1532
|
+
if (!shouldInclude(selectedValues, s)) continue;
|
|
1533
|
+
const existing = emitted.get(key);
|
|
1534
|
+
if (existing === void 0) {
|
|
1535
|
+
emitted.set(key, s);
|
|
1532
1536
|
yield s;
|
|
1533
|
-
}
|
|
1537
|
+
} else require_joined_file_suggestion.mergeJoinedFileSuggestions(existing, s);
|
|
1534
1538
|
}
|
|
1535
1539
|
};
|
|
1536
1540
|
let shouldTryFallback = false;
|
|
@@ -1543,14 +1547,16 @@ function multiple(parser, options = {}) {
|
|
|
1543
1547
|
if (shouldTryFallback) yield* yieldUnique(syncParser.suggest(require_execution_context.withChildContext(context, itemIndex, suggestFallbackState), prefix));
|
|
1544
1548
|
}, async function* () {
|
|
1545
1549
|
const selectedValues = await collectSelectedValuesAsync();
|
|
1546
|
-
const emitted = /* @__PURE__ */ new
|
|
1550
|
+
const emitted = /* @__PURE__ */ new Map();
|
|
1547
1551
|
const yieldUnique = async function* (suggestions) {
|
|
1548
1552
|
for await (const s of suggestions) {
|
|
1549
1553
|
const key = suggestionKey(s);
|
|
1550
|
-
if (shouldInclude(selectedValues, s)
|
|
1551
|
-
|
|
1554
|
+
if (!shouldInclude(selectedValues, s)) continue;
|
|
1555
|
+
const existing = emitted.get(key);
|
|
1556
|
+
if (existing === void 0) {
|
|
1557
|
+
emitted.set(key, s);
|
|
1552
1558
|
yield s;
|
|
1553
|
-
}
|
|
1559
|
+
} else require_joined_file_suggestion.mergeJoinedFileSuggestions(existing, s);
|
|
1554
1560
|
}
|
|
1555
1561
|
};
|
|
1556
1562
|
let shouldTryFallback = false;
|
package/dist/modifiers.js
CHANGED
|
@@ -4,6 +4,7 @@ import { dispatchByMode, dispatchIterableByMode, mapModeValue, wrapForMode } fro
|
|
|
4
4
|
import { defineForwardedEffectfulSchedulingNodes } from "./dependency-runtime.js";
|
|
5
5
|
import { defineInheritedAnnotationParser, defineParseLanes, defineSourceBindingOnlyAnnotationCompletionParser, getOwnParseLanes, unmatchedNonCliDependencySourceStateMarker } from "./internal/parser.js";
|
|
6
6
|
import { getDelegatedAnnotationState, hasDelegatedAnnotationCarrier, isAnnotationWrappedInitialState, normalizeDelegatedAnnotationState, normalizeNestedDelegatedAnnotationState } from "./annotation-state.js";
|
|
7
|
+
import { mergeJoinedFileSuggestions } from "./internal/joined-file-suggestion.js";
|
|
7
8
|
import { getCommandDocMetadata, withCommandDocMetadata } from "./internal/command-doc-metadata.js";
|
|
8
9
|
import { defineKnownCompletionLookup, defineOptionMatch, definePassThroughPriority, getKnownCompletion, getOptionMatch, getPassThroughPriority } from "./internal/passthrough.js";
|
|
9
10
|
import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
|
|
@@ -1516,6 +1517,7 @@ function multiple(parser, options = {}) {
|
|
|
1516
1517
|
"file",
|
|
1517
1518
|
suggestion.type,
|
|
1518
1519
|
suggestion.pattern ?? "",
|
|
1520
|
+
suggestion.prefix ?? "",
|
|
1519
1521
|
suggestion.includeHidden === true,
|
|
1520
1522
|
suggestion.extensions == null ? "" : suggestion.extensions.toSorted().join("\0"),
|
|
1521
1523
|
description
|
|
@@ -1523,14 +1525,16 @@ function multiple(parser, options = {}) {
|
|
|
1523
1525
|
};
|
|
1524
1526
|
return dispatchIterableByMode(parser.mode, function* () {
|
|
1525
1527
|
const selectedValues = collectSelectedValuesSync();
|
|
1526
|
-
const emitted = /* @__PURE__ */ new
|
|
1528
|
+
const emitted = /* @__PURE__ */ new Map();
|
|
1527
1529
|
const yieldUnique = function* (suggestions) {
|
|
1528
1530
|
for (const s of suggestions) {
|
|
1529
1531
|
const key = suggestionKey(s);
|
|
1530
|
-
if (shouldInclude(selectedValues, s)
|
|
1531
|
-
|
|
1532
|
+
if (!shouldInclude(selectedValues, s)) continue;
|
|
1533
|
+
const existing = emitted.get(key);
|
|
1534
|
+
if (existing === void 0) {
|
|
1535
|
+
emitted.set(key, s);
|
|
1532
1536
|
yield s;
|
|
1533
|
-
}
|
|
1537
|
+
} else mergeJoinedFileSuggestions(existing, s);
|
|
1534
1538
|
}
|
|
1535
1539
|
};
|
|
1536
1540
|
let shouldTryFallback = false;
|
|
@@ -1543,14 +1547,16 @@ function multiple(parser, options = {}) {
|
|
|
1543
1547
|
if (shouldTryFallback) yield* yieldUnique(syncParser.suggest(withChildContext(context, itemIndex, suggestFallbackState), prefix));
|
|
1544
1548
|
}, async function* () {
|
|
1545
1549
|
const selectedValues = await collectSelectedValuesAsync();
|
|
1546
|
-
const emitted = /* @__PURE__ */ new
|
|
1550
|
+
const emitted = /* @__PURE__ */ new Map();
|
|
1547
1551
|
const yieldUnique = async function* (suggestions) {
|
|
1548
1552
|
for await (const s of suggestions) {
|
|
1549
1553
|
const key = suggestionKey(s);
|
|
1550
|
-
if (shouldInclude(selectedValues, s)
|
|
1551
|
-
|
|
1554
|
+
if (!shouldInclude(selectedValues, s)) continue;
|
|
1555
|
+
const existing = emitted.get(key);
|
|
1556
|
+
if (existing === void 0) {
|
|
1557
|
+
emitted.set(key, s);
|
|
1552
1558
|
yield s;
|
|
1553
|
-
}
|
|
1559
|
+
} else mergeJoinedFileSuggestions(existing, s);
|
|
1554
1560
|
}
|
|
1555
1561
|
};
|
|
1556
1562
|
let shouldTryFallback = false;
|
package/dist/primitives.cjs
CHANGED
|
@@ -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_joined_file_suggestion = require('./internal/joined-file-suggestion.cjs');
|
|
9
10
|
const require_command_doc_metadata = require('./internal/command-doc-metadata.cjs');
|
|
10
11
|
const require_passthrough = require('./internal/passthrough.cjs');
|
|
11
12
|
const require_command_alias = require('./internal/command-alias.cjs');
|
|
@@ -253,33 +254,33 @@ function* getSuggestionsWithDependency(valueParser, prefix, dependencyRegistry,
|
|
|
253
254
|
}
|
|
254
255
|
yield* valueParser.suggest(prefix);
|
|
255
256
|
}
|
|
257
|
+
/** Returns the joined prefix accepted by option parsing. */
|
|
258
|
+
function joinedOptionPrefix(names, input) {
|
|
259
|
+
return names.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2).map((name) => name + (name.startsWith("/") ? ":" : "=")).find((prefix) => input.startsWith(prefix));
|
|
260
|
+
}
|
|
256
261
|
/**
|
|
257
262
|
* Internal sync helper for option suggest functionality.
|
|
258
263
|
* @internal
|
|
259
264
|
*/
|
|
260
265
|
function* suggestOptionSync(optionNames$1, valueParser, hidden, description, context, prefix) {
|
|
261
|
-
if (hidden) return;
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
+
if (hidden || context.optionsTerminated) return;
|
|
267
|
+
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
268
|
+
const joinedPrefix = joinedOptionPrefix(optionNames$1, prefix);
|
|
269
|
+
if (joinedPrefix !== void 0 && !expectingValue) {
|
|
270
|
+
const optionPart = joinedPrefix.slice(0, -1);
|
|
271
|
+
const valuePart = prefix.slice(joinedPrefix.length);
|
|
266
272
|
if (optionNames$1.includes(optionPart)) {
|
|
267
273
|
if (valueParser && valueParser.suggest) {
|
|
268
274
|
const valueSuggestions = getSuggestionsWithDependency(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
269
275
|
for (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
270
276
|
kind: "literal",
|
|
271
|
-
text: `${
|
|
272
|
-
description: suggestion.description
|
|
273
|
-
};
|
|
274
|
-
else yield {
|
|
275
|
-
kind: "literal",
|
|
276
|
-
text: `${optionPart}=${suggestion.pattern || ""}`,
|
|
277
|
+
text: `${joinedPrefix}${suggestion.text}`,
|
|
277
278
|
description: suggestion.description
|
|
278
279
|
};
|
|
280
|
+
else yield require_joined_file_suggestion.joinedFileSuggestion(joinedPrefix, suggestion, valuePart);
|
|
279
281
|
}
|
|
280
282
|
}
|
|
281
283
|
} else {
|
|
282
|
-
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
283
284
|
if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
284
285
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
285
286
|
if (prefix === "-" && optionName$1.length !== 2) continue;
|
|
@@ -343,28 +344,24 @@ async function* getSuggestionsWithDependencyAsync(valueParser, prefix, dependenc
|
|
|
343
344
|
* @internal
|
|
344
345
|
*/
|
|
345
346
|
async function* suggestOptionAsync(optionNames$1, valueParser, hidden, description, context, prefix) {
|
|
346
|
-
if (hidden) return;
|
|
347
|
-
const
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
const
|
|
347
|
+
if (hidden || context.optionsTerminated) return;
|
|
348
|
+
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
349
|
+
const joinedPrefix = joinedOptionPrefix(optionNames$1, prefix);
|
|
350
|
+
if (joinedPrefix !== void 0 && !expectingValue) {
|
|
351
|
+
const optionPart = joinedPrefix.slice(0, -1);
|
|
352
|
+
const valuePart = prefix.slice(joinedPrefix.length);
|
|
351
353
|
if (optionNames$1.includes(optionPart)) {
|
|
352
354
|
if (valueParser && valueParser.suggest) {
|
|
353
355
|
const valueSuggestions = getSuggestionsWithDependencyAsync(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
354
356
|
for await (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
355
357
|
kind: "literal",
|
|
356
|
-
text: `${
|
|
357
|
-
description: suggestion.description
|
|
358
|
-
};
|
|
359
|
-
else yield {
|
|
360
|
-
kind: "literal",
|
|
361
|
-
text: `${optionPart}=${suggestion.pattern || ""}`,
|
|
358
|
+
text: `${joinedPrefix}${suggestion.text}`,
|
|
362
359
|
description: suggestion.description
|
|
363
360
|
};
|
|
361
|
+
else yield require_joined_file_suggestion.joinedFileSuggestion(joinedPrefix, suggestion, valuePart);
|
|
364
362
|
}
|
|
365
363
|
}
|
|
366
364
|
} else {
|
|
367
|
-
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
368
365
|
if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
369
366
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
370
367
|
if (prefix === "-" && optionName$1.length !== 2) continue;
|
|
@@ -922,8 +919,8 @@ function flag(...args) {
|
|
|
922
919
|
error: require_message.message`${require_message.optionNames(optionNames$1)}: ${state.error}`
|
|
923
920
|
};
|
|
924
921
|
},
|
|
925
|
-
suggest(
|
|
926
|
-
if (require_usage.isSuggestionHidden(options.hidden)) return [];
|
|
922
|
+
suggest(context, prefix) {
|
|
923
|
+
if (require_usage.isSuggestionHidden(options.hidden) || context.optionsTerminated) return [];
|
|
927
924
|
const suggestions = [];
|
|
928
925
|
if (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+")) {
|
|
929
926
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
package/dist/primitives.js
CHANGED
|
@@ -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 { joinedFileSuggestion } from "./internal/joined-file-suggestion.js";
|
|
9
10
|
import { getCommandDocMetadata, withCommandDocMetadata } from "./internal/command-doc-metadata.js";
|
|
10
11
|
import { defineKnownCompletion, defineOptionMatch, definePassThroughPriority, getOptionMatch, getPassThroughFailure, getPassThroughPriority } from "./internal/passthrough.js";
|
|
11
12
|
import { hiddenCommandAliasesKey } from "./internal/command-alias.js";
|
|
@@ -253,33 +254,33 @@ function* getSuggestionsWithDependency(valueParser, prefix, dependencyRegistry,
|
|
|
253
254
|
}
|
|
254
255
|
yield* valueParser.suggest(prefix);
|
|
255
256
|
}
|
|
257
|
+
/** Returns the joined prefix accepted by option parsing. */
|
|
258
|
+
function joinedOptionPrefix(names, input) {
|
|
259
|
+
return names.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2).map((name) => name + (name.startsWith("/") ? ":" : "=")).find((prefix) => input.startsWith(prefix));
|
|
260
|
+
}
|
|
256
261
|
/**
|
|
257
262
|
* Internal sync helper for option suggest functionality.
|
|
258
263
|
* @internal
|
|
259
264
|
*/
|
|
260
265
|
function* suggestOptionSync(optionNames$1, valueParser, hidden, description, context, prefix) {
|
|
261
|
-
if (hidden) return;
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
+
if (hidden || context.optionsTerminated) return;
|
|
267
|
+
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
268
|
+
const joinedPrefix = joinedOptionPrefix(optionNames$1, prefix);
|
|
269
|
+
if (joinedPrefix !== void 0 && !expectingValue) {
|
|
270
|
+
const optionPart = joinedPrefix.slice(0, -1);
|
|
271
|
+
const valuePart = prefix.slice(joinedPrefix.length);
|
|
266
272
|
if (optionNames$1.includes(optionPart)) {
|
|
267
273
|
if (valueParser && valueParser.suggest) {
|
|
268
274
|
const valueSuggestions = getSuggestionsWithDependency(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
269
275
|
for (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
270
276
|
kind: "literal",
|
|
271
|
-
text: `${
|
|
272
|
-
description: suggestion.description
|
|
273
|
-
};
|
|
274
|
-
else yield {
|
|
275
|
-
kind: "literal",
|
|
276
|
-
text: `${optionPart}=${suggestion.pattern || ""}`,
|
|
277
|
+
text: `${joinedPrefix}${suggestion.text}`,
|
|
277
278
|
description: suggestion.description
|
|
278
279
|
};
|
|
280
|
+
else yield joinedFileSuggestion(joinedPrefix, suggestion, valuePart);
|
|
279
281
|
}
|
|
280
282
|
}
|
|
281
283
|
} else {
|
|
282
|
-
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
283
284
|
if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
284
285
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
285
286
|
if (prefix === "-" && optionName$1.length !== 2) continue;
|
|
@@ -343,28 +344,24 @@ async function* getSuggestionsWithDependencyAsync(valueParser, prefix, dependenc
|
|
|
343
344
|
* @internal
|
|
344
345
|
*/
|
|
345
346
|
async function* suggestOptionAsync(optionNames$1, valueParser, hidden, description, context, prefix) {
|
|
346
|
-
if (hidden) return;
|
|
347
|
-
const
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
const
|
|
347
|
+
if (hidden || context.optionsTerminated) return;
|
|
348
|
+
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
349
|
+
const joinedPrefix = joinedOptionPrefix(optionNames$1, prefix);
|
|
350
|
+
if (joinedPrefix !== void 0 && !expectingValue) {
|
|
351
|
+
const optionPart = joinedPrefix.slice(0, -1);
|
|
352
|
+
const valuePart = prefix.slice(joinedPrefix.length);
|
|
351
353
|
if (optionNames$1.includes(optionPart)) {
|
|
352
354
|
if (valueParser && valueParser.suggest) {
|
|
353
355
|
const valueSuggestions = getSuggestionsWithDependencyAsync(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
354
356
|
for await (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
355
357
|
kind: "literal",
|
|
356
|
-
text: `${
|
|
357
|
-
description: suggestion.description
|
|
358
|
-
};
|
|
359
|
-
else yield {
|
|
360
|
-
kind: "literal",
|
|
361
|
-
text: `${optionPart}=${suggestion.pattern || ""}`,
|
|
358
|
+
text: `${joinedPrefix}${suggestion.text}`,
|
|
362
359
|
description: suggestion.description
|
|
363
360
|
};
|
|
361
|
+
else yield joinedFileSuggestion(joinedPrefix, suggestion, valuePart);
|
|
364
362
|
}
|
|
365
363
|
}
|
|
366
364
|
} else {
|
|
367
|
-
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
368
365
|
if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
369
366
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
370
367
|
if (prefix === "-" && optionName$1.length !== 2) continue;
|
|
@@ -922,8 +919,8 @@ function flag(...args) {
|
|
|
922
919
|
error: message`${optionNames(optionNames$1)}: ${state.error}`
|
|
923
920
|
};
|
|
924
921
|
},
|
|
925
|
-
suggest(
|
|
926
|
-
if (isSuggestionHidden(options.hidden)) return [];
|
|
922
|
+
suggest(context, prefix) {
|
|
923
|
+
if (isSuggestionHidden(options.hidden) || context.optionsTerminated) return [];
|
|
927
924
|
const suggestions = [];
|
|
928
925
|
if (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+")) {
|
|
929
926
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
package/dist/suggestion.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const require_usage = require('./usage.cjs');
|
|
2
2
|
const require_message = require('./message.cjs');
|
|
3
|
+
const require_joined_file_suggestion = require('./internal/joined-file-suggestion.cjs');
|
|
3
4
|
|
|
4
5
|
//#region src/suggestion.ts
|
|
5
6
|
/**
|
|
@@ -322,22 +323,27 @@ function appendValueHint(base, input, candidates, options) {
|
|
|
322
323
|
*
|
|
323
324
|
* For literal suggestions, the text itself is used as the key.
|
|
324
325
|
* For file suggestions, a composite key is created from the type,
|
|
325
|
-
* extensions, and
|
|
326
|
+
* extensions, pattern, and insertion prefix.
|
|
326
327
|
*
|
|
327
328
|
* @param suggestion The suggestion to create a key for
|
|
328
329
|
* @returns A string key that uniquely identifies this suggestion
|
|
329
330
|
* @internal
|
|
330
331
|
*/
|
|
331
332
|
function getSuggestionKey(suggestion) {
|
|
332
|
-
if (suggestion.kind === "literal") return suggestion.text
|
|
333
|
-
return `
|
|
333
|
+
if (suggestion.kind === "literal") return `literal:${suggestion.text}`;
|
|
334
|
+
return `file:${JSON.stringify([
|
|
335
|
+
suggestion.type,
|
|
336
|
+
suggestion.extensions?.toSorted().join(",") ?? "",
|
|
337
|
+
suggestion.pattern ?? "",
|
|
338
|
+
suggestion.prefix ?? ""
|
|
339
|
+
])}`;
|
|
334
340
|
}
|
|
335
341
|
/**
|
|
336
342
|
* Removes duplicate suggestions from an array while preserving order.
|
|
337
343
|
*
|
|
338
344
|
* Suggestions are considered duplicates if they have the same key:
|
|
339
345
|
* - Literal suggestions: same text
|
|
340
|
-
* - File suggestions: same type, extensions, and
|
|
346
|
+
* - File suggestions: same type, extensions, pattern, and insertion prefix
|
|
341
347
|
*
|
|
342
348
|
* The first occurrence of each unique suggestion is kept. For file
|
|
343
349
|
* suggestions, `includeHidden` is merged across duplicates: if any
|
|
@@ -370,7 +376,8 @@ function deduplicateSuggestions(suggestions) {
|
|
|
370
376
|
if (existing == null) {
|
|
371
377
|
entries.set(key, suggestion);
|
|
372
378
|
order.push(key);
|
|
373
|
-
} else if (suggestion.kind === "
|
|
379
|
+
} else if (suggestion.kind === "literal" && existing.kind === "literal") require_joined_file_suggestion.mergeJoinedFileSuggestions(existing, suggestion);
|
|
380
|
+
else if (suggestion.kind === "file" && existing.kind === "file" && suggestion.includeHidden === true && existing.includeHidden !== true) entries.set(key, {
|
|
374
381
|
...existing,
|
|
375
382
|
includeHidden: true
|
|
376
383
|
});
|
package/dist/suggestion.d.cts
CHANGED
|
@@ -202,7 +202,7 @@ declare function appendValueHint(base: Message, input: string, candidates: reado
|
|
|
202
202
|
*
|
|
203
203
|
* Suggestions are considered duplicates if they have the same key:
|
|
204
204
|
* - Literal suggestions: same text
|
|
205
|
-
* - File suggestions: same type, extensions, and
|
|
205
|
+
* - File suggestions: same type, extensions, pattern, and insertion prefix
|
|
206
206
|
*
|
|
207
207
|
* The first occurrence of each unique suggestion is kept. For file
|
|
208
208
|
* suggestions, `includeHidden` is merged across duplicates: if any
|
package/dist/suggestion.d.ts
CHANGED
|
@@ -202,7 +202,7 @@ declare function appendValueHint(base: Message, input: string, candidates: reado
|
|
|
202
202
|
*
|
|
203
203
|
* Suggestions are considered duplicates if they have the same key:
|
|
204
204
|
* - Literal suggestions: same text
|
|
205
|
-
* - File suggestions: same type, extensions, and
|
|
205
|
+
* - File suggestions: same type, extensions, pattern, and insertion prefix
|
|
206
206
|
*
|
|
207
207
|
* The first occurrence of each unique suggestion is kept. For file
|
|
208
208
|
* suggestions, `includeHidden` is merged across duplicates: if any
|