parcel_sourcemap/
utils.rs1use std::borrow::Cow;
3use std::iter::repeat;
4
5pub fn is_abs_path(s: &str) -> bool {
6 if s.starts_with('/') || s.starts_with('\\') {
7 return true;
8 } else if s.len() > 3 {
9 let b = s.as_bytes();
10 if b[1] == b':'
11 && (b[2] == b'/' || b[2] == b'\\')
12 && ((b[0] >= b'a' && b[0] <= b'z') || (b[0] >= b'A' && b[0] <= b'Z'))
13 {
14 return true;
15 }
16 }
17
18 false
20}
21
22fn get_common_prefix_len<'a>(items: &'a [Cow<'a, [&'a str]>]) -> usize {
23 if items.is_empty() {
24 return 0;
25 }
26
27 let shortest = &items[0];
28 let mut max_idx = None;
29 for seq in items.iter() {
30 let mut seq_max_idx = None;
31 for (idx, &comp) in shortest.iter().enumerate() {
32 if seq.get(idx) != Some(&comp) {
33 break;
34 }
35 seq_max_idx = Some(idx);
36 }
37 if max_idx.is_none() || seq_max_idx < max_idx {
38 max_idx = seq_max_idx;
39 }
40 }
41
42 if let Some(max_idx) = max_idx {
43 max_idx + 1
44 } else {
45 0
46 }
47}
48
49fn chunk_path(p: &str) -> Vec<&str> {
50 return p
51 .split(&['/', '\\'][..])
52 .filter(|x| !x.is_empty() && *x != ".")
53 .collect();
54}
55
56pub fn make_relative_path(base: &str, target: &str) -> String {
58 let mut target_str = target;
59 {
60 let target_lower = target.to_ascii_lowercase();
61 if target_lower.strip_prefix("file://").is_some() {
62 target_str = &target[7..];
63 }
64 }
65
66 if !is_abs_path(target_str) {
67 if target_str.contains(':') {
68 String::from(target_str)
69 } else {
70 return chunk_path(target_str).join("/");
71 }
72 } else {
73 let target_path: Vec<&str> = chunk_path(target_str);
74 let base_dir: Vec<&str> = chunk_path(base);
75 let items = vec![
76 Cow::Borrowed(base_dir.as_slice()),
77 Cow::Borrowed(target_path.as_slice()),
78 ];
79 let prefix_len = get_common_prefix_len(&items);
80 let mut rel_list: Vec<&str> = repeat("..").take(base_dir.len() - prefix_len).collect();
81 rel_list.extend_from_slice(&target_path[prefix_len..]);
82 rel_list.join("/")
83 }
84}
85
86#[test]
87fn test_make_relative_path() {
88 assert_eq!(
89 &make_relative_path("/foo/bar", "/foo/bar/baz.map"),
90 "baz.map"
91 );
92 assert_eq!(
93 &make_relative_path("/foo/bar/.", "/foo/bar/baz.map"),
94 "baz.map"
95 );
96 assert_eq!(
97 &make_relative_path("/foo/bar", "/foo/baz.map"),
98 "../baz.map"
99 );
100 assert_eq!(&make_relative_path("/some/abs/path", "foo.js"), "foo.js");
101 assert_eq!(
102 &make_relative_path("C:\\blah\\sub", "C:\\blah\\foo.js"),
103 "../foo.js"
104 );
105 assert_eq!(&make_relative_path("/", "./test.js"), "test.js");
106}