summaryrefslogtreecommitdiff
path: root/cli/rt/02_console.js
diff options
context:
space:
mode:
Diffstat (limited to 'cli/rt/02_console.js')
-rw-r--r--cli/rt/02_console.js538
1 files changed, 438 insertions, 100 deletions
diff --git a/cli/rt/02_console.js b/cli/rt/02_console.js
index 00ecd3aac..b07ccf187 100644
--- a/cli/rt/02_console.js
+++ b/cli/rt/02_console.js
@@ -1,6 +1,7 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
((window) => {
+ const core = window.Deno.core;
const exposeForTest = window.__bootstrap.internals.exposeForTest;
const {
stripColor,
@@ -162,15 +163,6 @@
const LINE_BREAKING_LENGTH = 80;
const MIN_GROUP_LENGTH = 6;
const STR_ABBREVIATE_SIZE = 100;
- // Char codes
- const CHAR_PERCENT = 37; /* % */
- const CHAR_LOWERCASE_S = 115; /* s */
- const CHAR_LOWERCASE_D = 100; /* d */
- const CHAR_LOWERCASE_I = 105; /* i */
- const CHAR_LOWERCASE_F = 102; /* f */
- const CHAR_LOWERCASE_O = 111; /* o */
- const CHAR_UPPERCASE_O = 79; /* O */
- const CHAR_LOWERCASE_C = 99; /* c */
const PROMISE_STRING_BASE_LENGTH = 12;
@@ -401,7 +393,7 @@
level,
inspectOptions,
) {
- const proxyDetails = Deno.core.getProxyDetails(value);
+ const proxyDetails = core.getProxyDetails(value);
if (proxyDetails != null) {
return inspectOptions.showProxy
? inspectProxy(proxyDetails, ctx, level, inspectOptions)
@@ -639,7 +631,7 @@
level,
inspectOptions,
) {
- const [state, result] = Deno.core.getPromiseDetails(value);
+ const [state, result] = core.getPromiseDetails(value);
if (state === PromiseState.Pending) {
return `Promise { ${cyan("<pending>")} }`;
@@ -810,116 +802,459 @@
}
}
- function inspectArgs(
- args,
- inspectOptions = {},
- ) {
+ const colorKeywords = new Map([
+ ["black", "#000000"],
+ ["silver", "#c0c0c0"],
+ ["gray", "#808080"],
+ ["white", "#ffffff"],
+ ["maroon", "#800000"],
+ ["red", "#ff0000"],
+ ["purple", "#800080"],
+ ["fuchsia", "#ff00ff"],
+ ["green", "#008000"],
+ ["lime", "#00ff00"],
+ ["olive", "#808000"],
+ ["yellow", "#ffff00"],
+ ["navy", "#000080"],
+ ["blue", "#0000ff"],
+ ["teal", "#008080"],
+ ["aqua", "#00ffff"],
+ ["orange", "#ffa500"],
+ ["aliceblue", "#f0f8ff"],
+ ["antiquewhite", "#faebd7"],
+ ["aquamarine", "#7fffd4"],
+ ["azure", "#f0ffff"],
+ ["beige", "#f5f5dc"],
+ ["bisque", "#ffe4c4"],
+ ["blanchedalmond", "#ffebcd"],
+ ["blueviolet", "#8a2be2"],
+ ["brown", "#a52a2a"],
+ ["burlywood", "#deb887"],
+ ["cadetblue", "#5f9ea0"],
+ ["chartreuse", "#7fff00"],
+ ["chocolate", "#d2691e"],
+ ["coral", "#ff7f50"],
+ ["cornflowerblue", "#6495ed"],
+ ["cornsilk", "#fff8dc"],
+ ["crimson", "#dc143c"],
+ ["cyan", "#00ffff"],
+ ["darkblue", "#00008b"],
+ ["darkcyan", "#008b8b"],
+ ["darkgoldenrod", "#b8860b"],
+ ["darkgray", "#a9a9a9"],
+ ["darkgreen", "#006400"],
+ ["darkgrey", "#a9a9a9"],
+ ["darkkhaki", "#bdb76b"],
+ ["darkmagenta", "#8b008b"],
+ ["darkolivegreen", "#556b2f"],
+ ["darkorange", "#ff8c00"],
+ ["darkorchid", "#9932cc"],
+ ["darkred", "#8b0000"],
+ ["darksalmon", "#e9967a"],
+ ["darkseagreen", "#8fbc8f"],
+ ["darkslateblue", "#483d8b"],
+ ["darkslategray", "#2f4f4f"],
+ ["darkslategrey", "#2f4f4f"],
+ ["darkturquoise", "#00ced1"],
+ ["darkviolet", "#9400d3"],
+ ["deeppink", "#ff1493"],
+ ["deepskyblue", "#00bfff"],
+ ["dimgray", "#696969"],
+ ["dimgrey", "#696969"],
+ ["dodgerblue", "#1e90ff"],
+ ["firebrick", "#b22222"],
+ ["floralwhite", "#fffaf0"],
+ ["forestgreen", "#228b22"],
+ ["gainsboro", "#dcdcdc"],
+ ["ghostwhite", "#f8f8ff"],
+ ["gold", "#ffd700"],
+ ["goldenrod", "#daa520"],
+ ["greenyellow", "#adff2f"],
+ ["grey", "#808080"],
+ ["honeydew", "#f0fff0"],
+ ["hotpink", "#ff69b4"],
+ ["indianred", "#cd5c5c"],
+ ["indigo", "#4b0082"],
+ ["ivory", "#fffff0"],
+ ["khaki", "#f0e68c"],
+ ["lavender", "#e6e6fa"],
+ ["lavenderblush", "#fff0f5"],
+ ["lawngreen", "#7cfc00"],
+ ["lemonchiffon", "#fffacd"],
+ ["lightblue", "#add8e6"],
+ ["lightcoral", "#f08080"],
+ ["lightcyan", "#e0ffff"],
+ ["lightgoldenrodyellow", "#fafad2"],
+ ["lightgray", "#d3d3d3"],
+ ["lightgreen", "#90ee90"],
+ ["lightgrey", "#d3d3d3"],
+ ["lightpink", "#ffb6c1"],
+ ["lightsalmon", "#ffa07a"],
+ ["lightseagreen", "#20b2aa"],
+ ["lightskyblue", "#87cefa"],
+ ["lightslategray", "#778899"],
+ ["lightslategrey", "#778899"],
+ ["lightsteelblue", "#b0c4de"],
+ ["lightyellow", "#ffffe0"],
+ ["limegreen", "#32cd32"],
+ ["linen", "#faf0e6"],
+ ["magenta", "#ff00ff"],
+ ["mediumaquamarine", "#66cdaa"],
+ ["mediumblue", "#0000cd"],
+ ["mediumorchid", "#ba55d3"],
+ ["mediumpurple", "#9370db"],
+ ["mediumseagreen", "#3cb371"],
+ ["mediumslateblue", "#7b68ee"],
+ ["mediumspringgreen", "#00fa9a"],
+ ["mediumturquoise", "#48d1cc"],
+ ["mediumvioletred", "#c71585"],
+ ["midnightblue", "#191970"],
+ ["mintcream", "#f5fffa"],
+ ["mistyrose", "#ffe4e1"],
+ ["moccasin", "#ffe4b5"],
+ ["navajowhite", "#ffdead"],
+ ["oldlace", "#fdf5e6"],
+ ["olivedrab", "#6b8e23"],
+ ["orangered", "#ff4500"],
+ ["orchid", "#da70d6"],
+ ["palegoldenrod", "#eee8aa"],
+ ["palegreen", "#98fb98"],
+ ["paleturquoise", "#afeeee"],
+ ["palevioletred", "#db7093"],
+ ["papayawhip", "#ffefd5"],
+ ["peachpuff", "#ffdab9"],
+ ["peru", "#cd853f"],
+ ["pink", "#ffc0cb"],
+ ["plum", "#dda0dd"],
+ ["powderblue", "#b0e0e6"],
+ ["rosybrown", "#bc8f8f"],
+ ["royalblue", "#4169e1"],
+ ["saddlebrown", "#8b4513"],
+ ["salmon", "#fa8072"],
+ ["sandybrown", "#f4a460"],
+ ["seagreen", "#2e8b57"],
+ ["seashell", "#fff5ee"],
+ ["sienna", "#a0522d"],
+ ["skyblue", "#87ceeb"],
+ ["slateblue", "#6a5acd"],
+ ["slategray", "#708090"],
+ ["slategrey", "#708090"],
+ ["snow", "#fffafa"],
+ ["springgreen", "#00ff7f"],
+ ["steelblue", "#4682b4"],
+ ["tan", "#d2b48c"],
+ ["thistle", "#d8bfd8"],
+ ["tomato", "#ff6347"],
+ ["turquoise", "#40e0d0"],
+ ["violet", "#ee82ee"],
+ ["wheat", "#f5deb3"],
+ ["whitesmoke", "#f5f5f5"],
+ ["yellowgreen", "#9acd32"],
+ ["rebeccapurple", "#663399"],
+ ]);
+
+ function parseCssColor(colorString) {
+ if (colorKeywords.has(colorString)) {
+ colorString = colorKeywords.get(colorString);
+ }
+ // deno-fmt-ignore
+ const hashMatch = colorString.match(/^#([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})?$/);
+ if (hashMatch != null) {
+ return [
+ Number(`0x${hashMatch[1]}`),
+ Number(`0x${hashMatch[2]}`),
+ Number(`0x${hashMatch[3]}`),
+ ];
+ }
+ // deno-fmt-ignore
+ const smallHashMatch = colorString.match(/^#([\dA-Fa-f])([\dA-Fa-f])([\dA-Fa-f])([\dA-Fa-f])?$/);
+ if (smallHashMatch != null) {
+ return [
+ Number(`0x${smallHashMatch[1]}0`),
+ Number(`0x${smallHashMatch[2]}0`),
+ Number(`0x${smallHashMatch[3]}0`),
+ ];
+ }
+ // deno-fmt-ignore
+ const rgbMatch = colorString.match(/^rgba?\(\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)\s*(,\s*([+\-]?\d*\.?\d+)\s*)?\)$/);
+ if (rgbMatch != null) {
+ return [
+ Math.round(Math.max(0, Math.min(255, Number(rgbMatch[1])))),
+ Math.round(Math.max(0, Math.min(255, Number(rgbMatch[2])))),
+ Math.round(Math.max(0, Math.min(255, Number(rgbMatch[3])))),
+ ];
+ }
+ // deno-fmt-ignore
+ const hslMatch = colorString.match(/^hsla?\(\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)%\s*,\s*([+\-]?\d*\.?\d+)%\s*(,\s*([+\-]?\d*\.?\d+)\s*)?\)$/);
+ if (hslMatch != null) {
+ // https://www.rapidtables.com/convert/color/hsl-to-rgb.html
+ let h = Number(hslMatch[1]) % 360;
+ if (h < 0) {
+ h += 360;
+ }
+ const s = Math.max(0, Math.min(100, Number(hslMatch[2]))) / 100;
+ const l = Math.max(0, Math.min(100, Number(hslMatch[3]))) / 100;
+ const c = (1 - Math.abs(2 * l - 1)) * s;
+ const x = c * (1 - Math.abs((h / 60) % 2 - 1));
+ const m = l - c / 2;
+ let r_;
+ let g_;
+ let b_;
+ if (h < 60) {
+ [r_, g_, b_] = [c, x, 0];
+ } else if (h < 120) {
+ [r_, g_, b_] = [x, c, 0];
+ } else if (h < 180) {
+ [r_, g_, b_] = [0, c, x];
+ } else if (h < 240) {
+ [r_, g_, b_] = [0, x, c];
+ } else if (h < 300) {
+ [r_, g_, b_] = [x, 0, c];
+ } else {
+ [r_, g_, b_] = [c, 0, x];
+ }
+ return [
+ Math.round((r_ + m) * 255),
+ Math.round((g_ + m) * 255),
+ Math.round((b_ + m) * 255),
+ ];
+ }
+ return null;
+ }
+
+ function parseCss(cssString) {
+ const css = {
+ backgroundColor: null,
+ color: null,
+ fontWeight: null,
+ fontStyle: null,
+ textDecorationColor: null,
+ textDecorationLine: [],
+ };
+
+ const rawEntries = [];
+ let inValue = false;
+ let currentKey = null;
+ let parenthesesDepth = 0;
+ currentPart = "";
+ for (let i = 0; i < cssString.length; i++) {
+ const c = cssString[i];
+ if (c == "(") {
+ parenthesesDepth++;
+ } else if (parenthesesDepth > 0) {
+ if (c == ")") {
+ parenthesesDepth--;
+ }
+ } else if (inValue) {
+ if (c == ";") {
+ const value = currentPart.trim();
+ if (value != "") {
+ rawEntries.push([currentKey, value]);
+ }
+ currentKey = null;
+ currentPart = "";
+ inValue = false;
+ continue;
+ }
+ } else if (c == ":") {
+ currentKey = currentPart.trim();
+ currentPart = "";
+ inValue = true;
+ continue;
+ }
+ currentPart += c;
+ }
+ if (inValue && parenthesesDepth == 0) {
+ const value = currentPart.trim();
+ if (value != "") {
+ rawEntries.push([currentKey, value]);
+ }
+ currentKey = null;
+ currentPart = "";
+ }
+
+ for (const [key, value] of rawEntries) {
+ if (key == "background-color") {
+ const color = parseCssColor(value);
+ if (color != null) {
+ css.backgroundColor = color;
+ }
+ } else if (key == "color") {
+ const color = parseCssColor(value);
+ if (color != null) {
+ css.color = color;
+ }
+ } else if (key == "font-weight") {
+ if (["normal", "bold"].includes(value)) {
+ css.fontWeight = value;
+ }
+ } else if (key == "font-style") {
+ if (["normal", "italic", "oblique", "oblique 14deg"].includes(value)) {
+ css.fontStyle = value;
+ }
+ } else if (key == "text-decoration-line") {
+ css.textDecorationLine = [];
+ for (const lineType of value.split(/\s+/g)) {
+ if (["line-through", "overline", "underline"].includes(lineType)) {
+ css.textDecorationLine.push(lineType);
+ }
+ }
+ } else if (key == "text-decoration-color") {
+ const color = parseCssColor(value);
+ if (color != null) {
+ css.textDecorationColor = color;
+ }
+ } else if (key == "text-decoration") {
+ css.textDecorationColor = null;
+ css.textDecorationLine = [];
+ for (const arg of value.split(/\s+/g)) {
+ const maybeColor = parseCssColor(arg);
+ if (maybeColor != null) {
+ css.textDecorationColor = maybeColor;
+ } else if (["line-through", "overline", "underline"].includes(arg)) {
+ css.textDecorationLine.push(arg);
+ }
+ }
+ }
+ }
+
+ return css;
+ }
+
+ function cssToAnsi(css) {
+ let ansi = "";
+ if (css.backgroundColor != null) {
+ const [r, g, b] = css.backgroundColor;
+ ansi += `\x1b[48;2;${r};${g};${b}m`;
+ } else {
+ ansi += "\x1b[49m";
+ }
+ if (css.color != null) {
+ const [r, g, b] = css.color;
+ ansi += `\x1b[38;2;${r};${g};${b}m`;
+ } else {
+ ansi += "\x1b[39m";
+ }
+ if (css.fontWeight == "bold") {
+ ansi += `\x1b[1m`;
+ } else {
+ ansi += "\x1b[22m";
+ }
+ if (["italic", "oblique"].includes(css.fontStyle)) {
+ ansi += `\x1b[3m`;
+ } else {
+ ansi += "\x1b[23m";
+ }
+ if (css.textDecorationColor != null) {
+ const [r, g, b] = css.textDecorationColor;
+ ansi += `\x1b[58;2;${r};${g};${b}m`;
+ } else {
+ ansi += "\x1b[59m";
+ }
+ if (css.textDecorationLine.includes("line-through")) {
+ ansi += "\x1b[9m";
+ } else {
+ ansi += "\x1b[29m";
+ }
+ if (css.textDecorationLine.includes("overline")) {
+ ansi += "\x1b[53m";
+ } else {
+ ansi += "\x1b[55m";
+ }
+ if (css.textDecorationLine.includes("underline")) {
+ ansi += "\x1b[4m";
+ } else {
+ ansi += "\x1b[24m";
+ }
+ return ansi;
+ }
+
+ function inspectArgs(args, inspectOptions = {}) {
+ const noColor = globalThis.Deno?.noColor ?? true;
const rInspectOptions = { ...DEFAULT_INSPECT_OPTIONS, ...inspectOptions };
const first = args[0];
let a = 0;
- let str = "";
- let join = "";
-
- if (typeof first === "string") {
- let tempStr;
- let lastPos = 0;
+ let string = "";
+ if (typeof first == "string" && args.length > 1) {
+ a++;
+ // Index of the first not-yet-appended character. Use this so we only
+ // have to append to `string` when a substitution occurs / at the end.
+ let appendedChars = 0;
+ let usedStyle = false;
for (let i = 0; i < first.length - 1; i++) {
- if (first.charCodeAt(i) === CHAR_PERCENT) {
- const nextChar = first.charCodeAt(++i);
- if (a + 1 !== args.length) {
- switch (nextChar) {
- case CHAR_LOWERCASE_S:
- // format as a string
- tempStr = String(args[++a]);
- break;
- case CHAR_LOWERCASE_D:
- case CHAR_LOWERCASE_I:
- // format as an integer
- const tempInteger = args[++a];
- if (typeof tempInteger === "bigint") {
- tempStr = `${tempInteger}n`;
- } else if (typeof tempInteger === "symbol") {
- tempStr = "NaN";
- } else {
- tempStr = `${parseInt(String(tempInteger), 10)}`;
- }
- break;
- case CHAR_LOWERCASE_F:
- // format as a floating point value
- const tempFloat = args[++a];
- if (typeof tempFloat === "symbol") {
- tempStr = "NaN";
- } else {
- tempStr = `${parseFloat(String(tempFloat))}`;
- }
- break;
- case CHAR_LOWERCASE_O:
- case CHAR_UPPERCASE_O:
- // format as an object
- tempStr = inspectValue(
- args[++a],
- new Set(),
- 0,
- rInspectOptions,
- );
- break;
- case CHAR_PERCENT:
- str += first.slice(lastPos, i);
- lastPos = i + 1;
- continue;
- case CHAR_LOWERCASE_C:
- // TODO: applies CSS style rules to the output string as specified
- continue;
- default:
- // any other character is not a correct placeholder
- continue;
+ if (first[i] == "%") {
+ const char = first[++i];
+ if (a < args.length) {
+ let formattedArg = null;
+ if (char == "s") {
+ // Format as a string.
+ formattedArg = String(args[a++]);
+ } else if (["d", "i"].includes(char)) {
+ // Format as an integer.
+ const value = args[a++];
+ if (typeof value == "bigint") {
+ formattedArg = `${value}n`;
+ } else if (typeof value == "number") {
+ formattedArg = `${parseInt(String(value))}`;
+ } else {
+ formattedArg = "NaN";
+ }
+ } else if (char == "f") {
+ // Format as a floating point value.
+ const value = args[a++];
+ if (typeof value == "number") {
+ formattedArg = `${value}`;
+ } else {
+ formattedArg = "NaN";
+ }
+ } else if (["O", "o"].includes(char)) {
+ // Format as an object.
+ formattedArg = inspectValue(
+ args[a++],
+ new Set(),
+ 0,
+ rInspectOptions,
+ );
+ } else if (char == "c") {
+ const value = args[a++];
+ formattedArg = noColor ? "" : cssToAnsi(parseCss(value));
+ if (formattedArg != "") {
+ usedStyle = true;
+ }
}
- if (lastPos !== i - 1) {
- str += first.slice(lastPos, i - 1);
+ if (formattedArg != null) {
+ string += first.slice(appendedChars, i - 1) + formattedArg;
+ appendedChars = i + 1;
}
-
- str += tempStr;
- lastPos = i + 1;
- } else if (nextChar === CHAR_PERCENT) {
- str += first.slice(lastPos, i);
- lastPos = i + 1;
+ }
+ if (char == "%") {
+ string += first.slice(appendedChars, i - 1) + "%";
+ appendedChars = i + 1;
}
}
}
-
- if (lastPos !== 0) {
- a++;
- join = " ";
- if (lastPos < first.length) {
- str += first.slice(lastPos);
- }
+ string += first.slice(appendedChars);
+ if (usedStyle) {
+ string += "\x1b[0m";
}
}
- while (a < args.length) {
- const value = args[a];
- str += join;
- if (typeof value === "string") {
- str += value;
- } else {
- // use default maximum depth for null or undefined argument
- str += inspectValue(value, new Set(), 0, rInspectOptions);
+ for (; a < args.length; a++) {
+ if (a > 0) {
+ string += " ";
}
- join = " ";
- a++;
+ // Use default maximum depth for null or undefined arguments.
+ string += inspectValue(args[a], new Set(), 0, rInspectOptions);
}
if (rInspectOptions.indentLevel > 0) {
const groupIndent = DEFAULT_INDENT.repeat(rInspectOptions.indentLevel);
- if (str.indexOf("\n") !== -1) {
- str = str.replace(/\n/g, `\n${groupIndent}`);
- }
- str = groupIndent + str;
+ string = groupIndent + string.replaceAll("\n", `\n${groupIndent}`);
}
- return str;
+ return string;
}
const countMap = new Map();
@@ -1202,7 +1537,10 @@
// Expose these fields to internalObject for tests.
exposeForTest("Console", Console);
+ exposeForTest("cssToAnsi", cssToAnsi);
exposeForTest("inspectArgs", inspectArgs);
+ exposeForTest("parseCss", parseCss);
+ exposeForTest("parseCssColor", parseCssColor);
window.__bootstrap.console = {
CSI,