#![allow(clippy::collapsible_match)]
pub mod options;
pub mod transforms;
pub use options::*;
pub use transforms::*;
pub use vize_atelier_core::{
ast, codegen, errors, parser, runtime_helpers, tokenizer, transform, Allocator, CompilerError,
Namespace, RootNode, TemplateChildNode,
};
use vize_atelier_core::codegen::CodegenResult;
use vize_atelier_core::{
codegen::generate,
options::{CodegenOptions, ParserOptions, TransformOptions},
parser::parse_with_options,
transform::transform as do_transform,
};
use vize_carton::Bump;
use vize_croquis::Croquis;
pub fn compile_template<'a>(
allocator: &'a Bump,
source: &'a str,
) -> (RootNode<'a>, Vec<CompilerError>, CodegenResult) {
compile_template_with_options(allocator, source, DomCompilerOptions::default())
}
pub fn compile_template_with_options<'a>(
allocator: &'a Bump,
source: &'a str,
options: DomCompilerOptions,
) -> (RootNode<'a>, Vec<CompilerError>, CodegenResult) {
let parser_opts = ParserOptions {
is_void_tag: vize_carton::is_void_tag,
is_native_tag: Some(vize_carton::is_native_tag),
is_pre_tag: |tag| tag == "pre",
get_namespace,
comments: options.comments,
..ParserOptions::default()
};
let (mut root, errors) = parse_with_options(allocator, source, parser_opts);
if !errors.is_empty() {
let codegen_result = CodegenResult {
code: String::new(),
preamble: String::new(),
map: None,
};
return (root, errors.to_vec(), codegen_result);
}
let transform_opts = TransformOptions {
prefix_identifiers: options.prefix_identifiers,
hoist_static: options.hoist_static,
cache_handlers: options.cache_handlers,
scope_id: options.scope_id.clone(),
ssr: options.ssr,
is_ts: options.is_ts,
inline: options.inline,
binding_metadata: options.binding_metadata.clone(),
..Default::default()
};
let analysis: Option<&Croquis> = options.croquis.map(|c| &*allocator.alloc(*c));
do_transform(allocator, &mut root, transform_opts, analysis);
let codegen_opts = CodegenOptions {
mode: options.mode,
source_map: options.source_map,
scope_id: options.scope_id.clone(),
ssr: options.ssr,
is_ts: options.is_ts,
inline: options.inline,
cache_handlers: options.cache_handlers,
binding_metadata: options.binding_metadata,
..Default::default()
};
let codegen_result = generate(&root, codegen_opts);
(root, errors.to_vec(), codegen_result)
}
fn get_namespace(tag: &str, parent: Option<&str>) -> Namespace {
if vize_carton::is_svg_tag(tag) {
return Namespace::Svg;
}
if vize_carton::is_math_ml_tag(tag) {
return Namespace::MathMl;
}
if let Some(parent_tag) = parent {
if vize_carton::is_svg_tag(parent_tag) && tag != "foreignObject" {
return Namespace::Svg;
}
if vize_carton::is_math_ml_tag(parent_tag)
&& tag != "annotation-xml"
&& tag != "foreignObject"
{
return Namespace::MathMl;
}
}
Namespace::Html
}
#[cfg(test)]
mod tests {
use super::*;
use vize_atelier_core::options::CodegenMode;
#[test]
fn test_compile_simple_element() {
let allocator = Bump::new();
let (root, errors, result) = compile_template(&allocator, "<div>hello</div>");
assert!(errors.is_empty());
assert_eq!(root.children.len(), 1);
let full_output = format!("{}\n{}", result.preamble, result.code);
assert!(
full_output.contains("_createElementBlock"),
"Expected output to contain _createElementBlock, got:\n{}",
full_output
);
}
#[test]
fn test_compile_svg() {
let allocator = Bump::new();
let (root, errors, _) = compile_template(&allocator, "<svg><circle /></svg>");
assert!(errors.is_empty());
if let TemplateChildNode::Element(el) = &root.children[0] {
assert_eq!(el.ns, Namespace::Svg);
}
}
#[test]
fn test_compile_with_options() {
let allocator = Bump::new();
let opts = DomCompilerOptions {
mode: CodegenMode::Module,
..Default::default()
};
let (_, errors, result) = compile_template_with_options(&allocator, "<div></div>", opts);
assert!(errors.is_empty());
assert!(!result.code.is_empty());
}
}