risedev/config/
provide_expander.rs
1use std::collections::HashMap;
16
17use anyhow::{Result, anyhow};
18use itertools::Itertools;
19use yaml_rust::Yaml;
20
21pub struct ProvideExpander {
23 all_items: HashMap<String, Yaml>,
24}
25
26impl ProvideExpander {
27 pub fn new(y: &Yaml) -> Result<Self> {
28 let y = y.as_vec().ok_or_else(|| anyhow!("expect an array"))?;
29 let mut all_items = HashMap::new();
30 for v in y {
31 let v = v.as_hash().ok_or_else(|| anyhow!("expect a hashmap"))?;
32 let id = v
33 .get(&Yaml::String("id".into()))
34 .ok_or_else(|| anyhow!("missing id field"))?;
35 let id = id
36 .as_str()
37 .ok_or_else(|| anyhow!("expect id to be a string"))?;
38 all_items.insert(id.to_owned(), Yaml::Hash(v.clone()));
39 }
40 Ok(Self {
41 all_items: Self::remove_provide(all_items)?,
42 })
43 }
44
45 fn remove_provide(all_items: HashMap<String, Yaml>) -> Result<HashMap<String, Yaml>> {
46 let all_items = all_items.into_iter().map(|(k, v)| {
47 let v = v.into_hash().ok_or_else(|| anyhow!("expect a hashmap"))?;
48 let v = v
49 .into_iter()
50 .filter(|(k, _)| {
51 if let Some(k) = k.as_str() {
52 !k.starts_with("provide-")
53 } else {
54 true
55 }
56 })
57 .collect();
58 Ok::<_, anyhow::Error>((k, Yaml::Hash(v)))
59 });
60 all_items.try_collect()
61 }
62
63 pub fn visit(&mut self, yaml: Yaml) -> Result<Yaml> {
64 let yaml = yaml
65 .into_vec()
66 .ok_or_else(|| anyhow!("expect an array"))?
67 .into_iter()
68 .map(|yaml| {
69 let map = yaml
70 .into_hash()
71 .ok_or_else(|| anyhow!("expect a hashmap"))?;
72 let map = map.into_iter().map(|(k, v)| {
73 if let Some(k) = k.as_str()
74 && k.starts_with("provide-")
75 {
76 let array = v
77 .as_vec()
78 .ok_or_else(|| anyhow!("expect an array of provide-"))?;
79 let array = array.iter().map(|item| {
80 let item = item
81 .as_str()
82 .ok_or_else(|| anyhow!("expect a string from provide"))?;
83 Ok::<_, anyhow::Error>(
84 self.all_items
85 .get(item)
86 .ok_or_else(|| anyhow!("{} not found", item))?
87 .clone(),
88 )
89 });
90 return Ok::<_, anyhow::Error>((
91 Yaml::String(k.to_owned()),
92 Yaml::Array(array.try_collect()?),
93 ));
94 }
95 Ok::<_, anyhow::Error>((k, v))
96 });
97 Ok::<_, anyhow::Error>(Yaml::Hash(map.try_collect()?))
98 });
99 Ok(Yaml::Array(yaml.try_collect()?))
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use yaml_rust::YamlLoader;
106
107 use super::*;
108
109 #[test]
110 fn test_expand_provide() {
111 let source = YamlLoader::load_from_str(
112 "
113- provide-b: [\"b\"]
114 test_field: a
115 id: a
116- provide-a: [\"a\"]
117 test_field: a
118 id: b
119 ",
120 )
121 .unwrap()
122 .remove(0);
123
124 let expected_result = YamlLoader::load_from_str(
125 "
126- provide-b:
127 - test_field: a
128 id: b
129 test_field: a
130 id: a
131- provide-a:
132 - test_field: a
133 id: a
134 test_field: a
135 id: b
136 ",
137 )
138 .unwrap()
139 .remove(0);
140
141 let mut visitor = ProvideExpander::new(&source).unwrap();
142
143 assert_eq!(visitor.visit(source).unwrap(), expected_result);
144 }
145}