Skip to content

Commit 9ddeb09

Browse files
authored
Add JSON pre-processor (#17125)
This PR adds a small JSON pre processor to improve parsing JSON files. Due to the sheer amount of potential `[` and `]` brackets, it could be that parsing JSON files are way slower than they need to be. We saw this while debugging this issue: #17092 # Test plan 1. Added test to verify the pre processing works 2. Existing tests still pass
1 parent 8bc633b commit 9ddeb09

File tree

4 files changed

+67
-0
lines changed

4 files changed

+67
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2323
- Ensure classes between `>` and `<` are properly extracted ([#17094](https://github.com/tailwindlabs/tailwindcss/pull/17094))
2424
- Treat starting single quote as verbatim text in Slim ([#17085](https://github.com/tailwindlabs/tailwindcss/pull/17085))
2525
- Ensure `.node` and `.wasm` files are not scanned for utilities ([#17123](https://github.com/tailwindlabs/tailwindcss/pull/17123))
26+
- Improve performance when scanning `JSON` files ([#17125](https://github.com/tailwindlabs/tailwindcss/pull/17125))
2627

2728
## [4.0.12] - 2025-03-07
2829

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use crate::cursor;
2+
use crate::extractor::pre_processors::pre_processor::PreProcessor;
3+
4+
#[derive(Debug, Default)]
5+
pub struct Json;
6+
7+
impl PreProcessor for Json {
8+
fn process(&self, content: &[u8]) -> Vec<u8> {
9+
let len = content.len();
10+
let mut result = content.to_vec();
11+
let mut cursor = cursor::Cursor::new(content);
12+
13+
while cursor.pos < len {
14+
match cursor.curr {
15+
// Consume strings as-is
16+
b'"' => {
17+
cursor.advance();
18+
19+
while cursor.pos < len {
20+
match cursor.curr {
21+
// Escaped character, skip ahead to the next character
22+
b'\\' => cursor.advance_twice(),
23+
24+
// End of the string
25+
b'"' => break,
26+
27+
// Everything else is valid
28+
_ => cursor.advance(),
29+
};
30+
}
31+
}
32+
33+
// Replace brackets and curlies with spaces
34+
b'[' | b'{' | b']' | b'}' => {
35+
result[cursor.pos] = b' ';
36+
}
37+
38+
// Consume everything else
39+
_ => {}
40+
};
41+
42+
cursor.advance();
43+
}
44+
45+
result
46+
}
47+
}
48+
49+
#[cfg(test)]
50+
mod tests {
51+
use super::Json;
52+
use crate::extractor::pre_processors::pre_processor::PreProcessor;
53+
54+
#[test]
55+
fn test_json_pre_processor() {
56+
let (input, expected) = (
57+
r#"[1,[2,[3,4,["flex flex-1 content-['hello_world']"]]], {"flex": true}]"#,
58+
r#" 1, 2, 3,4, "flex flex-1 content-['hello_world']" , "flex": true "#,
59+
);
60+
61+
Json::test(input, expected);
62+
}
63+
}

crates/oxide/src/extractor/pre_processors/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod haml;
2+
pub mod json;
23
pub mod pre_processor;
34
pub mod pug;
45
pub mod razor;
@@ -7,6 +8,7 @@ pub mod slim;
78
pub mod svelte;
89

910
pub use haml::*;
11+
pub use json::*;
1012
pub use pre_processor::*;
1113
pub use pug::*;
1214
pub use razor::*;

crates/oxide/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,7 @@ pub fn pre_process_input(content: &[u8], extension: &str) -> Vec<u8> {
470470
match extension {
471471
"cshtml" | "razor" => Razor.process(content),
472472
"haml" => Haml.process(content),
473+
"json" => Json.process(content),
473474
"pug" => Pug.process(content),
474475
"rb" | "erb" => Ruby.process(content),
475476
"slim" => Slim.process(content),

0 commit comments

Comments
 (0)