@@ -230,6 +230,11 @@ pub fn debug_id_from_bytes_hashed(bytes: &[u8]) -> DebugId {
230
230
DebugId :: from_uuid ( uuid:: Builder :: from_sha1_bytes ( sha1_bytes) . into_uuid ( ) )
231
231
}
232
232
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
+
233
238
/// Computes a normalized sourcemap URL from a source file's own URL und the relative URL of its sourcemap.
234
239
///
235
240
/// 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 {
238
243
///
239
244
/// Leading `./` segments will be preserved.
240
245
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
242
248
. rsplit_once ( '/' )
243
249
. map ( |( base, _) | base)
244
250
. unwrap_or ( "" ) ;
@@ -249,7 +255,13 @@ pub fn normalize_sourcemap_url(source_url: &str, sourcemap_url: &str) -> String
249
255
cutoff += 2 ;
250
256
}
251
257
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
+ ) )
253
265
}
254
266
255
267
/// 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
269
281
. split ( '/' )
270
282
. filter ( |& segment| segment != "." )
271
283
. peekable ( ) ;
284
+
272
285
let mut candidate_segments = candidate
273
286
. split ( '/' )
274
287
. filter ( |& segment| segment != "." )
@@ -481,6 +494,41 @@ something else
481
494
482
495
#[ test]
483
496
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
+
484
532
assert_eq ! (
485
533
normalize_sourcemap_url( "foo/bar/baz.js" , "baz.js.map" ) ,
486
534
"foo/bar/baz.js.map"
0 commit comments