Skip to content

Commit 2d83b88

Browse files
fixed stacktrace parser to support col nums (for quickjs_ng)
1 parent 8e203fb commit 2d83b88

File tree

1 file changed

+58
-27
lines changed

1 file changed

+58
-27
lines changed

src/typescript/mod.rs

Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ struct StackEntry {
252252
function_name: String,
253253
file_name: String,
254254
line_number: Option<u32>,
255+
column_number: Option<u32>,
255256
}
256257

257258
impl FromStr for StackEntry {
@@ -270,24 +271,20 @@ impl FromStr for StackEntry {
270271
if file_name.ends_with(')') {
271272
file_name = file_name.as_str()[..file_name.len() - 1].to_string();
272273
}
274+
file_name = file_name.replace("://", "_double_point_placeholder_//");
273275

274-
let mut line_number = None;
276+
let parts: Vec<&str> = file_name.split(':').collect();
275277

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());
287283

288284
Ok(StackEntry {
289285
function_name,
290286
file_name,
287+
column_number,
291288
line_number,
292289
})
293290
}
@@ -308,14 +305,17 @@ fn serialize_stack(entries: &[StackEntry]) -> String {
308305
let mut result = String::new();
309306

310307
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+
};
315317

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));
319319

320320
result.push('\n');
321321
}
@@ -329,35 +329,49 @@ pub(crate) fn unmap_stack_trace(stack_trace: &str) -> String {
329329
}
330330

331331
pub fn fix_stack_trace(stack_trace: &str, maps: &HashMap<String, String>) -> String {
332+
log::trace!("fix_stack_trace:\n{stack_trace}");
332333
match parse_stack_trace(stack_trace) {
333334
Ok(mut parsed_stack) => {
334335
for stack_trace_entry in parsed_stack.iter_mut() {
335336
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+
);
336341
if let Some(line_number) = stack_trace_entry.line_number {
342+
log::trace!("lookup line number:{line_number}");
337343
match swc::sourcemap::SourceMap::from_reader(io::Cursor::new(map_str)) {
338344
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+
) {
342349
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}");
343352
stack_trace_entry.line_number = Some(original_line);
353+
stack_trace_entry.column_number = Some(original_column);
344354
}
345355
}
346356
Err(_) => {
347-
log::debug!(
357+
log::trace!(
348358
"could not parse source_map for {}",
349359
stack_trace_entry.file_name.as_str()
350360
);
351361
}
352362
}
353363
}
364+
} else {
365+
log::trace!("no map found for {}", stack_trace_entry.file_name.as_str());
354366
}
355367

356368
// Now you have the original filename and line number
357369
// You can use them as needed
358370
}
359371

360-
serialize_stack(&parsed_stack)
372+
let ret = serialize_stack(&parsed_stack);
373+
log::trace!("fix_stack_trace ret:\n{ret}");
374+
ret
361375
}
362376
Err(_) => {
363377
log::error!("could not parse stack: \n{}", stack_trace);
@@ -393,7 +407,7 @@ pub mod tests {
393407
}
394408
#[test]
395409
fn test_stack_map() {
396-
let rt = QuickJsRuntimeBuilder::new().build();
410+
let rt = init_test_rt();
397411
println!("testing ts");
398412
let script = Script::new(
399413
"test.ts",
@@ -406,8 +420,9 @@ pub mod tests {
406420
function t_ts(a: string, b: num): boolean {
407421
return a.a.a === "hi";
408422
}
423+
409424
t_ts("hello", 1337);
410-
"#,
425+
"#,
411426
);
412427
let _res = rt
413428
.eval_sync(None, script)
@@ -418,12 +433,28 @@ pub mod tests {
418433
}
419434
#[test]
420435
fn test_stack_parse() {
436+
// just to init logging;
437+
let _rt = init_test_rt();
438+
421439
let stack = r#"
422-
at func (file.ts:88)
440+
at func (file.ts:88:12)
423441
at doWriteTransactioned (gcsproject:///gcs_objectstore/ObjectStore.ts:170)
424442
"#;
425443
match parse_stack_trace(stack) {
426444
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+
427458
assert_eq!(
428459
serialize_stack(&a).as_str(),
429460
r#" at func (file.ts:88)

0 commit comments

Comments
 (0)