mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
Fix class extraction followed by ( in Slim (#17278)
This PR fixes an issue where using the class shorthand in Slim
templates, followed by an `(` results in the last class being ignored.
E.g.:
```slim
body.border-t-4.p-8(class="#{body_classes}" data-hotwire-native="#{hotwire_native_app?}" data-controller="update-time-zone")
```
This is because we will eventually extract `p-8` but it's followed by an
invalid boundary character `(`.
To solve this, we make sure to replace the `(` with a space. We already
do a similar thing when the classes are followed by an `[`.
One caveat, we _can_ have `(` in our classes, like `bg-(--my-color)`.
But in my testing this is not something that can be used in the
shorthand version.
E.g.:
```slim
div.bg-(--my-color)
```
Compiles to:
```html
<div --my-color="" class="bg-"></div>
```
So I didn't add any special handling for this. Even when trying to
escape the `(`, `-` and `)` characters, it still doesn't work. E.g.:
```slim
div.bg-\(--my-color\)
```
Compiles to:
```html
<div class="bg-">\(--my-color\)</div>
```
# Test plan
1. Added test for the issue
2. Existing tests pass
3. Verified via the extractor tool:
| Before | After |
| --- | --- |
| <img width="958" alt="image"
src="https://github.com/user-attachments/assets/f72c420e-5429-424f-a01d-12f724062bf2"
/> | <img width="958" alt="image"
src="https://github.com/user-attachments/assets/b0cc8f2f-97a8-4fca-8813-3bb1da8d99a8"
/> |
---
Fixes: #17277
This commit is contained in:
parent
d698c10836
commit
f369e22172
@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Remove redundant `line-height: initial` from Preflight ([#15212](https://github.com/tailwindlabs/tailwindcss/pull/15212))
|
||||
- Prevent segfault when loaded in a worker thread on Linux ([#17276](https://github.com/tailwindlabs/tailwindcss/pull/17276))
|
||||
- Ensure multiple `--value(…)` or `--modifier(…)` calls don't delete subsequent declarations ([#17273](https://github.com/tailwindlabs/tailwindcss/pull/17273))
|
||||
- Fix class extraction followed by `(` in Slim ([#17278](https://github.com/tailwindlabs/tailwindcss/pull/17278))
|
||||
|
||||
## [4.0.14] - 2025-03-13
|
||||
|
||||
|
||||
@ -80,6 +80,23 @@ impl PreProcessor for Slim {
|
||||
bracket_stack.push(cursor.curr);
|
||||
}
|
||||
|
||||
// In slim the class name shorthand can be followed by a parenthesis. E.g.:
|
||||
//
|
||||
// ```slim
|
||||
// body.border-t-4.p-8(attr=value)
|
||||
// ^ Not part of the p-8 class
|
||||
// ```
|
||||
//
|
||||
// This means that we need to replace all these `(` and `)` with spaces to make
|
||||
// sure that we can extract the `p-8`.
|
||||
//
|
||||
// However, we also need to make sure that we keep the parens that are part of the
|
||||
// utility class. E.g.: `bg-(--my-color)`.
|
||||
b'(' if bracket_stack.is_empty() && !matches!(cursor.prev, b'-' | b'/') => {
|
||||
result[cursor.pos] = b' ';
|
||||
bracket_stack.push(cursor.curr);
|
||||
}
|
||||
|
||||
b'(' | b'[' | b'{' => {
|
||||
bracket_stack.push(cursor.curr);
|
||||
}
|
||||
@ -116,7 +133,7 @@ mod tests {
|
||||
" bg-red-500 2xl:flex bg-green-200 3xl:flex",
|
||||
),
|
||||
// Keep dots in strings
|
||||
(r#"div(class="px-2.5")"#, r#"div(class="px-2.5")"#),
|
||||
(r#"div(class="px-2.5")"#, r#"div class="px-2.5")"#),
|
||||
// Replace top-level `(a-z0-9)[` with `$1 `. E.g.: `.flex[x]` -> `.flex x]`
|
||||
(".text-xl.text-red-600[", " text-xl text-red-600 "),
|
||||
// But keep important brackets:
|
||||
@ -194,6 +211,42 @@ mod tests {
|
||||
Slim::test_extract_contains(input, vec!["text-red-500", "text-3xl"]);
|
||||
}
|
||||
|
||||
// https://github.com/tailwindlabs/tailwindcss/issues/17277
|
||||
#[test]
|
||||
fn test_class_shorthand_followed_by_parens() {
|
||||
let input = r#"
|
||||
body.border-t-4.p-8(class="\#{body_classes}" data-hotwire-native="\#{hotwire_native_app?}" data-controller="update-time-zone")
|
||||
"#;
|
||||
Slim::test_extract_contains(input, vec!["border-t-4", "p-8"]);
|
||||
|
||||
// Additional test with CSS Variable shorthand syntax in the attribute itself because `(`
|
||||
// and `)` are not valid in the class shorthand version.
|
||||
//
|
||||
// Also included an arbitrary value including `(` and `)` to make sure that we don't
|
||||
// accidentally remove those either.
|
||||
let input = r#"
|
||||
body.p-8(class="bg-(--my-color) bg-(--my-color)/(--my-opacity) bg-[url(https://example.com)]")
|
||||
"#;
|
||||
Slim::test_extract_contains(
|
||||
input,
|
||||
vec![
|
||||
"p-8",
|
||||
"bg-(--my-color)",
|
||||
"bg-(--my-color)/(--my-opacity)",
|
||||
"bg-[url(https://example.com)]",
|
||||
],
|
||||
);
|
||||
|
||||
// Top-level class shorthand with parens
|
||||
let input = r#"
|
||||
div class="bg-(--my-color) bg-(--my-color)/(--my-opacity)"
|
||||
"#;
|
||||
Slim::test_extract_contains(
|
||||
input,
|
||||
vec!["bg-(--my-color)", "bg-(--my-color)/(--my-opacity)"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strings_only_occur_when_nested() {
|
||||
let input = r#"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user