@optique/core 1.2.11 → 1.2.13
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
|
@@ -514,12 +514,16 @@ function analyzeNoMatchContext(parsers) {
|
|
|
514
514
|
* construction. This is a programmer error, not a user error.
|
|
515
515
|
*/
|
|
516
516
|
var DuplicateOptionError = class extends Error {
|
|
517
|
+
/** The option name shared by multiple fields. */
|
|
518
|
+
optionName;
|
|
519
|
+
/** The fields declaring the option. */
|
|
520
|
+
sources;
|
|
517
521
|
constructor(optionName$1, sources) {
|
|
518
522
|
const sourceNames = sources.map((s) => typeof s === "symbol" ? s.description ?? s.toString() : s);
|
|
519
523
|
super(`Duplicate option name "${optionName$1}" found in fields: ${sourceNames.join(", ")}. Each option name must be unique within a parser combinator.`);
|
|
524
|
+
this.name = "DuplicateOptionError";
|
|
520
525
|
this.optionName = optionName$1;
|
|
521
526
|
this.sources = sources;
|
|
522
|
-
this.name = "DuplicateOptionError";
|
|
523
527
|
}
|
|
524
528
|
};
|
|
525
529
|
/**
|
|
@@ -527,6 +531,8 @@ var DuplicateOptionError = class extends Error {
|
|
|
527
531
|
* during parser construction. This is a programmer error, not a user error.
|
|
528
532
|
*/
|
|
529
533
|
var DuplicateCommandNameError = class extends TypeError {
|
|
534
|
+
commandName;
|
|
535
|
+
sources;
|
|
530
536
|
constructor(commandName, sources) {
|
|
531
537
|
const sourceNames = sources.map((s) => typeof s === "symbol" ? s.description ?? s.toString() : s);
|
|
532
538
|
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
|
@@ -514,12 +514,16 @@ function analyzeNoMatchContext(parsers) {
|
|
|
514
514
|
* construction. This is a programmer error, not a user error.
|
|
515
515
|
*/
|
|
516
516
|
var DuplicateOptionError = class extends Error {
|
|
517
|
+
/** The option name shared by multiple fields. */
|
|
518
|
+
optionName;
|
|
519
|
+
/** The fields declaring the option. */
|
|
520
|
+
sources;
|
|
517
521
|
constructor(optionName$1, sources) {
|
|
518
522
|
const sourceNames = sources.map((s) => typeof s === "symbol" ? s.description ?? s.toString() : s);
|
|
519
523
|
super(`Duplicate option name "${optionName$1}" found in fields: ${sourceNames.join(", ")}. Each option name must be unique within a parser combinator.`);
|
|
524
|
+
this.name = "DuplicateOptionError";
|
|
520
525
|
this.optionName = optionName$1;
|
|
521
526
|
this.sources = sources;
|
|
522
|
-
this.name = "DuplicateOptionError";
|
|
523
527
|
}
|
|
524
528
|
};
|
|
525
529
|
/**
|
|
@@ -527,6 +531,8 @@ var DuplicateOptionError = class extends Error {
|
|
|
527
531
|
* during parser construction. This is a programmer error, not a user error.
|
|
528
532
|
*/
|
|
529
533
|
var DuplicateCommandNameError = class extends TypeError {
|
|
534
|
+
commandName;
|
|
535
|
+
sources;
|
|
530
536
|
constructor(commandName, sources) {
|
|
531
537
|
const sourceNames = sources.map((s) => typeof s === "symbol" ? s.description ?? s.toString() : s);
|
|
532
538
|
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 };
|
|
@@ -630,6 +630,14 @@ type Suggestion = {
|
|
|
630
630
|
* The current prefix/pattern for fallback when native completion is unavailable.
|
|
631
631
|
*/
|
|
632
632
|
readonly pattern?: string;
|
|
633
|
+
/**
|
|
634
|
+
* Literal text at the start of `pattern` that is preserved on insertion
|
|
635
|
+
* but excluded from native filesystem matching, such as `output=`.
|
|
636
|
+
* Shell adapters ignore it if it does not lead both the pattern and
|
|
637
|
+
* the current word. Regenerate installed scripts to use this field.
|
|
638
|
+
* @since 1.1.13
|
|
639
|
+
*/
|
|
640
|
+
readonly prefix?: string;
|
|
633
641
|
/**
|
|
634
642
|
* The type of file system entries to complete.
|
|
635
643
|
*/
|
|
@@ -630,6 +630,14 @@ type Suggestion = {
|
|
|
630
630
|
* The current prefix/pattern for fallback when native completion is unavailable.
|
|
631
631
|
*/
|
|
632
632
|
readonly pattern?: string;
|
|
633
|
+
/**
|
|
634
|
+
* Literal text at the start of `pattern` that is preserved on insertion
|
|
635
|
+
* but excluded from native filesystem matching, such as `output=`.
|
|
636
|
+
* Shell adapters ignore it if it does not lead both the pattern and
|
|
637
|
+
* the current word. Regenerate installed scripts to use this field.
|
|
638
|
+
* @since 1.1.13
|
|
639
|
+
*/
|
|
640
|
+
readonly prefix?: string;
|
|
633
641
|
/**
|
|
634
642
|
* The type of file system entries to complete.
|
|
635
643
|
*/
|
package/dist/modifiers.cjs
CHANGED
|
@@ -3,6 +3,7 @@ const require_message = require('./message.cjs');
|
|
|
3
3
|
const require_mode_dispatch = require('./internal/mode-dispatch.cjs');
|
|
4
4
|
const require_internal_parser = require('./internal/parser.cjs');
|
|
5
5
|
const require_annotation_state = require('./annotation-state.cjs');
|
|
6
|
+
const require_joined_file_suggestion = require('./internal/joined-file-suggestion.cjs');
|
|
6
7
|
const require_command_doc_metadata = require('./internal/command-doc-metadata.cjs');
|
|
7
8
|
const require_passthrough = require('./internal/passthrough.cjs');
|
|
8
9
|
const require_execution_context = require('./execution-context.cjs');
|
|
@@ -1482,6 +1483,7 @@ function multiple(parser, options = {}) {
|
|
|
1482
1483
|
"file",
|
|
1483
1484
|
suggestion.type,
|
|
1484
1485
|
suggestion.pattern ?? "",
|
|
1486
|
+
suggestion.prefix ?? "",
|
|
1485
1487
|
suggestion.includeHidden === true,
|
|
1486
1488
|
suggestion.extensions == null ? "" : suggestion.extensions.toSorted().join("\0"),
|
|
1487
1489
|
description
|
|
@@ -1489,14 +1491,16 @@ function multiple(parser, options = {}) {
|
|
|
1489
1491
|
};
|
|
1490
1492
|
return require_mode_dispatch.dispatchIterableByMode(parser.mode, function* () {
|
|
1491
1493
|
const selectedValues = collectSelectedValuesSync();
|
|
1492
|
-
const emitted = /* @__PURE__ */ new
|
|
1494
|
+
const emitted = /* @__PURE__ */ new Map();
|
|
1493
1495
|
const yieldUnique = function* (suggestions) {
|
|
1494
1496
|
for (const s of suggestions) {
|
|
1495
1497
|
const key = suggestionKey(s);
|
|
1496
|
-
if (shouldInclude(selectedValues, s)
|
|
1497
|
-
|
|
1498
|
+
if (!shouldInclude(selectedValues, s)) continue;
|
|
1499
|
+
const existing = emitted.get(key);
|
|
1500
|
+
if (existing === void 0) {
|
|
1501
|
+
emitted.set(key, s);
|
|
1498
1502
|
yield s;
|
|
1499
|
-
}
|
|
1503
|
+
} else require_joined_file_suggestion.mergeJoinedFileSuggestions(existing, s);
|
|
1500
1504
|
}
|
|
1501
1505
|
};
|
|
1502
1506
|
let shouldTryFallback = false;
|
|
@@ -1509,14 +1513,16 @@ function multiple(parser, options = {}) {
|
|
|
1509
1513
|
if (shouldTryFallback) yield* yieldUnique(syncParser.suggest(require_execution_context.withChildContext(context, itemIndex, suggestFallbackState), prefix));
|
|
1510
1514
|
}, async function* () {
|
|
1511
1515
|
const selectedValues = await collectSelectedValuesAsync();
|
|
1512
|
-
const emitted = /* @__PURE__ */ new
|
|
1516
|
+
const emitted = /* @__PURE__ */ new Map();
|
|
1513
1517
|
const yieldUnique = async function* (suggestions) {
|
|
1514
1518
|
for await (const s of suggestions) {
|
|
1515
1519
|
const key = suggestionKey(s);
|
|
1516
|
-
if (shouldInclude(selectedValues, s)
|
|
1517
|
-
|
|
1520
|
+
if (!shouldInclude(selectedValues, s)) continue;
|
|
1521
|
+
const existing = emitted.get(key);
|
|
1522
|
+
if (existing === void 0) {
|
|
1523
|
+
emitted.set(key, s);
|
|
1518
1524
|
yield s;
|
|
1519
|
-
}
|
|
1525
|
+
} else require_joined_file_suggestion.mergeJoinedFileSuggestions(existing, s);
|
|
1520
1526
|
}
|
|
1521
1527
|
};
|
|
1522
1528
|
let shouldTryFallback = false;
|
package/dist/modifiers.js
CHANGED
|
@@ -3,6 +3,7 @@ import { formatMessage, message, text } from "./message.js";
|
|
|
3
3
|
import { dispatchByMode, dispatchIterableByMode, mapModeValue, wrapForMode } from "./internal/mode-dispatch.js";
|
|
4
4
|
import { defineInheritedAnnotationParser, defineParseLanes, defineSourceBindingOnlyAnnotationCompletionParser, getOwnParseLanes, unmatchedNonCliDependencySourceStateMarker } from "./internal/parser.js";
|
|
5
5
|
import { getDelegatedAnnotationState, hasDelegatedAnnotationCarrier, isAnnotationWrappedInitialState, normalizeDelegatedAnnotationState, normalizeNestedDelegatedAnnotationState } from "./annotation-state.js";
|
|
6
|
+
import { mergeJoinedFileSuggestions } from "./internal/joined-file-suggestion.js";
|
|
6
7
|
import { getCommandDocMetadata, withCommandDocMetadata } from "./internal/command-doc-metadata.js";
|
|
7
8
|
import { defineKnownCompletionLookup, defineOptionMatch, definePassThroughPriority, getKnownCompletion, getOptionMatch, getPassThroughPriority } from "./internal/passthrough.js";
|
|
8
9
|
import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
|
|
@@ -1482,6 +1483,7 @@ function multiple(parser, options = {}) {
|
|
|
1482
1483
|
"file",
|
|
1483
1484
|
suggestion.type,
|
|
1484
1485
|
suggestion.pattern ?? "",
|
|
1486
|
+
suggestion.prefix ?? "",
|
|
1485
1487
|
suggestion.includeHidden === true,
|
|
1486
1488
|
suggestion.extensions == null ? "" : suggestion.extensions.toSorted().join("\0"),
|
|
1487
1489
|
description
|
|
@@ -1489,14 +1491,16 @@ function multiple(parser, options = {}) {
|
|
|
1489
1491
|
};
|
|
1490
1492
|
return dispatchIterableByMode(parser.mode, function* () {
|
|
1491
1493
|
const selectedValues = collectSelectedValuesSync();
|
|
1492
|
-
const emitted = /* @__PURE__ */ new
|
|
1494
|
+
const emitted = /* @__PURE__ */ new Map();
|
|
1493
1495
|
const yieldUnique = function* (suggestions) {
|
|
1494
1496
|
for (const s of suggestions) {
|
|
1495
1497
|
const key = suggestionKey(s);
|
|
1496
|
-
if (shouldInclude(selectedValues, s)
|
|
1497
|
-
|
|
1498
|
+
if (!shouldInclude(selectedValues, s)) continue;
|
|
1499
|
+
const existing = emitted.get(key);
|
|
1500
|
+
if (existing === void 0) {
|
|
1501
|
+
emitted.set(key, s);
|
|
1498
1502
|
yield s;
|
|
1499
|
-
}
|
|
1503
|
+
} else mergeJoinedFileSuggestions(existing, s);
|
|
1500
1504
|
}
|
|
1501
1505
|
};
|
|
1502
1506
|
let shouldTryFallback = false;
|
|
@@ -1509,14 +1513,16 @@ function multiple(parser, options = {}) {
|
|
|
1509
1513
|
if (shouldTryFallback) yield* yieldUnique(syncParser.suggest(withChildContext(context, itemIndex, suggestFallbackState), prefix));
|
|
1510
1514
|
}, async function* () {
|
|
1511
1515
|
const selectedValues = await collectSelectedValuesAsync();
|
|
1512
|
-
const emitted = /* @__PURE__ */ new
|
|
1516
|
+
const emitted = /* @__PURE__ */ new Map();
|
|
1513
1517
|
const yieldUnique = async function* (suggestions) {
|
|
1514
1518
|
for await (const s of suggestions) {
|
|
1515
1519
|
const key = suggestionKey(s);
|
|
1516
|
-
if (shouldInclude(selectedValues, s)
|
|
1517
|
-
|
|
1520
|
+
if (!shouldInclude(selectedValues, s)) continue;
|
|
1521
|
+
const existing = emitted.get(key);
|
|
1522
|
+
if (existing === void 0) {
|
|
1523
|
+
emitted.set(key, s);
|
|
1518
1524
|
yield s;
|
|
1519
|
-
}
|
|
1525
|
+
} else mergeJoinedFileSuggestions(existing, s);
|
|
1520
1526
|
}
|
|
1521
1527
|
};
|
|
1522
1528
|
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');
|
|
@@ -247,33 +248,33 @@ function* getSuggestionsWithDependency(valueParser, prefix, dependencyRegistry,
|
|
|
247
248
|
}
|
|
248
249
|
yield* valueParser.suggest(prefix);
|
|
249
250
|
}
|
|
251
|
+
/** Returns the joined prefix accepted by option parsing. */
|
|
252
|
+
function joinedOptionPrefix(names, input) {
|
|
253
|
+
return names.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2).map((name) => name + (name.startsWith("/") ? ":" : "=")).find((prefix) => input.startsWith(prefix));
|
|
254
|
+
}
|
|
250
255
|
/**
|
|
251
256
|
* Internal sync helper for option suggest functionality.
|
|
252
257
|
* @internal
|
|
253
258
|
*/
|
|
254
259
|
function* suggestOptionSync(optionNames$1, valueParser, hidden, description, context, prefix) {
|
|
255
|
-
if (hidden) return;
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
const
|
|
260
|
+
if (hidden || context.optionsTerminated) return;
|
|
261
|
+
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
262
|
+
const joinedPrefix = joinedOptionPrefix(optionNames$1, prefix);
|
|
263
|
+
if (joinedPrefix !== void 0 && !expectingValue) {
|
|
264
|
+
const optionPart = joinedPrefix.slice(0, -1);
|
|
265
|
+
const valuePart = prefix.slice(joinedPrefix.length);
|
|
260
266
|
if (optionNames$1.includes(optionPart)) {
|
|
261
267
|
if (valueParser && valueParser.suggest) {
|
|
262
268
|
const valueSuggestions = getSuggestionsWithDependency(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
263
269
|
for (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
264
270
|
kind: "literal",
|
|
265
|
-
text: `${
|
|
266
|
-
description: suggestion.description
|
|
267
|
-
};
|
|
268
|
-
else yield {
|
|
269
|
-
kind: "literal",
|
|
270
|
-
text: `${optionPart}=${suggestion.pattern || ""}`,
|
|
271
|
+
text: `${joinedPrefix}${suggestion.text}`,
|
|
271
272
|
description: suggestion.description
|
|
272
273
|
};
|
|
274
|
+
else yield require_joined_file_suggestion.joinedFileSuggestion(joinedPrefix, suggestion, valuePart);
|
|
273
275
|
}
|
|
274
276
|
}
|
|
275
277
|
} else {
|
|
276
|
-
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
277
278
|
if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
278
279
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
279
280
|
if (prefix === "-" && optionName$1.length !== 2) continue;
|
|
@@ -337,28 +338,24 @@ async function* getSuggestionsWithDependencyAsync(valueParser, prefix, dependenc
|
|
|
337
338
|
* @internal
|
|
338
339
|
*/
|
|
339
340
|
async function* suggestOptionAsync(optionNames$1, valueParser, hidden, description, context, prefix) {
|
|
340
|
-
if (hidden) return;
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
const
|
|
341
|
+
if (hidden || context.optionsTerminated) return;
|
|
342
|
+
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
343
|
+
const joinedPrefix = joinedOptionPrefix(optionNames$1, prefix);
|
|
344
|
+
if (joinedPrefix !== void 0 && !expectingValue) {
|
|
345
|
+
const optionPart = joinedPrefix.slice(0, -1);
|
|
346
|
+
const valuePart = prefix.slice(joinedPrefix.length);
|
|
345
347
|
if (optionNames$1.includes(optionPart)) {
|
|
346
348
|
if (valueParser && valueParser.suggest) {
|
|
347
349
|
const valueSuggestions = getSuggestionsWithDependencyAsync(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
348
350
|
for await (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
349
351
|
kind: "literal",
|
|
350
|
-
text: `${
|
|
351
|
-
description: suggestion.description
|
|
352
|
-
};
|
|
353
|
-
else yield {
|
|
354
|
-
kind: "literal",
|
|
355
|
-
text: `${optionPart}=${suggestion.pattern || ""}`,
|
|
352
|
+
text: `${joinedPrefix}${suggestion.text}`,
|
|
356
353
|
description: suggestion.description
|
|
357
354
|
};
|
|
355
|
+
else yield require_joined_file_suggestion.joinedFileSuggestion(joinedPrefix, suggestion, valuePart);
|
|
358
356
|
}
|
|
359
357
|
}
|
|
360
358
|
} else {
|
|
361
|
-
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
362
359
|
if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
363
360
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
364
361
|
if (prefix === "-" && optionName$1.length !== 2) continue;
|
|
@@ -916,8 +913,8 @@ function flag(...args) {
|
|
|
916
913
|
error: require_message.message`${require_message.optionNames(optionNames$1)}: ${state.error}`
|
|
917
914
|
};
|
|
918
915
|
},
|
|
919
|
-
suggest(
|
|
920
|
-
if (require_usage.isSuggestionHidden(options.hidden)) return [];
|
|
916
|
+
suggest(context, prefix) {
|
|
917
|
+
if (require_usage.isSuggestionHidden(options.hidden) || context.optionsTerminated) return [];
|
|
921
918
|
const suggestions = [];
|
|
922
919
|
if (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+")) {
|
|
923
920
|
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 { replayDerivedParser, replayDerivedParserAsync } 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";
|
|
@@ -247,33 +248,33 @@ function* getSuggestionsWithDependency(valueParser, prefix, dependencyRegistry,
|
|
|
247
248
|
}
|
|
248
249
|
yield* valueParser.suggest(prefix);
|
|
249
250
|
}
|
|
251
|
+
/** Returns the joined prefix accepted by option parsing. */
|
|
252
|
+
function joinedOptionPrefix(names, input) {
|
|
253
|
+
return names.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2).map((name) => name + (name.startsWith("/") ? ":" : "=")).find((prefix) => input.startsWith(prefix));
|
|
254
|
+
}
|
|
250
255
|
/**
|
|
251
256
|
* Internal sync helper for option suggest functionality.
|
|
252
257
|
* @internal
|
|
253
258
|
*/
|
|
254
259
|
function* suggestOptionSync(optionNames$1, valueParser, hidden, description, context, prefix) {
|
|
255
|
-
if (hidden) return;
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
const
|
|
260
|
+
if (hidden || context.optionsTerminated) return;
|
|
261
|
+
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
262
|
+
const joinedPrefix = joinedOptionPrefix(optionNames$1, prefix);
|
|
263
|
+
if (joinedPrefix !== void 0 && !expectingValue) {
|
|
264
|
+
const optionPart = joinedPrefix.slice(0, -1);
|
|
265
|
+
const valuePart = prefix.slice(joinedPrefix.length);
|
|
260
266
|
if (optionNames$1.includes(optionPart)) {
|
|
261
267
|
if (valueParser && valueParser.suggest) {
|
|
262
268
|
const valueSuggestions = getSuggestionsWithDependency(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
263
269
|
for (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
264
270
|
kind: "literal",
|
|
265
|
-
text: `${
|
|
266
|
-
description: suggestion.description
|
|
267
|
-
};
|
|
268
|
-
else yield {
|
|
269
|
-
kind: "literal",
|
|
270
|
-
text: `${optionPart}=${suggestion.pattern || ""}`,
|
|
271
|
+
text: `${joinedPrefix}${suggestion.text}`,
|
|
271
272
|
description: suggestion.description
|
|
272
273
|
};
|
|
274
|
+
else yield joinedFileSuggestion(joinedPrefix, suggestion, valuePart);
|
|
273
275
|
}
|
|
274
276
|
}
|
|
275
277
|
} else {
|
|
276
|
-
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
277
278
|
if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
278
279
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
279
280
|
if (prefix === "-" && optionName$1.length !== 2) continue;
|
|
@@ -337,28 +338,24 @@ async function* getSuggestionsWithDependencyAsync(valueParser, prefix, dependenc
|
|
|
337
338
|
* @internal
|
|
338
339
|
*/
|
|
339
340
|
async function* suggestOptionAsync(optionNames$1, valueParser, hidden, description, context, prefix) {
|
|
340
|
-
if (hidden) return;
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
const
|
|
341
|
+
if (hidden || context.optionsTerminated) return;
|
|
342
|
+
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
343
|
+
const joinedPrefix = joinedOptionPrefix(optionNames$1, prefix);
|
|
344
|
+
if (joinedPrefix !== void 0 && !expectingValue) {
|
|
345
|
+
const optionPart = joinedPrefix.slice(0, -1);
|
|
346
|
+
const valuePart = prefix.slice(joinedPrefix.length);
|
|
345
347
|
if (optionNames$1.includes(optionPart)) {
|
|
346
348
|
if (valueParser && valueParser.suggest) {
|
|
347
349
|
const valueSuggestions = getSuggestionsWithDependencyAsync(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
348
350
|
for await (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
349
351
|
kind: "literal",
|
|
350
|
-
text: `${
|
|
351
|
-
description: suggestion.description
|
|
352
|
-
};
|
|
353
|
-
else yield {
|
|
354
|
-
kind: "literal",
|
|
355
|
-
text: `${optionPart}=${suggestion.pattern || ""}`,
|
|
352
|
+
text: `${joinedPrefix}${suggestion.text}`,
|
|
356
353
|
description: suggestion.description
|
|
357
354
|
};
|
|
355
|
+
else yield joinedFileSuggestion(joinedPrefix, suggestion, valuePart);
|
|
358
356
|
}
|
|
359
357
|
}
|
|
360
358
|
} else {
|
|
361
|
-
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
362
359
|
if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
363
360
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
364
361
|
if (prefix === "-" && optionName$1.length !== 2) continue;
|
|
@@ -916,8 +913,8 @@ function flag(...args) {
|
|
|
916
913
|
error: message`${optionNames(optionNames$1)}: ${state.error}`
|
|
917
914
|
};
|
|
918
915
|
},
|
|
919
|
-
suggest(
|
|
920
|
-
if (isSuggestionHidden(options.hidden)) return [];
|
|
916
|
+
suggest(context, prefix) {
|
|
917
|
+
if (isSuggestionHidden(options.hidden) || context.optionsTerminated) return [];
|
|
921
918
|
const suggestions = [];
|
|
922
919
|
if (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+")) {
|
|
923
920
|
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_message = require('./message.cjs');
|
|
2
2
|
const require_usage = require('./usage.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
|