From f498e4a97c9cea91da3341dc3d25dda779e0b03e Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 7 Mar 2025 12:19:01 +0100 Subject: [PATCH] Ensure extracting candidates from JS embedded in a PHP string works as expected (#17031) This PR fixes an issue where candidates are not properly extractor when they end in `\`. This can happen if you embed a programming language like JS inside another language like PHP where you need to escape some strings. Here is an example of Livewire flux: ```blade @php if ($sidebarIsStashable) { $attributes = $attributes->merge([ 'x-init' => '$el.classList.add(\'-translate-x-full\'); $el.classList.add(\'transition-transform\')', // ^ ^ ]); } @endphp
class('border-r w-64 p-4 min-h-dvh max-h-dvh top-0 fixed left-0') }}> {{ $slot }}
``` Where the `\'` is causing some issues. Another solution might be to add a custom pre processor for blade files where we drop the escaped characters, but that felt overkill for now because some escapes are still valid. Fixes: #17023 # Test plan 1. Added a test to cover this case. 2. Existing tests still pass --- CHANGELOG.md | 1 + crates/oxide/src/extractor/boundary.rs | 12 ++++++++++ crates/oxide/src/extractor/mod.rs | 33 ++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cbb3aee9..3c303d731 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ensure strings in Pug and Slim templates are handled correctly ([#17000](https://github.com/tailwindlabs/tailwindcss/pull/17000)) - Ensure `}` and `{` are valid boundary characters when extracting candidates ([#17001](https://github.com/tailwindlabs/tailwindcss/pull/17001)) - Add `razor`/`cshtml` pre processing ([#17027](https://github.com/tailwindlabs/tailwindcss/pull/17027)) +- Ensure extracting candidates from JS embedded in a PHP string works as expected ([#17031](https://github.com/tailwindlabs/tailwindcss/pull/17031)) ## [4.0.11] - 2025-03-06 diff --git a/crates/oxide/src/extractor/boundary.rs b/crates/oxide/src/extractor/boundary.rs index 3d13d895c..4e0f22089 100644 --- a/crates/oxide/src/extractor/boundary.rs +++ b/crates/oxide/src/extractor/boundary.rs @@ -97,6 +97,18 @@ enum Class { // ^ // ``` #[bytes(b'=')] + // Escaped character when embedding one language in another via strings, e.g.: + // + // ``` + // $attributes->merge([ + // 'x-init' => '$el.classList.add(\'-translate-x-full\'); $el.classList.add(\'transition-transform\')', + // ^ ^ + // ]); + // ``` + // + // In this case there is some JavaScript embedded in an string in PHP and some of the quotes + // need to be escaped. + #[bytes(b'\\')] After, #[fallback] diff --git a/crates/oxide/src/extractor/mod.rs b/crates/oxide/src/extractor/mod.rs index baf983831..e6e88b8f1 100644 --- a/crates/oxide/src/extractor/mod.rs +++ b/crates/oxide/src/extractor/mod.rs @@ -888,6 +888,39 @@ mod tests { ); } + #[test] + fn test_js_embedded_in_php_syntax() { + // Escaped single quotes + let input = r#" + @php + if ($sidebarIsStashable) { + $attributes = $attributes->merge([ + 'x-init' => '$el.classList.add(\'-translate-x-full\'); $el.classList.add(\'transition-transform\')', + ]); + } + @endphp + "#; + assert_extract_candidates_contains( + input, + vec!["-translate-x-full", "transition-transform"], + ); + + // Double quotes + let input = r#" + @php + if ($sidebarIsStashable) { + $attributes = $attributes->merge([ + 'x-init' => "\$el.classList.add('-translate-x-full'); \$el.classList.add('transition-transform')", + ]); + } + @endphp + "#; + assert_extract_candidates_contains( + input, + vec!["-translate-x-full", "transition-transform"], + ); + } + // https://github.com/tailwindlabs/tailwindcss/issues/16978 #[test] fn test_classes_containing_number_followed_by_dash_or_underscore() {