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:
parent
50a9c2b575
commit
bcdbfc00f0
2 changed files with 87 additions and 18 deletions
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue