main
rs 35 lines 1.43 KB
Raw
1 //! Deep ASTs must survive deserialization when the caller disables
2 //! serde_json's recursion limit, as the napi entrypoint does. The tolerant
3 //! statement deserializer reparses captured raw text internally; those
4 //! reparses must not reintroduce the default depth limit.
5
6 use react_compiler_ast::File;
7 use serde::Deserialize;
8
9 fn from_json_str_unbounded(s: &str) -> serde_json::Result<File> {
10 let mut deserializer = serde_json::Deserializer::from_str(s);
11 deserializer.disable_recursion_limit();
12 File::deserialize(&mut deserializer)
13 }
14
15 #[test]
16 fn statement_nested_beyond_default_recursion_limit_deserializes() {
17 let depth = 400;
18 let mut expr = r#"{"type":"Identifier","name":"x"}"#.to_string();
19 for _ in 0..depth {
20 expr = format!(r#"{{"type":"CallExpression","callee":{expr},"arguments":[]}}"#);
21 }
22 let json = format!(
23 r#"{{"type":"File","program":{{"type":"Program","sourceType":"module","body":[{{"type":"ExpressionStatement","expression":{expr}}}],"directives":[]}}}}"#
24 );
25
26 // Parse on a large stack like the napi entrypoint does; without the limit,
27 // depth is bounded by stack, not by serde_json's counter.
28 let file = std::thread::Builder::new()
29 .stack_size(64 * 1024 * 1024)
30 .spawn(move || from_json_str_unbounded(&json).expect("deep statement must deserialize"))
31 .expect("spawn")
32 .join()
33 .expect("join");
34 assert_eq!(file.program.body.len(), 1);
35 }