@optique/core 1.1.13-dev.2823 → 1.1.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 +1639 -237
- package/dist/completion.js +1639 -237
- 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/modifiers.cjs +13 -8
- package/dist/modifiers.js +13 -8
- package/dist/primitives.cjs +19 -22
- package/dist/primitives.js +19 -22
- package/dist/suggestion.cjs +3 -1
- package/dist/suggestion.js +3 -1
- package/package.json +2 -2
package/dist/constructs.cjs
CHANGED
|
@@ -513,12 +513,16 @@ function analyzeNoMatchContext(parsers) {
|
|
|
513
513
|
* construction. This is a programmer error, not a user error.
|
|
514
514
|
*/
|
|
515
515
|
var DuplicateOptionError = class extends Error {
|
|
516
|
+
/** The option name shared by multiple fields. */
|
|
517
|
+
optionName;
|
|
518
|
+
/** The fields declaring the option. */
|
|
519
|
+
sources;
|
|
516
520
|
constructor(optionName$1, sources) {
|
|
517
521
|
const sourceNames = sources.map((s) => typeof s === "symbol" ? s.description ?? s.toString() : s);
|
|
518
522
|
super(`Duplicate option name "${optionName$1}" found in fields: ${sourceNames.join(", ")}. Each option name must be unique within a parser combinator.`);
|
|
523
|
+
this.name = "DuplicateOptionError";
|
|
519
524
|
this.optionName = optionName$1;
|
|
520
525
|
this.sources = sources;
|
|
521
|
-
this.name = "DuplicateOptionError";
|
|
522
526
|
}
|
|
523
527
|
};
|
|
524
528
|
/**
|
|
@@ -526,6 +530,8 @@ var DuplicateOptionError = class extends Error {
|
|
|
526
530
|
* during parser construction. This is a programmer error, not a user error.
|
|
527
531
|
*/
|
|
528
532
|
var DuplicateCommandNameError = class extends TypeError {
|
|
533
|
+
commandName;
|
|
534
|
+
sources;
|
|
529
535
|
constructor(commandName, sources) {
|
|
530
536
|
const sourceNames = sources.map((s) => typeof s === "symbol" ? s.description ?? s.toString() : s);
|
|
531
537
|
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
|
@@ -102,7 +102,9 @@ interface OrErrorOptions {
|
|
|
102
102
|
* construction. This is a programmer error, not a user error.
|
|
103
103
|
*/
|
|
104
104
|
declare class DuplicateOptionError extends Error {
|
|
105
|
+
/** The option name shared by multiple fields. */
|
|
105
106
|
readonly optionName: string;
|
|
107
|
+
/** The fields declaring the option. */
|
|
106
108
|
readonly sources: readonly (string | symbol)[];
|
|
107
109
|
constructor(optionName: string, sources: readonly (string | symbol)[]);
|
|
108
110
|
}
|
package/dist/constructs.d.ts
CHANGED
|
@@ -102,7 +102,9 @@ interface OrErrorOptions {
|
|
|
102
102
|
* construction. This is a programmer error, not a user error.
|
|
103
103
|
*/
|
|
104
104
|
declare class DuplicateOptionError extends Error {
|
|
105
|
+
/** The option name shared by multiple fields. */
|
|
105
106
|
readonly optionName: string;
|
|
107
|
+
/** The fields declaring the option. */
|
|
106
108
|
readonly sources: readonly (string | symbol)[];
|
|
107
109
|
constructor(optionName: string, sources: readonly (string | symbol)[]);
|
|
108
110
|
}
|
package/dist/constructs.js
CHANGED
|
@@ -513,12 +513,16 @@ function analyzeNoMatchContext(parsers) {
|
|
|
513
513
|
* construction. This is a programmer error, not a user error.
|
|
514
514
|
*/
|
|
515
515
|
var DuplicateOptionError = class extends Error {
|
|
516
|
+
/** The option name shared by multiple fields. */
|
|
517
|
+
optionName;
|
|
518
|
+
/** The fields declaring the option. */
|
|
519
|
+
sources;
|
|
516
520
|
constructor(optionName$1, sources) {
|
|
517
521
|
const sourceNames = sources.map((s) => typeof s === "symbol" ? s.description ?? s.toString() : s);
|
|
518
522
|
super(`Duplicate option name "${optionName$1}" found in fields: ${sourceNames.join(", ")}. Each option name must be unique within a parser combinator.`);
|
|
523
|
+
this.name = "DuplicateOptionError";
|
|
519
524
|
this.optionName = optionName$1;
|
|
520
525
|
this.sources = sources;
|
|
521
|
-
this.name = "DuplicateOptionError";
|
|
522
526
|
}
|
|
523
527
|
};
|
|
524
528
|
/**
|
|
@@ -526,6 +530,8 @@ var DuplicateOptionError = class extends Error {
|
|
|
526
530
|
* during parser construction. This is a programmer error, not a user error.
|
|
527
531
|
*/
|
|
528
532
|
var DuplicateCommandNameError = class extends TypeError {
|
|
533
|
+
commandName;
|
|
534
|
+
sources;
|
|
529
535
|
constructor(commandName, sources) {
|
|
530
536
|
const sourceNames = sources.map((s) => typeof s === "symbol" ? s.description ?? s.toString() : s);
|
|
531
537
|
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 };
|
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');
|
|
@@ -1319,14 +1320,16 @@ function multiple(parser, options = {}) {
|
|
|
1319
1320
|
};
|
|
1320
1321
|
return require_mode_dispatch.dispatchIterableByMode(parser.mode, function* () {
|
|
1321
1322
|
const selectedValues = collectSelectedValuesSync();
|
|
1322
|
-
const emitted = /* @__PURE__ */ new
|
|
1323
|
+
const emitted = /* @__PURE__ */ new Map();
|
|
1323
1324
|
const yieldUnique = function* (suggestions) {
|
|
1324
1325
|
for (const s of suggestions) {
|
|
1325
1326
|
const key = suggestionKey(s);
|
|
1326
|
-
if (shouldInclude(selectedValues, s)
|
|
1327
|
-
|
|
1327
|
+
if (!shouldInclude(selectedValues, s)) continue;
|
|
1328
|
+
const existing = emitted.get(key);
|
|
1329
|
+
if (existing === void 0) {
|
|
1330
|
+
emitted.set(key, s);
|
|
1328
1331
|
yield s;
|
|
1329
|
-
}
|
|
1332
|
+
} else require_joined_file_suggestion.mergeJoinedFileSuggestions(existing, s);
|
|
1330
1333
|
}
|
|
1331
1334
|
};
|
|
1332
1335
|
let shouldTryFallback = false;
|
|
@@ -1339,14 +1342,16 @@ function multiple(parser, options = {}) {
|
|
|
1339
1342
|
if (shouldTryFallback) yield* yieldUnique(syncParser.suggest(require_execution_context.withChildContext(context, itemIndex, suggestFallbackState), prefix));
|
|
1340
1343
|
}, async function* () {
|
|
1341
1344
|
const selectedValues = await collectSelectedValuesAsync();
|
|
1342
|
-
const emitted = /* @__PURE__ */ new
|
|
1345
|
+
const emitted = /* @__PURE__ */ new Map();
|
|
1343
1346
|
const yieldUnique = async function* (suggestions) {
|
|
1344
1347
|
for await (const s of suggestions) {
|
|
1345
1348
|
const key = suggestionKey(s);
|
|
1346
|
-
if (shouldInclude(selectedValues, s)
|
|
1347
|
-
|
|
1349
|
+
if (!shouldInclude(selectedValues, s)) continue;
|
|
1350
|
+
const existing = emitted.get(key);
|
|
1351
|
+
if (existing === void 0) {
|
|
1352
|
+
emitted.set(key, s);
|
|
1348
1353
|
yield s;
|
|
1349
|
-
}
|
|
1354
|
+
} else require_joined_file_suggestion.mergeJoinedFileSuggestions(existing, s);
|
|
1350
1355
|
}
|
|
1351
1356
|
};
|
|
1352
1357
|
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";
|
|
@@ -1319,14 +1320,16 @@ function multiple(parser, options = {}) {
|
|
|
1319
1320
|
};
|
|
1320
1321
|
return dispatchIterableByMode(parser.mode, function* () {
|
|
1321
1322
|
const selectedValues = collectSelectedValuesSync();
|
|
1322
|
-
const emitted = /* @__PURE__ */ new
|
|
1323
|
+
const emitted = /* @__PURE__ */ new Map();
|
|
1323
1324
|
const yieldUnique = function* (suggestions) {
|
|
1324
1325
|
for (const s of suggestions) {
|
|
1325
1326
|
const key = suggestionKey(s);
|
|
1326
|
-
if (shouldInclude(selectedValues, s)
|
|
1327
|
-
|
|
1327
|
+
if (!shouldInclude(selectedValues, s)) continue;
|
|
1328
|
+
const existing = emitted.get(key);
|
|
1329
|
+
if (existing === void 0) {
|
|
1330
|
+
emitted.set(key, s);
|
|
1328
1331
|
yield s;
|
|
1329
|
-
}
|
|
1332
|
+
} else mergeJoinedFileSuggestions(existing, s);
|
|
1330
1333
|
}
|
|
1331
1334
|
};
|
|
1332
1335
|
let shouldTryFallback = false;
|
|
@@ -1339,14 +1342,16 @@ function multiple(parser, options = {}) {
|
|
|
1339
1342
|
if (shouldTryFallback) yield* yieldUnique(syncParser.suggest(withChildContext(context, itemIndex, suggestFallbackState), prefix));
|
|
1340
1343
|
}, async function* () {
|
|
1341
1344
|
const selectedValues = await collectSelectedValuesAsync();
|
|
1342
|
-
const emitted = /* @__PURE__ */ new
|
|
1345
|
+
const emitted = /* @__PURE__ */ new Map();
|
|
1343
1346
|
const yieldUnique = async function* (suggestions) {
|
|
1344
1347
|
for await (const s of suggestions) {
|
|
1345
1348
|
const key = suggestionKey(s);
|
|
1346
|
-
if (shouldInclude(selectedValues, s)
|
|
1347
|
-
|
|
1349
|
+
if (!shouldInclude(selectedValues, s)) continue;
|
|
1350
|
+
const existing = emitted.get(key);
|
|
1351
|
+
if (existing === void 0) {
|
|
1352
|
+
emitted.set(key, s);
|
|
1348
1353
|
yield s;
|
|
1349
|
-
}
|
|
1354
|
+
} else mergeJoinedFileSuggestions(existing, s);
|
|
1350
1355
|
}
|
|
1351
1356
|
};
|
|
1352
1357
|
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');
|
|
@@ -246,33 +247,33 @@ function* getSuggestionsWithDependency(valueParser, prefix, dependencyRegistry,
|
|
|
246
247
|
}
|
|
247
248
|
yield* valueParser.suggest(prefix);
|
|
248
249
|
}
|
|
250
|
+
/** Returns the joined prefix accepted by option parsing. */
|
|
251
|
+
function joinedOptionPrefix(names, input) {
|
|
252
|
+
return names.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2).map((name) => name + (name.startsWith("/") ? ":" : "=")).find((prefix) => input.startsWith(prefix));
|
|
253
|
+
}
|
|
249
254
|
/**
|
|
250
255
|
* Internal sync helper for option suggest functionality.
|
|
251
256
|
* @internal
|
|
252
257
|
*/
|
|
253
258
|
function* suggestOptionSync(optionNames$1, valueParser, hidden, description, context, prefix) {
|
|
254
259
|
if (hidden || context.optionsTerminated) return;
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
const
|
|
260
|
+
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
261
|
+
const joinedPrefix = joinedOptionPrefix(optionNames$1, prefix);
|
|
262
|
+
if (joinedPrefix !== void 0 && !expectingValue) {
|
|
263
|
+
const optionPart = joinedPrefix.slice(0, -1);
|
|
264
|
+
const valuePart = prefix.slice(joinedPrefix.length);
|
|
259
265
|
if (optionNames$1.includes(optionPart)) {
|
|
260
266
|
if (valueParser && valueParser.suggest) {
|
|
261
267
|
const valueSuggestions = getSuggestionsWithDependency(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
262
268
|
for (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
263
269
|
kind: "literal",
|
|
264
|
-
text: `${
|
|
265
|
-
description: suggestion.description
|
|
266
|
-
};
|
|
267
|
-
else yield {
|
|
268
|
-
kind: "literal",
|
|
269
|
-
text: `${optionPart}=${suggestion.pattern || ""}`,
|
|
270
|
+
text: `${joinedPrefix}${suggestion.text}`,
|
|
270
271
|
description: suggestion.description
|
|
271
272
|
};
|
|
273
|
+
else yield require_joined_file_suggestion.joinedFileSuggestion(joinedPrefix, suggestion, valuePart);
|
|
272
274
|
}
|
|
273
275
|
}
|
|
274
276
|
} else {
|
|
275
|
-
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
276
277
|
if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
277
278
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
278
279
|
if (prefix === "-" && optionName$1.length !== 2) continue;
|
|
@@ -337,27 +338,23 @@ async function* getSuggestionsWithDependencyAsync(valueParser, prefix, dependenc
|
|
|
337
338
|
*/
|
|
338
339
|
async function* suggestOptionAsync(optionNames$1, valueParser, hidden, description, context, prefix) {
|
|
339
340
|
if (hidden || context.optionsTerminated) return;
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
const
|
|
341
|
+
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
342
|
+
const joinedPrefix = joinedOptionPrefix(optionNames$1, prefix);
|
|
343
|
+
if (joinedPrefix !== void 0 && !expectingValue) {
|
|
344
|
+
const optionPart = joinedPrefix.slice(0, -1);
|
|
345
|
+
const valuePart = prefix.slice(joinedPrefix.length);
|
|
344
346
|
if (optionNames$1.includes(optionPart)) {
|
|
345
347
|
if (valueParser && valueParser.suggest) {
|
|
346
348
|
const valueSuggestions = getSuggestionsWithDependencyAsync(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
347
349
|
for await (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
348
350
|
kind: "literal",
|
|
349
|
-
text: `${
|
|
350
|
-
description: suggestion.description
|
|
351
|
-
};
|
|
352
|
-
else yield {
|
|
353
|
-
kind: "literal",
|
|
354
|
-
text: `${optionPart}=${suggestion.pattern || ""}`,
|
|
351
|
+
text: `${joinedPrefix}${suggestion.text}`,
|
|
355
352
|
description: suggestion.description
|
|
356
353
|
};
|
|
354
|
+
else yield require_joined_file_suggestion.joinedFileSuggestion(joinedPrefix, suggestion, valuePart);
|
|
357
355
|
}
|
|
358
356
|
}
|
|
359
357
|
} else {
|
|
360
|
-
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
361
358
|
if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
362
359
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
363
360
|
if (prefix === "-" && optionName$1.length !== 2) continue;
|
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";
|
|
@@ -246,33 +247,33 @@ function* getSuggestionsWithDependency(valueParser, prefix, dependencyRegistry,
|
|
|
246
247
|
}
|
|
247
248
|
yield* valueParser.suggest(prefix);
|
|
248
249
|
}
|
|
250
|
+
/** Returns the joined prefix accepted by option parsing. */
|
|
251
|
+
function joinedOptionPrefix(names, input) {
|
|
252
|
+
return names.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2).map((name) => name + (name.startsWith("/") ? ":" : "=")).find((prefix) => input.startsWith(prefix));
|
|
253
|
+
}
|
|
249
254
|
/**
|
|
250
255
|
* Internal sync helper for option suggest functionality.
|
|
251
256
|
* @internal
|
|
252
257
|
*/
|
|
253
258
|
function* suggestOptionSync(optionNames$1, valueParser, hidden, description, context, prefix) {
|
|
254
259
|
if (hidden || context.optionsTerminated) return;
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
const
|
|
260
|
+
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
261
|
+
const joinedPrefix = joinedOptionPrefix(optionNames$1, prefix);
|
|
262
|
+
if (joinedPrefix !== void 0 && !expectingValue) {
|
|
263
|
+
const optionPart = joinedPrefix.slice(0, -1);
|
|
264
|
+
const valuePart = prefix.slice(joinedPrefix.length);
|
|
259
265
|
if (optionNames$1.includes(optionPart)) {
|
|
260
266
|
if (valueParser && valueParser.suggest) {
|
|
261
267
|
const valueSuggestions = getSuggestionsWithDependency(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
262
268
|
for (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
263
269
|
kind: "literal",
|
|
264
|
-
text: `${
|
|
265
|
-
description: suggestion.description
|
|
266
|
-
};
|
|
267
|
-
else yield {
|
|
268
|
-
kind: "literal",
|
|
269
|
-
text: `${optionPart}=${suggestion.pattern || ""}`,
|
|
270
|
+
text: `${joinedPrefix}${suggestion.text}`,
|
|
270
271
|
description: suggestion.description
|
|
271
272
|
};
|
|
273
|
+
else yield joinedFileSuggestion(joinedPrefix, suggestion, valuePart);
|
|
272
274
|
}
|
|
273
275
|
}
|
|
274
276
|
} else {
|
|
275
|
-
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
276
277
|
if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
277
278
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
278
279
|
if (prefix === "-" && optionName$1.length !== 2) continue;
|
|
@@ -337,27 +338,23 @@ async function* getSuggestionsWithDependencyAsync(valueParser, prefix, dependenc
|
|
|
337
338
|
*/
|
|
338
339
|
async function* suggestOptionAsync(optionNames$1, valueParser, hidden, description, context, prefix) {
|
|
339
340
|
if (hidden || context.optionsTerminated) return;
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
const
|
|
341
|
+
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
342
|
+
const joinedPrefix = joinedOptionPrefix(optionNames$1, prefix);
|
|
343
|
+
if (joinedPrefix !== void 0 && !expectingValue) {
|
|
344
|
+
const optionPart = joinedPrefix.slice(0, -1);
|
|
345
|
+
const valuePart = prefix.slice(joinedPrefix.length);
|
|
344
346
|
if (optionNames$1.includes(optionPart)) {
|
|
345
347
|
if (valueParser && valueParser.suggest) {
|
|
346
348
|
const valueSuggestions = getSuggestionsWithDependencyAsync(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
347
349
|
for await (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
348
350
|
kind: "literal",
|
|
349
|
-
text: `${
|
|
350
|
-
description: suggestion.description
|
|
351
|
-
};
|
|
352
|
-
else yield {
|
|
353
|
-
kind: "literal",
|
|
354
|
-
text: `${optionPart}=${suggestion.pattern || ""}`,
|
|
351
|
+
text: `${joinedPrefix}${suggestion.text}`,
|
|
355
352
|
description: suggestion.description
|
|
356
353
|
};
|
|
354
|
+
else yield joinedFileSuggestion(joinedPrefix, suggestion, valuePart);
|
|
357
355
|
}
|
|
358
356
|
}
|
|
359
357
|
} else {
|
|
360
|
-
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
361
358
|
if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
362
359
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
363
360
|
if (prefix === "-" && optionName$1.length !== 2) continue;
|
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
|
/**
|
|
@@ -310,7 +311,8 @@ function deduplicateSuggestions(suggestions) {
|
|
|
310
311
|
if (existing == null) {
|
|
311
312
|
entries.set(key, suggestion);
|
|
312
313
|
order.push(key);
|
|
313
|
-
} else if (suggestion.kind === "
|
|
314
|
+
} else if (suggestion.kind === "literal" && existing.kind === "literal") require_joined_file_suggestion.mergeJoinedFileSuggestions(existing, suggestion);
|
|
315
|
+
else if (suggestion.kind === "file" && existing.kind === "file" && suggestion.includeHidden === true && existing.includeHidden !== true) entries.set(key, {
|
|
314
316
|
...existing,
|
|
315
317
|
includeHidden: true
|
|
316
318
|
});
|
package/dist/suggestion.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { message, optionName, text } from "./message.js";
|
|
2
2
|
import { extractCommandNames, extractOptionNames, isSuggestionHidden } from "./usage.js";
|
|
3
|
+
import { mergeJoinedFileSuggestions } from "./internal/joined-file-suggestion.js";
|
|
3
4
|
|
|
4
5
|
//#region src/suggestion.ts
|
|
5
6
|
/**
|
|
@@ -310,7 +311,8 @@ function deduplicateSuggestions(suggestions) {
|
|
|
310
311
|
if (existing == null) {
|
|
311
312
|
entries.set(key, suggestion);
|
|
312
313
|
order.push(key);
|
|
313
|
-
} else if (suggestion.kind === "
|
|
314
|
+
} else if (suggestion.kind === "literal" && existing.kind === "literal") mergeJoinedFileSuggestions(existing, suggestion);
|
|
315
|
+
else if (suggestion.kind === "file" && existing.kind === "file" && suggestion.includeHidden === true && existing.includeHidden !== true) entries.set(key, {
|
|
314
316
|
...existing,
|
|
315
317
|
includeHidden: true
|
|
316
318
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optique/core",
|
|
3
|
-
"version": "1.1.13
|
|
3
|
+
"version": "1.1.13",
|
|
4
4
|
"description": "Type-safe combinatorial command-line interface parser",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"CLI",
|
|
@@ -196,7 +196,7 @@
|
|
|
196
196
|
},
|
|
197
197
|
"sideEffects": false,
|
|
198
198
|
"devDependencies": {
|
|
199
|
-
"@optique/env": "1.1.13
|
|
199
|
+
"@optique/env": "1.1.13",
|
|
200
200
|
"@types/node": "^24.0.0",
|
|
201
201
|
"fast-check": "^4.7.0",
|
|
202
202
|
"tsdown": "^0.13.0",
|