blob: e08fc445e110f5a374fab80bcc903135b2d1ad42 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
// tslint:disable-next-line:no-any
type ConsoleContext = Set<any>;
// tslint:disable-next-line:no-any
function getClassInstanceName(instance: any): string {
if (typeof instance !== "object") {
return "";
}
if (instance && instance.__proto__ && instance.__proto__.constructor) {
return instance.__proto__.constructor.name; // could be "Object" or "Array"
}
return "";
}
// tslint:disable-next-line:no-any
function stringify(ctx: ConsoleContext, value: any): string {
switch (typeof value) {
case "string":
return value;
case "number":
case "boolean":
case "undefined":
case "symbol":
return String(value);
case "function":
if (value.name && value.name !== "anonymous") {
// from MDN spec
return `[Function: ${value.name}]`;
}
return "[Function]";
case "object":
if (value === null) {
return "null";
}
if (ctx.has(value)) {
return "[Circular]";
}
ctx.add(value);
const entries: string[] = [];
if (Array.isArray(value)) {
for (const el of value) {
entries.push(stringifyWithQuotes(ctx, el));
}
ctx.delete(value);
if (entries.length === 0) {
return "[]";
}
return `[ ${entries.join(", ")} ]`;
} else {
let baseString = "";
const className = getClassInstanceName(value);
let shouldShowClassName = false;
if (className && className !== "Object" && className !== "anonymous") {
shouldShowClassName = true;
}
for (const key of Object.keys(value)) {
entries.push(`${key}: ${stringifyWithQuotes(ctx, value[key])}`);
}
ctx.delete(value);
if (entries.length === 0) {
baseString = "{}";
} else {
baseString = `{ ${entries.join(", ")} }`;
}
if (shouldShowClassName) {
baseString = `${className} ${baseString}`;
}
return baseString;
}
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 {
switch (typeof value) {
case "string":
return `"${value}"`;
default:
return stringify(ctx, value);
}
}
// tslint:disable-next-line:no-any
export function stringifyArgs(args: any[]): 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));
}
}
return out.join(" ");
}
type PrintFunc = (x: string) => void;
export class Console {
constructor(private printFunc: PrintFunc) {}
// tslint:disable-next-line:no-any
log(...args: any[]): void {
this.printFunc(stringifyArgs(args));
}
debug = this.log;
info = this.log;
// tslint:disable-next-line:no-any
warn(...args: any[]): void {
// TODO Log to stderr.
this.printFunc(stringifyArgs(args));
}
error = this.warn;
// tslint:disable-next-line:no-any
assert(condition: boolean, ...args: any[]): void {
if (!condition) {
throw new Error(`Assertion failed: ${stringifyArgs(args)}`);
}
}
}
|