@@ -15,86 +15,92 @@ import type {ConsoleMessage} from '../third_party/index.js';
1515
1616export interface ConsoleFormatterOptions {
1717 fetchDetailedData ?: boolean ;
18- id ? : number ;
18+ id : number ;
1919 devTools ?: TargetUniverse ;
2020 resolvedStackTraceForTesting ?: DevTools . DevTools . StackTrace . StackTrace . StackTrace ;
2121}
2222
23+ export interface FormattableMessage {
24+ type : string ;
25+ text : string ;
26+ argsCount : number ;
27+
28+ // Present when details are fetched.
29+ args : unknown [ ] ;
30+ stackTrace ?: DevTools . DevTools . StackTrace . StackTrace . StackTrace ;
31+ }
32+
2333export class ConsoleFormatter {
24- #msg: ConsoleMessage | Error | UncaughtError ;
25- #resolvedArgs: unknown [ ] = [ ] ;
26- #resolvedStackTrace?: DevTools . DevTools . StackTrace . StackTrace . StackTrace ;
27- #id?: number ;
34+ readonly #id: number ;
35+ readonly #msg: FormattableMessage ;
2836
29- private constructor (
30- msg : ConsoleMessage | Error | UncaughtError ,
31- options ?: ConsoleFormatterOptions ,
32- ) {
37+ constructor ( id : number , msg : FormattableMessage ) {
38+ this . #id = id ;
3339 this . #msg = msg ;
34- this . #id = options ?. id ;
35- this . #resolvedStackTrace = options ?. resolvedStackTraceForTesting ;
3640 }
3741
3842 static async from (
39- msg : ConsoleMessage | Error | UncaughtError ,
40- options ? : ConsoleFormatterOptions ,
43+ message : ConsoleMessage | Error | UncaughtError ,
44+ options : ConsoleFormatterOptions ,
4145 ) : Promise < ConsoleFormatter > {
42- const formatter = new ConsoleFormatter ( msg , options ) ;
43- if ( options ?. fetchDetailedData ) {
44- await formatter . #loadDetailedData( options ?. devTools ) ;
46+ if ( ConsoleFormatter . #isConsoleMessage( message ) ) {
47+ const msg : FormattableMessage = {
48+ type : message . type ( ) ,
49+ text : message . text ( ) ,
50+ argsCount : message . args ( ) . length ,
51+ args : [ ] ,
52+ } ;
53+ if ( options . fetchDetailedData ) {
54+ msg . args = await Promise . all (
55+ message . args ( ) . map ( async ( arg , i ) => {
56+ try {
57+ return await arg . jsonValue ( ) ;
58+ } catch {
59+ return `<error: Argument ${ i } is no longer available>` ;
60+ }
61+ } ) ,
62+ ) ;
63+ if ( options . devTools ) {
64+ msg . stackTrace = await createStackTraceForConsoleMessage (
65+ options . devTools ,
66+ message ,
67+ ) ;
68+ }
69+ }
70+ return new ConsoleFormatter ( options . id , msg ) ;
4571 }
46- return formatter ;
72+
73+ const msg : FormattableMessage = {
74+ type : 'error' ,
75+ text : message . message ,
76+ argsCount : 0 ,
77+ args : [ ] ,
78+ } ;
79+ if (
80+ options . fetchDetailedData &&
81+ options . devTools &&
82+ 'stackTrace' in message &&
83+ message . stackTrace
84+ ) {
85+ msg . stackTrace = await createStackTrace (
86+ options . devTools ,
87+ message . stackTrace ,
88+ message . targetId ,
89+ ) ;
90+ }
91+ return new ConsoleFormatter ( options . id , msg ) ;
4792 }
4893
49- #isConsoleMessage(
94+ static #isConsoleMessage(
5095 msg : ConsoleMessage | Error | UncaughtError ,
5196 ) : msg is ConsoleMessage {
5297 // No `instanceof` as tests mock `ConsoleMessage`.
5398 return 'args' in msg && typeof msg . args === 'function' ;
5499 }
55100
56- async #loadDetailedData( devTools ?: TargetUniverse ) : Promise < void > {
57- if ( this . #msg instanceof Error ) {
58- return ;
59- }
60-
61- if ( this . #isConsoleMessage( this . #msg) ) {
62- this . #resolvedArgs = await Promise . all (
63- this . #msg. args ( ) . map ( async ( arg , i ) => {
64- try {
65- return await arg . jsonValue ( ) ;
66- } catch {
67- return `<error: Argument ${ i } is no longer available>` ;
68- }
69- } ) ,
70- ) ;
71- }
72-
73- if ( devTools ) {
74- try {
75- if ( this . #isConsoleMessage( this . #msg) ) {
76- this . #resolvedStackTrace = await createStackTraceForConsoleMessage (
77- devTools ,
78- this . #msg,
79- ) ;
80- } else if ( this . #msg. stackTrace ) {
81- this . #resolvedStackTrace = await createStackTrace (
82- devTools ,
83- this . #msg. stackTrace ,
84- this . #msg. targetId ,
85- ) ;
86- }
87- } catch {
88- // ignore
89- }
90- }
91- }
92-
93101 // The short format for a console message.
94102 toString ( ) : string {
95- const type = this . #getType( ) ;
96- const text = this . #getText( ) ;
97- const argsCount = this . #getArgsCount( ) ;
103+ const { type, text, argsCount} = this . #msg;
98104 const idPart = this . #id !== undefined ? `msgid=${ this . #id} ` : '' ;
99105 return `${ idPart } [${ type } ] ${ text } (${ argsCount } args)` ;
100106 }
@@ -103,49 +109,25 @@ export class ConsoleFormatter {
103109 toStringDetailed ( ) : string {
104110 const result = [
105111 this . #id !== undefined ? `ID: ${ this . #id} ` : '' ,
106- `Message: ${ this . #getType ( ) } > ${ this . #getText ( ) } ` ,
112+ `Message: ${ this . #msg . type } > ${ this . #msg . text } ` ,
107113 this . #formatArgs( ) ,
108- this . #formatStackTrace( this . #resolvedStackTrace ) ,
114+ this . #formatStackTrace( this . #msg . stackTrace ) ,
109115 ] . filter ( line => ! ! line ) ;
110116 return result . join ( '\n' ) ;
111117 }
112118
113- #getType( ) : string {
114- if ( ! this . #isConsoleMessage( this . #msg) ) {
115- return 'error' ;
116- }
117- return this . #msg. type ( ) ;
118- }
119-
120- #getText( ) : string {
121- if ( ! this . #isConsoleMessage( this . #msg) ) {
122- return this . #msg. message ;
123- }
124- return this . #msg. text ( ) ;
125- }
126-
127119 #getArgs( ) : unknown [ ] {
128- if ( ! this . #isConsoleMessage( this . #msg) ) {
129- return [ ] ;
130- }
131- if ( this . #resolvedArgs. length > 0 ) {
132- const args = [ ...this . #resolvedArgs] ;
120+ if ( this . #msg. args . length > 0 ) {
121+ const args = [ ...this . #msg. args ] ;
133122 // If there is no text, the first argument serves as text (see formatMessage).
134- if ( ! this . #msg. text ( ) ) {
123+ if ( ! this . #msg. text ) {
135124 args . shift ( ) ;
136125 }
137126 return args ;
138127 }
139128 return [ ] ;
140129 }
141130
142- #getArgsCount( ) : number {
143- if ( ! this . #isConsoleMessage( this . #msg) ) {
144- return 0 ;
145- }
146- return this . #resolvedArgs. length || this . #msg. args ( ) . length ;
147- }
148-
149131 #formatArg( arg : unknown ) {
150132 return typeof arg === 'object' ? JSON . stringify ( arg ) : String ( arg ) ;
151133 }
@@ -208,22 +190,22 @@ export class ConsoleFormatter {
208190 }
209191 toJSON ( ) : object {
210192 return {
211- type : this . #getType ( ) ,
212- text : this . #getText ( ) ,
213- argsCount : this . #getArgsCount ( ) ,
193+ type : this . #msg . type ,
194+ text : this . #msg . text ,
195+ argsCount : this . #msg . argsCount ,
214196 id : this . #id,
215197 } ;
216198 }
217199
218200 toJSONDetailed ( ) : object {
219201 return {
220202 id : this . #id,
221- type : this . #getType ( ) ,
222- text : this . #getText ( ) ,
203+ type : this . #msg . type ,
204+ text : this . #msg . text ,
223205 args : this . #getArgs( ) . map ( arg =>
224206 typeof arg === 'object' ? arg : String ( arg ) ,
225207 ) ,
226- stackTrace : this . #resolvedStackTrace ,
208+ stackTrace : this . #msg . stackTrace ,
227209 } ;
228210 }
229211}
0 commit comments