rspack_core/cache/
snapshot.rs1use rspack_cacheable::{cacheable, utils::PortablePath, with::As};
2use rspack_regex::RspackRegex;
3
4#[cacheable]
6#[derive(Debug, Clone, Hash)]
7pub enum PathMatcher {
8 String(#[cacheable(with=As<PortablePath>)] String),
9 Regexp(RspackRegex),
10}
11
12impl PathMatcher {
13 fn try_match(&self, path: &str) -> bool {
14 match self {
15 Self::String(string) => path.contains(string),
16 Self::Regexp(regex) => regex.test(path),
17 }
18 }
19}
20
21#[cacheable]
23#[derive(Debug, Clone, Hash)]
24pub struct SnapshotOptions {
25 immutable_paths: Vec<PathMatcher>,
27 unmanaged_paths: Vec<PathMatcher>,
30 managed_paths: Vec<PathMatcher>,
32 dependencies: SnapshotStrategyOptions,
33 context_dependencies: SnapshotStrategyOptions,
34}
35
36impl Default for SnapshotOptions {
37 fn default() -> Self {
38 Self {
39 immutable_paths: Default::default(),
40 unmanaged_paths: Default::default(),
41 managed_paths: Default::default(),
42 dependencies: SnapshotStrategyOptions::hash_and_timestamp(),
43 context_dependencies: SnapshotStrategyOptions::timestamp(),
44 }
45 }
46}
47
48#[cacheable]
49#[derive(Debug, Clone, Copy, Hash)]
50pub struct SnapshotStrategyOptions {
51 pub hash: bool,
52 pub timestamp: bool,
53}
54
55impl SnapshotStrategyOptions {
56 pub const fn new(hash: bool, timestamp: bool) -> Self {
57 Self { hash, timestamp }
58 }
59
60 pub const fn hash() -> Self {
61 Self::new(true, false)
62 }
63
64 pub const fn timestamp() -> Self {
65 Self::new(false, true)
66 }
67
68 pub const fn hash_and_timestamp() -> Self {
69 Self::new(true, true)
70 }
71}
72
73impl Default for SnapshotStrategyOptions {
74 fn default() -> Self {
75 Self::timestamp()
76 }
77}
78
79impl SnapshotOptions {
80 pub fn new(
81 immutable_paths: Vec<PathMatcher>,
82 unmanaged_paths: Vec<PathMatcher>,
83 managed_paths: Vec<PathMatcher>,
84 ) -> Self {
85 Self {
86 immutable_paths,
87 unmanaged_paths,
88 managed_paths,
89 ..Default::default()
90 }
91 }
92
93 pub fn dependencies_strategy(&self) -> SnapshotStrategyOptions {
94 self.dependencies
95 }
96
97 pub fn context_dependencies_strategy(&self) -> SnapshotStrategyOptions {
98 self.context_dependencies
99 }
100
101 pub fn is_immutable_path(&self, path_str: &str) -> bool {
102 for item in &self.immutable_paths {
103 if item.try_match(path_str) {
104 return true;
105 }
106 }
107 false
108 }
109
110 pub fn is_managed_path(&self, path_str: &str) -> bool {
111 for item in &self.unmanaged_paths {
112 if item.try_match(path_str) {
113 return false;
114 }
115 }
116
117 for item in &self.managed_paths {
118 if item.try_match(path_str) {
119 return true;
120 }
121 }
122 false
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use rspack_regex::RspackRegex;
129
130 use super::{PathMatcher, SnapshotOptions};
131
132 #[test]
133 fn should_path_matcher_works() {
134 let matcher = PathMatcher::String("abc".into());
135 assert!(matcher.try_match("aabcc"));
136 assert!(matcher.try_match("abccd"));
137 assert!(matcher.try_match("xxabc"));
138 assert!(!matcher.try_match("aadcc"));
139
140 let matcher = PathMatcher::Regexp(RspackRegex::new("[0-9]").unwrap());
141 assert!(matcher.try_match("aa0cc"));
142 assert!(matcher.try_match("3cc"));
143 assert!(!matcher.try_match("abc"));
144 }
145
146 #[test]
147 fn should_snapshot_options_works() {
148 let options = SnapshotOptions::new(
149 vec![
150 PathMatcher::String("constant".into()),
151 PathMatcher::Regexp(RspackRegex::new("global/[A-Z]+").unwrap()),
152 ],
153 vec![
154 PathMatcher::String("node_modules/test1".into()),
155 PathMatcher::Regexp(RspackRegex::new("test_modules/test.+").unwrap()),
156 ],
157 vec![
158 PathMatcher::String("node_modules".into()),
159 PathMatcher::Regexp(RspackRegex::new("test_modules/.+").unwrap()),
160 ],
161 );
162
163 assert!(options.is_immutable_path("/root/project/constant/var.js"));
164 assert!(options.is_immutable_path("/root/project/constant1/var.js"));
165 assert!(options.is_immutable_path("/root/project/1constant/var.js"));
166
167 assert!(options.is_immutable_path("/root/project/global/NAME.js"));
168 assert!(options.is_immutable_path("/root/project/global/Name.js"));
169 assert!(!options.is_immutable_path("/root/project/global/var.js"));
170
171 assert!(options.is_managed_path("/root/project/node_modules/var.js"));
172 assert!(!options.is_managed_path("/root/project/node_modules/test1/var.js"));
173
174 assert!(options.is_managed_path("/root/project/test_modules/var.js"));
175 assert!(!options.is_managed_path("/root/project/test_modules/test1/var.js"));
176 }
177}