diff --git a/js/console.ts b/js/console.ts index d3bd5bb6bb3fae..51798d79d7d970 100644 --- a/js/console.ts +++ b/js/console.ts @@ -1,5 +1,13 @@ // tslint:disable-next-line:no-any type ConsoleContext = Set; +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 { @@ -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) { @@ -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 = ""; @@ -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); @@ -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; @@ -88,15 +113,20 @@ 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]"; @@ -104,25 +134,42 @@ function stringify(ctx: ConsoleContext, value: any): string { } // 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(), a)); + out.push( + // use default maximum depth for null or undefined argument + stringify( + // tslint:disable-next-line:no-any + new Set(), + a, + 0, + // tslint:disable-next-line:triple-equals + options.depth != undefined ? options.depth : DEFAULT_MAX_DEPTH + ) + ); } } return out.join(" "); @@ -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); diff --git a/js/console_test.ts b/js/console_test.ts index 94a627a5ff68e1..9e6a37256ce3ff 100644 --- a/js/console_test.ts +++ b/js/console_test.ts @@ -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"); @@ -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) { diff --git a/js/dom_types.ts b/js/dom_types.ts index e3f75e48869d04..d59f1165e3860e 100644 --- a/js/dom_types.ts +++ b/js/dom_types.ts @@ -103,8 +103,8 @@ 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; @@ -112,8 +112,8 @@ export interface URLSearchParams { * 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( diff --git a/js/fetch_test.ts b/js/fetch_test.ts index 9d76cb6ba4bb84..7e2177350ea3cf 100644 --- a/js/fetch_test.ts +++ b/js/fetch_test.ts @@ -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 @@ -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) { @@ -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" + ); } }); @@ -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" diff --git a/website/app.js b/website/app.js index 3281cd3cf721c9..da29797a8640b1 100644 --- a/website/app.js +++ b/website/app.js @@ -148,7 +148,7 @@ export async function main() { categories: sha1List }, y: { - label: "seconds", + label: "seconds" } } });