Skip to content

Commit c032825

Browse files
authored
fix(sourcemaps): Fix mismatches between path and URL on Windows (#2414)
Attempts to fix #2413
1 parent 5e5949c commit c032825

File tree

1 file changed

+50
-2
lines changed

1 file changed

+50
-2
lines changed

src/utils/sourcemaps/inject.rs

+50-2
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,11 @@ pub fn debug_id_from_bytes_hashed(bytes: &[u8]) -> DebugId {
230230
DebugId::from_uuid(uuid::Builder::from_sha1_bytes(sha1_bytes).into_uuid())
231231
}
232232

233+
/// Ensures paths are always separated by `/` even on Windows
234+
pub fn canonicalize_path_sep_to_unix(path: &str) -> String {
235+
path.replace(std::path::MAIN_SEPARATOR, "/")
236+
}
237+
233238
/// Computes a normalized sourcemap URL from a source file's own URL und the relative URL of its sourcemap.
234239
///
235240
/// Roughly, this will combine a source URL of `some/dir/source.js` and a sourcemap URL of `path/to/source.min.js`
@@ -238,7 +243,8 @@ pub fn debug_id_from_bytes_hashed(bytes: &[u8]) -> DebugId {
238243
///
239244
/// Leading `./` segments will be preserved.
240245
pub fn normalize_sourcemap_url(source_url: &str, sourcemap_url: &str) -> String {
241-
let base_url = source_url
246+
let canonicalized_source_url = canonicalize_path_sep_to_unix(source_url);
247+
let base_url = canonicalized_source_url
242248
.rsplit_once('/')
243249
.map(|(base, _)| base)
244250
.unwrap_or("");
@@ -249,7 +255,13 @@ pub fn normalize_sourcemap_url(source_url: &str, sourcemap_url: &str) -> String
249255
cutoff += 2;
250256
}
251257

252-
format!("{}{}", &joined[..cutoff], clean_path(&joined[cutoff..]))
258+
// At the end we do a split by MAIN_SEPARATOR as everything operates with `/` in the code but
259+
// `clean_path` and `join_path` uses the system separator.
260+
canonicalize_path_sep_to_unix(&format!(
261+
"{}{}",
262+
&joined[..cutoff],
263+
clean_path(&joined[cutoff..])
264+
))
253265
}
254266

255267
/// Returns a list of those paths among `candidate_paths` that differ from `expected_path` in
@@ -269,6 +281,7 @@ pub fn find_matching_paths(candidate_paths: &[String], expected_path: &str) -> V
269281
.split('/')
270282
.filter(|&segment| segment != ".")
271283
.peekable();
284+
272285
let mut candidate_segments = candidate
273286
.split('/')
274287
.filter(|&segment| segment != ".")
@@ -481,6 +494,41 @@ something else
481494

482495
#[test]
483496
fn test_normalize_sourcemap_url() {
497+
// TODO: Enable the following test and make it pass
498+
// Linux allows having `\` in a file name but our path helpers,
499+
// specifically `join_path` and `clean_path` from `symbolic::common`,
500+
// do not use `std::path::MAIN_SEPARATOR` and instead tries to guess
501+
// the path style by the existence of a `\` in the path. This is
502+
// problematic because it can lead to incorrect path normalization.
503+
// assert_eq!(
504+
// normalize_sourcemap_url("/foo/ba\\r/baz.js", "baz.js.map"),
505+
// "/foo/ba\\r/baz.js.map"
506+
// );
507+
508+
assert_eq!(
509+
normalize_sourcemap_url(
510+
&format!("foo{0}bar{0}baz.js", std::path::MAIN_SEPARATOR),
511+
&format!("..{0}.{0}baz.js.map", std::path::MAIN_SEPARATOR)
512+
),
513+
"foo/baz.js.map"
514+
);
515+
516+
assert_eq!(
517+
normalize_sourcemap_url(
518+
&format!("foo{0}bar{0}baz.js", std::path::MAIN_SEPARATOR),
519+
".././baz.js.map"
520+
),
521+
"foo/baz.js.map"
522+
);
523+
524+
assert_eq!(
525+
normalize_sourcemap_url(
526+
"foo/bar/baz.js",
527+
&format!("..{0}.{0}baz.js.map", std::path::MAIN_SEPARATOR)
528+
),
529+
"foo/baz.js.map"
530+
);
531+
484532
assert_eq!(
485533
normalize_sourcemap_url("foo/bar/baz.js", "baz.js.map"),
486534
"foo/bar/baz.js.map"

0 commit comments

Comments
 (0)