use crate::ast::{RootNode, RuntimeHelper, TemplateChildNode};
use super::context::CodegenContext;
use super::element::helpers::is_dynamic_component_tag;
use super::helpers::to_valid_asset_identifier;
use vize_carton::{String, camelize, capitalize};
pub(super) fn is_ignorable_root_text(child: &TemplateChildNode<'_>) -> bool {
matches!(child, TemplateChildNode::Text(text) if text.content.chars().all(|c| c.is_whitespace()))
}
fn imported_directive_binding_name(name: &str) -> String {
let camel = camelize(name);
let pascal = capitalize(&camel);
let mut binding = String::with_capacity(1 + pascal.len());
binding.push('v');
binding.push_str(&pascal);
binding
}
fn is_self_component_reference(component: &str, component_name: &str) -> bool {
if component == component_name {
return true;
}
let camel = camelize(component);
let pascal = capitalize(&camel);
pascal == component_name
}
pub(super) fn generate_preamble_from_helpers(
ctx: &CodegenContext,
helpers: &[RuntimeHelper],
) -> String {
if helpers.is_empty() {
return String::default();
}
let estimated_capacity = 32 + helpers.len() * 24;
let mut preamble = String::with_capacity(estimated_capacity);
match ctx.options.mode {
crate::options::CodegenMode::Module => {
preamble.push_str("import { ");
for (i, h) in helpers.iter().enumerate() {
if i > 0 {
preamble.push_str(", ");
}
preamble.push_str(h.name());
preamble.push_str(" as ");
preamble.push_str(ctx.helper(*h));
}
preamble.push_str(" } from \"");
preamble.push_str(ctx.runtime_module_name.as_str());
preamble.push_str("\"\n");
}
crate::options::CodegenMode::Function => {
preamble.push_str("const { ");
for (i, h) in helpers.iter().enumerate() {
if i > 0 {
preamble.push_str(", ");
}
preamble.push_str(h.name());
preamble.push_str(": ");
preamble.push_str(ctx.helper(*h));
}
preamble.push_str(" } = ");
preamble.push_str(ctx.runtime_global_name.as_str());
preamble.push('\n');
}
}
preamble
}
pub(super) fn generate_function_signature(ctx: &mut CodegenContext) {
if ctx.options.ssr {
ctx.push("function ssrRender(_ctx, _push, _parent, _attrs) {");
} else {
match ctx.options.mode {
crate::options::CodegenMode::Module => {
if ctx.options.binding_metadata.is_some() {
ctx.push(
"export function render(_ctx, _cache, $props, $setup, $data, $options) {",
);
} else {
ctx.push("export function render(_ctx, _cache) {");
}
}
crate::options::CodegenMode::Function => {
ctx.push("function render(_ctx, _cache, $props, $setup, $data, $options) {");
}
}
}
}
pub(super) fn generate_assets(ctx: &mut CodegenContext, root: &RootNode<'_>) {
let mut has_resolved_assets = false;
for component in root.components.iter() {
if ctx.resolve_component_binding_name(component).is_some() {
continue;
}
if super::helpers::is_builtin_component(component).is_some() {
continue;
}
if is_dynamic_component_tag(component) {
continue;
}
ctx.use_helper(RuntimeHelper::ResolveComponent);
ctx.push("const ");
ctx.push(&to_valid_asset_identifier("component", component));
ctx.push(" = ");
ctx.push(ctx.helper(RuntimeHelper::ResolveComponent));
ctx.push("(\"");
ctx.push(component);
ctx.push("\"");
if ctx
.options
.component_name
.as_deref()
.is_some_and(|name| is_self_component_reference(component, name))
{
ctx.push(", true");
}
ctx.push(")");
ctx.newline();
has_resolved_assets = true;
}
for directive in root.directives.iter() {
ctx.push("const ");
ctx.push(&to_valid_asset_identifier("directive", directive));
ctx.push(" = ");
let binding_name = imported_directive_binding_name(directive);
let uses_imported_binding = ctx
.options
.binding_metadata
.as_ref()
.is_some_and(|m| m.bindings.contains_key(binding_name.as_str()));
if uses_imported_binding {
ctx.push(&binding_name);
} else {
ctx.use_helper(RuntimeHelper::ResolveDirective);
ctx.push(ctx.helper(RuntimeHelper::ResolveDirective));
ctx.push("(\"");
ctx.push(directive);
ctx.push("\")");
}
ctx.newline();
has_resolved_assets = true;
}
if has_resolved_assets {
ctx.newline();
}
}