Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 6 commits into from
Sep 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 69 additions & 17 deletions js/console.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
// tslint:disable-next-line:no-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
function getClassInstanceName(instance: any): string {
Expand All @@ -25,11 +33,16 @@ function createFunctionString(value: Function, ctx: ConsoleContext): string {
return `[${cstrName}]`;
}

// tslint:disable-next-line:no-any
function createArrayString(value: any[], ctx: ConsoleContext): string {
function createArrayString(
// tslint:disable-next-line:no-any
value: any[],
ctx: ConsoleContext,
level: number,
maxLevel: number
): string {
const entries: string[] = [];
for (const el of value) {
entries.push(stringifyWithQuotes(ctx, el));
entries.push(stringifyWithQuotes(ctx, el, level + 1, maxLevel));
}
ctx.delete(value);
if (entries.length === 0) {
Expand All @@ -38,8 +51,13 @@ function createArrayString(value: any[], ctx: ConsoleContext): string {
return `[ ${entries.join(", ")} ]`;
}

// tslint:disable-next-line:no-any
function createObjectString(value: any, ctx: ConsoleContext): string {
function createObjectString(
// tslint:disable-next-line:no-any
value: any,
ctx: ConsoleContext,
level: number,
maxLevel: number
): string {
const entries: string[] = [];
let baseString = "";

Expand All @@ -50,7 +68,9 @@ function createObjectString(value: any, ctx: ConsoleContext): string {
}

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);
Expand All @@ -68,8 +88,13 @@ function createObjectString(value: any, ctx: ConsoleContext): string {
return baseString;
}

// tslint:disable-next-line:no-any
function stringify(ctx: ConsoleContext, value: any): string {
function stringify(
ctx: ConsoleContext,
// tslint:disable-next-line:no-any
value: any,
level: number,
maxLevel: number
): string {
switch (typeof value) {
case "string":
return value;
Expand All @@ -88,41 +113,63 @@ function stringify(ctx: ConsoleContext, value: any): string {
if (ctx.has(value)) {
return "[Circular]";
}

if (level >= maxLevel) {
return `[object]`;
}

ctx.add(value);

if (value instanceof Error) {
return value.stack! || "";
} else if (Array.isArray(value)) {
// tslint:disable-next-line:no-any
return createArrayString(value as any[], ctx);
return createArrayString(value as any[], ctx, level, maxLevel);
} else {
return createObjectString(value, ctx);
return createObjectString(value, ctx, level, maxLevel);
}
default:
return "[Not Implemented]";
}
}

// Print strings when they are inside of arrays or objects with quotes
// tslint:disable-next-line:no-any
function stringifyWithQuotes(ctx: ConsoleContext, value: any): string {
function stringifyWithQuotes(
ctx: ConsoleContext,
// tslint:disable-next-line:no-any
value: any,
level: number,
maxLevel: number
): string {
switch (typeof value) {
case "string":
return `"${value}"`;
default:
return stringify(ctx, value);
return stringify(ctx, value, level, maxLevel);
}
}

// tslint:disable-next-line:no-any
export function stringifyArgs(args: any[]): string {
export function stringifyArgs(
// tslint:disable-next-line:no-any
args: any[],
options: ConsoleOptions = {}
): string {
const out: string[] = [];
for (const a of args) {
if (typeof a === "string") {
out.push(a);
} else {
// tslint:disable-next-line:no-any
out.push(stringify(new Set<any>(), a));
out.push(
// use default maximum depth for null or undefined argument
stringify(
// tslint:disable-next-line:no-any
new Set<any>(),
a,
0,
// tslint:disable-next-line:triple-equals
options.depth != undefined ? options.depth : DEFAULT_MAX_DEPTH
)
);
}
}
return out.join(" ");
Expand All @@ -141,6 +188,11 @@ export class Console {
debug = 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
warn(...args: any[]): void {
this.printFunc(stringifyArgs(args), true);
Expand Down
19 changes: 18 additions & 1 deletion js/console_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ test(function consoleTestStringifyCircular() {

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("s"), "s");
Expand All @@ -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() {
class MyError extends Error {
constructor(msg: string) {
Expand Down
8 changes: 4 additions & 4 deletions js/dom_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,17 +103,17 @@ export interface URLSearchParams {
*/
set(name: string, value: string): void;
/**
* Sort all key/value pairs contained in this object in place
* and return undefined. The sort order is according to Unicode
* Sort all key/value pairs contained in this object in place
* and return undefined. The sort order is according to Unicode
* code points of the keys.
*/
sort(): void;
/**
* Returns a query string suitable for use in a URL.
*/
toString(): string;
/**
* Iterates over each name-value pair in the query
/**
* Iterates over each name-value pair in the query
* and invokes the given function.
*/
forEach(
Expand Down
23 changes: 13 additions & 10 deletions js/fetch_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ testPerm({ net: true }, async function fetchBlob() {
assertEqual(blob.size, Number(headers.get("Content-Length")));
});

// Logic heavily copied from web-platform-tests, make
// Logic heavily copied from web-platform-tests, make
// sure pass mostly header basic test
/* tslint:disable-next-line:max-line-length */
// ref: https://github.com/web-platform-tests/wpt/blob/7c50c216081d6ea3c9afe553ee7b64534020a1b2/fetch/api/headers/headers-basic.html
Expand All @@ -68,17 +68,17 @@ test(function newHeaderTest() {
});

const headerDict = {
"name1": "value1",
"name2": "value2",
"name3": "value3",
"name4": undefined,
name1: "value1",
name2: "value2",
name3: "value3",
name4: undefined,
"Content-Type": "value4"
};
const headerSeq = [];
for (const name in headerDict) {
headerSeq.push([name, headerDict[name]]);
}

test(function newHeaderWithSequence() {
const headers = new Headers(headerSeq);
for (const name in headerDict) {
Expand Down Expand Up @@ -123,7 +123,10 @@ test(function headerHasSuccess() {
for (const name in headerDict) {
assert(headers.has(name), "headers has name " + name);
/* tslint:disable-next-line:max-line-length */
assert(!headers.has("nameNotInHeaders"), "headers do not have header: nameNotInHeaders");
assert(
!headers.has("nameNotInHeaders"),
"headers do not have header: nameNotInHeaders"
);
}
});

Expand All @@ -145,9 +148,9 @@ test(function headerGetSuccess() {
});

const headerEntriesDict = {
"name1": "value1",
"Name2": "value2",
"name": "value3",
name1: "value1",
Name2: "value2",
name: "value3",
"content-Type": "value4",
"Content-Typ": "value5",
"Content-Types": "value6"
Expand Down
2 changes: 1 addition & 1 deletion website/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export async function main() {
categories: sha1List
},
y: {
label: "seconds",
label: "seconds"
}
}
});
Expand Down