nodejs_resolver/
kind.rs

1use crate::Resolver;
2use daachorse::{CharwiseDoubleArrayAhoCorasick, CharwiseDoubleArrayAhoCorasickBuilder, MatchKind};
3use once_cell::sync::Lazy;
4
5#[derive(Debug, Clone, Copy, PartialEq)]
6pub enum PathKind {
7    Relative,
8    AbsoluteWin,
9    AbsolutePosix,
10    Internal,
11    Normal,
12}
13
14static ABSOLUTE_WIN_PATTERN_LENGTH_TWO: [&str; 52] = [
15    "a:", "b:", "c:", "d:", "e:", "f:", "g:", "h:", "i:", "j:", "k:", "l:", "m:", "n:", "o:", "p:",
16    "q:", "r:", "s:", "t:", "u:", "v:", "w:", "x:", "y:", "z:", "A:", "B:", "C:", "D:", "E:", "F:",
17    "G:", "H:", "I:", "J:", "K:", "L:", "M:", "N:", "O:", "P:", "Q:", "R:", "S:", "T:", "U:", "V:",
18    "W:", "X:", "Y:", "Z:",
19];
20
21static ABSOLUTE_WIN_PATTERN_REST: [&str; 104] = [
22    "a:\\", "b:\\", "c:\\", "d:\\", "e:\\", "f:\\", "g:\\", "h:\\", "i:\\", "j:\\", "k:\\", "l:\\",
23    "m:\\", "n:\\", "o:\\", "p:\\", "q:\\", "r:\\", "s:\\", "t:\\", "u:\\", "v:\\", "w:\\", "x:\\",
24    "y:\\", "z:\\", "A:\\", "B:\\", "C:\\", "D:\\", "E:\\", "F:\\", "G:\\", "H:\\", "I:\\", "J:\\",
25    "K:\\", "L:\\", "M:\\", "N:\\", "O:\\", "P:\\", "Q:\\", "R:\\", "S:\\", "T:\\", "U:\\", "V:\\",
26    "W:\\", "X:\\", "Y:\\", "Z:\\", "a:/", "b:/", "c:/", "d:/", "e:/", "f:/", "g:/", "h:/", "i:/",
27    "j:/", "k:/", "l:/", "m:/", "n:/", "o:/", "p:/", "q:/", "r:/", "s:/", "t:/", "u:/", "v:/",
28    "w:/", "x:/", "y:/", "z:/", "A:/", "B:/", "C:/", "D:/", "E:/", "F:/", "G:/", "H:/", "I:/",
29    "J:/", "K:/", "L:/", "M:/", "N:/", "O:/", "P:/", "Q:/", "R:/", "S:/", "T:/", "U:/", "V:/",
30    "W:/", "X:/", "Y:/", "Z:/",
31];
32
33static PMA: Lazy<CharwiseDoubleArrayAhoCorasick<usize>> = Lazy::new(|| {
34    CharwiseDoubleArrayAhoCorasickBuilder::new()
35        .match_kind(MatchKind::LeftmostLongest)
36        .build(ABSOLUTE_WIN_PATTERN_REST)
37        .unwrap()
38});
39
40impl Resolver {
41    pub(crate) fn get_target_kind(target: &str) -> PathKind {
42        if target.is_empty() {
43            return PathKind::Relative;
44        }
45
46        let path_kind = if target.starts_with('#') {
47            PathKind::Internal
48        } else if target.starts_with('/') {
49            PathKind::AbsolutePosix
50        } else if target == "."
51            || target.starts_with("./")
52            || target.starts_with("../")
53            || target == ".."
54        {
55            PathKind::Relative
56        } else {
57            if target.len() == 2 && ABSOLUTE_WIN_PATTERN_LENGTH_TWO.contains(&target) {
58                return PathKind::AbsoluteWin;
59            }
60            let mut iter = PMA.leftmost_find_iter(target);
61            if let Some(mat) = iter.next() {
62                let match_pattern_len = ABSOLUTE_WIN_PATTERN_REST[mat.value()].len();
63                if mat.start() == 0 && mat.end() - mat.start() == match_pattern_len {
64                    return PathKind::AbsoluteWin;
65                }
66            }
67            PathKind::Normal
68        };
69        path_kind
70    }
71}
72
73#[test]
74fn test_resolver() {
75    assert!(matches!(Resolver::get_target_kind(""), PathKind::Relative));
76    assert!(matches!(Resolver::get_target_kind("."), PathKind::Relative));
77    assert!(matches!(
78        Resolver::get_target_kind(".."),
79        PathKind::Relative
80    ));
81    assert!(matches!(
82        Resolver::get_target_kind("../a.js"),
83        PathKind::Relative
84    ));
85    assert!(matches!(
86        Resolver::get_target_kind("./a.js"),
87        PathKind::Relative
88    ));
89    assert!(matches!(
90        Resolver::get_target_kind("D:"),
91        PathKind::AbsoluteWin
92    ));
93    assert!(matches!(
94        Resolver::get_target_kind("C:path"),
95        PathKind::Normal
96    ));
97    assert!(matches!(
98        Resolver::get_target_kind("C:\\a"),
99        PathKind::AbsoluteWin
100    ));
101    assert!(matches!(
102        Resolver::get_target_kind("c:/a"),
103        PathKind::AbsoluteWin
104    ));
105    assert!(matches!(
106        Resolver::get_target_kind("cc:/a"),
107        PathKind::Normal
108    ));
109    assert!(matches!(Resolver::get_target_kind("fs"), PathKind::Normal));
110}