1use crate::error::WasmError;
7use std::collections::HashMap;
8use wasm_bindgen::prelude::*;
9use webui_parser::plugin::webui::WebUIParserPlugin;
10use webui_parser::{CssStrategy, HtmlParser};
11use webui_protocol::WebUIProtocol;
12
13#[wasm_bindgen]
17pub fn build_protocol(files: JsValue, entry: &str) -> Result<Vec<u8>, JsValue> {
18 let files_map: HashMap<String, String> =
19 serde_wasm_bindgen::from_value(files).map_err(|e| JsValue::from_str(&e.to_string()))?;
20
21 build_protocol_inner(&files_map, entry).map_err(|e| JsValue::from_str(&e.to_string()))
22}
23
24pub(crate) fn build_protocol_inner(
25 files: &HashMap<String, String>,
26 entry: &str,
27) -> Result<Vec<u8>, WasmError> {
28 let protocol = parse_to_protocol(files, entry)?;
29 protocol.to_protobuf().map_err(WasmError::Protocol)
30}
31
32fn register_components(
35 parser: &mut HtmlParser,
36 files: &HashMap<String, String>,
37 entry: &str,
38) -> Result<(), WasmError> {
39 for (filename, content) in files {
40 if filename != entry && filename.ends_with(".html") {
41 let tag_name = filename.trim_end_matches(".html");
42 if tag_name.contains('-') {
43 let css_key = format!("{tag_name}.css");
44 let css = files.get(&css_key).map(String::as_str);
45 parser
46 .component_registry_mut()
47 .register_component(tag_name, content, css)?;
48 }
49 }
50 }
51 Ok(())
52}
53
54pub(crate) fn parse_to_protocol(
57 files: &HashMap<String, String>,
58 entry: &str,
59) -> Result<WebUIProtocol, WasmError> {
60 let entry_html = files
61 .get(entry)
62 .ok_or_else(|| WasmError::MissingEntry(entry.to_string()))?;
63
64 let mut parser =
65 HtmlParser::with_plugin_options(Box::new(WebUIParserPlugin::new()), CssStrategy::Style);
66 register_components(&mut parser, files, entry)?;
67 parser.parse(entry, entry_html)?;
68 parser.take_plugin_artifacts()?;
69
70 Ok(WebUIProtocol::new(parser.into_fragment_records()))
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn build_protocol_reports_missing_entry() {
79 let files = HashMap::new();
80 let err = build_protocol_inner(&files, "index.html").unwrap_err();
81 assert_eq!(err.to_string(), "Entry file 'index.html' not found");
82 }
83}