summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
author迷渡 <justjavac@gmail.com>2019-01-25 01:07:08 +0800
committerRyan Dahl <ry@tinyclouds.org>2019-01-24 12:07:08 -0500
commit6904628aaa1c18e5438d0ec0564968094482b0c4 (patch)
tree8243c00630e97663d429262d18ea4057f9c5db50 /js
parent7f88b5fff3fe8aed2073d4347d3ab847fc4c528a (diff)
console output with format (#1565)
Diffstat (limited to 'js')
-rw-r--r--js/console.ts137
-rw-r--r--js/console_test.ts74
2 files changed, 191 insertions, 20 deletions
diff --git a/js/console.ts b/js/console.ts
index 7fec47471..a9f2db021 100644
--- a/js/console.ts
+++ b/js/console.ts
@@ -14,6 +14,16 @@ type ConsoleOptions = Partial<{
// Default depth of logging nested objects
const DEFAULT_MAX_DEPTH = 4;
+// Char codes
+const CHAR_PERCENT = 37; /* % */
+const CHAR_LOWERCASE_S = 115; /* s */
+const CHAR_LOWERCASE_D = 100; /* d */
+const CHAR_LOWERCASE_I = 105; /* i */
+const CHAR_LOWERCASE_F = 102; /* f */
+const CHAR_LOWERCASE_O = 111; /* o */
+const CHAR_UPPERCASE_O = 79; /* O */
+const CHAR_LOWERCASE_C = 99; /* c */
+
// tslint:disable-next-line:no-any
function getClassInstanceName(instance: any): string {
if (typeof instance !== "object") {
@@ -342,38 +352,125 @@ export function stringifyArgs(
args: any[],
options: ConsoleOptions = {}
): string {
- const out: string[] = [];
- const { collapsedAt, indentLevel } = options;
- for (const a of args) {
- if (typeof a === "string") {
- out.push(a);
+ const first = args[0];
+ let a = 0;
+ let str = "";
+ let join = "";
+
+ if (typeof first === "string") {
+ let tempStr: string;
+ let lastPos = 0;
+
+ for (let i = 0; i < first.length - 1; i++) {
+ if (first.charCodeAt(i) === CHAR_PERCENT) {
+ const nextChar = first.charCodeAt(++i);
+ if (a + 1 !== args.length) {
+ switch (nextChar) {
+ case CHAR_LOWERCASE_S:
+ // format as a string
+ tempStr = String(args[++a]);
+ break;
+ case CHAR_LOWERCASE_D:
+ case CHAR_LOWERCASE_I:
+ // format as an integer
+ const tempInteger = args[++a];
+ if (typeof tempInteger === "bigint") {
+ tempStr = `${tempInteger}n`;
+ } else if (typeof tempInteger === "symbol") {
+ tempStr = "NaN";
+ } else {
+ tempStr = `${parseInt(tempInteger, 10)}`;
+ }
+ break;
+ case CHAR_LOWERCASE_F:
+ // format as a floating point value
+ const tempFloat = args[++a];
+ if (typeof tempFloat === "symbol") {
+ tempStr = "NaN";
+ } else {
+ tempStr = `${parseFloat(tempFloat)}`;
+ }
+ break;
+ case CHAR_LOWERCASE_O:
+ case CHAR_UPPERCASE_O:
+ // format as an object
+ tempStr = stringify(
+ args[++a],
+ // tslint:disable-next-line:no-any
+ new Set<any>(),
+ 0,
+ // tslint:disable-next-line:triple-equals
+ options.depth != undefined ? options.depth : DEFAULT_MAX_DEPTH
+ );
+ break;
+ case CHAR_PERCENT:
+ str += first.slice(lastPos, i);
+ lastPos = i + 1;
+ continue;
+ case CHAR_LOWERCASE_C:
+ // TODO: applies CSS style rules to the output string as specified
+ continue;
+ default:
+ // any other character is not a correct placeholder
+ continue;
+ }
+
+ if (lastPos !== i - 1) {
+ str += first.slice(lastPos, i - 1);
+ }
+
+ str += tempStr;
+ lastPos = i + 1;
+ } else if (nextChar === CHAR_PERCENT) {
+ str += first.slice(lastPos, i);
+ lastPos = i + 1;
+ }
+ }
+ }
+
+ if (lastPos !== 0) {
+ a++;
+ join = " ";
+ if (lastPos < first.length) {
+ str += first.slice(lastPos);
+ }
+ }
+ }
+
+ while (a < args.length) {
+ const value = args[a];
+ str += join;
+ if (typeof value === "string") {
+ str += value;
} else {
- out.push(
- // use default maximum depth for null or undefined argument
- stringify(
- a,
- // tslint:disable-next-line:no-any
- new Set<any>(),
- 0,
- // tslint:disable-next-line:triple-equals
- options.depth != undefined ? options.depth : DEFAULT_MAX_DEPTH
- )
+ // use default maximum depth for null or undefined argument
+ str += stringify(
+ value,
+ // tslint:disable-next-line:no-any
+ new Set<any>(),
+ 0,
+ // tslint:disable-next-line:triple-equals
+ options.depth != undefined ? options.depth : DEFAULT_MAX_DEPTH
);
}
+ join = " ";
+ a++;
}
- let outstr = out.join(" ");
+
+ const { collapsedAt, indentLevel } = options;
if (
!isCollapsed(collapsedAt, indentLevel) &&
indentLevel != null &&
indentLevel > 0
) {
const groupIndent = " ".repeat(indentLevel);
- if (outstr.indexOf("\n") !== -1) {
- outstr = outstr.replace(/\n/g, `\n${groupIndent}`);
+ if (str.indexOf("\n") !== -1) {
+ str = str.replace(/\n/g, `\n${groupIndent}`);
}
- outstr = groupIndent + outstr;
+ str = groupIndent + str;
}
- return outstr;
+
+ return str;
}
type PrintFunc = (x: string, isErr?: boolean, printsNewline?: boolean) => void;
diff --git a/js/console_test.ts b/js/console_test.ts
index 21116f7c5..46a349784 100644
--- a/js/console_test.ts
+++ b/js/console_test.ts
@@ -145,6 +145,80 @@ test(function consoleTestStringifyWithDepth() {
);
});
+test(function consoleTestWithIntegerFormatSpecifier() {
+ assertEqual(stringify("%i"), "%i");
+ assertEqual(stringify("%i", 42.0), "42");
+ assertEqual(stringify("%i", 42), "42");
+ assertEqual(stringify("%i", "42"), "42");
+ assertEqual(stringify("%i", "42.0"), "42");
+ assertEqual(stringify("%i", 1.5), "1");
+ assertEqual(stringify("%i", -0.5), "0");
+ assertEqual(stringify("%i", ""), "NaN");
+ assertEqual(stringify("%i", Symbol()), "NaN");
+ assertEqual(stringify("%i %d", 42, 43), "42 43");
+ assertEqual(stringify("%d %i", 42), "42 %i");
+ assertEqual(stringify("%d", 12345678901234567890123), "1");
+ assertEqual(
+ stringify("%i", 12345678901234567890123n),
+ "12345678901234567890123n"
+ );
+});
+
+test(function consoleTestWithFloatFormatSpecifier() {
+ assertEqual(stringify("%f"), "%f");
+ assertEqual(stringify("%f", 42.0), "42");
+ assertEqual(stringify("%f", 42), "42");
+ assertEqual(stringify("%f", "42"), "42");
+ assertEqual(stringify("%f", "42.0"), "42");
+ assertEqual(stringify("%f", 1.5), "1.5");
+ assertEqual(stringify("%f", -0.5), "-0.5");
+ assertEqual(stringify("%f", Math.PI), "3.141592653589793");
+ assertEqual(stringify("%f", ""), "NaN");
+ assertEqual(stringify("%f", Symbol("foo")), "NaN");
+ assertEqual(stringify("%f", 5n), "5");
+ assertEqual(stringify("%f %f", 42, 43), "42 43");
+ assertEqual(stringify("%f %f", 42), "42 %f");
+});
+
+test(function consoleTestWithStringFormatSpecifier() {
+ assertEqual(stringify("%s"), "%s");
+ assertEqual(stringify("%s", undefined), "undefined");
+ assertEqual(stringify("%s", "foo"), "foo");
+ assertEqual(stringify("%s", 42), "42");
+ assertEqual(stringify("%s", "42"), "42");
+ assertEqual(stringify("%s %s", 42, 43), "42 43");
+ assertEqual(stringify("%s %s", 42), "42 %s");
+ assertEqual(stringify("%s", Symbol("foo")), "Symbol(foo)");
+});
+
+test(function consoleTestWithObjectFormatSpecifier() {
+ assertEqual(stringify("%o"), "%o");
+ assertEqual(stringify("%o", 42), "42");
+ assertEqual(stringify("%o", "foo"), "foo");
+ assertEqual(stringify("o: %o, a: %O", {}, []), "o: {}, a: []");
+ assertEqual(stringify("%o", { a: 42 }), "{ a: 42 }");
+ assertEqual(
+ stringify("%o", { a: { b: { c: { d: new Set([1]) } } } }),
+ "{ a: { b: { c: { d: [Set] } } } }"
+ );
+});
+
+test(function consoleTestWithVariousOrInvalidFormatSpecifier() {
+ assertEqual(stringify("%s:%s"), "%s:%s");
+ assertEqual(stringify("%i:%i"), "%i:%i");
+ assertEqual(stringify("%d:%d"), "%d:%d");
+ assertEqual(stringify("%%s%s", "foo"), "%sfoo");
+ assertEqual(stringify("%s:%s", undefined), "undefined:%s");
+ assertEqual(stringify("%s:%s", "foo", "bar"), "foo:bar");
+ assertEqual(stringify("%s:%s", "foo", "bar", "baz"), "foo:bar baz");
+ assertEqual(stringify("%%%s%%", "hi"), "%hi%");
+ assertEqual(stringify("%d:%d", 12), "12:%d");
+ assertEqual(stringify("%i:%i", 12), "12:%i");
+ assertEqual(stringify("%f:%f", 12), "12:%f");
+ assertEqual(stringify("o: %o, a: %o", {}), "o: {}, a: %o");
+ assertEqual(stringify("abc%", 1), "abc% 1");
+});
+
test(function consoleTestCallToStringOnLabel() {
const methods = ["count", "countReset", "time", "timeLog", "timeEnd"];