extern crate lazy_static;
pub mod errors;
#[deprecated]
pub mod parser_old;
use errors::CompileError;
use fervid_codegen::CodegenContext;
pub use fervid_core::*;
use fervid_parser::SfcParser;
use fervid_transform::{style::should_transform_style_block, transform_sfc, TransformSfcOptions};
use fxhash::FxHasher32;
use std::{
borrow::Cow,
hash::{Hash, Hasher},
};
use swc_core::{common::FileName, ecma::ast::Expr};
#[derive(Debug, Clone)]
pub struct CompileOptions<'o> {
pub filename: Cow<'o, str>,
pub id: Cow<'o, str>,
pub is_prod: Option<bool>,
pub ssr: Option<bool>,
pub gen_default_as: Option<Cow<'o, str>>,
pub source_map: Option<bool>,
}
pub struct CompileResult {
pub code: String,
pub file_hash: String,
pub errors: Vec<CompileError>,
pub styles: Vec<CompileEmittedStyle>,
pub other_assets: Vec<CompileEmittedAsset>,
pub source_map: Option<String>,
}
pub struct CompileEmittedStyle {
pub code: String,
pub is_compiled: bool,
pub lang: String,
pub is_scoped: bool,
}
pub struct CompileEmittedAsset {
pub lo: u32,
pub hi: u32,
pub tag_name: String,
pub content: String,
}
pub fn compile(source: &str, options: CompileOptions) -> Result<CompileResult, CompileError> {
let mut all_errors = Vec::<CompileError>::new();
let is_prod = options.is_prod.unwrap_or_default();
let mut sfc_parsing_errors = Vec::new();
let mut parser = SfcParser::new(source, &mut sfc_parsing_errors);
let sfc = parser.parse_sfc()?;
all_errors.extend(sfc_parsing_errors.into_iter().map(From::from));
let file_hash = {
let mut hasher = FxHasher32::default();
source.hash(&mut hasher);
let num = hasher.finish();
format!("{:x}", num)
};
let mut transform_errors = Vec::new();
let transform_options = TransformSfcOptions {
is_prod,
scope_id: &file_hash,
filename: &options.filename,
};
let transform_result = transform_sfc(sfc, transform_options, &mut transform_errors);
all_errors.extend(transform_errors.into_iter().map(From::from));
let mut ctx = CodegenContext::with_bindings_helper(transform_result.bindings_helper);
let template_expr: Option<Expr> = transform_result
.template_block
.and_then(|template_block| ctx.generate_sfc_template(&template_block));
let sfc_module = ctx.generate_module(
template_expr,
*transform_result.module,
transform_result.exported_obj,
transform_result.setup_fn,
options.gen_default_as.as_deref(),
);
let (code, source_map) = CodegenContext::stringify(
&source,
&sfc_module,
FileName::Custom(options.filename.to_string()),
options.source_map.unwrap_or(false),
false,
);
let styles = transform_result
.style_blocks
.into_iter()
.map(|style_block| CompileEmittedStyle {
code: style_block.content.to_string(),
is_compiled: should_transform_style_block(&style_block),
lang: style_block.lang.to_string(),
is_scoped: style_block.is_scoped,
})
.collect();
let other_assets = transform_result
.custom_blocks
.into_iter()
.map(|block| {
CompileEmittedAsset {
lo: 0, hi: 0, tag_name: block.starting_tag.tag_name.to_string(),
content: block.content.to_string(),
}
})
.collect();
Ok(CompileResult {
code,
file_hash,
errors: all_errors,
styles,
other_assets,
source_map,
})
}
pub fn compile_sync_naive(source: &str, is_prod: bool) -> Result<String, String> {
let mut errors = Vec::new();
let mut parser = SfcParser::new(source, &mut errors);
let sfc = parser.parse_sfc().map_err(|err| {
return err.to_string();
})?;
let file_hash = {
let mut hasher = FxHasher32::default();
source.hash(&mut hasher);
let num = hasher.finish();
format!("{:x}", num)
};
let mut transform_errors = Vec::new();
let tranform_options = TransformSfcOptions {
is_prod,
scope_id: &file_hash,
filename: "anonymous.vue".into(),
};
let transform_result = transform_sfc(sfc, tranform_options, &mut transform_errors);
let mut ctx = CodegenContext::with_bindings_helper(transform_result.bindings_helper);
let template_expr: Option<Expr> = transform_result
.template_block
.and_then(|template_block| ctx.generate_sfc_template(&template_block));
let sfc_module = ctx.generate_module(
template_expr,
*transform_result.module,
transform_result.exported_obj,
transform_result.setup_fn,
None,
);
let (compiled_code, _map) =
CodegenContext::stringify(&source, &sfc_module, FileName::Anon, false, false);
Ok(compiled_code)
}