@@ -252,6 +252,7 @@ struct StackEntry {
252
252
function_name : String ,
253
253
file_name : String ,
254
254
line_number : Option < u32 > ,
255
+ column_number : Option < u32 > ,
255
256
}
256
257
257
258
impl FromStr for StackEntry {
@@ -270,24 +271,20 @@ impl FromStr for StackEntry {
270
271
if file_name. ends_with ( ')' ) {
271
272
file_name = file_name. as_str ( ) [ ..file_name. len ( ) - 1 ] . to_string ( ) ;
272
273
}
274
+ file_name = file_name. replace ( "://" , "_double_point_placeholder_//" ) ;
273
275
274
- let mut line_number = None ;
276
+ let parts : Vec < & str > = file_name . split ( ':' ) . collect ( ) ;
275
277
276
- if let Some ( i) = file_name. rfind ( ':' ) {
277
- let line_num_part = & file_name. as_str ( ) [ i..] ;
278
-
279
- line_number = match line_num_part. parse :: < u32 > ( ) {
280
- Ok ( num) => {
281
- file_name = file_name. as_str ( ) [ ..i - 1 ] . to_string ( ) ;
282
- Some ( num)
283
- }
284
- Err ( _) => None ,
285
- } ;
286
- }
278
+ let file_name = parts[ 0 ]
279
+ . to_string ( )
280
+ . replace ( "_double_point_placeholder_//" , "://" ) ;
281
+ let line_number = parts. get ( 1 ) . and_then ( |s| s. parse :: < u32 > ( ) . ok ( ) ) ;
282
+ let column_number = parts. get ( 2 ) . and_then ( |s| s. parse :: < u32 > ( ) . ok ( ) ) ;
287
283
288
284
Ok ( StackEntry {
289
285
function_name,
290
286
file_name,
287
+ column_number,
291
288
line_number,
292
289
} )
293
290
}
@@ -308,14 +305,17 @@ fn serialize_stack(entries: &[StackEntry]) -> String {
308
305
let mut result = String :: new ( ) ;
309
306
310
307
for entry in entries {
311
- result. push_str ( & format ! (
312
- " at {} ({})" ,
313
- entry. function_name, entry. file_name
314
- ) ) ;
308
+ let fname_lnum = if let Some ( line_number) = entry. line_number {
309
+ if let Some ( column_number) = entry. column_number {
310
+ format ! ( "{}:{line_number}:{column_number}" , entry. file_name)
311
+ } else {
312
+ format ! ( "{}:{line_number}" , entry. file_name)
313
+ }
314
+ } else {
315
+ entry. file_name . clone ( )
316
+ } ;
315
317
316
- if let Some ( line_number) = entry. line_number {
317
- result. push_str ( & format ! ( ":{}" , line_number) ) ;
318
- }
318
+ result. push_str ( & format ! ( " at {} ({fname_lnum})" , entry. function_name) ) ;
319
319
320
320
result. push ( '\n' ) ;
321
321
}
@@ -329,35 +329,49 @@ pub(crate) fn unmap_stack_trace(stack_trace: &str) -> String {
329
329
}
330
330
331
331
pub fn fix_stack_trace ( stack_trace : & str , maps : & HashMap < String , String > ) -> String {
332
+ log:: trace!( "fix_stack_trace:\n {stack_trace}" ) ;
332
333
match parse_stack_trace ( stack_trace) {
333
334
Ok ( mut parsed_stack) => {
334
335
for stack_trace_entry in parsed_stack. iter_mut ( ) {
335
336
if let Some ( map_str) = maps. get ( stack_trace_entry. file_name . as_str ( ) ) {
337
+ log:: trace!(
338
+ "fix_stack_trace:found map for file {}:\n {map_str}" ,
339
+ stack_trace_entry. file_name. as_str( )
340
+ ) ;
336
341
if let Some ( line_number) = stack_trace_entry. line_number {
342
+ log:: trace!( "lookup line number:{line_number}" ) ;
337
343
match swc:: sourcemap:: SourceMap :: from_reader ( io:: Cursor :: new ( map_str) ) {
338
344
Ok ( source_map) => {
339
- if let Some ( original_location) =
340
- source_map. lookup_token ( line_number, 0 )
341
- {
345
+ if let Some ( original_location) = source_map. lookup_token (
346
+ line_number,
347
+ stack_trace_entry. column_number . unwrap_or ( 1 ) ,
348
+ ) {
342
349
let original_line = original_location. get_src_line ( ) ;
350
+ let original_column = original_location. get_src_col ( ) ;
351
+ log:: trace!( "lookup original_line:{original_line}" ) ;
343
352
stack_trace_entry. line_number = Some ( original_line) ;
353
+ stack_trace_entry. column_number = Some ( original_column) ;
344
354
}
345
355
}
346
356
Err ( _) => {
347
- log:: debug !(
357
+ log:: trace !(
348
358
"could not parse source_map for {}" ,
349
359
stack_trace_entry. file_name. as_str( )
350
360
) ;
351
361
}
352
362
}
353
363
}
364
+ } else {
365
+ log:: trace!( "no map found for {}" , stack_trace_entry. file_name. as_str( ) ) ;
354
366
}
355
367
356
368
// Now you have the original filename and line number
357
369
// You can use them as needed
358
370
}
359
371
360
- serialize_stack ( & parsed_stack)
372
+ let ret = serialize_stack ( & parsed_stack) ;
373
+ log:: trace!( "fix_stack_trace ret:\n {ret}" ) ;
374
+ ret
361
375
}
362
376
Err ( _) => {
363
377
log:: error!( "could not parse stack: \n {}" , stack_trace) ;
@@ -393,7 +407,7 @@ pub mod tests {
393
407
}
394
408
#[ test]
395
409
fn test_stack_map ( ) {
396
- let rt = QuickJsRuntimeBuilder :: new ( ) . build ( ) ;
410
+ let rt = init_test_rt ( ) ;
397
411
println ! ( "testing ts" ) ;
398
412
let script = Script :: new (
399
413
"test.ts" ,
@@ -406,8 +420,9 @@ pub mod tests {
406
420
function t_ts(a: string, b: num): boolean {
407
421
return a.a.a === "hi";
408
422
}
423
+
409
424
t_ts("hello", 1337);
410
- "#,
425
+ "# ,
411
426
) ;
412
427
let _res = rt
413
428
. eval_sync ( None , script)
@@ -418,12 +433,28 @@ pub mod tests {
418
433
}
419
434
#[ test]
420
435
fn test_stack_parse ( ) {
436
+ // just to init logging;
437
+ let _rt = init_test_rt ( ) ;
438
+
421
439
let stack = r#"
422
- at func (file.ts:88)
440
+ at func (file.ts:88:12 )
423
441
at doWriteTransactioned (gcsproject:///gcs_objectstore/ObjectStore.ts:170)
424
442
"# ;
425
443
match parse_stack_trace ( stack) {
426
444
Ok ( a) => {
445
+ assert_eq ! ( a[ 0 ] . file_name, "file.ts" ) ;
446
+ assert_eq ! ( a[ 0 ] . line_number, Some ( 88 ) ) ;
447
+ assert_eq ! ( a[ 0 ] . column_number, Some ( 12 ) ) ;
448
+ assert_eq ! ( a[ 0 ] . function_name, "func" ) ;
449
+
450
+ assert_eq ! (
451
+ a[ 1 ] . file_name,
452
+ "gcsproject:///gcs_objectstore/ObjectStore.ts"
453
+ ) ;
454
+ assert_eq ! ( a[ 1 ] . line_number, Some ( 170 ) ) ;
455
+ assert_eq ! ( a[ 1 ] . column_number, None ) ;
456
+ assert_eq ! ( a[ 1 ] . function_name, "doWriteTransactioned" ) ;
457
+
427
458
assert_eq ! (
428
459
serialize_stack( & a) . as_str( ) ,
429
460
r#" at func (file.ts:88)
0 commit comments