1use super::*;
2
3#[derive(Debug, Clone, PartialEq)]
4pub struct Recipe {
5 pub attributes: Vec<Attribute>,
6 pub content: String,
7 pub dependencies: Vec<Dependency>,
8 pub name: TextNode,
9 pub parameters: Vec<Parameter>,
10 pub range: lsp::Range,
11 pub shebang: Option<TextNode>,
12}
13
14impl Recipe {
15 #[must_use]
16 pub fn find_attribute(&self, name: &str) -> Option<&Attribute> {
17 self
18 .attributes
19 .iter()
20 .find(|attribute| attribute.name.value == name)
21 }
22
23 #[must_use]
24 pub fn groups(&self) -> HashSet<Group> {
25 let mut groups = HashSet::new();
26
27 for attribute in &self.attributes {
28 let attribute_name = attribute.name.value.as_str();
29
30 if let Some(targets) = Group::targets(attribute_name) {
31 groups.extend(targets);
32 }
33 }
34
35 if groups.is_empty() {
36 groups.insert(Group::Any);
37 }
38
39 groups
40 }
41
42 #[must_use]
43 pub fn has_attribute(&self, name: &str) -> bool {
44 self
45 .attributes
46 .iter()
47 .any(|attribute| attribute.name.value == name)
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn recipe_groups_no_attributes() {
57 let recipe = Recipe {
58 name: TextNode {
59 value: "test".into(),
60 range: lsp::Range::at(0, 0, 0, 4),
61 },
62 attributes: vec![],
63 dependencies: vec![],
64 shebang: None,
65 parameters: vec![],
66 content: "test:\n echo test".to_string(),
67 range: lsp::Range::at(0, 0, 2, 0),
68 };
69
70 assert_eq!(recipe.groups(), HashSet::from([Group::Any]));
71 }
72
73 #[test]
74 fn recipe_groups_single_attribute() {
75 let recipe = Recipe {
76 name: TextNode {
77 value: "test".into(),
78 range: lsp::Range::at(1, 0, 1, 4),
79 },
80 attributes: vec![Attribute {
81 name: TextNode {
82 value: "linux".to_string(),
83 range: lsp::Range::at(0, 1, 0, 6),
84 },
85 arguments: vec![],
86 target: Some(AttributeTarget::Recipe),
87 range: lsp::Range::at(0, 0, 1, 0),
88 }],
89 dependencies: vec![],
90 shebang: None,
91 parameters: vec![],
92 content: "[linux]\ntest:\n echo test".to_string(),
93 range: lsp::Range::at(0, 0, 3, 0),
94 };
95
96 assert_eq!(recipe.groups(), HashSet::from([Group::Linux]));
97 }
98
99 #[test]
100 fn recipe_groups_multiple_attributes() {
101 let recipe = Recipe {
102 name: TextNode {
103 value: "test".into(),
104 range: lsp::Range::at(2, 0, 2, 4),
105 },
106 attributes: vec![
107 Attribute {
108 name: TextNode {
109 value: "linux".to_string(),
110 range: lsp::Range::at(0, 1, 0, 6),
111 },
112 arguments: vec![],
113 target: Some(AttributeTarget::Recipe),
114 range: lsp::Range::at(0, 0, 1, 0),
115 },
116 Attribute {
117 name: TextNode {
118 value: "windows".to_string(),
119 range: lsp::Range::at(1, 1, 1, 8),
120 },
121 arguments: vec![],
122 target: Some(AttributeTarget::Recipe),
123 range: lsp::Range::at(1, 0, 2, 0),
124 },
125 ],
126 dependencies: vec![],
127 shebang: None,
128 parameters: vec![],
129 content: "[linux]\n[windows]\ntest:\n echo test".to_string(),
130 range: lsp::Range::at(0, 0, 4, 0),
131 };
132
133 assert_eq!(
134 recipe.groups(),
135 HashSet::from([Group::Linux, Group::Windows])
136 );
137 }
138
139 #[test]
140 fn recipe_groups_all_attributes() {
141 let recipe = Recipe {
142 name: TextNode {
143 value: "test".into(),
144 range: lsp::Range::at(8, 0, 8, 4),
145 },
146 attributes: vec![
147 Attribute {
148 name: TextNode {
149 value: "linux".to_string(),
150 range: lsp::Range::at(0, 1, 0, 6),
151 },
152 arguments: vec![],
153 target: Some(AttributeTarget::Recipe),
154 range: lsp::Range::at(0, 0, 1, 0),
155 },
156 Attribute {
157 name: TextNode {
158 value: "windows".to_string(),
159 range: lsp::Range::at(1, 1, 1, 8),
160 },
161 arguments: vec![],
162 target: Some(AttributeTarget::Recipe),
163 range: lsp::Range::at(1, 0, 2, 0),
164 },
165 Attribute {
166 name: TextNode {
167 value: "macos".to_string(),
168 range: lsp::Range::at(2, 1, 2, 6),
169 },
170 arguments: vec![],
171 target: Some(AttributeTarget::Recipe),
172 range: lsp::Range::at(2, 0, 3, 0),
173 },
174 Attribute {
175 name: TextNode {
176 value: "unix".to_string(),
177 range: lsp::Range::at(3, 1, 3, 5),
178 },
179 arguments: vec![],
180 target: Some(AttributeTarget::Recipe),
181 range: lsp::Range::at(3, 0, 4, 0),
182 },
183 Attribute {
184 name: TextNode {
185 value: "dragonfly".to_string(),
186 range: lsp::Range::at(4, 1, 4, 10),
187 },
188 arguments: vec![],
189 target: Some(AttributeTarget::Recipe),
190 range: lsp::Range::at(4, 0, 5, 0),
191 },
192 Attribute {
193 name: TextNode {
194 value: "freebsd".to_string(),
195 range: lsp::Range::at(5, 1, 5, 8),
196 },
197 arguments: vec![],
198 target: Some(AttributeTarget::Recipe),
199 range: lsp::Range::at(5, 0, 6, 0),
200 },
201 Attribute {
202 name: TextNode {
203 value: "netbsd".to_string(),
204 range: lsp::Range::at(6, 1, 6, 7),
205 },
206 arguments: vec![],
207 target: Some(AttributeTarget::Recipe),
208 range: lsp::Range::at(6, 0, 7, 0),
209 },
210 Attribute {
211 name: TextNode {
212 value: "openbsd".to_string(),
213 range: lsp::Range::at(7, 1, 7, 8),
214 },
215 arguments: vec![],
216 target: Some(AttributeTarget::Recipe),
217 range: lsp::Range::at(7, 0, 8, 0),
218 },
219 ],
220 dependencies: vec![],
221 shebang: None,
222 parameters: vec![],
223 content:
224 "[linux]\n[windows]\n[macos]\n[unix]\n[dragonfly]\n[freebsd]\n[netbsd]\n[openbsd]\ntest:\n echo test"
225 .to_string(),
226 range: lsp::Range::at(0, 0, 10, 0),
227 };
228
229 assert_eq!(
230 recipe.groups(),
231 HashSet::from([
232 Group::Android,
233 Group::Dragonfly,
234 Group::Freebsd,
235 Group::Linux,
236 Group::Macos,
237 Group::Netbsd,
238 Group::Openbsd,
239 Group::Windows,
240 ])
241 );
242 }
243
244 #[test]
245 fn recipe_groups_non_os_attributes() {
246 let recipe = Recipe {
247 name: TextNode {
248 value: "test".into(),
249 range: lsp::Range::at(1, 0, 1, 4),
250 },
251 attributes: vec![Attribute {
252 name: TextNode {
253 value: "private".to_string(),
254 range: lsp::Range::at(0, 1, 0, 8),
255 },
256 arguments: vec![],
257 target: Some(AttributeTarget::Recipe),
258 range: lsp::Range::at(0, 0, 1, 0),
259 }],
260 dependencies: vec![],
261 shebang: None,
262 parameters: vec![],
263 content: "[private]\ntest:\n echo test".to_string(),
264 range: lsp::Range::at(0, 0, 3, 0),
265 };
266
267 assert_eq!(recipe.groups(), HashSet::from([Group::Any]));
268 }
269}