mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
Handle ' syntax in ClojureScript when extracting classes (#18888)
This PR fixes an issue where the `'` syntax in ClojureScript was not handled properly, resulting in missing extracted classes. This PR now supports the following ClojureScript syntaxes: ```cljs ; Keyword (print 'text-red-500) ; List (print '(flex flex-col underline)) ; Vector (print '[flex flex-col underline]) ``` ### Test plan 1. Added regression tests 2. Verified that we extract classes correctly now in various scenarios: Top is before, bottom is with this PR: <img width="1335" height="1862" alt="image" src="https://github.com/user-attachments/assets/746aa073-25f8-41f8-b71c-ba83a33065aa" /> Fixes: #18882
This commit is contained in:
parent
1334c99db8
commit
274be93fd8
@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- Nothing yet!
|
||||
### Fixed
|
||||
|
||||
- Handle `'` syntax in ClojureScript when extracting classes ([#18888](https://github.com/tailwindlabs/tailwindcss/pull/18888))
|
||||
|
||||
## [4.1.13] - 2025-09-03
|
||||
|
||||
|
||||
@ -108,6 +108,75 @@ impl PreProcessor for Clojure {
|
||||
}
|
||||
}
|
||||
|
||||
// Handle quote with a list, e.g.: `'(…)`
|
||||
// and with a vector, e.g.: `'[…]`
|
||||
b'\'' if matches!(cursor.next, b'[' | b'(') => {
|
||||
result[cursor.pos] = b' ';
|
||||
cursor.advance();
|
||||
result[cursor.pos] = b' ';
|
||||
let end = match cursor.curr {
|
||||
b'[' => b']',
|
||||
b'(' => b')',
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// Consume until the closing `]`
|
||||
while cursor.pos < len {
|
||||
match cursor.curr {
|
||||
x if x == end => {
|
||||
result[cursor.pos] = b' ';
|
||||
break;
|
||||
}
|
||||
|
||||
// Consume strings as-is
|
||||
b'"' => {
|
||||
result[cursor.pos] = b' ';
|
||||
cursor.advance();
|
||||
|
||||
while cursor.pos < len {
|
||||
match cursor.curr {
|
||||
// Escaped character, skip ahead to the next character
|
||||
b'\\' => cursor.advance_twice(),
|
||||
|
||||
// End of the string
|
||||
b'"' => {
|
||||
result[cursor.pos] = b' ';
|
||||
break;
|
||||
}
|
||||
|
||||
// Everything else is valid
|
||||
_ => cursor.advance(),
|
||||
};
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
cursor.advance();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle quote with a keyword, e.g.: `'bg-white`
|
||||
b'\'' if !cursor.next.is_ascii_whitespace() => {
|
||||
result[cursor.pos] = b' ';
|
||||
cursor.advance();
|
||||
|
||||
while cursor.pos < len {
|
||||
match cursor.curr {
|
||||
// End of keyword.
|
||||
_ if !is_keyword_character(cursor.curr) => {
|
||||
result[cursor.pos] = b' ';
|
||||
break;
|
||||
}
|
||||
|
||||
// Consume everything else.
|
||||
_ => {}
|
||||
};
|
||||
|
||||
cursor.advance();
|
||||
}
|
||||
}
|
||||
|
||||
// Aggressively discard everything else, reducing false positives and preventing
|
||||
// characters surrounding keywords from producing false negatives.
|
||||
// E.g.:
|
||||
@ -281,4 +350,87 @@ mod tests {
|
||||
vec!["py-5", "flex", "pr-1.5", "bg-white", "bg-black"],
|
||||
);
|
||||
}
|
||||
|
||||
// https://github.com/tailwindlabs/tailwindcss/issues/18882
|
||||
#[test]
|
||||
fn test_extract_from_symbol_list() {
|
||||
let input = r#"
|
||||
[:div {:class '[z-1 z-2
|
||||
z-3 z-4]}]
|
||||
"#;
|
||||
Clojure::test_extract_contains(input, vec!["z-1", "z-2", "z-3", "z-4"]);
|
||||
|
||||
// https://github.com/tailwindlabs/tailwindcss/pull/18345#issuecomment-3253403847
|
||||
let input = r#"
|
||||
(def hl-class-names '[ring ring-blue-500])
|
||||
|
||||
[:div
|
||||
{:class (cond-> '[input w-full]
|
||||
textarea? (conj 'textarea)
|
||||
(seq errors) (concat '[border-red-500 bg-red-100])
|
||||
highlight? (concat hl-class-names))}]
|
||||
"#;
|
||||
Clojure::test_extract_contains(
|
||||
input,
|
||||
vec![
|
||||
"ring",
|
||||
"ring-blue-500",
|
||||
"input",
|
||||
"w-full",
|
||||
"textarea",
|
||||
"border-red-500",
|
||||
"bg-red-100",
|
||||
],
|
||||
);
|
||||
|
||||
let input = r#"
|
||||
[:div
|
||||
{:class '[h-100 lg:h-200 max-w-32 mx-auto py-60
|
||||
flex flex-col justify-end items-center
|
||||
lg:flex-row lg:justify-between
|
||||
bg-cover bg-center bg-no-repeat rounded-3xl overflow-hidden
|
||||
font-semibold text-gray-900]}]
|
||||
"#;
|
||||
Clojure::test_extract_contains(
|
||||
input,
|
||||
vec![
|
||||
"h-100",
|
||||
"lg:h-200",
|
||||
"max-w-32",
|
||||
"mx-auto",
|
||||
"py-60",
|
||||
"flex",
|
||||
"flex-col",
|
||||
"justify-end",
|
||||
"items-center",
|
||||
"lg:flex-row",
|
||||
"lg:justify-between",
|
||||
"bg-cover",
|
||||
"bg-center",
|
||||
"bg-no-repeat",
|
||||
"rounded-3xl",
|
||||
"overflow-hidden",
|
||||
"font-semibold",
|
||||
"text-gray-900",
|
||||
],
|
||||
);
|
||||
|
||||
// `/` is invalid and requires explicit quoting
|
||||
let input = r#"
|
||||
'[p-32 "text-black/50"]
|
||||
"#;
|
||||
Clojure::test_extract_contains(input, vec!["p-32", "text-black/50"]);
|
||||
|
||||
// `[…]` is invalid and requires explicit quoting
|
||||
let input = r#"
|
||||
(print '[ring ring-blue-500 "bg-[#0088cc]"])
|
||||
"#;
|
||||
Clojure::test_extract_contains(input, vec!["ring", "ring-blue-500", "bg-[#0088cc]"]);
|
||||
|
||||
// `'(…)` looks similar to `[…]` but uses parentheses instead of brackets
|
||||
let input = r#"
|
||||
(print '(ring ring-blue-500 "bg-[#0088cc]"))
|
||||
"#;
|
||||
Clojure::test_extract_contains(input, vec!["ring", "ring-blue-500", "bg-[#0088cc]"]);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user