diff --git a/crates/oxide/src/extractor/pre_processors/vue.rs b/crates/oxide/src/extractor/pre_processors/vue.rs index ae037435cdb9..94378210dbca 100644 --- a/crates/oxide/src/extractor/pre_processors/vue.rs +++ b/crates/oxide/src/extractor/pre_processors/vue.rs @@ -5,7 +5,18 @@ use regex::Regex; use std::sync; static TEMPLATE_REGEX: sync::LazyLock = sync::LazyLock::new(|| { - Regex::new(r#" + "#, + ) + .unwrap() }); #[derive(Debug, Default)] @@ -17,10 +28,16 @@ impl PreProcessor for Vue { // Only process template tags if content is valid UTF-8 if let Ok(content_as_str) = std::str::from_utf8(content) { - for (_, [lang, body]) in TEMPLATE_REGEX - .captures_iter(content_as_str) - .map(|c| c.extract()) - { + for captures in TEMPLATE_REGEX.captures_iter(content_as_str) { + let lang = captures + .get(1) + .or_else(|| captures.get(2)) + .expect("template lang capture should exist") + .as_str(); + let body = captures + .get(3) + .expect("template body capture should exist") + .as_str(); let replaced = pre_process_input(body.as_bytes().to_vec(), lang); result = result.replace(body, replaced); } @@ -46,6 +63,69 @@ mod tests { Vue::test_extract_contains(input, vec!["bg-neutral-900", "text-red-500"]); } + #[test] + fn test_vue_template_pug_with_attributes_and_whitespace() { + for input in [ + r#" + + "#, + r#" + + "#, + ] { + Vue::test_extract_contains(input, vec!["bg-neutral-900", "text-red-500"]); + } + } + + #[test] + fn test_vue_template_does_not_treat_data_lang_as_lang() { + let input = r#" + + "#; + + Vue::test(input, input); + } + + #[test] + fn test_vue_template_does_not_treat_quoted_values_as_lang() { + for attributes in [ + r#"data-config=" lang='pug'""#, + r#"data-config=' lang="pug"'"#, + r#"lang="html" data-config=" lang='pug'""#, + r#"data-config=' lang="pug"' lang="html""#, + ] { + let input = format!(r#""#); + + Vue::test(&input, &input); + } + } + + #[test] + fn test_vue_template_pug_with_quoted_attribute_values() { + for attributes in [ + r#"data-config=" lang='html'" lang="pug""#, + r#"lang='pug' data-config=' lang="html"'"#, + r#"data-config="a > b.c" lang='pug'"#, + r#"lang="pug" data-config='a > b.c'"#, + r#"functional data-test=true lang="pug""#, + ] { + let input = format!(""); + let expected = format!(""); + + Vue::test(&input, &expected); + Vue::test_extract_contains(&input, vec!["flex", "items-center"]); + } + } + #[test] fn test_invalid_utf8_does_not_panic() { // Invalid UTF-8 sequence: 0x80 is a continuation byte without a leading byte