@ape-egg/vibe-compiler 4.3.2 → 4.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ape-egg/vibe-compiler",
3
- "version": "4.3.2",
3
+ "version": "4.3.6",
4
4
  "type": "module",
5
5
  "description": "Optional Rust compiler for Vibe \u2014 pre-renders, inlines components, and optimizes iterations. The runtime never needs it.",
6
6
  "homepage": "https://vibe.korte.kim",
package/src/Cargo.lock CHANGED
@@ -1599,7 +1599,7 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
1599
1599
 
1600
1600
  [[package]]
1601
1601
  name = "vibe-compiler"
1602
- version = "4.3.2"
1602
+ version = "4.3.6"
1603
1603
  dependencies = [
1604
1604
  "clap",
1605
1605
  "colored",
package/src/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "vibe-compiler"
3
- version = "4.3.2"
3
+ version = "4.3.6"
4
4
  edition = "2021"
5
5
  description = "Vibe framework compiler - compiles Vibe source files into optimized output"
6
6
  authors = ["Kim Korte"]
@@ -653,6 +653,51 @@ fn is_iter_prop_root(template: &str) -> bool {
653
653
  /// literal props inject the value (bare boolean attrs → true, strings
654
654
  /// JSON-quoted, numerics raw).
655
655
  fn substitute_props(template: &str, props: &[(String, String)]) -> String {
656
+ let raw_text_re =
657
+ regex::Regex::new(r"(?is)(<(?:script|style)\b[^>]*>)(.*?)(</(?:script|style)\s*>)").unwrap();
658
+
659
+ let mut out = String::with_capacity(template.len());
660
+ let mut last = 0;
661
+ for caps in raw_text_re.captures_iter(template) {
662
+ let whole = caps.get(0).unwrap();
663
+ out.push_str(&substitute_props_in(&template[last..whole.start()], props, true));
664
+ out.push_str(&substitute_props_in(caps.get(1).unwrap().as_str(), props, true));
665
+ out.push_str(&substitute_props_in(caps.get(2).unwrap().as_str(), props, false));
666
+ out.push_str(caps.get(3).unwrap().as_str());
667
+ last = whole.end();
668
+ }
669
+ out.push_str(&substitute_props_in(&template[last..], props, true));
670
+ out
671
+ }
672
+
673
+ fn escape_attr_value(value: &str) -> String {
674
+ value
675
+ .replace('&', "&amp;")
676
+ .replace('"', "&quot;")
677
+ .replace('\'', "&#39;")
678
+ }
679
+
680
+ fn decode_entities(value: &str) -> String {
681
+ value
682
+ .replace("&quot;", "\"")
683
+ .replace("&#34;", "\"")
684
+ .replace("&apos;", "'")
685
+ .replace("&#39;", "'")
686
+ .replace("&lt;", "<")
687
+ .replace("&gt;", ">")
688
+ .replace("&nbsp;", "\u{a0}")
689
+ .replace("&amp;", "&")
690
+ }
691
+
692
+ fn substitute_props_in(template: &str, props: &[(String, String)], entity_decoded: bool) -> String {
693
+ let escaped = |value: &str| {
694
+ if entity_decoded {
695
+ escape_attr_value(value)
696
+ } else {
697
+ value.to_string()
698
+ }
699
+ };
700
+
656
701
  let binding_re = regex::Regex::new(r"@\[([^\]]+)\]").unwrap();
657
702
  let directive_re = regex::Regex::new(r"(?s)<!--\s*(if|else if|each)\s+(.*?)\s*-->").unwrap();
658
703
  let event_re = regex::Regex::new(r#"\bon(\w+)="([^"]*)""#).unwrap();
@@ -660,7 +705,8 @@ fn substitute_props(template: &str, props: &[(String, String)]) -> String {
660
705
 
661
706
  let mut html = template.to_string();
662
707
 
663
- for (prop_name, prop_value) in props {
708
+ for (prop_name, raw_value) in props {
709
+ let prop_value = decode_entities(raw_value);
664
710
  let exact_re =
665
711
  regex::Regex::new(&format!(r"(?i)@\[{}\]", regex::escape(prop_name))).unwrap();
666
712
 
@@ -668,23 +714,31 @@ fn substitute_props(template: &str, props: &[(String, String)]) -> String {
668
714
  .strip_prefix("@[")
669
715
  .and_then(|v| v.strip_suffix(']'));
670
716
 
671
- let (exact_repl, ident_repl, each_repl, state_repl) = if let Some(path) = binding_path {
672
- (
673
- format!("@[{}]", path),
674
- format!("({})", path),
675
- path.to_string(),
676
- path.to_string(),
677
- )
678
- } else {
679
- let literal = if prop_value.is_empty() {
680
- "true".to_string()
681
- } else if numeric_re.is_match(prop_value) {
682
- prop_value.clone()
717
+ let (exact_repl, ident_repl, directive_repl, each_repl, state_repl) =
718
+ if let Some(path) = binding_path {
719
+ (
720
+ format!("@[{}]", path),
721
+ format!("({})", path),
722
+ format!("({})", path),
723
+ path.to_string(),
724
+ path.to_string(),
725
+ )
683
726
  } else {
684
- serde_json::to_string(prop_value).unwrap()
727
+ let literal = if prop_value.is_empty() {
728
+ "true".to_string()
729
+ } else if numeric_re.is_match(&prop_value) {
730
+ prop_value.clone()
731
+ } else {
732
+ serde_json::to_string(&prop_value).unwrap()
733
+ };
734
+ (
735
+ escaped(&prop_value),
736
+ escaped(&literal),
737
+ literal.clone(),
738
+ literal.clone(),
739
+ escaped(&literal),
740
+ )
685
741
  };
686
- (prop_value.clone(), literal.clone(), literal.clone(), literal)
687
- };
688
742
 
689
743
  html = exact_re
690
744
  .replace_all(&html, regex::NoExpand(exact_repl.as_str()))
@@ -706,7 +760,7 @@ fn substitute_props(template: &str, props: &[(String, String)]) -> String {
706
760
  .replace_all(&html, |c: &regex::Captures| {
707
761
  let kw = c.get(1).unwrap().as_str();
708
762
  let expr = c.get(2).unwrap().as_str();
709
- let repl = if kw == "each" { each_repl.as_str() } else { ident_repl.as_str() };
763
+ let repl = if kw == "each" { each_repl.as_str() } else { directive_repl.as_str() };
710
764
  let rewritten = substitute_identifier(expr, prop_name, repl);
711
765
  if rewritten == expr {
712
766
  c.get(0).unwrap().as_str().to_string()