1use crate::{
4 json::{
5 canonicalize_json_path, check_json_key_exists, parse_json, parse_json_coerce,
6 parse_json_keys, resolve_type,
7 },
8 Cheatcode, Cheatcodes, Result,
9 Vm::*,
10};
11use alloy_dyn_abi::DynSolType;
12use alloy_sol_types::SolValue;
13use foundry_common::fs;
14use foundry_config::fs_permissions::FsAccessKind;
15use serde_json::Value as JsonValue;
16use toml::Value as TomlValue;
17
18impl Cheatcode for keyExistsTomlCall {
19 fn apply(&self, _state: &mut Cheatcodes) -> Result {
20 let Self { toml, key } = self;
21 check_json_key_exists(&toml_to_json_string(toml)?, key)
22 }
23}
24
25impl Cheatcode for parseToml_0Call {
26 fn apply(&self, _state: &mut Cheatcodes) -> Result {
27 let Self { toml } = self;
28 parse_toml(toml, "$")
29 }
30}
31
32impl Cheatcode for parseToml_1Call {
33 fn apply(&self, _state: &mut Cheatcodes) -> Result {
34 let Self { toml, key } = self;
35 parse_toml(toml, key)
36 }
37}
38
39impl Cheatcode for parseTomlUintCall {
40 fn apply(&self, _state: &mut Cheatcodes) -> Result {
41 let Self { toml, key } = self;
42 parse_toml_coerce(toml, key, &DynSolType::Uint(256))
43 }
44}
45
46impl Cheatcode for parseTomlUintArrayCall {
47 fn apply(&self, _state: &mut Cheatcodes) -> Result {
48 let Self { toml, key } = self;
49 parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::Uint(256))))
50 }
51}
52
53impl Cheatcode for parseTomlIntCall {
54 fn apply(&self, _state: &mut Cheatcodes) -> Result {
55 let Self { toml, key } = self;
56 parse_toml_coerce(toml, key, &DynSolType::Int(256))
57 }
58}
59
60impl Cheatcode for parseTomlIntArrayCall {
61 fn apply(&self, _state: &mut Cheatcodes) -> Result {
62 let Self { toml, key } = self;
63 parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::Int(256))))
64 }
65}
66
67impl Cheatcode for parseTomlBoolCall {
68 fn apply(&self, _state: &mut Cheatcodes) -> Result {
69 let Self { toml, key } = self;
70 parse_toml_coerce(toml, key, &DynSolType::Bool)
71 }
72}
73
74impl Cheatcode for parseTomlBoolArrayCall {
75 fn apply(&self, _state: &mut Cheatcodes) -> Result {
76 let Self { toml, key } = self;
77 parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::Bool)))
78 }
79}
80
81impl Cheatcode for parseTomlAddressCall {
82 fn apply(&self, _state: &mut Cheatcodes) -> Result {
83 let Self { toml, key } = self;
84 parse_toml_coerce(toml, key, &DynSolType::Address)
85 }
86}
87
88impl Cheatcode for parseTomlAddressArrayCall {
89 fn apply(&self, _state: &mut Cheatcodes) -> Result {
90 let Self { toml, key } = self;
91 parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::Address)))
92 }
93}
94
95impl Cheatcode for parseTomlStringCall {
96 fn apply(&self, _state: &mut Cheatcodes) -> Result {
97 let Self { toml, key } = self;
98 parse_toml_coerce(toml, key, &DynSolType::String)
99 }
100}
101
102impl Cheatcode for parseTomlStringArrayCall {
103 fn apply(&self, _state: &mut Cheatcodes) -> Result {
104 let Self { toml, key } = self;
105 parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::String)))
106 }
107}
108
109impl Cheatcode for parseTomlBytesCall {
110 fn apply(&self, _state: &mut Cheatcodes) -> Result {
111 let Self { toml, key } = self;
112 parse_toml_coerce(toml, key, &DynSolType::Bytes)
113 }
114}
115
116impl Cheatcode for parseTomlBytesArrayCall {
117 fn apply(&self, _state: &mut Cheatcodes) -> Result {
118 let Self { toml, key } = self;
119 parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::Bytes)))
120 }
121}
122
123impl Cheatcode for parseTomlBytes32Call {
124 fn apply(&self, _state: &mut Cheatcodes) -> Result {
125 let Self { toml, key } = self;
126 parse_toml_coerce(toml, key, &DynSolType::FixedBytes(32))
127 }
128}
129
130impl Cheatcode for parseTomlBytes32ArrayCall {
131 fn apply(&self, _state: &mut Cheatcodes) -> Result {
132 let Self { toml, key } = self;
133 parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::FixedBytes(32))))
134 }
135}
136
137impl Cheatcode for parseTomlType_0Call {
138 fn apply(&self, _state: &mut Cheatcodes) -> Result {
139 let Self { toml, typeDescription } = self;
140 parse_toml_coerce(toml, "$", &resolve_type(typeDescription)?).map(|v| v.abi_encode())
141 }
142}
143
144impl Cheatcode for parseTomlType_1Call {
145 fn apply(&self, _state: &mut Cheatcodes) -> Result {
146 let Self { toml, key, typeDescription } = self;
147 parse_toml_coerce(toml, key, &resolve_type(typeDescription)?).map(|v| v.abi_encode())
148 }
149}
150
151impl Cheatcode for parseTomlTypeArrayCall {
152 fn apply(&self, _state: &mut Cheatcodes) -> Result {
153 let Self { toml, key, typeDescription } = self;
154 let ty = resolve_type(typeDescription)?;
155 parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(ty))).map(|v| v.abi_encode())
156 }
157}
158
159impl Cheatcode for parseTomlKeysCall {
160 fn apply(&self, _state: &mut Cheatcodes) -> Result {
161 let Self { toml, key } = self;
162 parse_toml_keys(toml, key)
163 }
164}
165
166impl Cheatcode for writeToml_0Call {
167 fn apply(&self, state: &mut Cheatcodes) -> Result {
168 let Self { json, path } = self;
169 let value =
170 serde_json::from_str(json).unwrap_or_else(|_| JsonValue::String(json.to_owned()));
171
172 let toml_string = format_json_to_toml(value)?;
173 super::fs::write_file(state, path.as_ref(), toml_string.as_bytes())
174 }
175}
176
177impl Cheatcode for writeToml_1Call {
178 fn apply(&self, state: &mut Cheatcodes) -> Result {
179 let Self { json, path, valueKey } = self;
180 let json =
181 serde_json::from_str(json).unwrap_or_else(|_| JsonValue::String(json.to_owned()));
182
183 let data_path = state.config.ensure_path_allowed(path, FsAccessKind::Read)?;
184 let toml_data = fs::read_to_string(data_path)?;
185 let json_data: JsonValue =
186 toml::from_str(&toml_data).map_err(|e| fmt_err!("failed parsing TOML: {e}"))?;
187 let value =
188 jsonpath_lib::replace_with(json_data, &canonicalize_json_path(valueKey), &mut |_| {
189 Some(json.clone())
190 })?;
191
192 let toml_string = format_json_to_toml(value)?;
193 super::fs::write_file(state, path.as_ref(), toml_string.as_bytes())
194 }
195}
196
197fn parse_toml_str(toml: &str) -> Result<TomlValue> {
199 toml::from_str(toml).map_err(|e| fmt_err!("failed parsing TOML: {e}"))
200}
201
202fn parse_toml(toml: &str, key: &str) -> Result {
204 parse_json(&toml_to_json_string(toml)?, key)
205}
206
207fn parse_toml_coerce(toml: &str, key: &str, ty: &DynSolType) -> Result {
209 parse_json_coerce(&toml_to_json_string(toml)?, key, ty)
210}
211
212fn parse_toml_keys(toml: &str, key: &str) -> Result {
214 parse_json_keys(&toml_to_json_string(toml)?, key)
215}
216
217fn toml_to_json_string(toml: &str) -> Result<String> {
219 let toml = parse_toml_str(toml)?;
220 let json = toml_to_json_value(toml);
221 serde_json::to_string(&json).map_err(|e| fmt_err!("failed to serialize JSON: {e}"))
222}
223
224fn format_json_to_toml(json: JsonValue) -> Result<String> {
226 let toml = json_to_toml_value(json);
227 toml::to_string_pretty(&toml).map_err(|e| fmt_err!("failed to serialize TOML: {e}"))
228}
229
230fn toml_to_json_value(toml: TomlValue) -> JsonValue {
232 match toml {
233 TomlValue::String(s) => match s.as_str() {
234 "null" => JsonValue::Null,
235 _ => JsonValue::String(s),
236 },
237 TomlValue::Integer(i) => JsonValue::Number(i.into()),
238 TomlValue::Float(f) => JsonValue::Number(serde_json::Number::from_f64(f).unwrap()),
239 TomlValue::Boolean(b) => JsonValue::Bool(b),
240 TomlValue::Array(a) => JsonValue::Array(a.into_iter().map(toml_to_json_value).collect()),
241 TomlValue::Table(t) => {
242 JsonValue::Object(t.into_iter().map(|(k, v)| (k, toml_to_json_value(v))).collect())
243 }
244 TomlValue::Datetime(d) => JsonValue::String(d.to_string()),
245 }
246}
247
248fn json_to_toml_value(json: JsonValue) -> TomlValue {
250 match json {
251 JsonValue::String(s) => TomlValue::String(s),
252 JsonValue::Number(n) => match n.as_i64() {
253 Some(i) => TomlValue::Integer(i),
254 None => match n.as_f64() {
255 Some(f) => TomlValue::Float(f),
256 None => TomlValue::String(n.to_string()),
257 },
258 },
259 JsonValue::Bool(b) => TomlValue::Boolean(b),
260 JsonValue::Array(a) => TomlValue::Array(a.into_iter().map(json_to_toml_value).collect()),
261 JsonValue::Object(o) => {
262 TomlValue::Table(o.into_iter().map(|(k, v)| (k, json_to_toml_value(v))).collect())
263 }
264 JsonValue::Null => TomlValue::String("null".to_string()),
265 }
266}