@optique/core 1.3.0-dev.2554 → 1.3.0-dev.2558
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/doc.cjs +1 -1
- package/dist/doc.js +1 -1
- package/dist/facade.cjs +23 -41
- package/dist/facade.js +24 -42
- package/dist/internal/terminal.cjs +2 -1
- package/dist/internal/terminal.d.cts +2 -2
- package/dist/internal/terminal.d.ts +2 -2
- package/dist/internal/terminal.js +2 -2
- package/dist/message-renderer.cjs +34 -0
- package/dist/message-renderer.d.cts +16 -1
- package/dist/message-renderer.d.ts +16 -1
- package/dist/message-renderer.js +34 -1
- package/dist/terminal-internal.cjs +43 -16
- package/dist/terminal-internal.d.cts +20 -2
- package/dist/terminal-internal.d.ts +20 -2
- package/dist/terminal-internal.js +43 -17
- package/dist/usage.cjs +52 -43
- package/dist/usage.js +53 -44
- package/package.json +2 -2
package/dist/doc.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const require_message_registry = require('./message-registry.cjs');
|
|
2
2
|
const require_terminal_internal = require('./terminal-internal.cjs');
|
|
3
|
+
const require_text_layout = require('./text-layout.cjs');
|
|
3
4
|
const require_message = require('./message.cjs');
|
|
4
5
|
const require_message_renderer = require('./message-renderer.cjs');
|
|
5
|
-
const require_text_layout = require('./text-layout.cjs');
|
|
6
6
|
const require_validate = require('./validate.cjs');
|
|
7
7
|
const require_usage = require('./usage.cjs');
|
|
8
8
|
|
package/dist/doc.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { messageRenderers } from "./message-registry.js";
|
|
2
2
|
import { cacheTerminalTheme, formatTerminalTerm, fragmentTokens, renderTerminalTerm, styleCode } from "./terminal-internal.js";
|
|
3
|
+
import { measureAnnotation, measureText, placeText, spaceAfterLabel } from "./text-layout.js";
|
|
3
4
|
import { cloneMessage, text } from "./message.js";
|
|
4
5
|
import { resolveMessageFormatter } from "./message-renderer.js";
|
|
5
|
-
import { measureAnnotation, measureText, placeText, spaceAfterLabel } from "./text-layout.js";
|
|
6
6
|
import { validateLabel, validateProgramName } from "./validate.js";
|
|
7
7
|
import { cloneUsageTerm, formatUsage, formatUsageTerm, isDocHidden } from "./usage.js";
|
|
8
8
|
|
package/dist/facade.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const require_internal_annotations = require('./internal/annotations.cjs');
|
|
2
2
|
const require_terminal_internal = require('./terminal-internal.cjs');
|
|
3
|
+
const require_text_layout = require('./text-layout.cjs');
|
|
3
4
|
const require_message = require('./message.cjs');
|
|
4
5
|
const require_message_renderer = require('./message-renderer.cjs');
|
|
5
|
-
const require_text_layout = require('./text-layout.cjs');
|
|
6
6
|
const require_validate = require('./validate.cjs');
|
|
7
7
|
const require_usage = require('./usage.cjs');
|
|
8
8
|
const require_doc = require('./doc.cjs');
|
|
@@ -517,27 +517,19 @@ function classifyParseFailure(failure, helpOptionNames, helpCommandNames, versio
|
|
|
517
517
|
* @since 0.6.0
|
|
518
518
|
*/
|
|
519
519
|
function handleCompletion(completionArgs, programName, parser, completionParser, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, termWidth, completionCommandDisplayName, completionOptionDisplayName, isOptionMode, sectionOrder, showUsage, rootOptionSuggestions = [], messageFormatter, theme) {
|
|
520
|
-
const formatMessage = require_message_renderer.resolveMessageFormatter({
|
|
521
|
-
messageFormatter,
|
|
522
|
-
theme
|
|
523
|
-
});
|
|
524
|
-
const errorLabel = () => require_text_layout.spaceAfterLabel(require_terminal_internal.renderTerminalTerm({
|
|
525
|
-
type: "errorLabel",
|
|
526
|
-
label: "Error:"
|
|
527
|
-
}, theme, colors));
|
|
528
520
|
const shellName = completionArgs[0] || "";
|
|
529
521
|
const args = completionArgs.slice(1);
|
|
530
522
|
const callOnError = (code, error) => onError(code, error);
|
|
531
523
|
const callOnCompletion = (code) => onCompletion(code);
|
|
532
524
|
if (!shellName) {
|
|
533
525
|
const error = require_message.message`Missing shell name for completion.`;
|
|
534
|
-
|
|
535
|
-
|
|
526
|
+
stderr(require_message_renderer.renderErrorMessage(error, {
|
|
527
|
+
messageFormatter,
|
|
528
|
+
theme,
|
|
536
529
|
colors,
|
|
537
530
|
quotes: !colors,
|
|
538
|
-
maxWidth
|
|
539
|
-
|
|
540
|
-
})}\n`);
|
|
531
|
+
maxWidth
|
|
532
|
+
}) + "\n");
|
|
541
533
|
if (completionParser) {
|
|
542
534
|
const displayName = isOptionMode ? completionOptionDisplayName ?? "--completion" : completionCommandDisplayName ?? "completion";
|
|
543
535
|
const doc = require_internal_parser.getDocPage(completionParser, [displayName]);
|
|
@@ -565,13 +557,13 @@ function handleCompletion(completionArgs, programName, parser, completionParser,
|
|
|
565
557
|
available.push(require_message.value(name));
|
|
566
558
|
}
|
|
567
559
|
const error = require_message.message`Unsupported shell ${shellName}. Available shells: ${available}.`;
|
|
568
|
-
|
|
569
|
-
|
|
560
|
+
stderr(require_message_renderer.renderErrorMessage(error, {
|
|
561
|
+
messageFormatter,
|
|
562
|
+
theme,
|
|
570
563
|
colors,
|
|
571
564
|
quotes: !colors,
|
|
572
|
-
maxWidth
|
|
573
|
-
|
|
574
|
-
})}`);
|
|
565
|
+
maxWidth
|
|
566
|
+
}));
|
|
575
567
|
return require_mode_dispatch.dispatchByMode(parser.mode, () => {
|
|
576
568
|
const result = callOnError(1, error);
|
|
577
569
|
if (result instanceof Promise) throw new RunParserError("Synchronous parser returned async result.");
|
|
@@ -882,14 +874,6 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
|
|
|
882
874
|
const { colors, messageFormatter, theme, maxWidth, termWidth, showDefault, showChoices, sectionOrder, showUsage, usageLine, commandList = "recursive", aboveError = "usage", onError = () => {
|
|
883
875
|
throw new RunParserError("Failed to parse command line arguments.");
|
|
884
876
|
}, stderr = console.error, stdout = console.log, brief, description, examples, author, bugs, footer } = options;
|
|
885
|
-
const formatMessage = require_message_renderer.resolveMessageFormatter({
|
|
886
|
-
messageFormatter,
|
|
887
|
-
theme
|
|
888
|
-
});
|
|
889
|
-
const errorLabel = () => require_text_layout.spaceAfterLabel(require_terminal_internal.renderTerminalTerm({
|
|
890
|
-
type: "errorLabel",
|
|
891
|
-
label: "Error:"
|
|
892
|
-
}, theme, colors));
|
|
893
877
|
let usagePrefix;
|
|
894
878
|
const usageLabel = () => usagePrefix ??= require_text_layout.spaceAfterLabel(require_terminal_internal.renderTerminalTerm({
|
|
895
879
|
type: "label",
|
|
@@ -1057,14 +1041,13 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
|
|
|
1057
1041
|
maxWidth: maxWidth == null ? void 0 : maxWidth - usageLabelWidth(),
|
|
1058
1042
|
expandCommands: true
|
|
1059
1043
|
}), usageLabelWidth())}`);
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
maxWidth,
|
|
1044
|
+
stderr(require_message_renderer.renderErrorMessage(validationError, {
|
|
1045
|
+
messageFormatter,
|
|
1046
|
+
theme,
|
|
1064
1047
|
colors,
|
|
1065
|
-
quotes: !colors
|
|
1066
|
-
|
|
1067
|
-
|
|
1048
|
+
quotes: !colors,
|
|
1049
|
+
maxWidth
|
|
1050
|
+
}));
|
|
1068
1051
|
return onError(1, validationError);
|
|
1069
1052
|
};
|
|
1070
1053
|
const displayHelp = (doc) => {
|
|
@@ -1177,14 +1160,13 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
|
|
|
1177
1160
|
maxWidth: maxWidth == null ? void 0 : maxWidth - usageLabelWidth(),
|
|
1178
1161
|
expandCommands: true
|
|
1179
1162
|
}), usageLabelWidth())}`);
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
maxWidth,
|
|
1163
|
+
stderr(require_message_renderer.renderErrorMessage(classified.error, {
|
|
1164
|
+
messageFormatter,
|
|
1165
|
+
theme,
|
|
1184
1166
|
colors,
|
|
1185
|
-
quotes: !colors
|
|
1186
|
-
|
|
1187
|
-
|
|
1167
|
+
quotes: !colors,
|
|
1168
|
+
maxWidth
|
|
1169
|
+
}));
|
|
1188
1170
|
return onError(1, classified.error);
|
|
1189
1171
|
};
|
|
1190
1172
|
if (aboveError === "help") {
|
package/dist/facade.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { injectAnnotations } from "./internal/annotations.js";
|
|
2
2
|
import { renderTerminalTerm } from "./terminal-internal.js";
|
|
3
|
-
import { commandLine, lineBreak, message, optionName, text, value } from "./message.js";
|
|
4
|
-
import { resolveMessageFormatter } from "./message-renderer.js";
|
|
5
3
|
import { measureText, spaceAfterLabel } from "./text-layout.js";
|
|
4
|
+
import { commandLine, lineBreak, message, optionName, text, value } from "./message.js";
|
|
5
|
+
import { renderErrorMessage } from "./message-renderer.js";
|
|
6
6
|
import { validateCommandNames, validateContextIds, validateMetaNameCollisions, validateOptionNames, validateProgramName } from "./validate.js";
|
|
7
7
|
import { cloneUsage, formatUsage, isSuggestionHidden, normalizeUsage } from "./usage.js";
|
|
8
8
|
import { formatDocPage } from "./doc.js";
|
|
@@ -517,27 +517,19 @@ function classifyParseFailure(failure, helpOptionNames, helpCommandNames, versio
|
|
|
517
517
|
* @since 0.6.0
|
|
518
518
|
*/
|
|
519
519
|
function handleCompletion(completionArgs, programName, parser, completionParser, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, termWidth, completionCommandDisplayName, completionOptionDisplayName, isOptionMode, sectionOrder, showUsage, rootOptionSuggestions = [], messageFormatter, theme) {
|
|
520
|
-
const formatMessage = resolveMessageFormatter({
|
|
521
|
-
messageFormatter,
|
|
522
|
-
theme
|
|
523
|
-
});
|
|
524
|
-
const errorLabel = () => spaceAfterLabel(renderTerminalTerm({
|
|
525
|
-
type: "errorLabel",
|
|
526
|
-
label: "Error:"
|
|
527
|
-
}, theme, colors));
|
|
528
520
|
const shellName = completionArgs[0] || "";
|
|
529
521
|
const args = completionArgs.slice(1);
|
|
530
522
|
const callOnError = (code, error) => onError(code, error);
|
|
531
523
|
const callOnCompletion = (code) => onCompletion(code);
|
|
532
524
|
if (!shellName) {
|
|
533
525
|
const error = message`Missing shell name for completion.`;
|
|
534
|
-
|
|
535
|
-
|
|
526
|
+
stderr(renderErrorMessage(error, {
|
|
527
|
+
messageFormatter,
|
|
528
|
+
theme,
|
|
536
529
|
colors,
|
|
537
530
|
quotes: !colors,
|
|
538
|
-
maxWidth
|
|
539
|
-
|
|
540
|
-
})}\n`);
|
|
531
|
+
maxWidth
|
|
532
|
+
}) + "\n");
|
|
541
533
|
if (completionParser) {
|
|
542
534
|
const displayName = isOptionMode ? completionOptionDisplayName ?? "--completion" : completionCommandDisplayName ?? "completion";
|
|
543
535
|
const doc = getDocPage(completionParser, [displayName]);
|
|
@@ -565,13 +557,13 @@ function handleCompletion(completionArgs, programName, parser, completionParser,
|
|
|
565
557
|
available.push(value(name));
|
|
566
558
|
}
|
|
567
559
|
const error = message`Unsupported shell ${shellName}. Available shells: ${available}.`;
|
|
568
|
-
|
|
569
|
-
|
|
560
|
+
stderr(renderErrorMessage(error, {
|
|
561
|
+
messageFormatter,
|
|
562
|
+
theme,
|
|
570
563
|
colors,
|
|
571
564
|
quotes: !colors,
|
|
572
|
-
maxWidth
|
|
573
|
-
|
|
574
|
-
})}`);
|
|
565
|
+
maxWidth
|
|
566
|
+
}));
|
|
575
567
|
return dispatchByMode(parser.mode, () => {
|
|
576
568
|
const result = callOnError(1, error);
|
|
577
569
|
if (result instanceof Promise) throw new RunParserError("Synchronous parser returned async result.");
|
|
@@ -882,14 +874,6 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
|
|
|
882
874
|
const { colors, messageFormatter, theme, maxWidth, termWidth, showDefault, showChoices, sectionOrder, showUsage, usageLine, commandList = "recursive", aboveError = "usage", onError = () => {
|
|
883
875
|
throw new RunParserError("Failed to parse command line arguments.");
|
|
884
876
|
}, stderr = console.error, stdout = console.log, brief, description, examples, author, bugs, footer } = options;
|
|
885
|
-
const formatMessage = resolveMessageFormatter({
|
|
886
|
-
messageFormatter,
|
|
887
|
-
theme
|
|
888
|
-
});
|
|
889
|
-
const errorLabel = () => spaceAfterLabel(renderTerminalTerm({
|
|
890
|
-
type: "errorLabel",
|
|
891
|
-
label: "Error:"
|
|
892
|
-
}, theme, colors));
|
|
893
877
|
let usagePrefix;
|
|
894
878
|
const usageLabel = () => usagePrefix ??= spaceAfterLabel(renderTerminalTerm({
|
|
895
879
|
type: "label",
|
|
@@ -1057,14 +1041,13 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
|
|
|
1057
1041
|
maxWidth: maxWidth == null ? void 0 : maxWidth - usageLabelWidth(),
|
|
1058
1042
|
expandCommands: true
|
|
1059
1043
|
}), usageLabelWidth())}`);
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
maxWidth,
|
|
1044
|
+
stderr(renderErrorMessage(validationError, {
|
|
1045
|
+
messageFormatter,
|
|
1046
|
+
theme,
|
|
1064
1047
|
colors,
|
|
1065
|
-
quotes: !colors
|
|
1066
|
-
|
|
1067
|
-
|
|
1048
|
+
quotes: !colors,
|
|
1049
|
+
maxWidth
|
|
1050
|
+
}));
|
|
1068
1051
|
return onError(1, validationError);
|
|
1069
1052
|
};
|
|
1070
1053
|
const displayHelp = (doc) => {
|
|
@@ -1177,14 +1160,13 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
|
|
|
1177
1160
|
maxWidth: maxWidth == null ? void 0 : maxWidth - usageLabelWidth(),
|
|
1178
1161
|
expandCommands: true
|
|
1179
1162
|
}), usageLabelWidth())}`);
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
maxWidth,
|
|
1163
|
+
stderr(renderErrorMessage(classified.error, {
|
|
1164
|
+
messageFormatter,
|
|
1165
|
+
theme,
|
|
1184
1166
|
colors,
|
|
1185
|
-
quotes: !colors
|
|
1186
|
-
|
|
1187
|
-
|
|
1167
|
+
quotes: !colors,
|
|
1168
|
+
maxWidth
|
|
1169
|
+
}));
|
|
1188
1170
|
return onError(1, classified.error);
|
|
1189
1171
|
};
|
|
1190
1172
|
if (aboveError === "help") {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
const require_displaywidth = require('../displaywidth.cjs');
|
|
2
2
|
const require_terminal_internal = require('../terminal-internal.cjs');
|
|
3
|
-
const require_message_renderer = require('../message-renderer.cjs');
|
|
4
3
|
const require_text_layout = require('../text-layout.cjs');
|
|
4
|
+
const require_message_renderer = require('../message-renderer.cjs');
|
|
5
5
|
|
|
6
6
|
exports.getDisplayWidth = require_displaywidth.getDisplayWidth;
|
|
7
7
|
exports.measureText = require_text_layout.measureText;
|
|
8
8
|
exports.placeText = require_text_layout.placeText;
|
|
9
|
+
exports.renderErrorMessage = require_message_renderer.renderErrorMessage;
|
|
9
10
|
exports.renderTerminalTerm = require_terminal_internal.renderTerminalTerm;
|
|
10
11
|
exports.resolveMessageFormatter = require_message_renderer.resolveMessageFormatter;
|
|
11
12
|
exports.spaceAfterLabel = require_text_layout.spaceAfterLabel;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getDisplayWidth } from "../displaywidth.cjs";
|
|
2
|
-
import { resolveMessageFormatter } from "../message-renderer.cjs";
|
|
2
|
+
import { renderErrorMessage, resolveMessageFormatter } from "../message-renderer.cjs";
|
|
3
3
|
import { renderTerminalTerm } from "../terminal-internal.cjs";
|
|
4
4
|
import { measureText, placeText, spaceAfterLabel } from "../text-layout.cjs";
|
|
5
|
-
export { getDisplayWidth, measureText, placeText, renderTerminalTerm, resolveMessageFormatter, spaceAfterLabel };
|
|
5
|
+
export { getDisplayWidth, measureText, placeText, renderErrorMessage, renderTerminalTerm, resolveMessageFormatter, spaceAfterLabel };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getDisplayWidth } from "../displaywidth.js";
|
|
2
|
-
import { resolveMessageFormatter } from "../message-renderer.js";
|
|
2
|
+
import { renderErrorMessage, resolveMessageFormatter } from "../message-renderer.js";
|
|
3
3
|
import { renderTerminalTerm } from "../terminal-internal.js";
|
|
4
4
|
import { measureText, placeText, spaceAfterLabel } from "../text-layout.js";
|
|
5
|
-
export { getDisplayWidth, measureText, placeText, renderTerminalTerm, resolveMessageFormatter, spaceAfterLabel };
|
|
5
|
+
export { getDisplayWidth, measureText, placeText, renderErrorMessage, renderTerminalTerm, resolveMessageFormatter, spaceAfterLabel };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getDisplayWidth } from "../displaywidth.js";
|
|
2
2
|
import { renderTerminalTerm } from "../terminal-internal.js";
|
|
3
|
-
import { resolveMessageFormatter } from "../message-renderer.js";
|
|
4
3
|
import { measureText, placeText, spaceAfterLabel } from "../text-layout.js";
|
|
4
|
+
import { renderErrorMessage, resolveMessageFormatter } from "../message-renderer.js";
|
|
5
5
|
|
|
6
|
-
export { getDisplayWidth, measureText, placeText, renderTerminalTerm, resolveMessageFormatter, spaceAfterLabel };
|
|
6
|
+
export { getDisplayWidth, measureText, placeText, renderErrorMessage, renderTerminalTerm, resolveMessageFormatter, spaceAfterLabel };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const require_message_registry = require('./message-registry.cjs');
|
|
2
|
+
const require_terminal_internal = require('./terminal-internal.cjs');
|
|
3
|
+
const require_text_layout = require('./text-layout.cjs');
|
|
2
4
|
const require_message = require('./message.cjs');
|
|
3
5
|
|
|
4
6
|
//#region src/message-renderer.ts
|
|
@@ -21,6 +23,38 @@ function resolveMessageFormatter(options) {
|
|
|
21
23
|
});
|
|
22
24
|
};
|
|
23
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Assembles a themed error prefix and a message at one layout boundary.
|
|
28
|
+
* Callers own streams, trailing newlines, and the default quoting policy.
|
|
29
|
+
* Opaque formatter output is appended unchanged, including empty output.
|
|
30
|
+
* @param message The original, unprefixed error message.
|
|
31
|
+
* @param options Theme, formatter, and physical-line layout options.
|
|
32
|
+
* @returns The prefixed message without an added trailing newline.
|
|
33
|
+
* @throws {TypeError} If initialWidth is not a finite integer.
|
|
34
|
+
* @throws {RangeError} If initialWidth is negative or a theme color is invalid.
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
function renderErrorMessage(message, options = {}) {
|
|
38
|
+
const occupied = options.initialWidth ?? 0;
|
|
39
|
+
if (!Number.isFinite(occupied) || !Number.isInteger(occupied)) throw new TypeError("Initial width must be a finite integer.");
|
|
40
|
+
if (occupied < 0) throw new RangeError("Initial width must be nonnegative.");
|
|
41
|
+
const colors = options.colors;
|
|
42
|
+
const prefix = require_text_layout.placeText(require_text_layout.spaceAfterLabel(require_terminal_internal.renderTerminalTerm({
|
|
43
|
+
type: "errorLabel",
|
|
44
|
+
label: "Error:"
|
|
45
|
+
}, options.theme, typeof colors === "object" ? true : colors, void 0, void 0, typeof colors === "object" ? colors.resetSuffix : void 0)), {
|
|
46
|
+
line: "",
|
|
47
|
+
column: occupied
|
|
48
|
+
}, options.maxWidth);
|
|
49
|
+
const formatted = resolveMessageFormatter(options)(message, {
|
|
50
|
+
colors,
|
|
51
|
+
quotes: options.quotes,
|
|
52
|
+
maxWidth: options.maxWidth,
|
|
53
|
+
initialWidth: prefix.cursor.column
|
|
54
|
+
});
|
|
55
|
+
return prefix.text + formatted;
|
|
56
|
+
}
|
|
24
57
|
|
|
25
58
|
//#endregion
|
|
59
|
+
exports.renderErrorMessage = renderErrorMessage;
|
|
26
60
|
exports.resolveMessageFormatter = resolveMessageFormatter;
|
|
@@ -15,5 +15,20 @@ declare function resolveMessageFormatter(options: {
|
|
|
15
15
|
readonly messageFormatter?: MessageFormatter;
|
|
16
16
|
readonly theme?: TerminalTheme;
|
|
17
17
|
}): (message: Message, options?: MessageFormatOptions, ambient?: TerminalStyle) => string;
|
|
18
|
+
/**
|
|
19
|
+
* Assembles a themed error prefix and a message at one layout boundary.
|
|
20
|
+
* Callers own streams, trailing newlines, and the default quoting policy.
|
|
21
|
+
* Opaque formatter output is appended unchanged, including empty output.
|
|
22
|
+
* @param message The original, unprefixed error message.
|
|
23
|
+
* @param options Theme, formatter, and physical-line layout options.
|
|
24
|
+
* @returns The prefixed message without an added trailing newline.
|
|
25
|
+
* @throws {TypeError} If initialWidth is not a finite integer.
|
|
26
|
+
* @throws {RangeError} If initialWidth is negative or a theme color is invalid.
|
|
27
|
+
* @internal
|
|
28
|
+
*/
|
|
29
|
+
declare function renderErrorMessage(message: Message, options?: MessageFormatOptions & {
|
|
30
|
+
readonly theme?: TerminalTheme;
|
|
31
|
+
readonly messageFormatter?: MessageFormatter;
|
|
32
|
+
}): string;
|
|
18
33
|
//#endregion
|
|
19
|
-
export { resolveMessageFormatter };
|
|
34
|
+
export { renderErrorMessage, resolveMessageFormatter };
|
|
@@ -15,5 +15,20 @@ declare function resolveMessageFormatter(options: {
|
|
|
15
15
|
readonly messageFormatter?: MessageFormatter;
|
|
16
16
|
readonly theme?: TerminalTheme;
|
|
17
17
|
}): (message: Message, options?: MessageFormatOptions, ambient?: TerminalStyle) => string;
|
|
18
|
+
/**
|
|
19
|
+
* Assembles a themed error prefix and a message at one layout boundary.
|
|
20
|
+
* Callers own streams, trailing newlines, and the default quoting policy.
|
|
21
|
+
* Opaque formatter output is appended unchanged, including empty output.
|
|
22
|
+
* @param message The original, unprefixed error message.
|
|
23
|
+
* @param options Theme, formatter, and physical-line layout options.
|
|
24
|
+
* @returns The prefixed message without an added trailing newline.
|
|
25
|
+
* @throws {TypeError} If initialWidth is not a finite integer.
|
|
26
|
+
* @throws {RangeError} If initialWidth is negative or a theme color is invalid.
|
|
27
|
+
* @internal
|
|
28
|
+
*/
|
|
29
|
+
declare function renderErrorMessage(message: Message, options?: MessageFormatOptions & {
|
|
30
|
+
readonly theme?: TerminalTheme;
|
|
31
|
+
readonly messageFormatter?: MessageFormatter;
|
|
32
|
+
}): string;
|
|
18
33
|
//#endregion
|
|
19
|
-
export { resolveMessageFormatter };
|
|
34
|
+
export { renderErrorMessage, resolveMessageFormatter };
|
package/dist/message-renderer.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { messageRenderers } from "./message-registry.js";
|
|
2
|
+
import { renderTerminalTerm } from "./terminal-internal.js";
|
|
3
|
+
import { placeText, spaceAfterLabel } from "./text-layout.js";
|
|
2
4
|
import { createMessageFormatter, formatMessage } from "./message.js";
|
|
3
5
|
|
|
4
6
|
//#region src/message-renderer.ts
|
|
@@ -21,6 +23,37 @@ function resolveMessageFormatter(options) {
|
|
|
21
23
|
});
|
|
22
24
|
};
|
|
23
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Assembles a themed error prefix and a message at one layout boundary.
|
|
28
|
+
* Callers own streams, trailing newlines, and the default quoting policy.
|
|
29
|
+
* Opaque formatter output is appended unchanged, including empty output.
|
|
30
|
+
* @param message The original, unprefixed error message.
|
|
31
|
+
* @param options Theme, formatter, and physical-line layout options.
|
|
32
|
+
* @returns The prefixed message without an added trailing newline.
|
|
33
|
+
* @throws {TypeError} If initialWidth is not a finite integer.
|
|
34
|
+
* @throws {RangeError} If initialWidth is negative or a theme color is invalid.
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
function renderErrorMessage(message, options = {}) {
|
|
38
|
+
const occupied = options.initialWidth ?? 0;
|
|
39
|
+
if (!Number.isFinite(occupied) || !Number.isInteger(occupied)) throw new TypeError("Initial width must be a finite integer.");
|
|
40
|
+
if (occupied < 0) throw new RangeError("Initial width must be nonnegative.");
|
|
41
|
+
const colors = options.colors;
|
|
42
|
+
const prefix = placeText(spaceAfterLabel(renderTerminalTerm({
|
|
43
|
+
type: "errorLabel",
|
|
44
|
+
label: "Error:"
|
|
45
|
+
}, options.theme, typeof colors === "object" ? true : colors, void 0, void 0, typeof colors === "object" ? colors.resetSuffix : void 0)), {
|
|
46
|
+
line: "",
|
|
47
|
+
column: occupied
|
|
48
|
+
}, options.maxWidth);
|
|
49
|
+
const formatted = resolveMessageFormatter(options)(message, {
|
|
50
|
+
colors,
|
|
51
|
+
quotes: options.quotes,
|
|
52
|
+
maxWidth: options.maxWidth,
|
|
53
|
+
initialWidth: prefix.cursor.column
|
|
54
|
+
});
|
|
55
|
+
return prefix.text + formatted;
|
|
56
|
+
}
|
|
24
57
|
|
|
25
58
|
//#endregion
|
|
26
|
-
export { resolveMessageFormatter };
|
|
59
|
+
export { renderErrorMessage, resolveMessageFormatter };
|
|
@@ -17,11 +17,29 @@ function valuesFormatter(theme) {
|
|
|
17
17
|
children: [require_terminal.defaultTerminalTheme.values(term, context)]
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
|
+
/** Default callback identity survives any number of per-pass caches. */
|
|
21
|
+
const defaultFormatters = new WeakSet(Object.values(require_terminal.defaultTerminalTheme).filter((value) => typeof value === "function"));
|
|
20
22
|
function formatTerminalTerm(term, theme = {}, quotes = false, usage) {
|
|
23
|
+
return formatTerminalLeaf(term, theme, quotes, usage).fragment;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Renders a semantic leaf and records the selected callback's provenance.
|
|
27
|
+
* @param term The semantic leaf to render.
|
|
28
|
+
* @param theme The optional role overrides.
|
|
29
|
+
* @param quotes Whether values should use their quoted representation.
|
|
30
|
+
* @param usage The leaf's position within a usage expression.
|
|
31
|
+
* @returns The fragment and whether its callback has default origin.
|
|
32
|
+
* @throws {TypeError} If the term is invalid or is a message-level hard break.
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
function formatTerminalLeaf(term, theme = {}, quotes = false, usage) {
|
|
21
36
|
const quote = (s) => quotes ? `\`${s}\`` : s;
|
|
22
37
|
let text;
|
|
23
38
|
switch (term.type) {
|
|
24
|
-
case "text": return
|
|
39
|
+
case "text": return {
|
|
40
|
+
fragment: terminalText(term.text),
|
|
41
|
+
defaultOrigin: true
|
|
42
|
+
};
|
|
25
43
|
case "lineBreak": throw new TypeError("Hard breaks must be rendered at the message level.");
|
|
26
44
|
case "optionName":
|
|
27
45
|
text = quote(term.optionName);
|
|
@@ -65,19 +83,25 @@ function formatTerminalTerm(term, theme = {}, quotes = false, usage) {
|
|
|
65
83
|
usage,
|
|
66
84
|
format: (child) => formatTerminalTerm(child, theme, quotes, usage)
|
|
67
85
|
};
|
|
86
|
+
function render(formatter, value) {
|
|
87
|
+
return {
|
|
88
|
+
fragment: formatter(value, ctx),
|
|
89
|
+
defaultOrigin: defaultFormatters.has(formatter)
|
|
90
|
+
};
|
|
91
|
+
}
|
|
68
92
|
switch (term.type) {
|
|
69
|
-
case "optionName": return (theme.optionName ?? require_terminal.defaultTerminalTheme.optionName
|
|
70
|
-
case "optionNames": return (theme.optionNames ?? require_terminal.defaultTerminalTheme.optionNames
|
|
71
|
-
case "metavar": return (theme.metavar ?? require_terminal.defaultTerminalTheme.metavar
|
|
72
|
-
case "value": return (theme.value ?? require_terminal.defaultTerminalTheme.value
|
|
73
|
-
case "values": return valuesFormatter(theme)
|
|
74
|
-
case "envVar": return (theme.envVar ?? require_terminal.defaultTerminalTheme.envVar
|
|
75
|
-
case "commandLine": return (theme.commandLine ?? require_terminal.defaultTerminalTheme.commandLine
|
|
76
|
-
case "url": return (theme.url ?? require_terminal.defaultTerminalTheme.url
|
|
77
|
-
case "programName": return (theme.programName ?? require_terminal.defaultTerminalTheme.programName
|
|
78
|
-
case "label": return (theme.label ?? require_terminal.defaultTerminalTheme.label
|
|
79
|
-
case "syntaxPunctuation": return (theme.syntaxPunctuation ?? require_terminal.defaultTerminalTheme.syntaxPunctuation
|
|
80
|
-
case "errorLabel": return (theme.errorLabel ?? require_terminal.defaultTerminalTheme.errorLabel
|
|
93
|
+
case "optionName": return render(theme.optionName ?? require_terminal.defaultTerminalTheme.optionName, term);
|
|
94
|
+
case "optionNames": return render(theme.optionNames ?? require_terminal.defaultTerminalTheme.optionNames, term);
|
|
95
|
+
case "metavar": return render(theme.metavar ?? require_terminal.defaultTerminalTheme.metavar, term);
|
|
96
|
+
case "value": return render(theme.value ?? require_terminal.defaultTerminalTheme.value, term);
|
|
97
|
+
case "values": return render(valuesFormatter(theme), term);
|
|
98
|
+
case "envVar": return render(theme.envVar ?? require_terminal.defaultTerminalTheme.envVar, term);
|
|
99
|
+
case "commandLine": return render(theme.commandLine ?? require_terminal.defaultTerminalTheme.commandLine, term);
|
|
100
|
+
case "url": return render(theme.url ?? require_terminal.defaultTerminalTheme.url, term);
|
|
101
|
+
case "programName": return render(theme.programName ?? require_terminal.defaultTerminalTheme.programName, term);
|
|
102
|
+
case "label": return render(theme.label ?? require_terminal.defaultTerminalTheme.label, term);
|
|
103
|
+
case "syntaxPunctuation": return render(theme.syntaxPunctuation ?? require_terminal.defaultTerminalTheme.syntaxPunctuation, term);
|
|
104
|
+
case "errorLabel": return render(theme.errorLabel ?? require_terminal.defaultTerminalTheme.errorLabel, term);
|
|
81
105
|
}
|
|
82
106
|
}
|
|
83
107
|
const colorNames = [
|
|
@@ -225,14 +249,14 @@ function serializeTokens(tokens, colors = false, resetSuffix = "", ambient = {})
|
|
|
225
249
|
* @since 1.3.0
|
|
226
250
|
* @internal
|
|
227
251
|
*/
|
|
228
|
-
function renderTerminalTerm(term, theme, colors, usage, ambient) {
|
|
229
|
-
return serializeTokens(fragmentTokens(formatTerminalTerm(term, theme, false, usage)), colors,
|
|
252
|
+
function renderTerminalTerm(term, theme, colors, usage, ambient, resetSuffix = "") {
|
|
253
|
+
return serializeTokens(fragmentTokens(formatTerminalTerm(term, theme, false, usage)), colors, resetSuffix, ambient);
|
|
230
254
|
}
|
|
231
255
|
/** Memoizes semantic leaves for one layout pass, including measurement. */
|
|
232
256
|
function cacheTerminalTheme(theme = {}) {
|
|
233
257
|
function cache(formatter) {
|
|
234
258
|
const fragments = /* @__PURE__ */ new Map();
|
|
235
|
-
|
|
259
|
+
const cached = (term, context) => {
|
|
236
260
|
const key = JSON.stringify([
|
|
237
261
|
term,
|
|
238
262
|
context.quotes,
|
|
@@ -245,6 +269,8 @@ function cacheTerminalTheme(theme = {}) {
|
|
|
245
269
|
}
|
|
246
270
|
return fragment;
|
|
247
271
|
};
|
|
272
|
+
if (defaultFormatters.has(formatter)) defaultFormatters.add(cached);
|
|
273
|
+
return cached;
|
|
248
274
|
}
|
|
249
275
|
return {
|
|
250
276
|
optionName: cache(theme.optionName ?? require_terminal.defaultTerminalTheme.optionName),
|
|
@@ -268,6 +294,7 @@ function cacheTerminalTheme(theme = {}) {
|
|
|
268
294
|
|
|
269
295
|
//#endregion
|
|
270
296
|
exports.cacheTerminalTheme = cacheTerminalTheme;
|
|
297
|
+
exports.formatTerminalLeaf = formatTerminalLeaf;
|
|
271
298
|
exports.formatTerminalTerm = formatTerminalTerm;
|
|
272
299
|
exports.fragmentTokens = fragmentTokens;
|
|
273
300
|
exports.renderTerminalTerm = renderTerminalTerm;
|
|
@@ -12,9 +12,27 @@ interface TerminalToken {
|
|
|
12
12
|
readonly scopes: readonly Scope[];
|
|
13
13
|
/** Layout-owned space, removable beside an explicit hard break. */
|
|
14
14
|
readonly separator?: boolean;
|
|
15
|
+
/** The historical program separator wraps before its following atom. */
|
|
16
|
+
readonly programBoundary?: boolean;
|
|
17
|
+
/** Enables only the legacy default formatter whitespace behavior. */
|
|
18
|
+
readonly legacyWhitespace?: boolean;
|
|
15
19
|
}
|
|
16
20
|
declare function terminalText(text: string): TerminalFragment;
|
|
17
21
|
declare function formatTerminalTerm(term: TerminalTerm, theme?: TerminalTheme, quotes?: boolean, usage?: TerminalFormatContext["usage"]): TerminalFragment;
|
|
22
|
+
/**
|
|
23
|
+
* Renders a semantic leaf and records the selected callback's provenance.
|
|
24
|
+
* @param term The semantic leaf to render.
|
|
25
|
+
* @param theme The optional role overrides.
|
|
26
|
+
* @param quotes Whether values should use their quoted representation.
|
|
27
|
+
* @param usage The leaf's position within a usage expression.
|
|
28
|
+
* @returns The fragment and whether its callback has default origin.
|
|
29
|
+
* @throws {TypeError} If the term is invalid or is a message-level hard break.
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
declare function formatTerminalLeaf(term: TerminalTerm, theme?: TerminalTheme, quotes?: boolean, usage?: TerminalFormatContext["usage"]): {
|
|
33
|
+
readonly fragment: TerminalFragment;
|
|
34
|
+
readonly defaultOrigin: boolean;
|
|
35
|
+
};
|
|
18
36
|
declare function styleCode(style: TerminalStyle): string;
|
|
19
37
|
declare function fragmentTokens(fragment: TerminalFragment, scopes?: readonly Scope[], inherited?: TerminalStyle): Generator<TerminalToken>;
|
|
20
38
|
declare function serializeTokens(tokens: Iterable<TerminalToken>, colors?: boolean, resetSuffix?: string, ambient?: TerminalStyle): string;
|
|
@@ -31,8 +49,8 @@ declare function serializeTokens(tokens: Iterable<TerminalToken>, colors?: boole
|
|
|
31
49
|
* @since 1.3.0
|
|
32
50
|
* @internal
|
|
33
51
|
*/
|
|
34
|
-
declare function renderTerminalTerm(term: TerminalTerm, theme?: TerminalTheme, colors?: boolean, usage?: TerminalFormatContext["usage"], ambient?: TerminalStyle): string;
|
|
52
|
+
declare function renderTerminalTerm(term: TerminalTerm, theme?: TerminalTheme, colors?: boolean, usage?: TerminalFormatContext["usage"], ambient?: TerminalStyle, resetSuffix?: string): string;
|
|
35
53
|
/** Memoizes semantic leaves for one layout pass, including measurement. */
|
|
36
54
|
declare function cacheTerminalTheme(theme?: TerminalTheme): TerminalTheme;
|
|
37
55
|
//#endregion
|
|
38
|
-
export { Scope, TerminalToken, cacheTerminalTheme, formatTerminalTerm, fragmentTokens, renderTerminalTerm, serializeTokens, styleCode, terminalText };
|
|
56
|
+
export { Scope, TerminalToken, cacheTerminalTheme, formatTerminalLeaf, formatTerminalTerm, fragmentTokens, renderTerminalTerm, serializeTokens, styleCode, terminalText };
|
|
@@ -12,9 +12,27 @@ interface TerminalToken {
|
|
|
12
12
|
readonly scopes: readonly Scope[];
|
|
13
13
|
/** Layout-owned space, removable beside an explicit hard break. */
|
|
14
14
|
readonly separator?: boolean;
|
|
15
|
+
/** The historical program separator wraps before its following atom. */
|
|
16
|
+
readonly programBoundary?: boolean;
|
|
17
|
+
/** Enables only the legacy default formatter whitespace behavior. */
|
|
18
|
+
readonly legacyWhitespace?: boolean;
|
|
15
19
|
}
|
|
16
20
|
declare function terminalText(text: string): TerminalFragment;
|
|
17
21
|
declare function formatTerminalTerm(term: TerminalTerm, theme?: TerminalTheme, quotes?: boolean, usage?: TerminalFormatContext["usage"]): TerminalFragment;
|
|
22
|
+
/**
|
|
23
|
+
* Renders a semantic leaf and records the selected callback's provenance.
|
|
24
|
+
* @param term The semantic leaf to render.
|
|
25
|
+
* @param theme The optional role overrides.
|
|
26
|
+
* @param quotes Whether values should use their quoted representation.
|
|
27
|
+
* @param usage The leaf's position within a usage expression.
|
|
28
|
+
* @returns The fragment and whether its callback has default origin.
|
|
29
|
+
* @throws {TypeError} If the term is invalid or is a message-level hard break.
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
declare function formatTerminalLeaf(term: TerminalTerm, theme?: TerminalTheme, quotes?: boolean, usage?: TerminalFormatContext["usage"]): {
|
|
33
|
+
readonly fragment: TerminalFragment;
|
|
34
|
+
readonly defaultOrigin: boolean;
|
|
35
|
+
};
|
|
18
36
|
declare function styleCode(style: TerminalStyle): string;
|
|
19
37
|
declare function fragmentTokens(fragment: TerminalFragment, scopes?: readonly Scope[], inherited?: TerminalStyle): Generator<TerminalToken>;
|
|
20
38
|
declare function serializeTokens(tokens: Iterable<TerminalToken>, colors?: boolean, resetSuffix?: string, ambient?: TerminalStyle): string;
|
|
@@ -31,8 +49,8 @@ declare function serializeTokens(tokens: Iterable<TerminalToken>, colors?: boole
|
|
|
31
49
|
* @since 1.3.0
|
|
32
50
|
* @internal
|
|
33
51
|
*/
|
|
34
|
-
declare function renderTerminalTerm(term: TerminalTerm, theme?: TerminalTheme, colors?: boolean, usage?: TerminalFormatContext["usage"], ambient?: TerminalStyle): string;
|
|
52
|
+
declare function renderTerminalTerm(term: TerminalTerm, theme?: TerminalTheme, colors?: boolean, usage?: TerminalFormatContext["usage"], ambient?: TerminalStyle, resetSuffix?: string): string;
|
|
35
53
|
/** Memoizes semantic leaves for one layout pass, including measurement. */
|
|
36
54
|
declare function cacheTerminalTheme(theme?: TerminalTheme): TerminalTheme;
|
|
37
55
|
//#endregion
|
|
38
|
-
export { Scope, TerminalToken, cacheTerminalTheme, formatTerminalTerm, fragmentTokens, renderTerminalTerm, serializeTokens, styleCode, terminalText };
|
|
56
|
+
export { Scope, TerminalToken, cacheTerminalTheme, formatTerminalLeaf, formatTerminalTerm, fragmentTokens, renderTerminalTerm, serializeTokens, styleCode, terminalText };
|
|
@@ -17,11 +17,29 @@ function valuesFormatter(theme) {
|
|
|
17
17
|
children: [defaultTerminalTheme.values(term, context)]
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
|
+
/** Default callback identity survives any number of per-pass caches. */
|
|
21
|
+
const defaultFormatters = new WeakSet(Object.values(defaultTerminalTheme).filter((value) => typeof value === "function"));
|
|
20
22
|
function formatTerminalTerm(term, theme = {}, quotes = false, usage) {
|
|
23
|
+
return formatTerminalLeaf(term, theme, quotes, usage).fragment;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Renders a semantic leaf and records the selected callback's provenance.
|
|
27
|
+
* @param term The semantic leaf to render.
|
|
28
|
+
* @param theme The optional role overrides.
|
|
29
|
+
* @param quotes Whether values should use their quoted representation.
|
|
30
|
+
* @param usage The leaf's position within a usage expression.
|
|
31
|
+
* @returns The fragment and whether its callback has default origin.
|
|
32
|
+
* @throws {TypeError} If the term is invalid or is a message-level hard break.
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
function formatTerminalLeaf(term, theme = {}, quotes = false, usage) {
|
|
21
36
|
const quote = (s) => quotes ? `\`${s}\`` : s;
|
|
22
37
|
let text;
|
|
23
38
|
switch (term.type) {
|
|
24
|
-
case "text": return
|
|
39
|
+
case "text": return {
|
|
40
|
+
fragment: terminalText(term.text),
|
|
41
|
+
defaultOrigin: true
|
|
42
|
+
};
|
|
25
43
|
case "lineBreak": throw new TypeError("Hard breaks must be rendered at the message level.");
|
|
26
44
|
case "optionName":
|
|
27
45
|
text = quote(term.optionName);
|
|
@@ -65,19 +83,25 @@ function formatTerminalTerm(term, theme = {}, quotes = false, usage) {
|
|
|
65
83
|
usage,
|
|
66
84
|
format: (child) => formatTerminalTerm(child, theme, quotes, usage)
|
|
67
85
|
};
|
|
86
|
+
function render(formatter, value) {
|
|
87
|
+
return {
|
|
88
|
+
fragment: formatter(value, ctx),
|
|
89
|
+
defaultOrigin: defaultFormatters.has(formatter)
|
|
90
|
+
};
|
|
91
|
+
}
|
|
68
92
|
switch (term.type) {
|
|
69
|
-
case "optionName": return (theme.optionName ?? defaultTerminalTheme.optionName
|
|
70
|
-
case "optionNames": return (theme.optionNames ?? defaultTerminalTheme.optionNames
|
|
71
|
-
case "metavar": return (theme.metavar ?? defaultTerminalTheme.metavar
|
|
72
|
-
case "value": return (theme.value ?? defaultTerminalTheme.value
|
|
73
|
-
case "values": return valuesFormatter(theme)
|
|
74
|
-
case "envVar": return (theme.envVar ?? defaultTerminalTheme.envVar
|
|
75
|
-
case "commandLine": return (theme.commandLine ?? defaultTerminalTheme.commandLine
|
|
76
|
-
case "url": return (theme.url ?? defaultTerminalTheme.url
|
|
77
|
-
case "programName": return (theme.programName ?? defaultTerminalTheme.programName
|
|
78
|
-
case "label": return (theme.label ?? defaultTerminalTheme.label
|
|
79
|
-
case "syntaxPunctuation": return (theme.syntaxPunctuation ?? defaultTerminalTheme.syntaxPunctuation
|
|
80
|
-
case "errorLabel": return (theme.errorLabel ?? defaultTerminalTheme.errorLabel
|
|
93
|
+
case "optionName": return render(theme.optionName ?? defaultTerminalTheme.optionName, term);
|
|
94
|
+
case "optionNames": return render(theme.optionNames ?? defaultTerminalTheme.optionNames, term);
|
|
95
|
+
case "metavar": return render(theme.metavar ?? defaultTerminalTheme.metavar, term);
|
|
96
|
+
case "value": return render(theme.value ?? defaultTerminalTheme.value, term);
|
|
97
|
+
case "values": return render(valuesFormatter(theme), term);
|
|
98
|
+
case "envVar": return render(theme.envVar ?? defaultTerminalTheme.envVar, term);
|
|
99
|
+
case "commandLine": return render(theme.commandLine ?? defaultTerminalTheme.commandLine, term);
|
|
100
|
+
case "url": return render(theme.url ?? defaultTerminalTheme.url, term);
|
|
101
|
+
case "programName": return render(theme.programName ?? defaultTerminalTheme.programName, term);
|
|
102
|
+
case "label": return render(theme.label ?? defaultTerminalTheme.label, term);
|
|
103
|
+
case "syntaxPunctuation": return render(theme.syntaxPunctuation ?? defaultTerminalTheme.syntaxPunctuation, term);
|
|
104
|
+
case "errorLabel": return render(theme.errorLabel ?? defaultTerminalTheme.errorLabel, term);
|
|
81
105
|
}
|
|
82
106
|
}
|
|
83
107
|
const colorNames = [
|
|
@@ -225,14 +249,14 @@ function serializeTokens(tokens, colors = false, resetSuffix = "", ambient = {})
|
|
|
225
249
|
* @since 1.3.0
|
|
226
250
|
* @internal
|
|
227
251
|
*/
|
|
228
|
-
function renderTerminalTerm(term, theme, colors, usage, ambient) {
|
|
229
|
-
return serializeTokens(fragmentTokens(formatTerminalTerm(term, theme, false, usage)), colors,
|
|
252
|
+
function renderTerminalTerm(term, theme, colors, usage, ambient, resetSuffix = "") {
|
|
253
|
+
return serializeTokens(fragmentTokens(formatTerminalTerm(term, theme, false, usage)), colors, resetSuffix, ambient);
|
|
230
254
|
}
|
|
231
255
|
/** Memoizes semantic leaves for one layout pass, including measurement. */
|
|
232
256
|
function cacheTerminalTheme(theme = {}) {
|
|
233
257
|
function cache(formatter) {
|
|
234
258
|
const fragments = /* @__PURE__ */ new Map();
|
|
235
|
-
|
|
259
|
+
const cached = (term, context) => {
|
|
236
260
|
const key = JSON.stringify([
|
|
237
261
|
term,
|
|
238
262
|
context.quotes,
|
|
@@ -245,6 +269,8 @@ function cacheTerminalTheme(theme = {}) {
|
|
|
245
269
|
}
|
|
246
270
|
return fragment;
|
|
247
271
|
};
|
|
272
|
+
if (defaultFormatters.has(formatter)) defaultFormatters.add(cached);
|
|
273
|
+
return cached;
|
|
248
274
|
}
|
|
249
275
|
return {
|
|
250
276
|
optionName: cache(theme.optionName ?? defaultTerminalTheme.optionName),
|
|
@@ -267,4 +293,4 @@ function cacheTerminalTheme(theme = {}) {
|
|
|
267
293
|
}
|
|
268
294
|
|
|
269
295
|
//#endregion
|
|
270
|
-
export { cacheTerminalTheme, formatTerminalTerm, fragmentTokens, renderTerminalTerm, serializeTokens, styleCode, terminalText };
|
|
296
|
+
export { cacheTerminalTheme, formatTerminalLeaf, formatTerminalTerm, fragmentTokens, renderTerminalTerm, serializeTokens, styleCode, terminalText };
|
package/dist/usage.cjs
CHANGED
|
@@ -196,34 +196,25 @@ function formatUsage(programName, usage, options = {}) {
|
|
|
196
196
|
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")))) {
|
|
197
197
|
const lines = [];
|
|
198
198
|
for (let command of lastTerm.terms) {
|
|
199
|
-
const firstTerm
|
|
200
|
-
if (firstTerm
|
|
199
|
+
const firstTerm = command[0];
|
|
200
|
+
if (firstTerm?.type === "command" && isUsageHidden(firstTerm.hidden)) continue;
|
|
201
201
|
if (usage.length > 1) command = [...usage.slice(0, -1), ...command];
|
|
202
202
|
lines.push(formatUsage(programName, command, options));
|
|
203
203
|
}
|
|
204
204
|
if (lines.length > 0) return lines.join("\n");
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
text: "\n",
|
|
219
|
-
width: -1,
|
|
220
|
-
scopes: []
|
|
221
|
-
} : {
|
|
222
|
-
text: " ",
|
|
223
|
-
width: 1,
|
|
224
|
-
scopes: []
|
|
225
|
-
};
|
|
226
|
-
return require_terminal_internal.serializeTokens([...programTokens, separator], options.colors) + wrapUsageTokens(terms, options, separator.width === -1 ? 0 : width + 1);
|
|
207
|
+
return wrapUsageTokens(function* () {
|
|
208
|
+
yield* usageLeafTokens({
|
|
209
|
+
type: "programName",
|
|
210
|
+
programName
|
|
211
|
+
}, options);
|
|
212
|
+
yield {
|
|
213
|
+
...usageSpace,
|
|
214
|
+
programBoundary: true
|
|
215
|
+
};
|
|
216
|
+
yield* formatUsageTerms(usage, options);
|
|
217
|
+
}(), options);
|
|
227
218
|
}
|
|
228
219
|
/**
|
|
229
220
|
* Normalizes a usage description by flattening nested exclusive terms,
|
|
@@ -453,15 +444,23 @@ function filterUsageForDisplay(usage, isHidden = isUsageHidden) {
|
|
|
453
444
|
}
|
|
454
445
|
return terms;
|
|
455
446
|
}
|
|
447
|
+
const usageSpace = {
|
|
448
|
+
text: " ",
|
|
449
|
+
width: 1,
|
|
450
|
+
scopes: [],
|
|
451
|
+
separator: true
|
|
452
|
+
};
|
|
453
|
+
function* usageLeafTokens(term, options, usage) {
|
|
454
|
+
const { fragment, defaultOrigin } = require_terminal_internal.formatTerminalLeaf(term, options.theme, false, usage);
|
|
455
|
+
for (const token of require_terminal_internal.fragmentTokens(fragment)) yield {
|
|
456
|
+
...token,
|
|
457
|
+
legacyWhitespace: defaultOrigin
|
|
458
|
+
};
|
|
459
|
+
}
|
|
456
460
|
function* formatUsageTerms(terms, options) {
|
|
457
461
|
let i = 0;
|
|
458
462
|
for (const t of terms) {
|
|
459
|
-
if (i > 0) yield
|
|
460
|
-
text: " ",
|
|
461
|
-
width: 1,
|
|
462
|
-
scopes: [],
|
|
463
|
-
separator: true
|
|
464
|
-
};
|
|
463
|
+
if (i > 0) yield usageSpace;
|
|
465
464
|
yield* formatUsageTermInternal(t, options);
|
|
466
465
|
i++;
|
|
467
466
|
}
|
|
@@ -487,8 +486,8 @@ function formatUsageTerm(term, options = {}) {
|
|
|
487
486
|
if (visibleTerms.length < 1) return "";
|
|
488
487
|
return wrapUsageTokens(formatUsageTermInternal(visibleTerms[0], options), options);
|
|
489
488
|
}
|
|
490
|
-
function wrapUsageTokens(input, options
|
|
491
|
-
return require_terminal_internal.serializeTokens(layoutUsageTokens(input, options
|
|
489
|
+
function wrapUsageTokens(input, options) {
|
|
490
|
+
return require_terminal_internal.serializeTokens(layoutUsageTokens(input, options), options.colors);
|
|
492
491
|
}
|
|
493
492
|
/** Keeps one layout-owned space between nonempty outputs on the same line. */
|
|
494
493
|
function* normalizeUsageSeparators(input) {
|
|
@@ -511,18 +510,33 @@ function* normalizeUsageSeparators(input) {
|
|
|
511
510
|
}
|
|
512
511
|
for (const item of pending) if (!item.separator) yield item;
|
|
513
512
|
}
|
|
514
|
-
function layoutUsageTokens(input, options
|
|
515
|
-
let lineWidth =
|
|
513
|
+
function layoutUsageTokens(input, options) {
|
|
514
|
+
let lineWidth = 0;
|
|
516
515
|
const output = [];
|
|
517
|
-
|
|
516
|
+
const tokens = [...normalizeUsageSeparators(input)];
|
|
517
|
+
for (const [index, token] of tokens.entries()) {
|
|
518
|
+
if (token.programBoundary && options.maxWidth != null) {
|
|
519
|
+
const next = tokens.find((item, i) => i > index && item.text !== "");
|
|
520
|
+
if (next != null && lineWidth + token.width + next.width > options.maxWidth) {
|
|
521
|
+
output.push({
|
|
522
|
+
text: "\n",
|
|
523
|
+
width: -1,
|
|
524
|
+
scopes: []
|
|
525
|
+
});
|
|
526
|
+
lineWidth = 0;
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
518
530
|
if (token.width === -1) {
|
|
519
531
|
output.push(token);
|
|
520
532
|
lineWidth = 0;
|
|
521
533
|
continue;
|
|
522
534
|
}
|
|
523
535
|
if (options.maxWidth != null && lineWidth > 0 && token.width > 0 && lineWidth + token.width > options.maxWidth) {
|
|
524
|
-
|
|
525
|
-
|
|
536
|
+
let lastIndex = output.length - 1;
|
|
537
|
+
while (lastIndex >= 0 && output[lastIndex].text === "") lastIndex--;
|
|
538
|
+
const last = output[lastIndex];
|
|
539
|
+
if (last?.text.endsWith(" ") && (last.separator || last.legacyWhitespace && (!options.colors || last.scopes.length === 0))) output[lastIndex] = {
|
|
526
540
|
...last,
|
|
527
541
|
text: last.text.slice(0, -1),
|
|
528
542
|
width: last.width - 1
|
|
@@ -533,7 +547,7 @@ function layoutUsageTokens(input, options, initialWidth = 0) {
|
|
|
533
547
|
scopes: []
|
|
534
548
|
});
|
|
535
549
|
lineWidth = 0;
|
|
536
|
-
if (token.text === " ") continue;
|
|
550
|
+
if (token.separator || token.legacyWhitespace && token.text === " ") continue;
|
|
537
551
|
}
|
|
538
552
|
output.push(token);
|
|
539
553
|
lineWidth += token.width;
|
|
@@ -542,7 +556,7 @@ function layoutUsageTokens(input, options, initialWidth = 0) {
|
|
|
542
556
|
}
|
|
543
557
|
function* formatUsageTermInternal(term, options) {
|
|
544
558
|
function leaf(t, usage) {
|
|
545
|
-
return
|
|
559
|
+
return usageLeafTokens(t, options, usage);
|
|
546
560
|
}
|
|
547
561
|
function punctuation(punctuation$1, kind) {
|
|
548
562
|
return leaf({
|
|
@@ -551,12 +565,7 @@ function* formatUsageTermInternal(term, options) {
|
|
|
551
565
|
kind
|
|
552
566
|
});
|
|
553
567
|
}
|
|
554
|
-
const space =
|
|
555
|
-
text: " ",
|
|
556
|
-
width: 1,
|
|
557
|
-
scopes: [],
|
|
558
|
-
separator: true
|
|
559
|
-
};
|
|
568
|
+
const space = usageSpace;
|
|
560
569
|
if (term.type === "argument") yield* leaf({
|
|
561
570
|
type: "metavar",
|
|
562
571
|
metavar: term.metavar
|
package/dist/usage.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getDisplayWidth } from "./displaywidth.js";
|
|
2
|
-
import { cacheTerminalTheme,
|
|
2
|
+
import { cacheTerminalTheme, formatTerminalLeaf, fragmentTokens, serializeTokens } from "./terminal-internal.js";
|
|
3
3
|
import { validateProgramName } from "./validate.js";
|
|
4
4
|
|
|
5
5
|
//#region src/usage.ts
|
|
@@ -196,34 +196,25 @@ function formatUsage(programName, usage, options = {}) {
|
|
|
196
196
|
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")))) {
|
|
197
197
|
const lines = [];
|
|
198
198
|
for (let command of lastTerm.terms) {
|
|
199
|
-
const firstTerm
|
|
200
|
-
if (firstTerm
|
|
199
|
+
const firstTerm = command[0];
|
|
200
|
+
if (firstTerm?.type === "command" && isUsageHidden(firstTerm.hidden)) continue;
|
|
201
201
|
if (usage.length > 1) command = [...usage.slice(0, -1), ...command];
|
|
202
202
|
lines.push(formatUsage(programName, command, options));
|
|
203
203
|
}
|
|
204
204
|
if (lines.length > 0) return lines.join("\n");
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
text: "\n",
|
|
219
|
-
width: -1,
|
|
220
|
-
scopes: []
|
|
221
|
-
} : {
|
|
222
|
-
text: " ",
|
|
223
|
-
width: 1,
|
|
224
|
-
scopes: []
|
|
225
|
-
};
|
|
226
|
-
return serializeTokens([...programTokens, separator], options.colors) + wrapUsageTokens(terms, options, separator.width === -1 ? 0 : width + 1);
|
|
207
|
+
return wrapUsageTokens(function* () {
|
|
208
|
+
yield* usageLeafTokens({
|
|
209
|
+
type: "programName",
|
|
210
|
+
programName
|
|
211
|
+
}, options);
|
|
212
|
+
yield {
|
|
213
|
+
...usageSpace,
|
|
214
|
+
programBoundary: true
|
|
215
|
+
};
|
|
216
|
+
yield* formatUsageTerms(usage, options);
|
|
217
|
+
}(), options);
|
|
227
218
|
}
|
|
228
219
|
/**
|
|
229
220
|
* Normalizes a usage description by flattening nested exclusive terms,
|
|
@@ -453,15 +444,23 @@ function filterUsageForDisplay(usage, isHidden = isUsageHidden) {
|
|
|
453
444
|
}
|
|
454
445
|
return terms;
|
|
455
446
|
}
|
|
447
|
+
const usageSpace = {
|
|
448
|
+
text: " ",
|
|
449
|
+
width: 1,
|
|
450
|
+
scopes: [],
|
|
451
|
+
separator: true
|
|
452
|
+
};
|
|
453
|
+
function* usageLeafTokens(term, options, usage) {
|
|
454
|
+
const { fragment, defaultOrigin } = formatTerminalLeaf(term, options.theme, false, usage);
|
|
455
|
+
for (const token of fragmentTokens(fragment)) yield {
|
|
456
|
+
...token,
|
|
457
|
+
legacyWhitespace: defaultOrigin
|
|
458
|
+
};
|
|
459
|
+
}
|
|
456
460
|
function* formatUsageTerms(terms, options) {
|
|
457
461
|
let i = 0;
|
|
458
462
|
for (const t of terms) {
|
|
459
|
-
if (i > 0) yield
|
|
460
|
-
text: " ",
|
|
461
|
-
width: 1,
|
|
462
|
-
scopes: [],
|
|
463
|
-
separator: true
|
|
464
|
-
};
|
|
463
|
+
if (i > 0) yield usageSpace;
|
|
465
464
|
yield* formatUsageTermInternal(t, options);
|
|
466
465
|
i++;
|
|
467
466
|
}
|
|
@@ -487,8 +486,8 @@ function formatUsageTerm(term, options = {}) {
|
|
|
487
486
|
if (visibleTerms.length < 1) return "";
|
|
488
487
|
return wrapUsageTokens(formatUsageTermInternal(visibleTerms[0], options), options);
|
|
489
488
|
}
|
|
490
|
-
function wrapUsageTokens(input, options
|
|
491
|
-
return serializeTokens(layoutUsageTokens(input, options
|
|
489
|
+
function wrapUsageTokens(input, options) {
|
|
490
|
+
return serializeTokens(layoutUsageTokens(input, options), options.colors);
|
|
492
491
|
}
|
|
493
492
|
/** Keeps one layout-owned space between nonempty outputs on the same line. */
|
|
494
493
|
function* normalizeUsageSeparators(input) {
|
|
@@ -511,18 +510,33 @@ function* normalizeUsageSeparators(input) {
|
|
|
511
510
|
}
|
|
512
511
|
for (const item of pending) if (!item.separator) yield item;
|
|
513
512
|
}
|
|
514
|
-
function layoutUsageTokens(input, options
|
|
515
|
-
let lineWidth =
|
|
513
|
+
function layoutUsageTokens(input, options) {
|
|
514
|
+
let lineWidth = 0;
|
|
516
515
|
const output = [];
|
|
517
|
-
|
|
516
|
+
const tokens = [...normalizeUsageSeparators(input)];
|
|
517
|
+
for (const [index, token] of tokens.entries()) {
|
|
518
|
+
if (token.programBoundary && options.maxWidth != null) {
|
|
519
|
+
const next = tokens.find((item, i) => i > index && item.text !== "");
|
|
520
|
+
if (next != null && lineWidth + token.width + next.width > options.maxWidth) {
|
|
521
|
+
output.push({
|
|
522
|
+
text: "\n",
|
|
523
|
+
width: -1,
|
|
524
|
+
scopes: []
|
|
525
|
+
});
|
|
526
|
+
lineWidth = 0;
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
518
530
|
if (token.width === -1) {
|
|
519
531
|
output.push(token);
|
|
520
532
|
lineWidth = 0;
|
|
521
533
|
continue;
|
|
522
534
|
}
|
|
523
535
|
if (options.maxWidth != null && lineWidth > 0 && token.width > 0 && lineWidth + token.width > options.maxWidth) {
|
|
524
|
-
|
|
525
|
-
|
|
536
|
+
let lastIndex = output.length - 1;
|
|
537
|
+
while (lastIndex >= 0 && output[lastIndex].text === "") lastIndex--;
|
|
538
|
+
const last = output[lastIndex];
|
|
539
|
+
if (last?.text.endsWith(" ") && (last.separator || last.legacyWhitespace && (!options.colors || last.scopes.length === 0))) output[lastIndex] = {
|
|
526
540
|
...last,
|
|
527
541
|
text: last.text.slice(0, -1),
|
|
528
542
|
width: last.width - 1
|
|
@@ -533,7 +547,7 @@ function layoutUsageTokens(input, options, initialWidth = 0) {
|
|
|
533
547
|
scopes: []
|
|
534
548
|
});
|
|
535
549
|
lineWidth = 0;
|
|
536
|
-
if (token.text === " ") continue;
|
|
550
|
+
if (token.separator || token.legacyWhitespace && token.text === " ") continue;
|
|
537
551
|
}
|
|
538
552
|
output.push(token);
|
|
539
553
|
lineWidth += token.width;
|
|
@@ -542,7 +556,7 @@ function layoutUsageTokens(input, options, initialWidth = 0) {
|
|
|
542
556
|
}
|
|
543
557
|
function* formatUsageTermInternal(term, options) {
|
|
544
558
|
function leaf(t, usage) {
|
|
545
|
-
return
|
|
559
|
+
return usageLeafTokens(t, options, usage);
|
|
546
560
|
}
|
|
547
561
|
function punctuation(punctuation$1, kind) {
|
|
548
562
|
return leaf({
|
|
@@ -551,12 +565,7 @@ function* formatUsageTermInternal(term, options) {
|
|
|
551
565
|
kind
|
|
552
566
|
});
|
|
553
567
|
}
|
|
554
|
-
const space =
|
|
555
|
-
text: " ",
|
|
556
|
-
width: 1,
|
|
557
|
-
scopes: [],
|
|
558
|
-
separator: true
|
|
559
|
-
};
|
|
568
|
+
const space = usageSpace;
|
|
560
569
|
if (term.type === "argument") yield* leaf({
|
|
561
570
|
type: "metavar",
|
|
562
571
|
metavar: term.metavar
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optique/core",
|
|
3
|
-
"version": "1.3.0-dev.
|
|
3
|
+
"version": "1.3.0-dev.2558",
|
|
4
4
|
"description": "Type-safe combinatorial command-line interface parser",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"CLI",
|
|
@@ -237,7 +237,7 @@
|
|
|
237
237
|
},
|
|
238
238
|
"sideEffects": false,
|
|
239
239
|
"devDependencies": {
|
|
240
|
-
"@optique/env": "1.3.0-dev.
|
|
240
|
+
"@optique/env": "1.3.0-dev.2558+85f681ee",
|
|
241
241
|
"@types/node": "^24.0.0",
|
|
242
242
|
"fast-check": "^4.7.0",
|
|
243
243
|
"tsdown": "^0.13.0",
|