@optique/core 1.4.0-dev.2758 → 1.4.0-dev.2892
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/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 +19 -24
- package/dist/primitives.js +19 -24
- package/dist/short-option.cjs +6 -1
- package/dist/short-option.js +6 -1
- 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
|
@@ -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_empty_input = require('./internal/empty-input.cjs');
|
|
8
9
|
const require_execution_context = require('./execution-context.cjs');
|
|
9
10
|
const require_short_option = require('./short-option.cjs');
|
|
@@ -1580,6 +1581,7 @@ function multiple(parser, options = {}) {
|
|
|
1580
1581
|
"file",
|
|
1581
1582
|
suggestion.type,
|
|
1582
1583
|
suggestion.pattern ?? "",
|
|
1584
|
+
suggestion.prefix ?? "",
|
|
1583
1585
|
suggestion.includeHidden === true,
|
|
1584
1586
|
suggestion.extensions == null ? "" : suggestion.extensions.toSorted().join("\0"),
|
|
1585
1587
|
description
|
|
@@ -1587,14 +1589,16 @@ function multiple(parser, options = {}) {
|
|
|
1587
1589
|
};
|
|
1588
1590
|
return require_mode_dispatch.dispatchIterableByMode(parser.mode, function* () {
|
|
1589
1591
|
const selectedValues = collectSelectedValuesSync();
|
|
1590
|
-
const emitted = /* @__PURE__ */ new
|
|
1592
|
+
const emitted = /* @__PURE__ */ new Map();
|
|
1591
1593
|
const yieldUnique = function* (suggestions) {
|
|
1592
1594
|
for (const s of suggestions) {
|
|
1593
1595
|
const key = suggestionKey(s);
|
|
1594
|
-
if (shouldInclude(selectedValues, s)
|
|
1595
|
-
|
|
1596
|
+
if (!shouldInclude(selectedValues, s)) continue;
|
|
1597
|
+
const existing = emitted.get(key);
|
|
1598
|
+
if (existing === void 0) {
|
|
1599
|
+
emitted.set(key, s);
|
|
1596
1600
|
yield s;
|
|
1597
|
-
}
|
|
1601
|
+
} else require_joined_file_suggestion.mergeJoinedFileSuggestions(existing, s);
|
|
1598
1602
|
}
|
|
1599
1603
|
};
|
|
1600
1604
|
let shouldTryFallback = false;
|
|
@@ -1607,14 +1611,16 @@ function multiple(parser, options = {}) {
|
|
|
1607
1611
|
if (shouldTryFallback) yield* yieldUnique(syncParser.suggest(require_execution_context.withChildContext(context, itemIndex, suggestFallbackState), prefix));
|
|
1608
1612
|
}, async function* () {
|
|
1609
1613
|
const selectedValues = await collectSelectedValuesAsync();
|
|
1610
|
-
const emitted = /* @__PURE__ */ new
|
|
1614
|
+
const emitted = /* @__PURE__ */ new Map();
|
|
1611
1615
|
const yieldUnique = async function* (suggestions) {
|
|
1612
1616
|
for await (const s of suggestions) {
|
|
1613
1617
|
const key = suggestionKey(s);
|
|
1614
|
-
if (shouldInclude(selectedValues, s)
|
|
1615
|
-
|
|
1618
|
+
if (!shouldInclude(selectedValues, s)) continue;
|
|
1619
|
+
const existing = emitted.get(key);
|
|
1620
|
+
if (existing === void 0) {
|
|
1621
|
+
emitted.set(key, s);
|
|
1616
1622
|
yield s;
|
|
1617
|
-
}
|
|
1623
|
+
} else require_joined_file_suggestion.mergeJoinedFileSuggestions(existing, s);
|
|
1618
1624
|
}
|
|
1619
1625
|
};
|
|
1620
1626
|
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 { acceptsEmptyInput, defineEmptyInputFacts, getEmptyInputFacts, multipleFacts, optionalLikeFacts, resolveEmptyStepState } from "./internal/empty-input.js";
|
|
8
9
|
import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
|
|
9
10
|
import { combinedOptionScope, repeatedOptionScope, scopeParser } from "./short-option.js";
|
|
@@ -1580,6 +1581,7 @@ function multiple(parser, options = {}) {
|
|
|
1580
1581
|
"file",
|
|
1581
1582
|
suggestion.type,
|
|
1582
1583
|
suggestion.pattern ?? "",
|
|
1584
|
+
suggestion.prefix ?? "",
|
|
1583
1585
|
suggestion.includeHidden === true,
|
|
1584
1586
|
suggestion.extensions == null ? "" : suggestion.extensions.toSorted().join("\0"),
|
|
1585
1587
|
description
|
|
@@ -1587,14 +1589,16 @@ function multiple(parser, options = {}) {
|
|
|
1587
1589
|
};
|
|
1588
1590
|
return dispatchIterableByMode(parser.mode, function* () {
|
|
1589
1591
|
const selectedValues = collectSelectedValuesSync();
|
|
1590
|
-
const emitted = /* @__PURE__ */ new
|
|
1592
|
+
const emitted = /* @__PURE__ */ new Map();
|
|
1591
1593
|
const yieldUnique = function* (suggestions) {
|
|
1592
1594
|
for (const s of suggestions) {
|
|
1593
1595
|
const key = suggestionKey(s);
|
|
1594
|
-
if (shouldInclude(selectedValues, s)
|
|
1595
|
-
|
|
1596
|
+
if (!shouldInclude(selectedValues, s)) continue;
|
|
1597
|
+
const existing = emitted.get(key);
|
|
1598
|
+
if (existing === void 0) {
|
|
1599
|
+
emitted.set(key, s);
|
|
1596
1600
|
yield s;
|
|
1597
|
-
}
|
|
1601
|
+
} else mergeJoinedFileSuggestions(existing, s);
|
|
1598
1602
|
}
|
|
1599
1603
|
};
|
|
1600
1604
|
let shouldTryFallback = false;
|
|
@@ -1607,14 +1611,16 @@ function multiple(parser, options = {}) {
|
|
|
1607
1611
|
if (shouldTryFallback) yield* yieldUnique(syncParser.suggest(withChildContext(context, itemIndex, suggestFallbackState), prefix));
|
|
1608
1612
|
}, async function* () {
|
|
1609
1613
|
const selectedValues = await collectSelectedValuesAsync();
|
|
1610
|
-
const emitted = /* @__PURE__ */ new
|
|
1614
|
+
const emitted = /* @__PURE__ */ new Map();
|
|
1611
1615
|
const yieldUnique = async function* (suggestions) {
|
|
1612
1616
|
for await (const s of suggestions) {
|
|
1613
1617
|
const key = suggestionKey(s);
|
|
1614
|
-
if (shouldInclude(selectedValues, s)
|
|
1615
|
-
|
|
1618
|
+
if (!shouldInclude(selectedValues, s)) continue;
|
|
1619
|
+
const existing = emitted.get(key);
|
|
1620
|
+
if (existing === void 0) {
|
|
1621
|
+
emitted.set(key, s);
|
|
1616
1622
|
yield s;
|
|
1617
|
-
}
|
|
1623
|
+
} else mergeJoinedFileSuggestions(existing, s);
|
|
1618
1624
|
}
|
|
1619
1625
|
};
|
|
1620
1626
|
let shouldTryFallback = false;
|
package/dist/primitives.cjs
CHANGED
|
@@ -7,6 +7,7 @@ const require_mode_dispatch = require('./internal/mode-dispatch.cjs');
|
|
|
7
7
|
const require_internal_dependency = require('./internal/dependency.cjs');
|
|
8
8
|
const require_dependency_runtime = require('./dependency-runtime.cjs');
|
|
9
9
|
const require_annotation_state = require('./annotation-state.cjs');
|
|
10
|
+
const require_joined_file_suggestion = require('./internal/joined-file-suggestion.cjs');
|
|
10
11
|
const require_empty_input = require('./internal/empty-input.cjs');
|
|
11
12
|
const require_execution_context = require('./execution-context.cjs');
|
|
12
13
|
const require_usage_internals = require('./usage-internals.cjs');
|
|
@@ -287,6 +288,10 @@ function* getSuggestionsWithDependency(valueParser, prefix, dependencyRegistry,
|
|
|
287
288
|
}
|
|
288
289
|
yield* valueParser.suggest(prefix);
|
|
289
290
|
}
|
|
291
|
+
/** Returns the joined prefix accepted by option parsing. */
|
|
292
|
+
function joinedOptionPrefix(names, input) {
|
|
293
|
+
return names.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2).map((name) => name + (name.startsWith("/") ? ":" : "=")).find((prefix) => input.startsWith(prefix));
|
|
294
|
+
}
|
|
290
295
|
/**
|
|
291
296
|
* Internal sync helper for option suggest functionality.
|
|
292
297
|
* @internal
|
|
@@ -307,28 +312,23 @@ function* suggestOptionSync(optionNames$1, valueParser, hidden, description, con
|
|
|
307
312
|
return;
|
|
308
313
|
}
|
|
309
314
|
}
|
|
310
|
-
const
|
|
311
|
-
if (
|
|
312
|
-
const optionPart =
|
|
313
|
-
const valuePart = prefix.slice(
|
|
315
|
+
const joinedPrefix = joinedOptionPrefix(optionNames$1, prefix);
|
|
316
|
+
if (joinedPrefix !== void 0 && !waitingForValue) {
|
|
317
|
+
const optionPart = joinedPrefix.slice(0, -1);
|
|
318
|
+
const valuePart = prefix.slice(joinedPrefix.length);
|
|
314
319
|
if (optionNames$1.includes(optionPart) && !/^-[^-]$/u.test(optionPart)) {
|
|
315
320
|
if (valueParser && valueParser.suggest) {
|
|
316
321
|
const valueSuggestions = getSuggestionsWithDependency(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
317
322
|
for (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
318
323
|
kind: "literal",
|
|
319
|
-
text: `${
|
|
320
|
-
description: suggestion.description
|
|
321
|
-
};
|
|
322
|
-
else yield {
|
|
323
|
-
kind: "literal",
|
|
324
|
-
text: `${optionPart}=${suggestion.pattern || ""}`,
|
|
324
|
+
text: `${joinedPrefix}${suggestion.text}`,
|
|
325
325
|
description: suggestion.description
|
|
326
326
|
};
|
|
327
|
+
else yield require_joined_file_suggestion.joinedFileSuggestion(joinedPrefix, suggestion, valuePart);
|
|
327
328
|
}
|
|
328
329
|
}
|
|
329
330
|
} else {
|
|
330
|
-
|
|
331
|
-
if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
331
|
+
if (!waitingForValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
332
332
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
333
333
|
if (prefix === "-" && !/^-[^-]$/u.test(optionName$1)) continue;
|
|
334
334
|
yield {
|
|
@@ -406,28 +406,23 @@ async function* suggestOptionAsync(optionNames$1, valueParser, hidden, descripti
|
|
|
406
406
|
return;
|
|
407
407
|
}
|
|
408
408
|
}
|
|
409
|
-
const
|
|
410
|
-
if (
|
|
411
|
-
const optionPart =
|
|
412
|
-
const valuePart = prefix.slice(
|
|
409
|
+
const joinedPrefix = joinedOptionPrefix(optionNames$1, prefix);
|
|
410
|
+
if (joinedPrefix !== void 0 && !waitingForValue) {
|
|
411
|
+
const optionPart = joinedPrefix.slice(0, -1);
|
|
412
|
+
const valuePart = prefix.slice(joinedPrefix.length);
|
|
413
413
|
if (optionNames$1.includes(optionPart) && !/^-[^-]$/u.test(optionPart)) {
|
|
414
414
|
if (valueParser && valueParser.suggest) {
|
|
415
415
|
const valueSuggestions = getSuggestionsWithDependencyAsync(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
416
416
|
for await (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
417
417
|
kind: "literal",
|
|
418
|
-
text: `${
|
|
419
|
-
description: suggestion.description
|
|
420
|
-
};
|
|
421
|
-
else yield {
|
|
422
|
-
kind: "literal",
|
|
423
|
-
text: `${optionPart}=${suggestion.pattern || ""}`,
|
|
418
|
+
text: `${joinedPrefix}${suggestion.text}`,
|
|
424
419
|
description: suggestion.description
|
|
425
420
|
};
|
|
421
|
+
else yield require_joined_file_suggestion.joinedFileSuggestion(joinedPrefix, suggestion, valuePart);
|
|
426
422
|
}
|
|
427
423
|
}
|
|
428
424
|
} else {
|
|
429
|
-
|
|
430
|
-
if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
425
|
+
if (!waitingForValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
431
426
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
432
427
|
if (prefix === "-" && !/^-[^-]$/u.test(optionName$1)) continue;
|
|
433
428
|
yield {
|
package/dist/primitives.js
CHANGED
|
@@ -7,6 +7,7 @@ import { dispatchByMode, dispatchIterableByMode, wrapForMode } from "./internal/
|
|
|
7
7
|
import { getDefaultValuesFunction, getDependencyIds, getSnapshottedDefaultDependencyValues, isDerivedValueParser, suggestWithDependency } from "./internal/dependency.js";
|
|
8
8
|
import { effectfulSchedulingNodesKey, exclusiveSourceScopeKey, includeSourceFailureChain, recordDerivedRawInput, replayDerivedParser, replayDerivedParserAsync, sourceCollectionExpansionKey } from "./dependency-runtime.js";
|
|
9
9
|
import { getWrappedChildParseState, getWrappedChildState, isAnnotationWrappedInitialState, normalizeInjectedAnnotationState } from "./annotation-state.js";
|
|
10
|
+
import { joinedFileSuggestion } from "./internal/joined-file-suggestion.js";
|
|
10
11
|
import { UNCHANGED, defineEmptyInputFacts, failingStepFacts } from "./internal/empty-input.js";
|
|
11
12
|
import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
|
|
12
13
|
import { extractLeadingCommandNames } from "./usage-internals.js";
|
|
@@ -287,6 +288,10 @@ function* getSuggestionsWithDependency(valueParser, prefix, dependencyRegistry,
|
|
|
287
288
|
}
|
|
288
289
|
yield* valueParser.suggest(prefix);
|
|
289
290
|
}
|
|
291
|
+
/** Returns the joined prefix accepted by option parsing. */
|
|
292
|
+
function joinedOptionPrefix(names, input) {
|
|
293
|
+
return names.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2).map((name) => name + (name.startsWith("/") ? ":" : "=")).find((prefix) => input.startsWith(prefix));
|
|
294
|
+
}
|
|
290
295
|
/**
|
|
291
296
|
* Internal sync helper for option suggest functionality.
|
|
292
297
|
* @internal
|
|
@@ -307,28 +312,23 @@ function* suggestOptionSync(optionNames$1, valueParser, hidden, description, con
|
|
|
307
312
|
return;
|
|
308
313
|
}
|
|
309
314
|
}
|
|
310
|
-
const
|
|
311
|
-
if (
|
|
312
|
-
const optionPart =
|
|
313
|
-
const valuePart = prefix.slice(
|
|
315
|
+
const joinedPrefix = joinedOptionPrefix(optionNames$1, prefix);
|
|
316
|
+
if (joinedPrefix !== void 0 && !waitingForValue) {
|
|
317
|
+
const optionPart = joinedPrefix.slice(0, -1);
|
|
318
|
+
const valuePart = prefix.slice(joinedPrefix.length);
|
|
314
319
|
if (optionNames$1.includes(optionPart) && !/^-[^-]$/u.test(optionPart)) {
|
|
315
320
|
if (valueParser && valueParser.suggest) {
|
|
316
321
|
const valueSuggestions = getSuggestionsWithDependency(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
317
322
|
for (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
318
323
|
kind: "literal",
|
|
319
|
-
text: `${
|
|
320
|
-
description: suggestion.description
|
|
321
|
-
};
|
|
322
|
-
else yield {
|
|
323
|
-
kind: "literal",
|
|
324
|
-
text: `${optionPart}=${suggestion.pattern || ""}`,
|
|
324
|
+
text: `${joinedPrefix}${suggestion.text}`,
|
|
325
325
|
description: suggestion.description
|
|
326
326
|
};
|
|
327
|
+
else yield joinedFileSuggestion(joinedPrefix, suggestion, valuePart);
|
|
327
328
|
}
|
|
328
329
|
}
|
|
329
330
|
} else {
|
|
330
|
-
|
|
331
|
-
if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
331
|
+
if (!waitingForValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
332
332
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
333
333
|
if (prefix === "-" && !/^-[^-]$/u.test(optionName$1)) continue;
|
|
334
334
|
yield {
|
|
@@ -406,28 +406,23 @@ async function* suggestOptionAsync(optionNames$1, valueParser, hidden, descripti
|
|
|
406
406
|
return;
|
|
407
407
|
}
|
|
408
408
|
}
|
|
409
|
-
const
|
|
410
|
-
if (
|
|
411
|
-
const optionPart =
|
|
412
|
-
const valuePart = prefix.slice(
|
|
409
|
+
const joinedPrefix = joinedOptionPrefix(optionNames$1, prefix);
|
|
410
|
+
if (joinedPrefix !== void 0 && !waitingForValue) {
|
|
411
|
+
const optionPart = joinedPrefix.slice(0, -1);
|
|
412
|
+
const valuePart = prefix.slice(joinedPrefix.length);
|
|
413
413
|
if (optionNames$1.includes(optionPart) && !/^-[^-]$/u.test(optionPart)) {
|
|
414
414
|
if (valueParser && valueParser.suggest) {
|
|
415
415
|
const valueSuggestions = getSuggestionsWithDependencyAsync(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
416
416
|
for await (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
417
417
|
kind: "literal",
|
|
418
|
-
text: `${
|
|
419
|
-
description: suggestion.description
|
|
420
|
-
};
|
|
421
|
-
else yield {
|
|
422
|
-
kind: "literal",
|
|
423
|
-
text: `${optionPart}=${suggestion.pattern || ""}`,
|
|
418
|
+
text: `${joinedPrefix}${suggestion.text}`,
|
|
424
419
|
description: suggestion.description
|
|
425
420
|
};
|
|
421
|
+
else yield joinedFileSuggestion(joinedPrefix, suggestion, valuePart);
|
|
426
422
|
}
|
|
427
423
|
}
|
|
428
424
|
} else {
|
|
429
|
-
|
|
430
|
-
if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
425
|
+
if (!waitingForValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
431
426
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
432
427
|
if (prefix === "-" && !/^-[^-]$/u.test(optionName$1)) continue;
|
|
433
428
|
yield {
|
package/dist/short-option.cjs
CHANGED
|
@@ -286,9 +286,14 @@ function attachedValuePrefix(context, prefix, optionNames) {
|
|
|
286
286
|
}
|
|
287
287
|
/** Preserves the prefix when embedding value suggestions in one token. @internal */
|
|
288
288
|
function prefixSuggestion(head, suggestion) {
|
|
289
|
+
if (suggestion.kind === "file") return {
|
|
290
|
+
...suggestion,
|
|
291
|
+
pattern: head + (suggestion.pattern ?? ""),
|
|
292
|
+
prefix: head + (suggestion.prefix ?? "")
|
|
293
|
+
};
|
|
289
294
|
return {
|
|
290
295
|
kind: "literal",
|
|
291
|
-
text: head +
|
|
296
|
+
text: head + suggestion.text,
|
|
292
297
|
...suggestion.description != null ? { description: suggestion.description } : {}
|
|
293
298
|
};
|
|
294
299
|
}
|
package/dist/short-option.js
CHANGED
|
@@ -286,9 +286,14 @@ function attachedValuePrefix(context, prefix, optionNames) {
|
|
|
286
286
|
}
|
|
287
287
|
/** Preserves the prefix when embedding value suggestions in one token. @internal */
|
|
288
288
|
function prefixSuggestion(head, suggestion) {
|
|
289
|
+
if (suggestion.kind === "file") return {
|
|
290
|
+
...suggestion,
|
|
291
|
+
pattern: head + (suggestion.pattern ?? ""),
|
|
292
|
+
prefix: head + (suggestion.prefix ?? "")
|
|
293
|
+
};
|
|
289
294
|
return {
|
|
290
295
|
kind: "literal",
|
|
291
|
-
text: head +
|
|
296
|
+
text: head + suggestion.text,
|
|
292
297
|
...suggestion.description != null ? { description: suggestion.description } : {}
|
|
293
298
|
};
|
|
294
299
|
}
|
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
|
package/dist/suggestion.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { extractCommandNames, extractOptionNames, isSuggestionHidden } from "./usage.js";
|
|
2
2
|
import { lineBreak, message, optionName, text, value } from "./message.js";
|
|
3
|
+
import { mergeJoinedFileSuggestions } from "./internal/joined-file-suggestion.js";
|
|
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") 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/valueparser.cjs
CHANGED
|
@@ -1089,7 +1089,8 @@ function prefixKeyValueSuggestion(suggestion, prefix, suffix = "") {
|
|
|
1089
1089
|
const text$1 = `${prefix}${textValue}${suffix}`;
|
|
1090
1090
|
if (suggestion.kind === "file" && suffix === "") return {
|
|
1091
1091
|
...suggestion,
|
|
1092
|
-
pattern: text$1
|
|
1092
|
+
pattern: text$1,
|
|
1093
|
+
prefix: `${prefix}${suggestion.prefix ?? ""}`
|
|
1093
1094
|
};
|
|
1094
1095
|
return suggestion.description == null ? {
|
|
1095
1096
|
kind: "literal",
|
package/dist/valueparser.js
CHANGED
|
@@ -1089,7 +1089,8 @@ function prefixKeyValueSuggestion(suggestion, prefix, suffix = "") {
|
|
|
1089
1089
|
const text$1 = `${prefix}${textValue}${suffix}`;
|
|
1090
1090
|
if (suggestion.kind === "file" && suffix === "") return {
|
|
1091
1091
|
...suggestion,
|
|
1092
|
-
pattern: text$1
|
|
1092
|
+
pattern: text$1,
|
|
1093
|
+
prefix: `${prefix}${suggestion.prefix ?? ""}`
|
|
1093
1094
|
};
|
|
1094
1095
|
return suggestion.description == null ? {
|
|
1095
1096
|
kind: "literal",
|