zpl_toolchain_jsonc_strip/
lib.rs1#[must_use]
13pub fn strip_jsonc(input: &str) -> String {
14 let mut out = String::with_capacity(input.len());
15 let chars: Vec<char> = input.chars().collect();
16 let len = chars.len();
17 let mut i = 0usize;
18 let mut in_str = false;
19
20 while i < len {
21 let c = chars[i];
22
23 if in_str {
24 out.push(c);
25 if c == '\\' && i + 1 < len {
26 i += 1;
28 out.push(chars[i]);
29 } else if c == '"' {
30 in_str = false;
31 }
32 i += 1;
33 continue;
34 }
35
36 if c == '"' {
37 in_str = true;
38 out.push(c);
39 i += 1;
40 continue;
41 }
42
43 if c == '/' && i + 1 < len {
44 let c2 = chars[i + 1];
45 if c2 == '/' {
46 i += 2;
47 while i < len && chars[i] != '\n' {
48 i += 1;
49 }
50 continue;
51 }
52 if c2 == '*' {
53 i += 2;
54 while i + 1 < len && !(chars[i] == '*' && chars[i + 1] == '/') {
55 i += 1;
56 }
57 i = (i + 2).min(len);
58 continue;
59 }
60 }
61
62 out.push(c);
63 i += 1;
64 }
65 out
66}
67
68#[cfg(test)]
69mod tests {
70 use super::strip_jsonc;
71
72 #[test]
73 fn strips_line_and_block_comments() {
74 let input = r#"
75{
76 // comment
77 "a": 1, /* inline */ "b": 2
78}
79"#;
80 let stripped = strip_jsonc(input);
81 assert!(!stripped.contains("comment"));
82 assert!(!stripped.contains("inline"));
83 assert!(stripped.contains("\"a\": 1"));
84 assert!(stripped.contains("\"b\": 2"));
85 }
86
87 #[test]
88 fn preserves_comment_like_text_in_strings() {
89 let input = r#"{ "url": "http://example.com/*x*/", "note":"//keep" }"#;
90 let stripped = strip_jsonc(input);
91 assert!(stripped.contains("http://example.com/*x*/"));
92 assert!(stripped.contains("\"note\":\"//keep\""));
93 }
94}