0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-10-29 08:58:01 -04:00

Limit depth of output in console.log for nested objects, and add console.dir (#826)

This commit is contained in:
Yingbo (Max) Wang 2018-09-30 15:10:20 -07:00 committed by Ryan Dahl
parent 50a9c2b575
commit bcdbfc00f0
2 changed files with 87 additions and 18 deletions

View file

@ -1,5 +1,13 @@
// tslint:disable-next-line:no-any // tslint:disable-next-line:no-any
type ConsoleContext = Set<any>; type ConsoleContext = Set<any>;
type ConsoleOptions = Partial<{
showHidden: boolean;
depth: number;
colors: boolean;
}>;
// Default depth of logging nested objects
const DEFAULT_MAX_DEPTH = 2;
// tslint:disable-next-line:no-any // tslint:disable-next-line:no-any
function getClassInstanceName(instance: any): string { function getClassInstanceName(instance: any): string {
@ -25,11 +33,16 @@ function createFunctionString(value: Function, ctx: ConsoleContext): string {
return `[${cstrName}]`; return `[${cstrName}]`;
} }
// tslint:disable-next-line:no-any function createArrayString(
function createArrayString(value: any[], ctx: ConsoleContext): string { // tslint:disable-next-line:no-any
value: any[],
ctx: ConsoleContext,
level: number,
maxLevel: number
): string {
const entries: string[] = []; const entries: string[] = [];
for (const el of value) { for (const el of value) {
entries.push(stringifyWithQuotes(ctx, el)); entries.push(stringifyWithQuotes(ctx, el, level + 1, maxLevel));
} }
ctx.delete(value); ctx.delete(value);
if (entries.length === 0) { if (entries.length === 0) {
@ -38,8 +51,13 @@ function createArrayString(value: any[], ctx: ConsoleContext): string {
return `[ ${entries.join(", ")} ]`; return `[ ${entries.join(", ")} ]`;
} }
// tslint:disable-next-line:no-any function createObjectString(
function createObjectString(value: any, ctx: ConsoleContext): string { // tslint:disable-next-line:no-any
value: any,
ctx: ConsoleContext,
level: number,
maxLevel: number
): string {
const entries: string[] = []; const entries: string[] = [];
let baseString = ""; let baseString = "";
@ -50,7 +68,9 @@ function createObjectString(value: any, ctx: ConsoleContext): string {
} }
for (const key of Object.keys(value)) { for (const key of Object.keys(value)) {
entries.push(`${key}: ${stringifyWithQuotes(ctx, value[key])}`); entries.push(
`${key}: ${stringifyWithQuotes(ctx, value[key], level + 1, maxLevel)}`
);
} }
ctx.delete(value); ctx.delete(value);
@ -68,8 +88,13 @@ function createObjectString(value: any, ctx: ConsoleContext): string {
return baseString; return baseString;
} }
// tslint:disable-next-line:no-any function stringify(
function stringify(ctx: ConsoleContext, value: any): string { ctx: ConsoleContext,
// tslint:disable-next-line:no-any
value: any,
level: number,
maxLevel: number
): string {
switch (typeof value) { switch (typeof value) {
case "string": case "string":
return value; return value;
@ -88,15 +113,20 @@ function stringify(ctx: ConsoleContext, value: any): string {
if (ctx.has(value)) { if (ctx.has(value)) {
return "[Circular]"; return "[Circular]";
} }
if (level >= maxLevel) {
return `[object]`;
}
ctx.add(value); ctx.add(value);
if (value instanceof Error) { if (value instanceof Error) {
return value.stack! || ""; return value.stack! || "";
} else if (Array.isArray(value)) { } else if (Array.isArray(value)) {
// tslint:disable-next-line:no-any // tslint:disable-next-line:no-any
return createArrayString(value as any[], ctx); return createArrayString(value as any[], ctx, level, maxLevel);
} else { } else {
return createObjectString(value, ctx); return createObjectString(value, ctx, level, maxLevel);
} }
default: default:
return "[Not Implemented]"; return "[Not Implemented]";
@ -104,25 +134,42 @@ function stringify(ctx: ConsoleContext, value: any): string {
} }
// Print strings when they are inside of arrays or objects with quotes // Print strings when they are inside of arrays or objects with quotes
// tslint:disable-next-line:no-any function stringifyWithQuotes(
function stringifyWithQuotes(ctx: ConsoleContext, value: any): string { ctx: ConsoleContext,
// tslint:disable-next-line:no-any
value: any,
level: number,
maxLevel: number
): string {
switch (typeof value) { switch (typeof value) {
case "string": case "string":
return `"${value}"`; return `"${value}"`;
default: default:
return stringify(ctx, value); return stringify(ctx, value, level, maxLevel);
} }
} }
// tslint:disable-next-line:no-any export function stringifyArgs(
export function stringifyArgs(args: any[]): string { // tslint:disable-next-line:no-any
args: any[],
options: ConsoleOptions = {}
): string {
const out: string[] = []; const out: string[] = [];
for (const a of args) { for (const a of args) {
if (typeof a === "string") { if (typeof a === "string") {
out.push(a); out.push(a);
} else { } else {
out.push(
// use default maximum depth for null or undefined argument
stringify(
// tslint:disable-next-line:no-any // tslint:disable-next-line:no-any
out.push(stringify(new Set<any>(), a)); new Set<any>(),
a,
0,
// tslint:disable-next-line:triple-equals
options.depth != undefined ? options.depth : DEFAULT_MAX_DEPTH
)
);
} }
} }
return out.join(" "); return out.join(" ");
@ -141,6 +188,11 @@ export class Console {
debug = this.log; debug = this.log;
info = this.log; info = this.log;
// tslint:disable-next-line:no-any
dir(obj: any, options: ConsoleOptions = {}) {
this.printFunc(stringifyArgs([obj], options));
}
// tslint:disable-next-line:no-any // tslint:disable-next-line:no-any
warn(...args: any[]): void { warn(...args: any[]): void {
this.printFunc(stringifyArgs(args), true); this.printFunc(stringifyArgs(args), true);

View file

@ -68,7 +68,7 @@ test(function consoleTestStringifyCircular() {
nestedObj.o = circularObj; nestedObj.o = circularObj;
const nestedObjExpected = `{ num: 1, bool: true, str: "a", method: [Function: method], asyncMethod: [AsyncFunction: asyncMethod], generatorMethod: [GeneratorFunction: generatorMethod], un: undefined, nu: null, arrowFunc: [Function: arrowFunc], extendedClass: Extended { a: 1, b: 2 }, nFunc: [Function], extendedCstr: [Function: Extended], o: { num: 2, bool: false, str: "b", method: [Function: method], un: undefined, nu: null, nested: [Circular], emptyObj: {}, arr: [ 1, "s", false, null, [Circular] ], baseClass: Base { a: 1 } } }`; const nestedObjExpected = `{ num: 1, bool: true, str: "a", method: [Function: method], asyncMethod: [AsyncFunction: asyncMethod], generatorMethod: [GeneratorFunction: generatorMethod], un: undefined, nu: null, arrowFunc: [Function: arrowFunc], extendedClass: Extended { a: 1, b: 2 }, nFunc: [Function], extendedCstr: [Function: Extended], o: { num: 2, bool: false, str: "b", method: [Function: method], un: undefined, nu: null, nested: [Circular], emptyObj: [object], arr: [object], baseClass: [object] } }`;
assertEqual(stringify(1), "1"); assertEqual(stringify(1), "1");
assertEqual(stringify("s"), "s"); assertEqual(stringify("s"), "s");
@ -92,6 +92,23 @@ test(function consoleTestStringifyCircular() {
); );
}); });
test(function consoleTestStringifyWithDepth() {
const nestedObj: any = { a: { b: { c: { d: { e: { f: 42 } } } } } };
assertEqual(
stringifyArgs([nestedObj], { depth: 3 }),
"{ a: { b: { c: [object] } } }"
);
assertEqual(
stringifyArgs([nestedObj], { depth: 4 }),
"{ a: { b: { c: { d: [object] } } } }"
);
assertEqual(stringifyArgs([nestedObj], { depth: 0 }), "[object]");
assertEqual(
stringifyArgs([nestedObj], { depth: null }),
"{ a: { b: [object] } }"
);
});
test(function consoleTestError() { test(function consoleTestError() {
class MyError extends Error { class MyError extends Error {
constructor(msg: string) { constructor(msg: string) {