summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
authorKevin (Kun) "Kassimo" Qian <kevinkassimo@gmail.com>2018-12-10 12:01:02 -0500
committerRyan Dahl <ry@tinyclouds.org>2018-12-10 12:01:02 -0500
commit1548792fb3530efb63432c0c704a3f0053410eb3 (patch)
tree908576c0c6c6192144edc070aef63bd9c74354ce /js
parentc427c2df427f477eb1214d8ff3fdfad36e191a6c (diff)
Add more console types formatting support (#1299)
Diffstat (limited to 'js')
-rw-r--r--js/console.ts224
-rw-r--r--js/console_test.ts33
2 files changed, 223 insertions, 34 deletions
diff --git a/js/console.ts b/js/console.ts
index ccfcf007b..3d2d65909 100644
--- a/js/console.ts
+++ b/js/console.ts
@@ -1,4 +1,5 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
+import { isTypedArray } from "./util";
// tslint:disable-next-line:no-any
type ConsoleContext = Set<any>;
@@ -9,7 +10,7 @@ type ConsoleOptions = Partial<{
}>;
// Default depth of logging nested objects
-const DEFAULT_MAX_DEPTH = 2;
+const DEFAULT_MAX_DEPTH = 4;
// tslint:disable-next-line:no-any
function getClassInstanceName(instance: any): string {
@@ -35,31 +36,165 @@ function createFunctionString(value: Function, ctx: ConsoleContext): string {
return `[${cstrName}]`;
}
-function createArrayString(
+interface IterablePrintConfig {
+ typeName: string;
+ displayName: string;
+ delims: [string, string];
+ entryHandler: (
+ // tslint:disable-next-line:no-any
+ entry: any,
+ ctx: ConsoleContext,
+ level: number,
+ maxLevel: number
+ ) => string;
+}
+
+function createIterableString(
// tslint:disable-next-line:no-any
- value: any[],
+ value: any,
ctx: ConsoleContext,
level: number,
- maxLevel: number
+ maxLevel: number,
+ config: IterablePrintConfig
): string {
+ if (level >= maxLevel) {
+ return `[${config.typeName}]`;
+ }
+ ctx.add(value);
+
const entries: string[] = [];
for (const el of value) {
- entries.push(stringifyWithQuotes(ctx, el, level + 1, maxLevel));
+ entries.push(config.entryHandler(el, ctx, level + 1, maxLevel));
}
ctx.delete(value);
- if (entries.length === 0) {
- return "[]";
- }
- return `[ ${entries.join(", ")} ]`;
+ const iPrefix = `${config.displayName ? config.displayName + " " : ""}`;
+ const iContent = entries.length === 0 ? "" : ` ${entries.join(", ")} `;
+ return `${iPrefix}${config.delims[0]}${iContent}${config.delims[1]}`;
}
-function createObjectString(
+function createArrayString(
+ // tslint:disable-next-line:no-any
+ value: any[],
+ ctx: ConsoleContext,
+ level: number,
+ maxLevel: number
+): string {
+ const printConfig: IterablePrintConfig = {
+ typeName: "Array",
+ displayName: "",
+ delims: ["[", "]"],
+ entryHandler: (el, ctx, level, maxLevel) =>
+ stringifyWithQuotes(el, ctx, level + 1, maxLevel)
+ };
+ return createIterableString(value, ctx, level, maxLevel, printConfig);
+}
+
+function createTypedArrayString(
+ typedArrayName: string,
// tslint:disable-next-line:no-any
value: any,
ctx: ConsoleContext,
level: number,
maxLevel: number
): string {
+ const printConfig: IterablePrintConfig = {
+ typeName: typedArrayName,
+ displayName: typedArrayName,
+ delims: ["[", "]"],
+ entryHandler: (el, ctx, level, maxLevel) =>
+ stringifyWithQuotes(el, ctx, level + 1, maxLevel)
+ };
+ return createIterableString(value, ctx, level, maxLevel, printConfig);
+}
+
+function createSetString(
+ // tslint:disable-next-line:no-any
+ value: Set<any>,
+ ctx: ConsoleContext,
+ level: number,
+ maxLevel: number
+): string {
+ const printConfig: IterablePrintConfig = {
+ typeName: "Set",
+ displayName: "Set",
+ delims: ["{", "}"],
+ entryHandler: (el, ctx, level, maxLevel) =>
+ stringifyWithQuotes(el, ctx, level + 1, maxLevel)
+ };
+ return createIterableString(value, ctx, level, maxLevel, printConfig);
+}
+
+function createMapString(
+ // tslint:disable-next-line:no-any
+ value: Map<any, any>,
+ ctx: ConsoleContext,
+ level: number,
+ maxLevel: number
+): string {
+ const printConfig: IterablePrintConfig = {
+ typeName: "Map",
+ displayName: "Map",
+ delims: ["{", "}"],
+ entryHandler: (el, ctx, level, maxLevel) => {
+ const [key, val] = el;
+ return `${stringifyWithQuotes(
+ key,
+ ctx,
+ level + 1,
+ maxLevel
+ )} => ${stringifyWithQuotes(val, ctx, level + 1, maxLevel)}`;
+ }
+ };
+ return createIterableString(value, ctx, level, maxLevel, printConfig);
+}
+
+function createWeakSetString(): string {
+ return "WeakSet { [items unknown] }"; // as seen in Node
+}
+
+function createWeakMapString(): string {
+ return "WeakMap { [items unknown] }"; // as seen in Node
+}
+
+function createDateString(value: Date) {
+ // without quotes, ISO format
+ return value.toISOString();
+}
+
+function createRegExpString(value: RegExp) {
+ return value.toString();
+}
+
+// tslint:disable-next-line:ban-types
+function createStringWrapperString(value: String) {
+ return `[String: "${value.toString()}"]`;
+}
+
+// tslint:disable-next-line:ban-types
+function createBooleanWrapperString(value: Boolean) {
+ return `[Boolean: ${value.toString()}]`;
+}
+
+// tslint:disable-next-line:ban-types
+function createNumberWrapperString(value: Number) {
+ return `[Number: ${value.toString()}]`;
+}
+
+// TODO: Promise, requires v8 bindings to get info
+// TODO: Proxy
+
+function createRawObjectString(
+ // tslint:disable-next-line:no-any
+ value: any,
+ ctx: ConsoleContext,
+ level: number,
+ maxLevel: number
+): string {
+ if (level >= maxLevel) {
+ return "[Object]";
+ }
+ ctx.add(value);
+
const entries: string[] = [];
let baseString = "";
@@ -71,7 +206,7 @@ function createObjectString(
for (const key of Object.keys(value)) {
entries.push(
- `${key}: ${stringifyWithQuotes(ctx, value[key], level + 1, maxLevel)}`
+ `${key}: ${stringifyWithQuotes(value[key], ctx, level + 1, maxLevel)}`
);
}
@@ -90,10 +225,54 @@ function createObjectString(
return baseString;
}
+function createObjectString(
+ // tslint:disable-next-line:no-any
+ value: any,
+ ...args: [ConsoleContext, number, number]
+): string {
+ if (value instanceof Error) {
+ return value.stack! || "";
+ } else if (Array.isArray(value)) {
+ return createArrayString(value, ...args);
+ } else if (value instanceof Number) {
+ // tslint:disable-next-line:ban-types
+ return createNumberWrapperString(value as Number);
+ } else if (value instanceof Boolean) {
+ // tslint:disable-next-line:ban-types
+ return createBooleanWrapperString(value as Boolean);
+ } else if (value instanceof String) {
+ // tslint:disable-next-line:ban-types
+ return createStringWrapperString(value as String);
+ } else if (value instanceof RegExp) {
+ return createRegExpString(value as RegExp);
+ } else if (value instanceof Date) {
+ return createDateString(value as Date);
+ } else if (value instanceof Set) {
+ // tslint:disable-next-line:no-any
+ return createSetString(value as Set<any>, ...args);
+ } else if (value instanceof Map) {
+ // tslint:disable-next-line:no-any
+ return createMapString(value as Map<any, any>, ...args);
+ } else if (value instanceof WeakSet) {
+ return createWeakSetString();
+ } else if (value instanceof WeakMap) {
+ return createWeakMapString();
+ } else if (isTypedArray(value)) {
+ return createTypedArrayString(
+ Object.getPrototypeOf(value).constructor.name,
+ value,
+ ...args
+ );
+ } else {
+ // Otherwise, default object formatting
+ return createRawObjectString(value, ...args);
+ }
+}
+
function stringify(
- ctx: ConsoleContext,
// tslint:disable-next-line:no-any
value: any,
+ ctx: ConsoleContext,
level: number,
maxLevel: number
): string {
@@ -118,20 +297,7 @@ function stringify(
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, level, maxLevel);
- } else {
- return createObjectString(value, ctx, level, maxLevel);
- }
+ return createObjectString(value, ctx, level, maxLevel);
default:
return "[Not Implemented]";
}
@@ -139,9 +305,9 @@ function stringify(
// Print strings when they are inside of arrays or objects with quotes
function stringifyWithQuotes(
- ctx: ConsoleContext,
// tslint:disable-next-line:no-any
value: any,
+ ctx: ConsoleContext,
level: number,
maxLevel: number
): string {
@@ -149,7 +315,7 @@ function stringifyWithQuotes(
case "string":
return `"${value}"`;
default:
- return stringify(ctx, value, level, maxLevel);
+ return stringify(value, ctx, level, maxLevel);
}
}
@@ -167,9 +333,9 @@ export function stringifyArgs(
out.push(
// use default maximum depth for null or undefined argument
stringify(
+ a,
// 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
diff --git a/js/console_test.ts b/js/console_test.ts
index a46edf29e..eb53ebb76 100644
--- a/js/console_test.ts
+++ b/js/console_test.ts
@@ -67,12 +67,30 @@ test(function consoleTestStringifyCircular() {
nestedObj.o = circularObj;
// tslint:disable-next-line:max-line-length
- 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] } }`;
+ 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 } } }`;
assertEqual(stringify(1), "1");
assertEqual(stringify(1n), "1n");
assertEqual(stringify("s"), "s");
assertEqual(stringify(false), "false");
+ // tslint:disable-next-line:no-construct
+ assertEqual(stringify(new Number(1)), "[Number: 1]");
+ // tslint:disable-next-line:no-construct
+ assertEqual(stringify(new Boolean(true)), "[Boolean: true]");
+ // tslint:disable-next-line:no-construct
+ assertEqual(stringify(new String("deno")), `[String: "deno"]`);
+ assertEqual(stringify(/[0-9]*/), "/[0-9]*/");
+ assertEqual(
+ stringify(new Date("2018-12-10T02:26:59.002Z")),
+ "2018-12-10T02:26:59.002Z"
+ );
+ assertEqual(stringify(new Set([1, 2, 3])), "Set { 1, 2, 3 }");
+ assertEqual(
+ stringify(new Map([[1, "one"], [2, "two"]])),
+ `Map { 1 => "one", 2 => "two" }`
+ );
+ assertEqual(stringify(new WeakSet()), "WeakSet { [items unknown] }");
+ assertEqual(stringify(new WeakMap()), "WeakMap { [items unknown] }");
assertEqual(stringify(Symbol(1)), "Symbol(1)");
assertEqual(stringify(null), "null");
assertEqual(stringify(undefined), "undefined");
@@ -84,6 +102,11 @@ test(function consoleTestStringifyCircular() {
stringify(async function* agf() {}),
"[AsyncGeneratorFunction: agf]"
);
+ assertEqual(stringify(new Uint8Array([1, 2, 3])), "Uint8Array [ 1, 2, 3 ]");
+ assertEqual(
+ stringify({ a: { b: { c: { d: new Set([1]) } } } }),
+ "{ a: { b: { c: { d: [Set] } } } }"
+ );
assertEqual(stringify(nestedObj), nestedObjExpected);
assertEqual(stringify(JSON), "{}");
assertEqual(
@@ -98,16 +121,16 @@ test(function consoleTestStringifyWithDepth() {
const nestedObj: any = { a: { b: { c: { d: { e: { f: 42 } } } } } };
assertEqual(
stringifyArgs([nestedObj], { depth: 3 }),
- "{ a: { b: { c: [object] } } }"
+ "{ a: { b: { c: [Object] } } }"
);
assertEqual(
stringifyArgs([nestedObj], { depth: 4 }),
- "{ a: { b: { c: { d: [object] } } } }"
+ "{ a: { b: { c: { d: [Object] } } } }"
);
- assertEqual(stringifyArgs([nestedObj], { depth: 0 }), "[object]");
+ assertEqual(stringifyArgs([nestedObj], { depth: 0 }), "[Object]");
assertEqual(
stringifyArgs([nestedObj], { depth: null }),
- "{ a: { b: [object] } }"
+ "{ a: { b: { c: { d: [Object] } } } }"
);
});