mirror of
https://github.com/denoland/deno.git
synced 2025-01-21 13:00:36 -05:00
feat(cli/console): Add Deno.InspectOptions::colors (#7742)
Ref: https://github.com/denoland/deno/pull/7516#pullrequestreview-489567120
This commit is contained in:
parent
2184cf5c07
commit
27ee4b2551
5 changed files with 89 additions and 55 deletions
14
cli/dts/lib.deno.ns.d.ts
vendored
14
cli/dts/lib.deno.ns.d.ts
vendored
|
@ -1941,19 +1941,21 @@ declare namespace Deno {
|
|||
export function run<T extends RunOptions = RunOptions>(opt: T): Process<T>;
|
||||
|
||||
export interface InspectOptions {
|
||||
/** Traversal depth for nested objects. Defaults to 4. */
|
||||
depth?: number;
|
||||
/** Sort Object, Set and Map entries by key. Defaults to false. */
|
||||
sorted?: boolean;
|
||||
/** Add a trailing comma for multiline collections. Defaults to false. */
|
||||
trailingComma?: boolean;
|
||||
/** Stylize output with ANSI colors. Defaults to false. */
|
||||
colors?: boolean;
|
||||
/** Try to fit more than one entry of a collection on the same line.
|
||||
* Defaults to true. */
|
||||
compact?: boolean;
|
||||
/** Traversal depth for nested objects. Defaults to 4. */
|
||||
depth?: number;
|
||||
/** The maximum number of iterable entries to print. Defaults to 100. */
|
||||
iterableLimit?: number;
|
||||
/** Show a Proxy's target and handler. Defaults to false. */
|
||||
showProxy?: boolean;
|
||||
/** Sort Object, Set and Map entries by key. Defaults to false. */
|
||||
sorted?: boolean;
|
||||
/** Add a trailing comma for multiline collections. Defaults to false. */
|
||||
trailingComma?: boolean;
|
||||
}
|
||||
|
||||
/** Converts the input into a string that has the same format as printed by
|
||||
|
|
|
@ -3,16 +3,7 @@
|
|||
((window) => {
|
||||
const core = window.Deno.core;
|
||||
const exposeForTest = window.__bootstrap.internals.exposeForTest;
|
||||
const {
|
||||
stripColor,
|
||||
yellow,
|
||||
dim,
|
||||
cyan,
|
||||
red,
|
||||
green,
|
||||
magenta,
|
||||
bold,
|
||||
} = window.__bootstrap.colors;
|
||||
const colors = window.__bootstrap.colors;
|
||||
|
||||
function isInvalidDate(x) {
|
||||
return isNaN(x.getTime());
|
||||
|
@ -88,7 +79,7 @@
|
|||
}
|
||||
|
||||
function getStringWidth(str) {
|
||||
str = stripColor(str).normalize("NFC");
|
||||
str = colors.stripColor(str).normalize("NFC");
|
||||
let width = 0;
|
||||
|
||||
for (const ch of str) {
|
||||
|
@ -165,6 +156,7 @@
|
|||
compact: true,
|
||||
iterableLimit: 100,
|
||||
showProxy: false,
|
||||
colors: false,
|
||||
};
|
||||
|
||||
const DEFAULT_INDENT = " "; // Default indent string
|
||||
|
@ -198,6 +190,10 @@
|
|||
return "";
|
||||
}
|
||||
|
||||
function maybeColor(fn, inspectOptions) {
|
||||
return inspectOptions.colors ? fn : (s) => s;
|
||||
}
|
||||
|
||||
function inspectFunction(value, _ctx) {
|
||||
if (customInspect in value && typeof value[customInspect] === "function") {
|
||||
try {
|
||||
|
@ -220,6 +216,7 @@
|
|||
options,
|
||||
inspectOptions,
|
||||
) {
|
||||
const cyan = maybeColor(colors.cyan, inspectOptions);
|
||||
if (level >= inspectOptions.depth) {
|
||||
return cyan(`[${options.typeName}]`);
|
||||
}
|
||||
|
@ -274,7 +271,7 @@
|
|||
} else {
|
||||
iContent = entries.length === 0 ? "" : ` ${entries.join(", ")} `;
|
||||
if (
|
||||
stripColor(iContent).length > LINE_BREAKING_LENGTH ||
|
||||
colors.stripColor(iContent).length > LINE_BREAKING_LENGTH ||
|
||||
!inspectOptions.compact
|
||||
) {
|
||||
iContent = `${initIndentation}${
|
||||
|
@ -309,7 +306,7 @@
|
|||
for (let i = 0; i < entriesLength; i++) {
|
||||
// Taking colors into account: removing the ANSI color
|
||||
// codes from the string before measuring its length
|
||||
const len = stripColor(entries[i]).length;
|
||||
const len = colors.stripColor(entries[i]).length;
|
||||
dataLen[i] = len;
|
||||
totalLength += len + separatorSpace;
|
||||
if (maxLength < len) maxLength = len;
|
||||
|
@ -414,6 +411,13 @@
|
|||
: inspectValue(proxyDetails[0], ctx, level, inspectOptions);
|
||||
}
|
||||
|
||||
const green = maybeColor(colors.green, inspectOptions);
|
||||
const yellow = maybeColor(colors.yellow, inspectOptions);
|
||||
const dim = maybeColor(colors.dim, inspectOptions);
|
||||
const cyan = maybeColor(colors.cyan, inspectOptions);
|
||||
const bold = maybeColor(colors.bold, inspectOptions);
|
||||
const red = maybeColor(colors.red, inspectOptions);
|
||||
|
||||
switch (typeof value) {
|
||||
case "string":
|
||||
return green(quoteString(value));
|
||||
|
@ -512,6 +516,7 @@
|
|||
level,
|
||||
inspectOptions,
|
||||
) {
|
||||
const green = maybeColor(colors.green, inspectOptions);
|
||||
switch (typeof value) {
|
||||
case "string":
|
||||
const trunc = value.length > STR_ABBREVIATE_SIZE
|
||||
|
@ -529,6 +534,7 @@
|
|||
level,
|
||||
inspectOptions,
|
||||
) {
|
||||
const dim = maybeColor(colors.dim, inspectOptions);
|
||||
const options = {
|
||||
typeName: "Array",
|
||||
displayName: "",
|
||||
|
@ -630,32 +636,39 @@
|
|||
);
|
||||
}
|
||||
|
||||
function inspectWeakSet() {
|
||||
function inspectWeakSet(inspectOptions) {
|
||||
const cyan = maybeColor(colors.cyan, inspectOptions);
|
||||
return `WeakSet { ${cyan("[items unknown]")} }`; // as seen in Node, with cyan color
|
||||
}
|
||||
|
||||
function inspectWeakMap() {
|
||||
function inspectWeakMap(inspectOptions) {
|
||||
const cyan = maybeColor(colors.cyan, inspectOptions);
|
||||
return `WeakMap { ${cyan("[items unknown]")} }`; // as seen in Node, with cyan color
|
||||
}
|
||||
|
||||
function inspectDate(value) {
|
||||
function inspectDate(value, inspectOptions) {
|
||||
// without quotes, ISO format, in magenta like before
|
||||
const magenta = maybeColor(colors.magenta, inspectOptions);
|
||||
return magenta(isInvalidDate(value) ? "Invalid Date" : value.toISOString());
|
||||
}
|
||||
|
||||
function inspectRegExp(value) {
|
||||
function inspectRegExp(value, inspectOptions) {
|
||||
const red = maybeColor(colors.red, inspectOptions);
|
||||
return red(value.toString()); // RegExps are red
|
||||
}
|
||||
|
||||
function inspectStringObject(value) {
|
||||
function inspectStringObject(value, inspectOptions) {
|
||||
const cyan = maybeColor(colors.cyan, inspectOptions);
|
||||
return cyan(`[String: "${value.toString()}"]`); // wrappers are in cyan
|
||||
}
|
||||
|
||||
function inspectBooleanObject(value) {
|
||||
function inspectBooleanObject(value, inspectOptions) {
|
||||
const cyan = maybeColor(colors.cyan, inspectOptions);
|
||||
return cyan(`[Boolean: ${value.toString()}]`); // wrappers are in cyan
|
||||
}
|
||||
|
||||
function inspectNumberObject(value) {
|
||||
function inspectNumberObject(value, inspectOptions) {
|
||||
const cyan = maybeColor(colors.cyan, inspectOptions);
|
||||
return cyan(`[Number: ${value.toString()}]`); // wrappers are in cyan
|
||||
}
|
||||
|
||||
|
@ -671,6 +684,9 @@
|
|||
level,
|
||||
inspectOptions,
|
||||
) {
|
||||
const cyan = maybeColor(colors.cyan, inspectOptions);
|
||||
const red = maybeColor(colors.red, inspectOptions);
|
||||
|
||||
const [state, result] = core.getPromiseDetails(value);
|
||||
|
||||
if (state === PromiseState.Pending) {
|
||||
|
@ -714,6 +730,8 @@
|
|||
level,
|
||||
inspectOptions,
|
||||
) {
|
||||
const cyan = maybeColor(colors.cyan, inspectOptions);
|
||||
|
||||
if (level >= inspectOptions.depth) {
|
||||
return cyan("[Object]"); // wrappers are in cyan
|
||||
}
|
||||
|
@ -770,7 +788,7 @@
|
|||
}
|
||||
// Making sure color codes are ignored when calculating the total length
|
||||
const totalLength = entries.length + level +
|
||||
stripColor(entries.join("")).length;
|
||||
colors.stripColor(entries.join("")).length;
|
||||
|
||||
ctx.delete(value);
|
||||
|
||||
|
@ -822,25 +840,25 @@
|
|||
} else if (Array.isArray(value)) {
|
||||
return inspectArray(value, consoleContext, level, inspectOptions);
|
||||
} else if (value instanceof Number) {
|
||||
return inspectNumberObject(value);
|
||||
return inspectNumberObject(value, inspectOptions);
|
||||
} else if (value instanceof Boolean) {
|
||||
return inspectBooleanObject(value);
|
||||
return inspectBooleanObject(value, inspectOptions);
|
||||
} else if (value instanceof String) {
|
||||
return inspectStringObject(value);
|
||||
return inspectStringObject(value, inspectOptions);
|
||||
} else if (value instanceof Promise) {
|
||||
return inspectPromise(value, consoleContext, level, inspectOptions);
|
||||
} else if (value instanceof RegExp) {
|
||||
return inspectRegExp(value);
|
||||
return inspectRegExp(value, inspectOptions);
|
||||
} else if (value instanceof Date) {
|
||||
return inspectDate(value);
|
||||
return inspectDate(value, inspectOptions);
|
||||
} else if (value instanceof Set) {
|
||||
return inspectSet(value, consoleContext, level, inspectOptions);
|
||||
} else if (value instanceof Map) {
|
||||
return inspectMap(value, consoleContext, level, inspectOptions);
|
||||
} else if (value instanceof WeakSet) {
|
||||
return inspectWeakSet();
|
||||
return inspectWeakSet(inspectOptions);
|
||||
} else if (value instanceof WeakMap) {
|
||||
return inspectWeakMap();
|
||||
return inspectWeakMap(inspectOptions);
|
||||
} else if (isTypedArray(value)) {
|
||||
return inspectTypedArray(
|
||||
Object.getPrototypeOf(value).constructor.name,
|
||||
|
@ -1318,6 +1336,11 @@
|
|||
const timerMap = new Map();
|
||||
const isConsoleInstance = Symbol("isConsoleInstance");
|
||||
|
||||
const CONSOLE_INSPECT_OPTIONS = {
|
||||
...DEFAULT_INSPECT_OPTIONS,
|
||||
colors: true,
|
||||
};
|
||||
|
||||
class Console {
|
||||
#printFunc = null;
|
||||
[isConsoleInstance] = false;
|
||||
|
@ -1339,6 +1362,7 @@
|
|||
log = (...args) => {
|
||||
this.#printFunc(
|
||||
inspectArgs(args, {
|
||||
...CONSOLE_INSPECT_OPTIONS,
|
||||
indentLevel: this.indentLevel,
|
||||
}) + "\n",
|
||||
false,
|
||||
|
@ -1349,7 +1373,10 @@
|
|||
info = this.log;
|
||||
|
||||
dir = (obj, options = {}) => {
|
||||
this.#printFunc(inspectArgs([obj], options) + "\n", false);
|
||||
this.#printFunc(
|
||||
inspectArgs([obj], { ...CONSOLE_INSPECT_OPTIONS, ...options }) + "\n",
|
||||
false,
|
||||
);
|
||||
};
|
||||
|
||||
dirxml = this.dir;
|
||||
|
@ -1357,6 +1384,7 @@
|
|||
warn = (...args) => {
|
||||
this.#printFunc(
|
||||
inspectArgs(args, {
|
||||
...CONSOLE_INSPECT_OPTIONS,
|
||||
indentLevel: this.indentLevel,
|
||||
}) + "\n",
|
||||
true,
|
||||
|
@ -1560,7 +1588,10 @@
|
|||
};
|
||||
|
||||
trace = (...args) => {
|
||||
const message = inspectArgs(args, { indentLevel: 0 });
|
||||
const message = inspectArgs(
|
||||
args,
|
||||
{ ...CONSOLE_INSPECT_OPTIONS, indentLevel: 0 },
|
||||
);
|
||||
const err = {
|
||||
name: "Trace",
|
||||
message,
|
||||
|
|
|
@ -8,7 +8,12 @@
|
|||
// std/fmt/colors auto determines whether to put colors in or not. We need
|
||||
// better infrastructure here so we can properly test the colors.
|
||||
|
||||
import { assert, assertEquals, unitTest } from "./test_util.ts";
|
||||
import {
|
||||
assert,
|
||||
assertEquals,
|
||||
assertStringContains,
|
||||
unitTest,
|
||||
} from "./test_util.ts";
|
||||
import { stripColor } from "../../../std/fmt/colors.ts";
|
||||
|
||||
const customInspect = Deno.customInspect;
|
||||
|
@ -1650,3 +1655,8 @@ unitTest(function inspectProxy(): void {
|
|||
"Proxy [ [Function: fn], { get: [Function: get] } ]",
|
||||
);
|
||||
});
|
||||
|
||||
unitTest(function inspectColors(): void {
|
||||
assertEquals(Deno.inspect(1), "1");
|
||||
assertStringContains(Deno.inspect(1, { colors: true }), "\x1b[");
|
||||
});
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
import { sprintf } from "./printf.ts";
|
||||
import { assertEquals } from "../testing/asserts.ts";
|
||||
import { cyan, yellow } from "./colors.ts";
|
||||
|
||||
const S = sprintf;
|
||||
|
||||
|
@ -607,12 +606,12 @@ Deno.test("testWeirdos", function (): void {
|
|||
Deno.test("formatV", function (): void {
|
||||
const a = { a: { a: { a: { a: { a: { a: { a: {} } } } } } } };
|
||||
assertEquals(S("%v", a), "[object Object]");
|
||||
assertEquals(S("%#v", a), `{ a: { a: { a: { a: ${cyan("[Object]")} } } } }`);
|
||||
assertEquals(S("%#v", a), `{ a: { a: { a: { a: [Object] } } } }`);
|
||||
assertEquals(
|
||||
S("%#.8v", a),
|
||||
"{ a: { a: { a: { a: { a: { a: { a: {} } } } } } } }",
|
||||
);
|
||||
assertEquals(S("%#.1v", a), `{ a: ${cyan("[Object]")} }`);
|
||||
assertEquals(S("%#.1v", a), `{ a: [Object] }`);
|
||||
});
|
||||
|
||||
Deno.test("formatJ", function (): void {
|
||||
|
@ -625,9 +624,7 @@ Deno.test("flagLessThan", function (): void {
|
|||
const aArray = [a, a, a];
|
||||
assertEquals(
|
||||
S("%<#.1v", aArray),
|
||||
`[ { a: ${cyan("[Object]")} }, { a: ${cyan("[Object]")} }, { a: ${
|
||||
cyan("[Object]")
|
||||
} } ]`,
|
||||
`[ { a: [Object] }, { a: [Object] }, { a: [Object] } ]`,
|
||||
);
|
||||
const fArray = [1.2345, 0.98765, 123456789.5678];
|
||||
assertEquals(S("%<.2f", fArray), "[ 1.23, 0.99, 123456789.57 ]");
|
||||
|
@ -649,27 +646,21 @@ Deno.test("testErrors", function (): void {
|
|||
assertEquals(S("%.*f", "a", 1.1), "%!(BAD PREC 'a')");
|
||||
assertEquals(
|
||||
S("%.[2]*f", 1.23, "p"),
|
||||
`%!(BAD PREC 'p')%!(EXTRA '${yellow("1.23")}')`,
|
||||
`%!(BAD PREC 'p')%!(EXTRA '1.23')`,
|
||||
);
|
||||
assertEquals(S("%.[2]*[1]f Yippie!", 1.23, "p"), "%!(BAD PREC 'p') Yippie!");
|
||||
|
||||
assertEquals(S("%[1]*.2f", "a", "p"), "%!(BAD WIDTH 'a')");
|
||||
|
||||
assertEquals(
|
||||
S("A", "a", "p"),
|
||||
`A%!(EXTRA '\x1b[32m"a"\x1b[39m' '\x1b[32m"p"\x1b[39m')`,
|
||||
);
|
||||
assertEquals(
|
||||
S("%[2]s %[2]s", "a", "p"),
|
||||
`p p%!(EXTRA '\x1b[32m"a"\x1b[39m')`,
|
||||
);
|
||||
assertEquals(S("A", "a", "p"), `A%!(EXTRA '"a"' '"p"')`);
|
||||
assertEquals(S("%[2]s %[2]s", "a", "p"), `p p%!(EXTRA '"a"')`);
|
||||
|
||||
// remains to be determined how to handle bad indices ...
|
||||
// (realistically) the entire error handling is still up for grabs.
|
||||
assertEquals(S("%[hallo]s %d %d %d", 1, 2, 3, 4), "%!(BAD INDEX) 2 3 4");
|
||||
assertEquals(
|
||||
S("%[5]s", 1, 2, 3, 4),
|
||||
`%!(BAD INDEX)%!(EXTRA '${yellow("2")}' '${yellow("3")}' '${yellow("4")}')`,
|
||||
`%!(BAD INDEX)%!(EXTRA '2' '3' '4')`,
|
||||
);
|
||||
assertEquals(S("%[5]f"), "%!(BAD INDEX)");
|
||||
assertEquals(S("%.[5]f"), "%!(BAD INDEX)");
|
||||
|
|
|
@ -21,13 +21,13 @@ export class AssertionError extends Error {
|
|||
|
||||
export function _format(v: unknown): string {
|
||||
return globalThis.Deno
|
||||
? stripColor(Deno.inspect(v, {
|
||||
? Deno.inspect(v, {
|
||||
depth: Infinity,
|
||||
sorted: true,
|
||||
trailingComma: true,
|
||||
compact: false,
|
||||
iterableLimit: Infinity,
|
||||
}))
|
||||
})
|
||||
: `"${String(v).replace(/(?=["\\])/g, "\\")}"`;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue