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:
parent
6752be05cd
commit
61108935f1
9 changed files with 104 additions and 13 deletions
2
cli/dts/lib.deno.ns.d.ts
vendored
2
cli/dts/lib.deno.ns.d.ts
vendored
|
@ -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
|
||||
|
|
|
@ -1 +1 @@
|
|||
Module { isMod4: true, [Symbol(Symbol.toStringTag)]: "Module" }
|
||||
Module { isMod4: true }
|
||||
|
|
|
@ -1 +1 @@
|
|||
Module { isMod4: true, [Symbol(Symbol.toStringTag)]: "Module" }
|
||||
Module { isMod4: true }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[WILDCARD][Function: Location]
|
||||
Location { [Symbol(Symbol.toStringTag)]: "Location" }
|
||||
Location {}
|
||||
Location {
|
||||
hash: "#bat",
|
||||
host: "foo",
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -1 +1 @@
|
|||
Module { [Symbol(Symbol.toStringTag)]: "Module" }
|
||||
Module {}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 } } } } } };
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue