use std::sync::Arc;
use farmfe_core::{
config::TargetEnv,
error::CompilationError,
swc_common::{input::SourceFileInput, DUMMY_SP},
swc_html_ast::{Attribute, Child, Document, Element, Namespace, Text},
};
use swc_error_reporters::handler::try_with_handler;
use swc_html_codegen::{
writer::basic::{BasicHtmlWriter, BasicHtmlWriterConfig},
CodeGenerator, CodegenConfig, Emit,
};
use swc_html_parser::{
lexer::Lexer,
parser::{Parser, ParserConfig},
};
use crate::sourcemap::create_swc_source_map;
pub fn parse_html_document(id: &str, content: Arc<String>) -> farmfe_core::error::Result<Document> {
let (cm, source_file) = create_swc_source_map(&id.into(), content);
let html_lexer = Lexer::new(SourceFileInput::from(&*source_file));
let mut parser = Parser::new(
html_lexer,
ParserConfig {
allow_self_closing: true,
..Default::default()
},
);
let parse_result = parser.parse_document();
try_with_handler(cm, Default::default(), |handler| {
match parse_result {
Ok(doc) => Ok(doc),
Err(e) => {
e.to_diagnostics(handler).emit();
Err(anyhow::Error::msg(e.to_diagnostics(handler).message()))
}
}
})
.map_err(|e| CompilationError::ParseError {
resolved_path: id.to_string(),
msg: e.to_pretty_string(),
})
}
pub fn codegen_html_document(document: &Document, minify: bool) -> String {
let mut html_code = String::new();
let html_writer = BasicHtmlWriter::new(&mut html_code, None, BasicHtmlWriterConfig::default());
let mut html_gen = CodeGenerator::new(
html_writer,
CodegenConfig {
minify,
..Default::default()
},
);
html_gen.emit(document).unwrap();
html_code
}
pub fn create_element(name: &str, text: Option<&str>, attrs: Vec<(&str, &str)>) -> Element {
Element {
span: DUMMY_SP,
tag_name: name.into(),
namespace: Namespace::HTML,
attributes: attrs
.into_iter()
.map(|(name, value)| create_attribute(name, Some(value)))
.collect(),
children: if text.is_some() {
vec![Child::Text(Text {
span: DUMMY_SP,
data: text.unwrap().into(),
raw: None,
})]
} else {
vec![]
},
content: None,
is_self_closing: false,
}
}
pub fn create_attribute(name: &str, value: Option<&str>) -> Attribute {
Attribute {
span: DUMMY_SP,
namespace: None,
prefix: None,
name: name.into(),
raw_name: None,
value: value.map(|v| v.into()),
raw_value: None,
}
}
pub fn get_farm_global_this(namespace: &str, target_env: &TargetEnv) -> String {
if target_env.is_node() {
format!("global['{namespace}']")
} else {
format!("window['{namespace}']")
}
}