1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
mod description;
mod kind;
mod map;
mod normalize;
mod options;
mod parse;
mod resolve;
use description::DescriptionFileInfo;
use kind::PathKind;
use options::ResolverOptions;
use std::{
collections::HashMap,
path::{Path, PathBuf},
};
#[derive(Default)]
pub struct Resolver {
options: ResolverOptions,
base_dir: Option<PathBuf>,
cache_dir_info: HashMap<PathBuf, DirInfo>,
cache_description_file_info: HashMap<PathBuf, DescriptionFileInfo>,
}
pub struct DirInfo {
pub description_file_path: PathBuf,
}
type ResolverError = String;
type RResult<T> = Result<T, ResolverError>;
type ResolverResult = RResult<Option<PathBuf>>;
impl Resolver {
pub fn with_base_dir(self, base_dir: &Path) -> Self {
Self {
base_dir: Some(base_dir.to_path_buf()),
..self
}
}
pub fn use_base_dir(&mut self, base_dir: &Path) {
self.base_dir = Some(base_dir.to_path_buf());
}
fn get_base_dir(&self) -> &PathBuf {
self.base_dir
.as_ref()
.unwrap_or_else(|| panic!("base_dir is not set"))
}
pub fn resolve(&mut self, target: &str) -> ResolverResult {
self._resolve(self.get_base_dir(), target.to_owned())
}
fn _resolve(&self, base_dir: &Path, target: String) -> ResolverResult {
let normalized_target = &if let Some(target_after_alias) = self.normalize_alias(target) {
target_after_alias
} else {
return Ok(None);
};
let part = Self::parse(normalized_target);
let request = &part.request;
let kind = Self::get_path_kind(request);
let dir = match kind {
PathKind::Empty => return Err(ResolverError::from("empty path")),
PathKind::BuildInModule => return Ok(Some(PathBuf::from(request))),
PathKind::AbsolutePosix | PathKind::AbsoluteWin => PathBuf::from("/"),
_ => base_dir.to_path_buf(),
};
let description_file_info = self.load_description_file(&dir.join(request))?;
let (base_dir, target) =
match self.get_real_target(&dir, request, &kind, &description_file_info) {
Some((dir, target)) => (dir, target),
None => return Ok(None),
};
(if matches!(
Self::get_path_kind(&target),
PathKind::AbsolutePosix | PathKind::AbsoluteWin | PathKind::Relative
) {
self.resolve_as_file(&base_dir, &target)
.or_else(|_| self.resolve_as_dir(&base_dir, &target))
} else {
self.resolve_as_modules(&base_dir, &target)
})
.and_then(|path| self.normalize_path(path, &part))
}
}