@ape-egg/vibe-compiler 4.3.27 → 4.3.28
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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ape-egg/vibe-compiler",
|
|
3
|
-
"version": "4.3.
|
|
3
|
+
"version": "4.3.28",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Optional Rust compiler for Vibe — pre-renders, inlines components, and optimizes iterations. The runtime never needs it.",
|
|
6
6
|
"homepage": "https://vibe.korte.kim",
|
|
@@ -7,6 +7,7 @@ use serde_json::Value;
|
|
|
7
7
|
use std::cell::RefCell;
|
|
8
8
|
use std::collections::{HashMap, BTreeMap};
|
|
9
9
|
use crate::compiler::iteration_optimizer::build_iteration_optimizations;
|
|
10
|
+
use crate::constants::DEFER_ATTR_PREFIX;
|
|
10
11
|
|
|
11
12
|
pub struct ManifestBuilder {
|
|
12
13
|
binding_regex: Regex,
|
|
@@ -127,7 +128,7 @@ impl ManifestBuilder {
|
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
NodeData::Element { name, attrs, .. } => {
|
|
130
|
-
let
|
|
131
|
+
let tag_name = name.local.to_string();
|
|
131
132
|
|
|
132
133
|
// Check attribute bindings (both value and name bindings)
|
|
133
134
|
let mut attr_bindings = BTreeMap::new();
|
|
@@ -170,9 +171,25 @@ impl ManifestBuilder {
|
|
|
170
171
|
// Store if we have any bindings
|
|
171
172
|
let has_name_bindings = name_bindings.iter().any(|b| b.is_some());
|
|
172
173
|
|
|
174
|
+
// A fetched component binds only src and key, as the runtime's
|
|
175
|
+
// parse does: every other attribute is a prop substituted into the
|
|
176
|
+
// fetched template. Bound here, a prop hydrates as a plain
|
|
177
|
+
// attribute and a falsy one strips itself before the fetch reads
|
|
178
|
+
// it. Restoration still carries every binding, so a stamped prop
|
|
179
|
+
// is back in its raw form before the fetch.
|
|
180
|
+
let attr_value = |n: &str| borrowed_attrs.iter().find(|a| &*a.name.local == n).map(|a| a.value.to_string());
|
|
181
|
+
let fetched = (tag_name == "component"
|
|
182
|
+
|| (tag_name == "div" && attr_value("class").is_some_and(|c| c.split_whitespace().any(|c| c == "component"))))
|
|
183
|
+
&& (attr_value("src").is_some() || attr_value(&format!("{}src", DEFER_ATTR_PREFIX)).is_some());
|
|
184
|
+
let bound: BTreeMap<String, String> = attr_bindings
|
|
185
|
+
.iter()
|
|
186
|
+
.filter(|(k, _)| !fetched || ["src", "key"].contains(&k.as_str()))
|
|
187
|
+
.map(|(k, v)| (k.clone(), v.clone()))
|
|
188
|
+
.collect();
|
|
189
|
+
|
|
173
190
|
// Set runtime-compatible fields at node level
|
|
174
|
-
if !
|
|
175
|
-
manifest_node.attributes = Some(
|
|
191
|
+
if !bound.is_empty() {
|
|
192
|
+
manifest_node.attributes = Some(bound);
|
|
176
193
|
}
|
|
177
194
|
if has_name_bindings {
|
|
178
195
|
manifest_node.name_bindings = Some(name_bindings.clone());
|
|
@@ -667,6 +684,24 @@ mod tests {
|
|
|
667
684
|
assert_eq!(result, vec!["Hello World"]);
|
|
668
685
|
}
|
|
669
686
|
|
|
687
|
+
// A prop on a fetched component is no attribute binding: hydrated as one, a
|
|
688
|
+
// falsy `open="@[flag]"` strips itself before the fetch reads it. It is
|
|
689
|
+
// still restored, so the fetch sees it raw.
|
|
690
|
+
#[test]
|
|
691
|
+
fn fetched_component_binds_only_src_and_key() {
|
|
692
|
+
let html = r#"<component src="@[src]" key="@[id]" open="@[flag]"></component><component open="@[flag]"></component>"#;
|
|
693
|
+
let manifest = ManifestBuilder::new().build_from_html(html, &json!({}), false).unwrap();
|
|
694
|
+
let body = manifest.children.get("html_0").unwrap().children.get("body_1").unwrap();
|
|
695
|
+
|
|
696
|
+
let fetched = body.children.get("component_0").unwrap();
|
|
697
|
+
assert_eq!(fetched.attributes.as_ref().unwrap().keys().collect::<Vec<_>>(), ["key", "src"]);
|
|
698
|
+
let restored = fetched.compiled.as_ref().unwrap().restoration.as_ref().unwrap().attributes.as_ref().unwrap();
|
|
699
|
+
assert_eq!(restored.get("open").unwrap(), "@[flag]");
|
|
700
|
+
|
|
701
|
+
let inline = body.children.get("component_1").unwrap();
|
|
702
|
+
assert_eq!(inline.attributes.as_ref().unwrap().get("open").unwrap(), "@[flag]");
|
|
703
|
+
}
|
|
704
|
+
|
|
670
705
|
#[test]
|
|
671
706
|
fn build_multiple_name_bindings() {
|
|
672
707
|
let html = r#"<div test @[theme] @[size]></div>"#;
|