Pre process Slim templates embedded in Ruby files (#17336)
This PR fixes an issue where embedded Slim templates inside of Ruby
files are not pre processed because we pre process based on a file
extension.
This PR also handles embedded SLIM templates using the following syntax:
```rb
slim_template <<~SLIM
.flex
.flex-1
h1 Hello World
.flex-1
p This is a test
SLIM
```
~~As far as I can tell, this is only a Slim template thing and not a
Haml template thing but I could be wrong here. See:
https://viewcomponent.org/guide/templates.html#interpolations~~
The ViewComponent package handles anything that looks like
`{lang}_template`, so the lang here will be used as the pre processing
language for now.
Fixes: #17334
# Test plan
1. Added test for this
2. Existing tests pass
3. Made sure that the snippet from the issue works as expected:
Added an example where we have a `slim_template` and a `svelte_template`
to prove that it embeds based on the language. I also added a
`html_template` with Svelte syntax to really make sure that that
_doesn't_ work.
<img width="1816" alt="image"
src="https://github.com/user-attachments/assets/35564a32-9c46-4b51-bb1f-e02f4ffe8b01"
/>
This commit is contained in:
parent
fac8f7df62
commit
711b9cd0db
4 changed files with 98 additions and 0 deletions
|
|
@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- Vite: Ensure that updates to an imported CSS file are properly propagated after updating templates ([#17347](https://github.com/tailwindlabs/tailwindcss/pull/17347))
|
||||
- Fix class extraction followed by `(` in Pug ([#17320](https://github.com/tailwindlabs/tailwindcss/pull/17320))
|
||||
- Pre process `Slim` templates embedded in Ruby files ([#17336](https://github.com/tailwindlabs/tailwindcss/pull/17336))
|
||||
|
||||
### [4.0.15] - 2025-03-20
|
||||
|
||||
|
|
|
|||
27
Cargo.lock
generated
27
Cargo.lock
generated
|
|
@ -27,6 +27,21 @@ dependencies = [
|
|||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
|
||||
dependencies = [
|
||||
"bit-vec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-vec"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
|
|
@ -156,6 +171,17 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fancy-regex"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"regex-automata 0.4.8",
|
||||
"regex-syntax 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fast-glob"
|
||||
version = "0.4.3"
|
||||
|
|
@ -538,6 +564,7 @@ dependencies = [
|
|||
"classification-macros",
|
||||
"crossbeam",
|
||||
"dunce",
|
||||
"fancy-regex",
|
||||
"fast-glob",
|
||||
"globwalk",
|
||||
"ignore",
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ bexpand = "1.2.0"
|
|||
fast-glob = "0.4.3"
|
||||
classification-macros = { path = "../classification-macros" }
|
||||
regex = "1.11.1"
|
||||
fancy-regex = "0.14.0"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.13.0"
|
||||
|
|
|
|||
|
|
@ -3,6 +3,14 @@
|
|||
use crate::cursor;
|
||||
use crate::extractor::bracket_stack;
|
||||
use crate::extractor::pre_processors::pre_processor::PreProcessor;
|
||||
use crate::pre_process_input;
|
||||
use bstr::ByteSlice;
|
||||
use fancy_regex::Regex;
|
||||
use std::sync;
|
||||
|
||||
static TEMPLATE_REGEX: sync::LazyLock<Regex> = sync::LazyLock::new(|| {
|
||||
Regex::new(r#"\s*(.*?)_template\s*<<[-~]?([A-Z]+?)\n([\s\S]*?)\2"#).unwrap()
|
||||
});
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Ruby;
|
||||
|
|
@ -14,6 +22,20 @@ impl PreProcessor for Ruby {
|
|||
let mut cursor = cursor::Cursor::new(content);
|
||||
let mut bracket_stack = bracket_stack::BracketStack::default();
|
||||
|
||||
// Extract embedded template languages
|
||||
// https://viewcomponent.org/guide/templates.html#interpolations
|
||||
let content_as_str = std::str::from_utf8(content).unwrap();
|
||||
for capture in TEMPLATE_REGEX
|
||||
.captures_iter(content_as_str)
|
||||
.filter_map(Result::ok)
|
||||
{
|
||||
let lang = capture.get(1).unwrap().as_str();
|
||||
let body = capture.get(3).unwrap().as_str();
|
||||
let replaced = pre_process_input(body.as_bytes(), lang);
|
||||
result = result.replace(body, replaced);
|
||||
}
|
||||
|
||||
// Ruby extraction
|
||||
while cursor.pos < len {
|
||||
// Looking for `%w` or `%W`
|
||||
if cursor.curr != b'%' && !matches!(cursor.next, b'w' | b'W') {
|
||||
|
|
@ -153,4 +175,51 @@ mod tests {
|
|||
Ruby::test_extract_contains(input, expected);
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/tailwindlabs/tailwindcss/issues/17334
|
||||
#[test]
|
||||
fn test_embedded_slim_extraction() {
|
||||
let input = r#"
|
||||
class QweComponent < ApplicationComponent
|
||||
slim_template <<~SLIM
|
||||
button.rounded-full.bg-red-500
|
||||
| Some text
|
||||
button.rounded-full(
|
||||
class="flex"
|
||||
)
|
||||
| Some text
|
||||
SLIM
|
||||
end
|
||||
"#;
|
||||
|
||||
Ruby::test_extract_contains(input, vec!["rounded-full", "bg-red-500", "flex"]);
|
||||
|
||||
// Embedded Svelte just to verify that we properly pick up the `{x}_template`
|
||||
let input = r#"
|
||||
class QweComponent < ApplicationComponent
|
||||
svelte_template <<~HTML
|
||||
<div class:flex="true"></div>
|
||||
HTML
|
||||
end
|
||||
"#;
|
||||
|
||||
Ruby::test_extract_contains(input, vec!["flex"]);
|
||||
|
||||
// Together in the same file
|
||||
let input = r#"
|
||||
class QweComponent < ApplicationComponent
|
||||
slim_template <<~SLIM
|
||||
button.z-1.z-2
|
||||
| Some text
|
||||
SLIM
|
||||
end
|
||||
|
||||
class QweComponent < ApplicationComponent
|
||||
svelte_template <<~HTML
|
||||
<div class:z-3="true"></div>
|
||||
HTML
|
||||
end
|
||||
"#;
|
||||
Ruby::test_extract_contains(input, vec!["z-1", "z-2", "z-3"]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue