Skip to content

Commit ea56c53

Browse files
bartlomiejuclaude
andcommitted
refactor: move location after snippet, clean up token descriptions
- Location line now appears after the code snippet instead of before - String literal token descriptions simplified (e.g. 'string literal ("./foo.js", "./foo.js")' -> "./foo.js") Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent c5c99f4 commit ea56c53

File tree

2 files changed

+37
-11
lines changed

2 files changed

+37
-11
lines changed

src/graph.rs

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -562,21 +562,48 @@ impl std::error::Error for ModuleErrorKind {
562562
}
563563
}
564564

565+
/// Cleans up SWC token descriptions in error messages.
566+
/// e.g. `'string literal ("./foo.js", "./foo.js")'` -> `"./foo.js"`
567+
fn clean_parse_message(message: &str) -> String {
568+
// Replace `'string literal ("{value}", "{value}")'` with `"{value}"`
569+
let mut result = message.to_string();
570+
while let Some(start) = result.find("'string literal (\"") {
571+
let after = &result[start + 18..]; // skip `'string literal ("`
572+
if let Some(quote_end) = after.find('"') {
573+
let value = &after[..quote_end];
574+
// Find the closing `)'`
575+
if let Some(end) = result[start..].find(")'") {
576+
let full_end = start + end + 2;
577+
result = format!(
578+
"{}\"{}\"{}",
579+
&result[..start],
580+
value,
581+
&result[full_end..]
582+
);
583+
continue;
584+
}
585+
}
586+
break;
587+
}
588+
result
589+
}
590+
565591
/// Reformats a parse diagnostic message into a nicer format with
566-
/// `-->` location arrows, line numbers, and carets.
592+
/// line numbers and carets, with the location shown after the snippet.
567593
///
568594
/// Input format (from ParseDiagnostic::Display):
569595
/// `{message} at {specifier}:{line}:{col}\n\n {source_line}\n {underline}`
570596
///
571597
/// Output format:
572-
/// `{message}\n at {specifier}:{line}:{col}\n\n {line_num} | {source_line}\n {carets}`
598+
/// `{message}\n |\nN | {source_line}\n | {carets}\n at {location}`
573599
fn format_parse_diagnostic(
574600
f: &mut fmt::Formatter<'_>,
575601
diagnostic: &str,
576602
) -> fmt::Result {
577603
// Try to parse the diagnostic format: "{message} at {location}\n\n {snippet}"
578604
if let Some(at_pos) = diagnostic.find(" at ") {
579-
let message = &diagnostic[..at_pos];
605+
let raw_message = &diagnostic[..at_pos];
606+
let message = clean_parse_message(raw_message);
580607

581608
// Find the end of the location line (first newline after " at ")
582609
let after_at = &diagnostic[at_pos + 4..];
@@ -593,7 +620,7 @@ fn format_parse_diagnostic(
593620
.nth(1)
594621
.and_then(|s| s.parse::<usize>().ok());
595622

596-
write!(f, "{message}\n at {location}")?;
623+
write!(f, "{message}")?;
597624

598625
if !rest.is_empty() {
599626
// The rest contains the source snippet, indented with " "
@@ -622,9 +649,7 @@ fn format_parse_diagnostic(
622649
let padding = " ".repeat(num_str.len());
623650
writeln!(f, "{padding} |")?;
624651
writeln!(f, "{num_str} | {src}")?;
625-
// Calculate indent: we need to align the underline under the source
626-
// The underline in the original starts at the same column as the
627-
// source, so we need to figure out the offset
652+
// Calculate indent: align the underline under the source
628653
let src_start = source_line
629654
.and_then(|s| {
630655
lines
@@ -641,13 +666,12 @@ fn format_parse_diagnostic(
641666
.map(|l| l.len() - l.trim_start().len())
642667
})
643668
.unwrap_or(2);
644-
// The offset of the underline relative to the source
645669
let offset = if ul_start >= src_start {
646670
ul_start - src_start
647671
} else {
648672
0
649673
};
650-
write!(
674+
writeln!(
651675
f,
652676
"{padding} | {}{}",
653677
" ".repeat(offset),
@@ -656,11 +680,13 @@ fn format_parse_diagnostic(
656680
} else {
657681
writeln!(f)?;
658682
writeln!(f, " {src}")?;
659-
write!(f, " {ul}")?;
683+
writeln!(f, " {ul}")?;
660684
}
661685
}
662686
}
663687

688+
write!(f, " at {location}")?;
689+
664690
Ok(())
665691
} else {
666692
// Fallback: just write the diagnostic as-is

tests/specs/graph/cjs/file_export.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export class Test {}
1212
"modules": [
1313
{
1414
"specifier": "file:///file.cjs",
15-
"error": "'import', and 'export' cannot be used outside of module code\n at file:///file.cjs:1:1\n |\n1 | export class Test {}\n | ~~~~~~"
15+
"error": "'import', and 'export' cannot be used outside of module code\n |\n1 | export class Test {}\n | ~~~~~~\n at file:///file.cjs:1:1"
1616
},
1717
{
1818
"kind": "esm",

0 commit comments

Comments
 (0)