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