@@ -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.
240245pub 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