use super::super::helpers::{to_camel_case, to_safe_identifier_fragment};
use super::super::types::VizeMapping;
use super::reserved_props::rewrite_reserved_template_prop;
use vize_carton::FxHashSet;
use vize_carton::String;
use vize_carton::append;
use vize_carton::cstr;
use vize_carton::profile;
use vize_croquis::analysis::ComponentUsage;
use vize_croquis::analyzer::strip_js_comments;
pub(crate) fn generate_component_prop_checks(
ts: &mut String,
mappings: &mut Vec<VizeMapping>,
usage: &ComponentUsage,
idx: usize,
template_prop_names: &FxHashSet<String>,
template_offset: u32,
indent: &str,
) {
let component_type_name = to_safe_identifier_fragment(usage.name.as_str());
for prop in &usage.props {
if prop.name.as_str() == "key" || prop.name.as_str() == "ref" {
continue;
}
if let Some(ref value) = prop.value
&& prop.is_dynamic
{
let prop_src_start = (template_offset + prop.start) as usize;
let prop_src_end = (template_offset + prop.end) as usize;
let value = profile!(
"canon.virtual_ts.prop_check.strip_comments",
strip_js_comments(value.as_str())
);
let trimmed_value = value.as_ref().trim();
let rewritten_value =
rewrite_reserved_template_prop(trimmed_value, template_prop_names);
let generated_value = rewritten_value
.as_ref()
.map_or_else(|| value.as_ref(), |s| s.as_str());
append!(
*ts,
"{indent}// @vize-map: prop -> {prop_src_start}:{prop_src_end}\n",
);
let safe_prop_name = to_safe_identifier_fragment(prop.name.as_str());
let expr_indent = if usage.vif_guard.is_some() {
cstr!("{indent} ")
} else {
indent.into()
};
if let Some(ref guard) = usage.vif_guard {
append!(*ts, "{indent}if ({guard}) {{\n");
}
let gen_stmt_start = ts.len();
let check_name = cstr!("__vize_prop_check_{idx}_{safe_prop_name}");
append!(
*ts,
"{expr_indent}const {check_name}: __{component_type_name}_{idx}_prop_{safe_prop_name} = {};\n",
generated_value,
);
let gen_stmt_end = ts.len();
append!(*ts, "{expr_indent}void {check_name};\n");
mappings.push(VizeMapping {
gen_range: gen_stmt_start..gen_stmt_end,
src_range: prop_src_start..prop_src_end,
sub_spans: Vec::new(),
});
if usage.vif_guard.is_some() {
append!(*ts, "{indent}}}\n");
}
}
}
generate_generic_props_call(
ts,
mappings,
usage,
idx,
template_prop_names,
template_offset,
indent,
);
}
fn generate_generic_props_call(
ts: &mut String,
mappings: &mut Vec<VizeMapping>,
usage: &ComponentUsage,
idx: usize,
template_prop_names: &FxHashSet<String>,
template_offset: u32,
indent: &str,
) {
let has_dynamic_props = usage.props.iter().any(|p| {
p.name.as_str() != "key" && p.name.as_str() != "ref" && p.value.is_some() && p.is_dynamic
});
if !has_dynamic_props {
return;
}
let component_type_name = to_safe_identifier_fragment(usage.name.as_str());
let expr_indent = if usage.vif_guard.is_some() {
cstr!("{indent} ")
} else {
indent.into()
};
if let Some(ref guard) = usage.vif_guard {
append!(*ts, "{indent}if ({guard}) {{\n");
}
append!(
*ts,
"{expr_indent}(undefined as unknown as __{component_type_name}_Check_{idx})({{\n",
);
for prop in &usage.props {
if prop.name.as_str() == "key" || prop.name.as_str() == "ref" {
continue;
}
let Some(ref value) = prop.value else {
continue;
};
if !prop.is_dynamic {
continue;
}
let prop_src_start = (template_offset + prop.start) as usize;
let prop_src_end = (template_offset + prop.end) as usize;
let value = strip_js_comments(value.as_str());
let trimmed_value = value.as_ref().trim();
let rewritten_value = rewrite_reserved_template_prop(trimmed_value, template_prop_names);
let generated_value = rewritten_value
.as_ref()
.map_or_else(|| value.as_ref(), |s| s.as_str());
let camel_prop_name = to_camel_case(prop.name.as_str());
append!(*ts, "{expr_indent} ");
let entry_gen_start = ts.len();
append!(*ts, "\"{camel_prop_name}\": {generated_value}");
let entry_gen_end = ts.len();
ts.push_str(",\n");
mappings.push(VizeMapping {
gen_range: entry_gen_start..entry_gen_end,
src_range: prop_src_start..prop_src_end,
sub_spans: Vec::new(),
});
}
append!(*ts, "{expr_indent}}});\n");
if usage.vif_guard.is_some() {
append!(*ts, "{indent}}}\n");
}
}