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)?;
210 let toml_data = fs::locked_read_to_string(&data_path)?;
211
212 let mut json_data: JsonValue =
214 toml::from_str(&toml_data).map_err(|e| fmt_err!("failed parsing TOML: {e}"))?;
215 upsert_json_value(&mut json_data, value, valueKey)?;
216
217 let toml_string = format_json_to_toml(json_data)?;
219 super::fs::write_file(state, path.as_ref(), toml_string.as_bytes())
220 }
221}
222
223fn parse_toml_str(toml: &str) -> Result<TomlValue> {
225 toml::from_str(toml).map_err(|e| fmt_err!("failed parsing TOML: {e}"))
226}
227
228fn parse_toml(toml: &str, key: &str, struct_defs: Option<&StructDefinitions>) -> Result {
230 parse_json(&toml_to_json_string(toml)?, key, struct_defs)
231}
232
233fn parse_toml_coerce(toml: &str, key: &str, ty: &DynSolType) -> Result {
235 parse_json_coerce(&toml_to_json_string(toml)?, key, ty)
236}
237
238fn parse_toml_keys(toml: &str, key: &str) -> Result {
240 parse_json_keys(&toml_to_json_string(toml)?, key)
241}
242
243fn toml_to_json_string(toml: &str) -> Result<String> {
245 let toml = parse_toml_str(toml)?;
246 let json = toml_to_json_value(toml);
247 serde_json::to_string(&json).map_err(|e| fmt_err!("failed to serialize JSON: {e}"))
248}
249
250fn format_json_to_toml(json: JsonValue) -> Result<String> {
252 let toml = json_to_toml_value(json);
253 toml::to_string_pretty(&toml).map_err(|e| fmt_err!("failed to serialize TOML: {e}"))
254}
255
256pub(super) fn toml_to_json_value(toml: TomlValue) -> JsonValue {
258 match toml {
259 TomlValue::String(s) => match s.as_str() {
260 "null" => JsonValue::Null,
261 _ => JsonValue::String(s),
262 },
263 TomlValue::Integer(i) => JsonValue::Number(i.into()),
264 TomlValue::Float(f) => match serde_json::Number::from_f64(f) {
265 Some(n) => JsonValue::Number(n),
266 None => JsonValue::String(f.to_string()),
267 },
268 TomlValue::Boolean(b) => JsonValue::Bool(b),
269 TomlValue::Array(a) => JsonValue::Array(a.into_iter().map(toml_to_json_value).collect()),
270 TomlValue::Table(t) => {
271 JsonValue::Object(t.into_iter().map(|(k, v)| (k, toml_to_json_value(v))).collect())
272 }
273 TomlValue::Datetime(d) => JsonValue::String(d.to_string()),
274 }
275}
276
277fn json_to_toml_value(json: JsonValue) -> TomlValue {
279 match json {
280 JsonValue::String(s) => TomlValue::String(s),
281 JsonValue::Number(n) => match n.as_i64() {
282 Some(i) => TomlValue::Integer(i),
283 None => match n.as_f64() {
284 Some(f) => TomlValue::Float(f),
285 None => TomlValue::String(n.to_string()),
286 },
287 },
288 JsonValue::Bool(b) => TomlValue::Boolean(b),
289 JsonValue::Array(a) => TomlValue::Array(a.into_iter().map(json_to_toml_value).collect()),
290 JsonValue::Object(o) => {
291 TomlValue::Table(o.into_iter().map(|(k, v)| (k, json_to_toml_value(v))).collect())
292 }
293 JsonValue::Null => TomlValue::String("null".to_string()),
294 }
295}