豆豆友情提示:这是一个非官方 GitHub 代理镜像,主要用于网络测试或访问加速。请勿在此进行登录、注册或处理任何敏感信息。进行这些操作请务必访问官方网站 github.com。 Raw 内容也通过此代理提供。
Skip to content

Commit d459266

Browse files
authored
chore: refactor ConsoleFormatter construction (#896)
This PR shuffles code around in `ConsoleFormatter` so the data flow is more clear and flexible. Instead of augmenting an existing instance via `#loadDetailedData` we pass the detailed data (if needed) via constructor. The overall public API stays exactly the same, only the internal implementation changed. This also makes it trivial to inject "resolved arguments for testing", which we'll need to test `SymbolizedError` instances as part of `resolvedArgs`. Drive-by: Make options and message ID mandatory. All call-sites already passed these so its a no-op to tighten the type here and we can simplify toString() a bit.
1 parent 8228fbf commit d459266

File tree

1 file changed

+74
-92
lines changed

1 file changed

+74
-92
lines changed

src/formatters/ConsoleFormatter.ts

Lines changed: 74 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -15,61 +15,68 @@ import type {ConsoleMessage} from '../third_party/index.js';
1515

1616
export interface ConsoleFormatterOptions {
1717
fetchDetailedData?: boolean;
18-
id?: number;
18+
id: number;
1919
devTools?: TargetUniverse;
20+
resolvedArgsForTesting?: unknown[];
2021
resolvedStackTraceForTesting?: DevTools.DevTools.StackTrace.StackTrace.StackTrace;
2122
}
2223

2324
export class ConsoleFormatter {
24-
#msg: ConsoleMessage | SymbolizedError;
25-
#resolvedArgs: unknown[] = [];
26-
#resolvedStackTrace?: DevTools.DevTools.StackTrace.StackTrace.StackTrace;
27-
#id?: number;
28-
29-
private constructor(
30-
msg: ConsoleMessage | SymbolizedError,
31-
options?: ConsoleFormatterOptions,
32-
) {
33-
this.#msg = msg;
34-
this.#id = options?.id;
35-
this.#resolvedStackTrace = options?.resolvedStackTraceForTesting;
25+
readonly #id: number;
26+
readonly #type: string;
27+
readonly #text: string;
28+
29+
readonly #argCount: number;
30+
readonly #resolvedArgs: unknown[];
31+
32+
readonly #stack?: DevTools.DevTools.StackTrace.StackTrace.StackTrace;
33+
readonly #cause?: SymbolizedError; // eslint-disable-line no-unused-private-class-members
34+
35+
private constructor(params: {
36+
id: number;
37+
type: string;
38+
text: string;
39+
argCount?: number;
40+
resolvedArgs?: unknown[];
41+
stack?: DevTools.DevTools.StackTrace.StackTrace.StackTrace;
42+
cause?: SymbolizedError;
43+
}) {
44+
this.#id = params.id;
45+
this.#type = params.type;
46+
this.#text = params.text;
47+
this.#argCount = params.argCount ?? 0;
48+
this.#resolvedArgs = params.resolvedArgs ?? [];
49+
this.#stack = params.stack;
50+
this.#cause = params.cause;
3651
}
3752

3853
static async from(
3954
msg: ConsoleMessage | UncaughtError,
40-
options?: ConsoleFormatterOptions,
55+
options: ConsoleFormatterOptions,
4156
): Promise<ConsoleFormatter> {
4257
if (msg instanceof UncaughtError) {
43-
return new ConsoleFormatter(
44-
await SymbolizedError.fromDetails({
45-
devTools: options?.devTools,
46-
details: msg.details,
47-
targetId: msg.targetId,
48-
includeStackAndCause: options?.fetchDetailedData,
49-
resolvedStackTraceForTesting: options?.resolvedStackTraceForTesting,
50-
}),
51-
options,
52-
);
58+
const error = await SymbolizedError.fromDetails({
59+
devTools: options?.devTools,
60+
details: msg.details,
61+
targetId: msg.targetId,
62+
includeStackAndCause: options?.fetchDetailedData,
63+
resolvedStackTraceForTesting: options?.resolvedStackTraceForTesting,
64+
});
65+
return new ConsoleFormatter({
66+
id: options.id,
67+
type: 'error',
68+
text: error.message,
69+
stack: error.stackTrace,
70+
cause: error.cause,
71+
});
5372
}
5473

55-
const formatter = new ConsoleFormatter(msg, options);
56-
if (options?.fetchDetailedData) {
57-
await formatter.#loadDetailedData(options?.devTools);
58-
}
59-
return formatter;
60-
}
61-
62-
#isConsoleMessage(
63-
msg: ConsoleMessage | SymbolizedError,
64-
): msg is ConsoleMessage {
65-
// No `instanceof` as tests mock `ConsoleMessage`.
66-
return 'args' in msg && typeof msg.args === 'function';
67-
}
68-
69-
async #loadDetailedData(devTools?: TargetUniverse): Promise<void> {
70-
if (this.#isConsoleMessage(this.#msg)) {
71-
this.#resolvedArgs = await Promise.all(
72-
this.#msg.args().map(async (arg, i) => {
74+
let resolvedArgs: unknown[] = [];
75+
if (options.resolvedArgsForTesting) {
76+
resolvedArgs = options.resolvedArgsForTesting;
77+
} else if (options.fetchDetailedData) {
78+
resolvedArgs = await Promise.all(
79+
msg.args().map(async (arg, i) => {
7380
try {
7481
return await arg.jsonValue();
7582
} catch {
@@ -79,80 +86,55 @@ export class ConsoleFormatter {
7986
);
8087
}
8188

82-
if (devTools) {
89+
let stack: DevTools.DevTools.StackTrace.StackTrace.StackTrace | undefined;
90+
if (options.resolvedStackTraceForTesting) {
91+
stack = options.resolvedStackTraceForTesting;
92+
} else if (options.fetchDetailedData && options.devTools) {
8393
try {
84-
if (this.#isConsoleMessage(this.#msg)) {
85-
this.#resolvedStackTrace = await createStackTraceForConsoleMessage(
86-
devTools,
87-
this.#msg,
88-
);
89-
}
94+
stack = await createStackTraceForConsoleMessage(options.devTools, msg);
9095
} catch {
9196
// ignore
9297
}
9398
}
99+
100+
return new ConsoleFormatter({
101+
id: options.id,
102+
type: msg.type(),
103+
text: msg.text(),
104+
argCount: resolvedArgs.length || msg.args().length,
105+
resolvedArgs,
106+
stack,
107+
});
94108
}
95109

96110
// The short format for a console message.
97111
toString(): string {
98-
const type = this.#getType();
99-
const text = this.#getText();
100-
const argsCount = this.#getArgsCount();
101-
const idPart = this.#id !== undefined ? `msgid=${this.#id} ` : '';
102-
return `${idPart}[${type}] ${text} (${argsCount} args)`;
112+
return `msgid=${this.#id} [${this.#type}] ${this.#text} (${this.#argCount} args)`;
103113
}
104114

105115
// The verbose format for a console message, including all details.
106116
toStringDetailed(): string {
107117
const result = [
108-
this.#id !== undefined ? `ID: ${this.#id}` : '',
109-
`Message: ${this.#getType()}> ${this.#getText()}`,
118+
`ID: ${this.#id}`,
119+
`Message: ${this.#type}> ${this.#text}`,
110120
this.#formatArgs(),
111-
this.#formatStackTrace(
112-
this.#msg instanceof SymbolizedError
113-
? this.#msg.stackTrace
114-
: this.#resolvedStackTrace,
115-
),
121+
this.#formatStackTrace(this.#stack),
116122
].filter(line => !!line);
117123
return result.join('\n');
118124
}
119125

120-
#getType(): string {
121-
if (!this.#isConsoleMessage(this.#msg)) {
122-
return 'error';
123-
}
124-
return this.#msg.type();
125-
}
126-
127-
#getText(): string {
128-
if (!this.#isConsoleMessage(this.#msg)) {
129-
return this.#msg.message;
130-
}
131-
return this.#msg.text();
132-
}
133-
134126
#getArgs(): unknown[] {
135-
if (!this.#isConsoleMessage(this.#msg)) {
136-
return [];
137-
}
138127
if (this.#resolvedArgs.length > 0) {
139128
const args = [...this.#resolvedArgs];
140129
// If there is no text, the first argument serves as text (see formatMessage).
141-
if (!this.#msg.text()) {
130+
if (!this.#text) {
142131
args.shift();
143132
}
144133
return args;
145134
}
146135
return [];
147136
}
148137

149-
#getArgsCount(): number {
150-
if (!this.#isConsoleMessage(this.#msg)) {
151-
return 0;
152-
}
153-
return this.#resolvedArgs.length || this.#msg.args().length;
154-
}
155-
156138
#formatArg(arg: unknown) {
157139
return typeof arg === 'object' ? JSON.stringify(arg) : String(arg);
158140
}
@@ -215,22 +197,22 @@ export class ConsoleFormatter {
215197
}
216198
toJSON(): object {
217199
return {
218-
type: this.#getType(),
219-
text: this.#getText(),
220-
argsCount: this.#getArgsCount(),
200+
type: this.#type,
201+
text: this.#text,
202+
argsCount: this.#argCount,
221203
id: this.#id,
222204
};
223205
}
224206

225207
toJSONDetailed(): object {
226208
return {
227209
id: this.#id,
228-
type: this.#getType(),
229-
text: this.#getText(),
210+
type: this.#type,
211+
text: this.#text,
230212
args: this.#getArgs().map(arg =>
231213
typeof arg === 'object' ? arg : String(arg),
232214
),
233-
stackTrace: this.#resolvedStackTrace,
215+
stackTrace: this.#stack,
234216
};
235217
}
236218
}

0 commit comments

Comments
 (0)