From 4538b3dd3488c68fc12e72f16198a62bcd2a47f4 Mon Sep 17 00:00:00 2001 From: LastLeaf Date: Fri, 23 Aug 2024 19:42:14 +0800 Subject: [PATCH 1/2] fix: template literal update path tree calculation (#141) --- glass-easel-template-compiler/src/group.rs | 35 +++++++-- .../src/proc_gen/expr.rs | 45 +++++++----- .../src/proc_gen/tag.rs | 20 +++--- glass-easel/tests/base/env.ts | 6 +- glass-easel/tests/tmpl/expression.test.ts | 72 +++++++++++++++++-- 5 files changed, 135 insertions(+), 43 deletions(-) diff --git a/glass-easel-template-compiler/src/group.rs b/glass-easel-template-compiler/src/group.rs index 44b6936..907576d 100644 --- a/glass-easel-template-compiler/src/group.rs +++ b/glass-easel-template-compiler/src/group.rs @@ -51,6 +51,17 @@ const RUNTIME_ITEMS: [(&'static str, &'static str); 4] = [ ("P", "function(a){return typeof a==='function'?a:()=>{}}"), ]; +const EXTRA_RUNTIME_ITEMS: [(&'static str, &'static str); 2] = [ + ("a", "function(a){for(var i=0;i { var modules = Object.create(null); @@ -98,21 +109,35 @@ fn runtime_fns( Ok(()) })?; } + w.expr_stmt(|w| { + write!(w, "var Q={{")?; + for (i, (k, v)) in EXTRA_RUNTIME_ITEMS.iter().enumerate() { + if i > 0 { + write!(w, ",")?; + } + write!(w, "{}:{}", k, v)?; + } + if need_wxs_runtime { + for (k, v) in WXS_RUNTIME_ITEMS.iter() { + write!(w, ",{}:{}", k, v)?; + } + } + write!(w, "}}")?; + Ok(()) + })?; if need_wxs_runtime { w.expr_stmt(|w| { write!(w, "{}", WXS_RUNTIME)?; Ok(()) })?; - w.expr_stmt(|w| { - write!(w, "var Q={{A:(x)=>x,B:(x)=>x}}")?; - Ok(()) - })?; } Ok(()) } fn runtime_var_list() -> Vec<&'static str> { - RUNTIME_ITEMS.iter().map(|(k, _)| *k).collect() + let mut ret: Vec<_> = RUNTIME_ITEMS.iter().map(|(k, _)| *k).collect(); + ret.push("Q"); + ret } /// A general template error. diff --git a/glass-easel-template-compiler/src/proc_gen/expr.rs b/glass-easel-template-compiler/src/proc_gen/expr.rs index 42a797f..909ce18 100644 --- a/glass-easel-template-compiler/src/proc_gen/expr.rs +++ b/glass-easel-template-compiler/src/proc_gen/expr.rs @@ -37,6 +37,7 @@ impl PathSliceList { list: &Vec, w: &mut W, scopes: &Vec, + is_template_data: bool, ) -> Result<(), TmplError> { if list.len() > 0 { let need_paren = list.len() > 1; @@ -48,7 +49,7 @@ impl PathSliceList { if i > 0 { write!(w, "||")?; } - write!(w, "{}", this.to_path_analysis_str(scopes)?)?; + write!(w, "{}", this.to_path_analysis_str(scopes, is_template_data)?)?; } if need_paren { write!(w, ")")?; @@ -209,7 +210,7 @@ impl PathSliceList { Ok(()) } - fn to_path_analysis_str(&self, scopes: &Vec) -> Result { + fn to_path_analysis_str(&self, scopes: &Vec, is_template_data: bool) -> Result { let mut ret = String::new(); for path_slice in self.0.iter() { match path_slice { @@ -235,7 +236,7 @@ impl PathSliceList { for (key, sub_pas_str, sub_p) in v.iter() { let mut sub_s = String::new(); let sub_pas_str = - sub_pas_str.to_path_analysis_str(sub_p, &mut sub_s, scopes)?; + sub_pas_str.to_path_analysis_str(sub_p, &mut sub_s, scopes, is_template_data)?; if let Some(_) = sub_pas_str { match key { Some(key) => { @@ -254,47 +255,55 @@ impl PathSliceList { } } } - if need_object_assign { - write!(ret, "{}Object.assign({{{}}})", prepend, s)?; + if is_template_data { + if need_object_assign { + write!(ret, "{}Object.assign({{{}}})", prepend, s)?; + } else { + write!(ret, "{}{{{}}}", prepend, s)?; + } } else { - write!(ret, "{}{{{}}}", prepend, s)?; + if need_object_assign { + write!(ret, "{}Q.b(Object.assign({{{}}}))", prepend, s)?; + } else { + write!(ret, "{}Q.b({{{}}})", prepend, s)?; + } } } PathSlice::CombineArr(v, spread) => { for (sub_pas, sub_p) in spread.iter() { let mut sub_s = String::new(); let sub_pas_str = - sub_pas.to_path_analysis_str(sub_p, &mut sub_s, scopes)?; + sub_pas.to_path_analysis_str(sub_p, &mut sub_s, scopes, is_template_data)?; if let Some(_) = sub_pas_str { - write!(ret, "({})===true||", sub_s)?; + write!(ret, "({})!==undefined||", sub_s)?; } } - write!(ret, "[")?; + write!(ret, "Q.a([")?; let mut next_need_comma_sep = false; for (sub_pas, sub_p) in v.iter() { if next_need_comma_sep { write!(ret, ",")?; } let mut s = String::new(); - let sub_pas_str = sub_pas.to_path_analysis_str(sub_p, &mut s, scopes)?; + let sub_pas_str = sub_pas.to_path_analysis_str(sub_p, &mut s, scopes, is_template_data)?; if let Some(_) = sub_pas_str { write!(ret, "{}", s)?; next_need_comma_sep = true; } } - write!(ret, "]")?; + write!(ret, "])")?; } PathSlice::Condition(cond, (true_pas, true_p), (false_pas, false_p)) => { - write!(ret, "({}?", cond)?; + write!(ret, "({}?", cond)?; // FIXME `cond` itself should calc its path slices? if true_pas - .to_path_analysis_str(true_p, &mut ret, scopes)? + .to_path_analysis_str(true_p, &mut ret, scopes, is_template_data)? .is_none() { write!(ret, "undefined")?; } write!(ret, ":")?; if false_pas - .to_path_analysis_str(false_p, &mut ret, scopes)? + .to_path_analysis_str(false_p, &mut ret, scopes, is_template_data)? .is_none() { write!(ret, "undefined")?; @@ -319,11 +328,12 @@ impl PathAnalysisState { sub_p: &Vec, w: &mut W, scopes: &Vec, + is_template_data: bool, ) -> Result, TmplError> { - PathSliceList::to_path_analysis_str_group_prefix(&sub_p, w, scopes)?; + PathSliceList::to_path_analysis_str_group_prefix(&sub_p, w, scopes, is_template_data)?; let ret = match self { PathAnalysisState::InPath(path_slices) => { - let s = path_slices.to_path_analysis_str(scopes)?; + let s = path_slices.to_path_analysis_str(scopes, is_template_data)?; write!(w, "{}", s)?; Some(()) } @@ -1228,8 +1238,9 @@ impl ExpressionProcGen { &self, w: &mut JsExprWriter, scopes: &Vec, + is_template_data: bool, ) -> Result<(), TmplError> { - let pas_str = self.pas.to_path_analysis_str(&self.sub_p, w, scopes)?; + let pas_str = self.pas.to_path_analysis_str(&self.sub_p, w, scopes, is_template_data)?; if let Some(_) = pas_str { // empty } else { diff --git a/glass-easel-template-compiler/src/proc_gen/tag.rs b/glass-easel-template-compiler/src/proc_gen/tag.rs index 41f8f12..5ec86c3 100644 --- a/glass-easel-template-compiler/src/proc_gen/tag.rs +++ b/glass-easel-template-compiler/src/proc_gen/tag.rs @@ -284,7 +284,7 @@ impl Node { let p = expression.to_proc_gen_prepare(w, scopes)?; w.expr_stmt(|w| { write!(w, r#"C||K||"#)?; - p.lvalue_state_expr(w, scopes)?; + p.lvalue_state_expr(w, scopes, false)?; write!(w, r#"?T(Y("#)?; p.value_expr(w)?; write!(w, r#")"#)?; @@ -952,7 +952,7 @@ impl Element { key => gen_lit_str(key), } )?; - p.lvalue_state_expr(w, scopes)?; + p.lvalue_state_expr(w, scopes, false)?; write!(w, ":undefined,")?; if lvalue_path_from_data_scope.is_some() { p.lvalue_path(w, scopes, None)?; @@ -1013,7 +1013,7 @@ impl Element { )?; p.value_expr(w)?; write!(w, ",K||(U?")?; - p.lvalue_state_expr(w, scopes)?; + p.lvalue_state_expr(w, scopes, true)?; write!(w, ":undefined)).C(C,T,E,B,F,S,J)")?; Ok(()) }) @@ -1070,7 +1070,7 @@ impl Element { } StaticStrOrProcGen::Dynamic(p) => { write!(w, r#"C||K||"#)?; - p.lvalue_state_expr(w, scopes)?; + p.lvalue_state_expr(w, scopes, false)?; write!(w, r#"?Y("#)?; p.value_expr(w)?; write!(w, "):undefined")?; @@ -1108,7 +1108,7 @@ impl Element { let p = expression.to_proc_gen_prepare(w, scopes)?; w.expr_stmt(|w| { write!(w, "if(C||K||")?; - p.lvalue_state_expr(w, scopes)?; + p.lvalue_state_expr(w, scopes, false)?; write!(w, ")R.l(N,{},", gen_lit_str(name))?; p.value_expr(w)?; if attr_name_maybe_event_binding(name) { @@ -1161,7 +1161,7 @@ fn write_attribute_value( let p = expression.to_proc_gen_prepare(w, scopes)?; w.expr_stmt(|w| { write!(w, "if(C||K||")?; - p.lvalue_state_expr(w, scopes)?; + p.lvalue_state_expr(w, scopes, false)?; write!(w, "){}(N,", method_name)?; p.value_expr(w)?; write!(w, ")")?; @@ -1247,7 +1247,7 @@ impl Attribute { let p = expression.to_proc_gen_prepare(w, scopes)?; w.expr_stmt(|w| { write!(w, "if(C||K||")?; - p.lvalue_state_expr(w, scopes)?; + p.lvalue_state_expr(w, scopes, false)?; write!(w, "){}(N,{},", method_name, gen_lit_str(&self.name.name))?; p.value_expr(w)?; write!(w, ")")?; @@ -1303,7 +1303,7 @@ impl Attribute { let p = expression.to_proc_gen_prepare(w, scopes)?; w.expr_stmt(|w| { write!(w, "if(C||K||")?; - p.lvalue_state_expr(w, scopes)?; + p.lvalue_state_expr(w, scopes, false)?; write!(w, ")O(N,{},", attr_name)?; p.value_expr(w)?; if self.is_model { @@ -1370,7 +1370,7 @@ impl Attribute { let p = expression.to_proc_gen_prepare(w, scopes)?; w.expr_stmt(|w| { write!(w, "if(C||K||")?; - p.lvalue_state_expr(w, scopes)?; + p.lvalue_state_expr(w, scopes, false)?; write!(w, ")R.p(N,{},", attr_name)?; p.value_expr(w)?; if p.has_script_lvalue_path(scopes) { @@ -1433,7 +1433,7 @@ impl EventBinding { let p = expression.to_proc_gen_prepare(w, scopes)?; w.expr_stmt(|w| { write!(w, "if(C||K||")?; - p.lvalue_state_expr(w, scopes)?; + p.lvalue_state_expr(w, scopes, false)?; write!(w, ")R.v(N,{},", gen_lit_str(&self.name.name),)?; p.value_expr(w)?; write!( diff --git a/glass-easel/tests/base/env.ts b/glass-easel/tests/base/env.ts index bdea340..25cd084 100644 --- a/glass-easel/tests/base/env.ts +++ b/glass-easel/tests/base/env.ts @@ -88,12 +88,8 @@ export const tmpl = (src: string, options?: TemplateOptions, filterFuncs?: Filte let genObjectSrc = `return ${group.getTmplGenObjectGroups()}` group.free() if (filterFuncs !== undefined) { - const A = filterFuncs.A || ((x) => x) const C = filterFuncs.C || 'undefined' - genObjectSrc = genObjectSrc.replace( - 'var Q={A:(x)=>x,B:(x)=>x}', - `var Q={A:${A.toString()},C:${C.toString()}}`, - ) + genObjectSrc = genObjectSrc.replace('var Q={', `var Q={C:${C.toString()},`) } // console.info(genObjectSrc) // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment diff --git a/glass-easel/tests/tmpl/expression.test.ts b/glass-easel/tests/tmpl/expression.test.ts index 81b1b35..e6d02ca 100644 --- a/glass-easel/tests/tmpl/expression.test.ts +++ b/glass-easel/tests/tmpl/expression.test.ts @@ -301,16 +301,17 @@ describe('binding expression', () => { test('object literal path analysis', () => { const onTChanged = jest.fn() const onUChanged = jest.fn() + const onAChanged = jest.fn() const subComp = glassEasel.registerElement({ template: tmpl(''), - properties: { t: String, u: String }, - observers: { t: onTChanged, u: onUChanged }, + properties: { t: String, u: String, a: Array }, + observers: { t: onTChanged, u: onUChanged, a: onAChanged }, }) const comp = glassEasel.registerElement({ using: { sub: subComp.general() }, template: tmpl(`