@optique/core 0.10.7-dev.485 → 1.0.0-dev.1109
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/README.md +4 -6
- package/dist/annotations.cjs +209 -1
- package/dist/annotations.d.cts +78 -1
- package/dist/annotations.d.ts +78 -1
- package/dist/annotations.js +201 -1
- package/dist/completion.cjs +186 -50
- package/dist/completion.js +186 -50
- package/dist/constructs.cjs +310 -78
- package/dist/constructs.d.cts +525 -644
- package/dist/constructs.d.ts +525 -644
- package/dist/constructs.js +311 -79
- package/dist/context.cjs +43 -3
- package/dist/context.d.cts +113 -5
- package/dist/context.d.ts +113 -5
- package/dist/context.js +41 -3
- package/dist/dependency.cjs +172 -66
- package/dist/dependency.d.cts +22 -2
- package/dist/dependency.d.ts +22 -2
- package/dist/dependency.js +172 -66
- package/dist/doc.cjs +46 -1
- package/dist/doc.d.cts +24 -0
- package/dist/doc.d.ts +24 -0
- package/dist/doc.js +46 -1
- package/dist/facade.cjs +702 -322
- package/dist/facade.d.cts +124 -190
- package/dist/facade.d.ts +124 -190
- package/dist/facade.js +703 -323
- package/dist/index.cjs +5 -0
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +3 -3
- package/dist/message.cjs +7 -4
- package/dist/message.js +7 -4
- package/dist/mode-dispatch.cjs +23 -1
- package/dist/mode-dispatch.d.cts +55 -0
- package/dist/mode-dispatch.d.ts +55 -0
- package/dist/mode-dispatch.js +21 -1
- package/dist/modifiers.cjs +210 -55
- package/dist/modifiers.js +211 -56
- package/dist/parser.cjs +80 -47
- package/dist/parser.d.cts +18 -3
- package/dist/parser.d.ts +18 -3
- package/dist/parser.js +82 -50
- package/dist/primitives.cjs +102 -37
- package/dist/primitives.d.cts +81 -24
- package/dist/primitives.d.ts +81 -24
- package/dist/primitives.js +103 -39
- package/dist/usage.cjs +88 -6
- package/dist/usage.d.cts +51 -13
- package/dist/usage.d.ts +51 -13
- package/dist/usage.js +85 -7
- package/dist/valueparser.cjs +371 -99
- package/dist/valueparser.d.cts +56 -7
- package/dist/valueparser.d.ts +56 -7
- package/dist/valueparser.js +371 -99
- package/package.json +10 -1
package/dist/usage.cjs
CHANGED
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
|
|
2
2
|
//#region src/usage.ts
|
|
3
3
|
/**
|
|
4
|
+
* Returns whether the term should be hidden from usage output.
|
|
5
|
+
*/
|
|
6
|
+
function isUsageHidden(hidden) {
|
|
7
|
+
return hidden === true || hidden === "usage" || hidden === "help";
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Returns whether the term should be hidden from documentation output.
|
|
11
|
+
*/
|
|
12
|
+
function isDocHidden(hidden) {
|
|
13
|
+
return hidden === true || hidden === "doc" || hidden === "help";
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Returns whether the term should be hidden from suggestion/error candidates.
|
|
17
|
+
*/
|
|
18
|
+
function isSuggestionHidden(hidden) {
|
|
19
|
+
return hidden === true;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Merges two hidden visibility settings by taking the union of restrictions.
|
|
23
|
+
*/
|
|
24
|
+
function mergeHidden(a, b) {
|
|
25
|
+
if (a == null) return b;
|
|
26
|
+
if (b == null) return a;
|
|
27
|
+
if (a === true || b === true) return true;
|
|
28
|
+
if (a === false) return b;
|
|
29
|
+
if (b === false) return a;
|
|
30
|
+
if (a === b) return a;
|
|
31
|
+
if (a === "help" || b === "help") return "help";
|
|
32
|
+
if ((a === "usage" || a === "doc") && (b === "usage" || b === "doc")) return "help";
|
|
33
|
+
return a;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
4
36
|
* Extracts all option names from a usage description.
|
|
5
37
|
*
|
|
6
38
|
* This function recursively traverses a {@link Usage} tree and collects all
|
|
@@ -25,7 +57,7 @@ function extractOptionNames(usage) {
|
|
|
25
57
|
function traverseUsage(terms) {
|
|
26
58
|
if (!terms || !Array.isArray(terms)) return;
|
|
27
59
|
for (const term of terms) if (term.type === "option") {
|
|
28
|
-
if (term.hidden) continue;
|
|
60
|
+
if (isSuggestionHidden(term.hidden)) continue;
|
|
29
61
|
for (const name of term.names) names.add(name);
|
|
30
62
|
} else if (term.type === "optional" || term.type === "multiple") traverseUsage(term.terms);
|
|
31
63
|
else if (term.type === "exclusive") for (const exclusiveUsage of term.terms) traverseUsage(exclusiveUsage);
|
|
@@ -58,7 +90,7 @@ function extractCommandNames(usage) {
|
|
|
58
90
|
function traverseUsage(terms) {
|
|
59
91
|
if (!terms || !Array.isArray(terms)) return;
|
|
60
92
|
for (const term of terms) if (term.type === "command") {
|
|
61
|
-
if (term.hidden) continue;
|
|
93
|
+
if (isSuggestionHidden(term.hidden)) continue;
|
|
62
94
|
names.add(term.name);
|
|
63
95
|
} else if (term.type === "optional" || term.type === "multiple") traverseUsage(term.terms);
|
|
64
96
|
else if (term.type === "exclusive") for (const exclusiveUsage of term.terms) traverseUsage(exclusiveUsage);
|
|
@@ -92,7 +124,7 @@ function extractArgumentMetavars(usage) {
|
|
|
92
124
|
function traverseUsage(terms) {
|
|
93
125
|
if (!terms || !Array.isArray(terms)) return;
|
|
94
126
|
for (const term of terms) if (term.type === "argument") {
|
|
95
|
-
if (term.hidden) continue;
|
|
127
|
+
if (isSuggestionHidden(term.hidden)) continue;
|
|
96
128
|
metavars.add(term.metavar);
|
|
97
129
|
} else if (term.type === "optional" || term.type === "multiple") traverseUsage(term.terms);
|
|
98
130
|
else if (term.type === "exclusive") for (const exclusiveUsage of term.terms) traverseUsage(exclusiveUsage);
|
|
@@ -117,14 +149,14 @@ function extractArgumentMetavars(usage) {
|
|
|
117
149
|
* @returns A formatted string representation of the usage description.
|
|
118
150
|
*/
|
|
119
151
|
function formatUsage(programName, usage, options = {}) {
|
|
120
|
-
usage = normalizeUsage(usage);
|
|
152
|
+
usage = normalizeUsage(filterUsageForDisplay(usage));
|
|
121
153
|
if (options.expandCommands) {
|
|
122
154
|
const lastTerm = usage.at(-1);
|
|
123
155
|
if (usage.length > 0 && usage.slice(0, -1).every((t) => t.type === "command") && lastTerm.type === "exclusive" && lastTerm.terms.every((t) => t.length > 0 && (t[0].type === "command" || t[0].type === "option" || t[0].type === "argument" || t[0].type === "optional" && t[0].terms.length === 1 && (t[0].terms[0].type === "command" || t[0].terms[0].type === "option" || t[0].terms[0].type === "argument")))) {
|
|
124
156
|
const lines = [];
|
|
125
157
|
for (let command of lastTerm.terms) {
|
|
126
158
|
const firstTerm = command[0];
|
|
127
|
-
if (firstTerm?.type === "command" && firstTerm.hidden) continue;
|
|
159
|
+
if (firstTerm?.type === "command" && isUsageHidden(firstTerm.hidden)) continue;
|
|
128
160
|
if (usage.length > 1) command = [...usage.slice(0, -1), ...command];
|
|
129
161
|
lines.push(formatUsage(programName, command, options));
|
|
130
162
|
}
|
|
@@ -205,9 +237,47 @@ function normalizeUsageTerm(term) {
|
|
|
205
237
|
};
|
|
206
238
|
} else return term;
|
|
207
239
|
}
|
|
240
|
+
function filterUsageForDisplay(usage) {
|
|
241
|
+
const terms = [];
|
|
242
|
+
for (const term of usage) {
|
|
243
|
+
if ((term.type === "argument" || term.type === "option" || term.type === "command" || term.type === "passthrough") && isUsageHidden(term.hidden)) continue;
|
|
244
|
+
if (term.type === "optional") {
|
|
245
|
+
const filtered = filterUsageForDisplay(term.terms);
|
|
246
|
+
if (filtered.length > 0) terms.push({
|
|
247
|
+
type: "optional",
|
|
248
|
+
terms: filtered
|
|
249
|
+
});
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (term.type === "multiple") {
|
|
253
|
+
const filtered = filterUsageForDisplay(term.terms);
|
|
254
|
+
if (filtered.length > 0) terms.push({
|
|
255
|
+
type: "multiple",
|
|
256
|
+
terms: filtered,
|
|
257
|
+
min: term.min
|
|
258
|
+
});
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
if (term.type === "exclusive") {
|
|
262
|
+
const filteredBranches = term.terms.map((branch) => {
|
|
263
|
+
const first = branch[0];
|
|
264
|
+
if (first?.type === "command" && isUsageHidden(first.hidden)) return [];
|
|
265
|
+
return filterUsageForDisplay(branch);
|
|
266
|
+
}).filter((branch) => branch.length > 0);
|
|
267
|
+
if (filteredBranches.length > 0) terms.push({
|
|
268
|
+
type: "exclusive",
|
|
269
|
+
terms: filteredBranches
|
|
270
|
+
});
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
terms.push(term);
|
|
274
|
+
}
|
|
275
|
+
return terms;
|
|
276
|
+
}
|
|
208
277
|
function* formatUsageTerms(terms, options) {
|
|
209
278
|
let i = 0;
|
|
210
279
|
for (const t of terms) {
|
|
280
|
+
if ("hidden" in t && (t.type === "argument" || t.type === "option" || t.type === "command" || t.type === "passthrough") && isUsageHidden(t.hidden)) continue;
|
|
211
281
|
if (i > 0) yield {
|
|
212
282
|
text: " ",
|
|
213
283
|
width: 1
|
|
@@ -226,9 +296,11 @@ function* formatUsageTerms(terms, options) {
|
|
|
226
296
|
* @returns A formatted string representation of the usage term.
|
|
227
297
|
*/
|
|
228
298
|
function formatUsageTerm(term, options = {}) {
|
|
299
|
+
const visibleTerms = filterUsageForDisplay([term]);
|
|
300
|
+
if (visibleTerms.length < 1) return "";
|
|
229
301
|
let lineWidth = 0;
|
|
230
302
|
let output = "";
|
|
231
|
-
for (const { text, width } of formatUsageTermInternal(
|
|
303
|
+
for (const { text, width } of formatUsageTermInternal(visibleTerms[0], options)) {
|
|
232
304
|
if (options.maxWidth != null && lineWidth + width > options.maxWidth) {
|
|
233
305
|
output += "\n";
|
|
234
306
|
lineWidth = 0;
|
|
@@ -347,6 +419,12 @@ function* formatUsageTermInternal(term, options) {
|
|
|
347
419
|
text: options?.colors ? `\x1b[2m${text}\x1b[0m` : text,
|
|
348
420
|
width: 5
|
|
349
421
|
};
|
|
422
|
+
} else if (term.type === "ellipsis") {
|
|
423
|
+
const text = "...";
|
|
424
|
+
yield {
|
|
425
|
+
text: options?.colors ? `\x1b[2m${text}\x1b[0m` : text,
|
|
426
|
+
width: 3
|
|
427
|
+
};
|
|
350
428
|
} else throw new TypeError(`Unknown usage term type: ${term["type"]}.`);
|
|
351
429
|
}
|
|
352
430
|
|
|
@@ -356,4 +434,8 @@ exports.extractCommandNames = extractCommandNames;
|
|
|
356
434
|
exports.extractOptionNames = extractOptionNames;
|
|
357
435
|
exports.formatUsage = formatUsage;
|
|
358
436
|
exports.formatUsageTerm = formatUsageTerm;
|
|
437
|
+
exports.isDocHidden = isDocHidden;
|
|
438
|
+
exports.isSuggestionHidden = isSuggestionHidden;
|
|
439
|
+
exports.isUsageHidden = isUsageHidden;
|
|
440
|
+
exports.mergeHidden = mergeHidden;
|
|
359
441
|
exports.normalizeUsage = normalizeUsage;
|
package/dist/usage.d.cts
CHANGED
|
@@ -12,6 +12,31 @@ import { NonEmptyString } from "./nonempty.cjs";
|
|
|
12
12
|
* - Plus-prefixed options (`+o`)
|
|
13
13
|
*/
|
|
14
14
|
type OptionName = `--${string}` | `-${string}` | `/${string}` | `+${string}`;
|
|
15
|
+
/**
|
|
16
|
+
* Visibility control for parser terms.
|
|
17
|
+
*
|
|
18
|
+
* - `true`: hidden from usage, documentation, and suggestions
|
|
19
|
+
* - `"usage"`: hidden from usage only
|
|
20
|
+
* - `"doc"`: hidden from documentation only
|
|
21
|
+
* - `"help"`: hidden from usage and documentation, but shown in suggestions
|
|
22
|
+
*/
|
|
23
|
+
type HiddenVisibility = boolean | "usage" | "doc" | "help";
|
|
24
|
+
/**
|
|
25
|
+
* Returns whether the term should be hidden from usage output.
|
|
26
|
+
*/
|
|
27
|
+
declare function isUsageHidden(hidden?: HiddenVisibility): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Returns whether the term should be hidden from documentation output.
|
|
30
|
+
*/
|
|
31
|
+
declare function isDocHidden(hidden?: HiddenVisibility): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Returns whether the term should be hidden from suggestion/error candidates.
|
|
34
|
+
*/
|
|
35
|
+
declare function isSuggestionHidden(hidden?: HiddenVisibility): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Merges two hidden visibility settings by taking the union of restrictions.
|
|
38
|
+
*/
|
|
39
|
+
declare function mergeHidden(a?: HiddenVisibility, b?: HiddenVisibility): HiddenVisibility | undefined;
|
|
15
40
|
/**
|
|
16
41
|
* Represents a single term in a command-line usage description.
|
|
17
42
|
*/
|
|
@@ -31,11 +56,10 @@ type UsageTerm =
|
|
|
31
56
|
*/
|
|
32
57
|
readonly metavar: NonEmptyString;
|
|
33
58
|
/**
|
|
34
|
-
*
|
|
35
|
-
* suggestions, and error suggestions.
|
|
59
|
+
* Visibility controls for this term.
|
|
36
60
|
* @since 0.9.0
|
|
37
61
|
*/
|
|
38
|
-
readonly hidden?:
|
|
62
|
+
readonly hidden?: HiddenVisibility;
|
|
39
63
|
}
|
|
40
64
|
/**
|
|
41
65
|
* An option term, which represents a command-line option that can
|
|
@@ -56,11 +80,10 @@ type UsageTerm =
|
|
|
56
80
|
*/
|
|
57
81
|
readonly metavar?: NonEmptyString;
|
|
58
82
|
/**
|
|
59
|
-
*
|
|
60
|
-
* suggestions, and "Did you mean?" error suggestions.
|
|
83
|
+
* Visibility controls for this term.
|
|
61
84
|
* @since 0.9.0
|
|
62
85
|
*/
|
|
63
|
-
readonly hidden?:
|
|
86
|
+
readonly hidden?: HiddenVisibility;
|
|
64
87
|
}
|
|
65
88
|
/**
|
|
66
89
|
* A command term, which represents a subcommand in the command-line
|
|
@@ -76,11 +99,16 @@ type UsageTerm =
|
|
|
76
99
|
*/
|
|
77
100
|
readonly name: string;
|
|
78
101
|
/**
|
|
79
|
-
*
|
|
80
|
-
*
|
|
102
|
+
* Optional usage line override for this command's own help page.
|
|
103
|
+
* This affects help/documentation rendering only.
|
|
104
|
+
* @since 1.0.0
|
|
105
|
+
*/
|
|
106
|
+
readonly usageLine?: Usage | ((defaultUsageLine: Usage) => Usage);
|
|
107
|
+
/**
|
|
108
|
+
* Visibility controls for this term.
|
|
81
109
|
* @since 0.9.0
|
|
82
110
|
*/
|
|
83
|
-
readonly hidden?:
|
|
111
|
+
readonly hidden?: HiddenVisibility;
|
|
84
112
|
}
|
|
85
113
|
/**
|
|
86
114
|
* An optional term, which represents an optional component
|
|
@@ -155,11 +183,21 @@ type UsageTerm =
|
|
|
155
183
|
*/
|
|
156
184
|
readonly type: "passthrough";
|
|
157
185
|
/**
|
|
158
|
-
*
|
|
159
|
-
* completion suggestions.
|
|
186
|
+
* Visibility controls for this term.
|
|
160
187
|
* @since 0.9.0
|
|
161
188
|
*/
|
|
162
|
-
readonly hidden?:
|
|
189
|
+
readonly hidden?: HiddenVisibility;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* An ellipsis term, which represents a summary placeholder in usage output.
|
|
193
|
+
* Unlike {@link passthrough}, this term has no parsing semantics and is used
|
|
194
|
+
* only for display.
|
|
195
|
+
* @since 1.0.0
|
|
196
|
+
*/ | {
|
|
197
|
+
/**
|
|
198
|
+
* The type of the term, which is always `"ellipsis"` for this term.
|
|
199
|
+
*/
|
|
200
|
+
readonly type: "ellipsis";
|
|
163
201
|
};
|
|
164
202
|
/**
|
|
165
203
|
* Represents a command-line usage description, which is a sequence of
|
|
@@ -330,4 +368,4 @@ interface UsageTermFormatOptions extends UsageFormatOptions {
|
|
|
330
368
|
*/
|
|
331
369
|
declare function formatUsageTerm(term: UsageTerm, options?: UsageTermFormatOptions): string;
|
|
332
370
|
//#endregion
|
|
333
|
-
export { OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, extractArgumentMetavars, extractCommandNames, extractOptionNames, formatUsage, formatUsageTerm, normalizeUsage };
|
|
371
|
+
export { HiddenVisibility, OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, extractArgumentMetavars, extractCommandNames, extractOptionNames, formatUsage, formatUsageTerm, isDocHidden, isSuggestionHidden, isUsageHidden, mergeHidden, normalizeUsage };
|
package/dist/usage.d.ts
CHANGED
|
@@ -12,6 +12,31 @@ import { NonEmptyString } from "./nonempty.js";
|
|
|
12
12
|
* - Plus-prefixed options (`+o`)
|
|
13
13
|
*/
|
|
14
14
|
type OptionName = `--${string}` | `-${string}` | `/${string}` | `+${string}`;
|
|
15
|
+
/**
|
|
16
|
+
* Visibility control for parser terms.
|
|
17
|
+
*
|
|
18
|
+
* - `true`: hidden from usage, documentation, and suggestions
|
|
19
|
+
* - `"usage"`: hidden from usage only
|
|
20
|
+
* - `"doc"`: hidden from documentation only
|
|
21
|
+
* - `"help"`: hidden from usage and documentation, but shown in suggestions
|
|
22
|
+
*/
|
|
23
|
+
type HiddenVisibility = boolean | "usage" | "doc" | "help";
|
|
24
|
+
/**
|
|
25
|
+
* Returns whether the term should be hidden from usage output.
|
|
26
|
+
*/
|
|
27
|
+
declare function isUsageHidden(hidden?: HiddenVisibility): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Returns whether the term should be hidden from documentation output.
|
|
30
|
+
*/
|
|
31
|
+
declare function isDocHidden(hidden?: HiddenVisibility): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Returns whether the term should be hidden from suggestion/error candidates.
|
|
34
|
+
*/
|
|
35
|
+
declare function isSuggestionHidden(hidden?: HiddenVisibility): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Merges two hidden visibility settings by taking the union of restrictions.
|
|
38
|
+
*/
|
|
39
|
+
declare function mergeHidden(a?: HiddenVisibility, b?: HiddenVisibility): HiddenVisibility | undefined;
|
|
15
40
|
/**
|
|
16
41
|
* Represents a single term in a command-line usage description.
|
|
17
42
|
*/
|
|
@@ -31,11 +56,10 @@ type UsageTerm =
|
|
|
31
56
|
*/
|
|
32
57
|
readonly metavar: NonEmptyString;
|
|
33
58
|
/**
|
|
34
|
-
*
|
|
35
|
-
* suggestions, and error suggestions.
|
|
59
|
+
* Visibility controls for this term.
|
|
36
60
|
* @since 0.9.0
|
|
37
61
|
*/
|
|
38
|
-
readonly hidden?:
|
|
62
|
+
readonly hidden?: HiddenVisibility;
|
|
39
63
|
}
|
|
40
64
|
/**
|
|
41
65
|
* An option term, which represents a command-line option that can
|
|
@@ -56,11 +80,10 @@ type UsageTerm =
|
|
|
56
80
|
*/
|
|
57
81
|
readonly metavar?: NonEmptyString;
|
|
58
82
|
/**
|
|
59
|
-
*
|
|
60
|
-
* suggestions, and "Did you mean?" error suggestions.
|
|
83
|
+
* Visibility controls for this term.
|
|
61
84
|
* @since 0.9.0
|
|
62
85
|
*/
|
|
63
|
-
readonly hidden?:
|
|
86
|
+
readonly hidden?: HiddenVisibility;
|
|
64
87
|
}
|
|
65
88
|
/**
|
|
66
89
|
* A command term, which represents a subcommand in the command-line
|
|
@@ -76,11 +99,16 @@ type UsageTerm =
|
|
|
76
99
|
*/
|
|
77
100
|
readonly name: string;
|
|
78
101
|
/**
|
|
79
|
-
*
|
|
80
|
-
*
|
|
102
|
+
* Optional usage line override for this command's own help page.
|
|
103
|
+
* This affects help/documentation rendering only.
|
|
104
|
+
* @since 1.0.0
|
|
105
|
+
*/
|
|
106
|
+
readonly usageLine?: Usage | ((defaultUsageLine: Usage) => Usage);
|
|
107
|
+
/**
|
|
108
|
+
* Visibility controls for this term.
|
|
81
109
|
* @since 0.9.0
|
|
82
110
|
*/
|
|
83
|
-
readonly hidden?:
|
|
111
|
+
readonly hidden?: HiddenVisibility;
|
|
84
112
|
}
|
|
85
113
|
/**
|
|
86
114
|
* An optional term, which represents an optional component
|
|
@@ -155,11 +183,21 @@ type UsageTerm =
|
|
|
155
183
|
*/
|
|
156
184
|
readonly type: "passthrough";
|
|
157
185
|
/**
|
|
158
|
-
*
|
|
159
|
-
* completion suggestions.
|
|
186
|
+
* Visibility controls for this term.
|
|
160
187
|
* @since 0.9.0
|
|
161
188
|
*/
|
|
162
|
-
readonly hidden?:
|
|
189
|
+
readonly hidden?: HiddenVisibility;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* An ellipsis term, which represents a summary placeholder in usage output.
|
|
193
|
+
* Unlike {@link passthrough}, this term has no parsing semantics and is used
|
|
194
|
+
* only for display.
|
|
195
|
+
* @since 1.0.0
|
|
196
|
+
*/ | {
|
|
197
|
+
/**
|
|
198
|
+
* The type of the term, which is always `"ellipsis"` for this term.
|
|
199
|
+
*/
|
|
200
|
+
readonly type: "ellipsis";
|
|
163
201
|
};
|
|
164
202
|
/**
|
|
165
203
|
* Represents a command-line usage description, which is a sequence of
|
|
@@ -330,4 +368,4 @@ interface UsageTermFormatOptions extends UsageFormatOptions {
|
|
|
330
368
|
*/
|
|
331
369
|
declare function formatUsageTerm(term: UsageTerm, options?: UsageTermFormatOptions): string;
|
|
332
370
|
//#endregion
|
|
333
|
-
export { OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, extractArgumentMetavars, extractCommandNames, extractOptionNames, formatUsage, formatUsageTerm, normalizeUsage };
|
|
371
|
+
export { HiddenVisibility, OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, extractArgumentMetavars, extractCommandNames, extractOptionNames, formatUsage, formatUsageTerm, isDocHidden, isSuggestionHidden, isUsageHidden, mergeHidden, normalizeUsage };
|
package/dist/usage.js
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
//#region src/usage.ts
|
|
2
2
|
/**
|
|
3
|
+
* Returns whether the term should be hidden from usage output.
|
|
4
|
+
*/
|
|
5
|
+
function isUsageHidden(hidden) {
|
|
6
|
+
return hidden === true || hidden === "usage" || hidden === "help";
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Returns whether the term should be hidden from documentation output.
|
|
10
|
+
*/
|
|
11
|
+
function isDocHidden(hidden) {
|
|
12
|
+
return hidden === true || hidden === "doc" || hidden === "help";
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Returns whether the term should be hidden from suggestion/error candidates.
|
|
16
|
+
*/
|
|
17
|
+
function isSuggestionHidden(hidden) {
|
|
18
|
+
return hidden === true;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Merges two hidden visibility settings by taking the union of restrictions.
|
|
22
|
+
*/
|
|
23
|
+
function mergeHidden(a, b) {
|
|
24
|
+
if (a == null) return b;
|
|
25
|
+
if (b == null) return a;
|
|
26
|
+
if (a === true || b === true) return true;
|
|
27
|
+
if (a === false) return b;
|
|
28
|
+
if (b === false) return a;
|
|
29
|
+
if (a === b) return a;
|
|
30
|
+
if (a === "help" || b === "help") return "help";
|
|
31
|
+
if ((a === "usage" || a === "doc") && (b === "usage" || b === "doc")) return "help";
|
|
32
|
+
return a;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
3
35
|
* Extracts all option names from a usage description.
|
|
4
36
|
*
|
|
5
37
|
* This function recursively traverses a {@link Usage} tree and collects all
|
|
@@ -24,7 +56,7 @@ function extractOptionNames(usage) {
|
|
|
24
56
|
function traverseUsage(terms) {
|
|
25
57
|
if (!terms || !Array.isArray(terms)) return;
|
|
26
58
|
for (const term of terms) if (term.type === "option") {
|
|
27
|
-
if (term.hidden) continue;
|
|
59
|
+
if (isSuggestionHidden(term.hidden)) continue;
|
|
28
60
|
for (const name of term.names) names.add(name);
|
|
29
61
|
} else if (term.type === "optional" || term.type === "multiple") traverseUsage(term.terms);
|
|
30
62
|
else if (term.type === "exclusive") for (const exclusiveUsage of term.terms) traverseUsage(exclusiveUsage);
|
|
@@ -57,7 +89,7 @@ function extractCommandNames(usage) {
|
|
|
57
89
|
function traverseUsage(terms) {
|
|
58
90
|
if (!terms || !Array.isArray(terms)) return;
|
|
59
91
|
for (const term of terms) if (term.type === "command") {
|
|
60
|
-
if (term.hidden) continue;
|
|
92
|
+
if (isSuggestionHidden(term.hidden)) continue;
|
|
61
93
|
names.add(term.name);
|
|
62
94
|
} else if (term.type === "optional" || term.type === "multiple") traverseUsage(term.terms);
|
|
63
95
|
else if (term.type === "exclusive") for (const exclusiveUsage of term.terms) traverseUsage(exclusiveUsage);
|
|
@@ -91,7 +123,7 @@ function extractArgumentMetavars(usage) {
|
|
|
91
123
|
function traverseUsage(terms) {
|
|
92
124
|
if (!terms || !Array.isArray(terms)) return;
|
|
93
125
|
for (const term of terms) if (term.type === "argument") {
|
|
94
|
-
if (term.hidden) continue;
|
|
126
|
+
if (isSuggestionHidden(term.hidden)) continue;
|
|
95
127
|
metavars.add(term.metavar);
|
|
96
128
|
} else if (term.type === "optional" || term.type === "multiple") traverseUsage(term.terms);
|
|
97
129
|
else if (term.type === "exclusive") for (const exclusiveUsage of term.terms) traverseUsage(exclusiveUsage);
|
|
@@ -116,14 +148,14 @@ function extractArgumentMetavars(usage) {
|
|
|
116
148
|
* @returns A formatted string representation of the usage description.
|
|
117
149
|
*/
|
|
118
150
|
function formatUsage(programName, usage, options = {}) {
|
|
119
|
-
usage = normalizeUsage(usage);
|
|
151
|
+
usage = normalizeUsage(filterUsageForDisplay(usage));
|
|
120
152
|
if (options.expandCommands) {
|
|
121
153
|
const lastTerm = usage.at(-1);
|
|
122
154
|
if (usage.length > 0 && usage.slice(0, -1).every((t) => t.type === "command") && lastTerm.type === "exclusive" && lastTerm.terms.every((t) => t.length > 0 && (t[0].type === "command" || t[0].type === "option" || t[0].type === "argument" || t[0].type === "optional" && t[0].terms.length === 1 && (t[0].terms[0].type === "command" || t[0].terms[0].type === "option" || t[0].terms[0].type === "argument")))) {
|
|
123
155
|
const lines = [];
|
|
124
156
|
for (let command of lastTerm.terms) {
|
|
125
157
|
const firstTerm = command[0];
|
|
126
|
-
if (firstTerm?.type === "command" && firstTerm.hidden) continue;
|
|
158
|
+
if (firstTerm?.type === "command" && isUsageHidden(firstTerm.hidden)) continue;
|
|
127
159
|
if (usage.length > 1) command = [...usage.slice(0, -1), ...command];
|
|
128
160
|
lines.push(formatUsage(programName, command, options));
|
|
129
161
|
}
|
|
@@ -204,9 +236,47 @@ function normalizeUsageTerm(term) {
|
|
|
204
236
|
};
|
|
205
237
|
} else return term;
|
|
206
238
|
}
|
|
239
|
+
function filterUsageForDisplay(usage) {
|
|
240
|
+
const terms = [];
|
|
241
|
+
for (const term of usage) {
|
|
242
|
+
if ((term.type === "argument" || term.type === "option" || term.type === "command" || term.type === "passthrough") && isUsageHidden(term.hidden)) continue;
|
|
243
|
+
if (term.type === "optional") {
|
|
244
|
+
const filtered = filterUsageForDisplay(term.terms);
|
|
245
|
+
if (filtered.length > 0) terms.push({
|
|
246
|
+
type: "optional",
|
|
247
|
+
terms: filtered
|
|
248
|
+
});
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (term.type === "multiple") {
|
|
252
|
+
const filtered = filterUsageForDisplay(term.terms);
|
|
253
|
+
if (filtered.length > 0) terms.push({
|
|
254
|
+
type: "multiple",
|
|
255
|
+
terms: filtered,
|
|
256
|
+
min: term.min
|
|
257
|
+
});
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
if (term.type === "exclusive") {
|
|
261
|
+
const filteredBranches = term.terms.map((branch) => {
|
|
262
|
+
const first = branch[0];
|
|
263
|
+
if (first?.type === "command" && isUsageHidden(first.hidden)) return [];
|
|
264
|
+
return filterUsageForDisplay(branch);
|
|
265
|
+
}).filter((branch) => branch.length > 0);
|
|
266
|
+
if (filteredBranches.length > 0) terms.push({
|
|
267
|
+
type: "exclusive",
|
|
268
|
+
terms: filteredBranches
|
|
269
|
+
});
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
terms.push(term);
|
|
273
|
+
}
|
|
274
|
+
return terms;
|
|
275
|
+
}
|
|
207
276
|
function* formatUsageTerms(terms, options) {
|
|
208
277
|
let i = 0;
|
|
209
278
|
for (const t of terms) {
|
|
279
|
+
if ("hidden" in t && (t.type === "argument" || t.type === "option" || t.type === "command" || t.type === "passthrough") && isUsageHidden(t.hidden)) continue;
|
|
210
280
|
if (i > 0) yield {
|
|
211
281
|
text: " ",
|
|
212
282
|
width: 1
|
|
@@ -225,9 +295,11 @@ function* formatUsageTerms(terms, options) {
|
|
|
225
295
|
* @returns A formatted string representation of the usage term.
|
|
226
296
|
*/
|
|
227
297
|
function formatUsageTerm(term, options = {}) {
|
|
298
|
+
const visibleTerms = filterUsageForDisplay([term]);
|
|
299
|
+
if (visibleTerms.length < 1) return "";
|
|
228
300
|
let lineWidth = 0;
|
|
229
301
|
let output = "";
|
|
230
|
-
for (const { text, width } of formatUsageTermInternal(
|
|
302
|
+
for (const { text, width } of formatUsageTermInternal(visibleTerms[0], options)) {
|
|
231
303
|
if (options.maxWidth != null && lineWidth + width > options.maxWidth) {
|
|
232
304
|
output += "\n";
|
|
233
305
|
lineWidth = 0;
|
|
@@ -346,8 +418,14 @@ function* formatUsageTermInternal(term, options) {
|
|
|
346
418
|
text: options?.colors ? `\x1b[2m${text}\x1b[0m` : text,
|
|
347
419
|
width: 5
|
|
348
420
|
};
|
|
421
|
+
} else if (term.type === "ellipsis") {
|
|
422
|
+
const text = "...";
|
|
423
|
+
yield {
|
|
424
|
+
text: options?.colors ? `\x1b[2m${text}\x1b[0m` : text,
|
|
425
|
+
width: 3
|
|
426
|
+
};
|
|
349
427
|
} else throw new TypeError(`Unknown usage term type: ${term["type"]}.`);
|
|
350
428
|
}
|
|
351
429
|
|
|
352
430
|
//#endregion
|
|
353
|
-
export { extractArgumentMetavars, extractCommandNames, extractOptionNames, formatUsage, formatUsageTerm, normalizeUsage };
|
|
431
|
+
export { extractArgumentMetavars, extractCommandNames, extractOptionNames, formatUsage, formatUsageTerm, isDocHidden, isSuggestionHidden, isUsageHidden, mergeHidden, normalizeUsage };
|