1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-25 15:29:32 -05:00

fix(console): log function object properties / do not log non-enumerable props by default (#9363)

This commit is contained in:
David DeSimone 2021-02-10 03:52:54 -08:00 committed by GitHub
parent 6752be05cd
commit 61108935f1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 104 additions and 13 deletions

View file

@ -2034,6 +2034,8 @@ declare namespace Deno {
trailingComma?: boolean;
/*** Evaluate the result of calling getters. Defaults to false. */
getters?: boolean;
/** Show an object's non-enumerable properties. Defaults to false. */
showHidden?: boolean;
}
/** Converts the input into a string that has the same format as printed by

View file

@ -1 +1 @@
Module { isMod4: true, [Symbol(Symbol.toStringTag)]: "Module" }
Module { isMod4: true }

View file

@ -1 +1 @@
Module { isMod4: true, [Symbol(Symbol.toStringTag)]: "Module" }
Module { isMod4: true }

View file

@ -1,5 +1,5 @@
[WILDCARD][Function: Location]
Location { [Symbol(Symbol.toStringTag)]: "Location" }
Location {}
Location {
hash: "#bat",
host: "foo",

View file

@ -1,4 +1,4 @@
[WILDCARD][Function: Location]
Location { [Symbol(Symbol.toStringTag)]: "Location" }
Location {}
error: Uncaught ReferenceError: Access to "location", run again with --location <href>.
[WILDCARD]

View file

@ -1 +1 @@
Module { [Symbol(Symbol.toStringTag)]: "Module" }
Module {}

View file

@ -1,5 +1,5 @@
loading [WILDCARD]a.js
loaded Module { default: [Function: Foo], [Symbol(Symbol.toStringTag)]: "Module" }
loaded Module { default: [Function: Foo] }
loading [WILDCARD]b.js
loaded Module { default: [Function: Bar], [Symbol(Symbol.toStringTag)]: "Module" }
loaded Module { default: [Function: Bar] }
all loaded

View file

@ -310,7 +310,7 @@ unitTest(function consoleTestStringifyCircular(): void {
assertEquals(stringify(nestedObj), nestedObjExpected);
assertEquals(
stringify(JSON),
'JSON { [Symbol(Symbol.toStringTag)]: "JSON" }',
"JSON {}",
);
assertEquals(
stringify(console),
@ -335,7 +335,6 @@ unitTest(function consoleTestStringifyCircular(): void {
clear: [Function: clear],
trace: [Function: trace],
indentLevel: 0,
[Symbol(Symbol.toStringTag)]: "console",
[Symbol(isConsoleInstance)]: true
}`,
);
@ -362,6 +361,50 @@ unitTest(function consoleTestStringifyFunctionWithPrototypeRemoved(): void {
assertEquals(stringify(agf), "[Function: agf]");
});
unitTest(function consoleTestStringifyFunctionWithProperties(): void {
const f = () => "test";
f.x = () => "foo";
f.y = 3;
f.z = () => "baz";
f.b = function bar() {};
f.a = new Map();
assertEquals(
stringify({ f }),
`{
f: [Function: f] { x: [Function], y: 3, z: [Function], b: [Function: bar], a: Map {} }
}`,
);
const t = () => {};
t.x = f;
f.s = f;
f.t = t;
assertEquals(
stringify({ f }),
`{
f: [Function: f] {
x: [Function],
y: 3,
z: [Function],
b: [Function: bar],
a: Map {},
s: [Circular],
t: [Function: t] { x: [Circular] }
}
}`,
);
assertEquals(
stringify(Array),
`[Function: Array]`,
);
assertEquals(
stripColor(Deno.inspect(Array, { showHidden: true })),
`[Function: Array] { [Symbol(Symbol.species)]: [Getter] }`,
);
});
unitTest(function consoleTestStringifyWithDepth(): void {
// deno-lint-ignore no-explicit-any
const nestedObj: any = { a: { b: { c: { d: { e: { f: 42 } } } } } };

View file

@ -17,6 +17,17 @@
return Object.prototype.hasOwnProperty.call(obj, v);
}
function propertyIsEnumerable(obj, prop) {
if (
obj == null ||
typeof obj.propertyIsEnumerable !== "function"
) {
return false;
}
return obj.propertyIsEnumerable(prop);
}
// Copyright Joyent, Inc. and other Node contributors. MIT license.
// Forked from Node's lib/internal/cli_table.js
@ -159,6 +170,7 @@
showProxy: false,
colors: false,
getters: false,
showHidden: false,
};
const DEFAULT_INDENT = " "; // Default indent string
@ -189,7 +201,8 @@
return inspectOptions.colors ? fn : (s) => s;
}
function inspectFunction(value, _ctx) {
function inspectFunction(value, ctx, level, inspectOptions) {
const cyan = maybeColor(colors.cyan, inspectOptions);
if (customInspect in value && typeof value[customInspect] === "function") {
return String(value[customInspect]());
}
@ -200,11 +213,32 @@
// use generic 'Function' instead.
cstrName = "Function";
}
// Our function may have properties, so we want to format those
// as if our function was an object
// If we didn't find any properties, we will just append an
// empty suffix.
let suffix = ``;
if (
Object.keys(value).length > 0 ||
Object.getOwnPropertySymbols(value).length > 0
) {
const propString = inspectRawObject(value, ctx, level, inspectOptions);
// Filter out the empty string for the case we only have
// non-enumerable symbols.
if (
propString.length > 0 &&
propString !== "{}"
) {
suffix = ` ${propString}`;
}
}
if (value.name && value.name !== "anonymous") {
// from MDN spec
return `[${cstrName}: ${value.name}]`;
return cyan(`[${cstrName}: ${value.name}]`) + suffix;
}
return `[${cstrName}]`;
return cyan(`[${cstrName}]`) + suffix;
}
function inspectIterable(
@ -429,7 +463,12 @@
case "bigint": // Bigints are yellow
return yellow(`${value}n`);
case "function": // Function string is cyan
return cyan(inspectFunction(value, ctx));
if (ctx.has(value)) {
// Circular string is cyan
return cyan("[Circular]");
}
return inspectFunction(value, ctx, level, inspectOptions);
case "object": // null is bold
if (value === null) {
return bold("null");
@ -797,6 +836,13 @@
}
for (const key of symbolKeys) {
if (
!inspectOptions.showHidden &&
!propertyIsEnumerable(value, key)
) {
continue;
}
if (inspectOptions.getters) {
let propertyValue;
let error;