From c4f6b56e503f5dd438b7deae2a2860e764f322c7 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Fri, 5 Jan 2024 10:29:04 +0100 Subject: [PATCH] feat(sourcemaps): Improve `sourcemaps resolve` command output (#1880) This PR makes two improvements to the sourcemaps resolve command output: - The PR changes the output line and column values from zero-indexed to one-indexed values. By switching to one-indexed values, the output line and column numbers use the same scale as the input values and follow the standard convention for line and column numbers in source code files. This change fixes the off-by-one error reported in Source mapping is offset when using switch statements #1863. - The output text has been restructured and clarified to indicate that the sourcemap resolver locates the closest token to the line and column input that the user provides. With this change, it should be clear to users that the source and minified file line/column locations reported in the output are the locations of this nearest token that the sourcemap resolver locates. This change is specifically intended to help avoid confusion in cases where the nearest token may in a different location (perhaps even, on a different line) than the search location provided in the user's input. Fixes GH-1863 --- src/commands/sourcemaps/resolve.rs | 81 ++++++++++++++----- .../sourcemaps/sourcemaps-resolve.trycmd | 17 ++-- 2 files changed, 71 insertions(+), 27 deletions(-) diff --git a/src/commands/sourcemaps/resolve.rs b/src/commands/sourcemaps/resolve.rs index 244b49dd66..71e5d727c2 100644 --- a/src/commands/sourcemaps/resolve.rs +++ b/src/commands/sourcemaps/resolve.rs @@ -1,3 +1,4 @@ +use std::cmp; use std::fs; use std::path::PathBuf; @@ -73,28 +74,65 @@ pub fn print_source(token: &Token<'_>, view: &SourceView) { } } +fn dst_location(token: &Token) -> (u32, u32) { + (token.get_dst_line() + 1, token.get_dst_col() + 1) +} + +fn src_location(token: &Token) -> (u32, u32) { + (token.get_src_line() + 1, token.get_src_col() + 1) +} + +fn as_string_len(to_string: T) -> usize { + to_string.to_string().len() +} + fn print_token(token: &Token<'_>) { - if let Some(name) = token.get_name() { - println!(" name: {name:?}"); - } else { - println!(" name: not found"); - } - if let Some(source) = token.get_source() { - println!(" source file: {source:?}"); - } else { - println!(" source file: not found"); - } - println!(" source line: {}", token.get_src_line()); - println!(" source column: {}", token.get_src_col()); - println!(" minified line: {}", token.get_dst_line()); - println!(" minified column: {}", token.get_dst_col()); + let token_display_name = match token.get_name() { + Some(name) => format!("token \"{name}\""), + None => String::from("token (unnamed)"), + }; + let source_file = match token.get_source() { + Some(file) => format!("{file:>4}"), + None => String::from("(unknown path)"), + }; + + let (dst_line, dst_col) = dst_location(token); + let [dst_line_digits, dst_col_digits] = [dst_line, dst_col].map(as_string_len); + + let (src_line, src_col) = src_location(token); + let [src_line_digits, src_col_digits] = [src_line, src_col].map(as_string_len); + + let line_align = cmp::max(dst_line_digits, src_line_digits); + let col_align = cmp::max(dst_col_digits, src_col_digits); + + let output_minified_line = format!( + "Found the nearest {token_display_name} at line {:>line_align$}, column {:>col_align$} in the minified file.", + dst_line, + dst_col, + ); + + let output_source_line = format!( + "- The same token is located at line {:>line_align$}, column {:>col_align$} in source file {}.", + src_line, + src_col, + source_file, + ); + + let output_minified_line_align = 2 + output_minified_line.len(); + let output_source_line_align = output_minified_line.len() + source_file.len() - 3; + + println!("{output_minified_line:>output_minified_line_align$}"); + println!(); + println!("{output_source_line:>output_source_line_align$}"); + println!("\n"); + if let Some(view) = token.get_source_view() { - println!(" source code:"); + println!(" Source code:"); print_source(token, view); } else if token.get_source_view().is_none() { - println!(" cannot find source"); + println!(" Cannot find source"); } else { - println!(" cannot find source line"); + println!(" Cannot find source line"); } } @@ -112,14 +150,19 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { }; println!("source map path: {sourcemap_path:?}"); println!("source map type: {ty}"); + println!(); // perform a lookup if let Some((line, column)) = lookup_pos(matches) { - println!("lookup line: {line}, column: {column}:"); + println!( + "Searching for token nearest to line {}, column {} in the minified file:\n", + line + 1, + column + 1 + ); if let Some(token) = sm.lookup_token(line, column) { print_token(&token); } else { - println!(" - no match"); + println!(" - no token found!"); } } diff --git a/tests/integration/_cases/sourcemaps/sourcemaps-resolve.trycmd b/tests/integration/_cases/sourcemaps/sourcemaps-resolve.trycmd index d053c0559c..35b116a929 100644 --- a/tests/integration/_cases/sourcemaps/sourcemaps-resolve.trycmd +++ b/tests/integration/_cases/sourcemaps/sourcemaps-resolve.trycmd @@ -3,14 +3,15 @@ $ sentry-cli sourcemaps resolve tests/integration/_fixtures/bundle.min.js.map -l ? success source map path: "tests/integration/_fixtures/bundle.min.js.map" source map type: regular -lookup line: 0, column: 39: - name: "bar" - source file: "webpack://webpack-plugin/./src/app.js" - source line: 1 - source column: 2 - minified line: 0 - minified column: 39 - source code: + +Searching for token nearest to line 1, column 40 in the minified file: + + Found the nearest token "bar" at line 1, column 40 in the minified file. + + - The same token is located at line 2, column 3 in source file webpack://webpack-plugin/./src/app.js. + + + Source code: function foo(msg) { bar(msg); }