diff --git a/Cargo.lock b/Cargo.lock index 17554c8..385bc4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -205,12 +205,23 @@ checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" dependencies = [ "log", "mac", - "markup5ever", + "markup5ever 0.11.0", "proc-macro2", "quote", "syn 1.0.109", ] +[[package]] +name = "html5ever" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55d958c2f74b664487a2035fe1dadb032c48718a03b63f3ab0b8537db8549ed4" +dependencies = [ + "log", + "markup5ever 0.35.0", + "match_token", +] + [[package]] name = "htmlua-apache-cgi" version = "0.1.0" @@ -224,7 +235,9 @@ name = "htmlua-parser" version = "0.1.0" dependencies = [ "anyhow", + "html5ever 0.35.0", "kuchikiki", + "markup5ever 0.11.0", "mlua", "tendril", ] @@ -256,7 +269,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8" dependencies = [ "cssparser", - "html5ever", + "html5ever 0.26.0", "indexmap", "matches", "selectors", @@ -329,6 +342,28 @@ dependencies = [ "tendril", ] +[[package]] +name = "markup5ever" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "311fe69c934650f8f19652b3946075f0fc41ad8757dbb68f1ca14e7900ecc1c3" +dependencies = [ + "log", + "tendril", + "web_atoms", +] + +[[package]] +name = "match_token" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac84fd3f360fcc43dc5f5d186f02a94192761a080e8bc58621ad4d12296a58cf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "matches" version = "0.1.10" @@ -445,6 +480,15 @@ dependencies = [ "phf_shared 0.10.0", ] +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_shared 0.11.3", +] + [[package]] name = "phf_codegen" version = "0.8.0" @@ -465,6 +509,16 @@ dependencies = [ "phf_shared 0.10.0", ] +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", +] + [[package]] name = "phf_generator" version = "0.8.0" @@ -901,6 +955,18 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "web_atoms" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ffde1dc01240bdf9992e3205668b235e59421fd085e8a317ed98da0178d414" +dependencies = [ + "phf 0.11.3", + "phf_codegen 0.11.3", + "string_cache", + "string_cache_codegen", +] + [[package]] name = "which" version = "7.0.3" diff --git a/htmlua-parser/Cargo.toml b/htmlua-parser/Cargo.toml index b611fde..c3ecb0f 100644 --- a/htmlua-parser/Cargo.toml +++ b/htmlua-parser/Cargo.toml @@ -5,7 +5,9 @@ edition = "2024" [dependencies] anyhow = "1.0.98" +html5ever = "0.35.0" kuchikiki = "0.8.2" +markup5ever = "0.11.0" mlua = { version = "0.10.5", features = ["lua54", "vendored", "serialize"] } tendril = "0.4.3" diff --git a/htmlua-parser/src/helpers.rs b/htmlua-parser/src/helpers.rs new file mode 100644 index 0000000..90439f7 --- /dev/null +++ b/htmlua-parser/src/helpers.rs @@ -0,0 +1,32 @@ +use std::{fs::File, io::{BufRead, BufReader, Read, Seek, SeekFrom}, path::PathBuf}; + +use anyhow::Result; +use kuchikiki::NodeRef; +use markup5ever::{LocalName, Namespace, QualName}; +use tendril::TendrilSink; + + + + +pub fn read_doc_from_file(path: PathBuf) -> Result { + + let mut file = File::open(path)?; + let mut reader = BufReader::new(&mut file); + + let mut first_line = String::new(); + reader.read_line(&mut first_line)?; + let first_line_trimmed = first_line.trim(); + + let is_whole_doc = first_line_trimmed.eq_ignore_ascii_case(""); + + file.seek(SeekFrom::Start(0))?; + let mut page_string = String::new(); + file.read_to_string(&mut page_string)?; + + if is_whole_doc { + Ok(kuchikiki::parse_html().one(page_string)) + } else { + let ctx_name = QualName::new(None, Namespace::from("http://www.w3.org/1999/xhtml"), LocalName::from("div")); + Ok(kuchikiki::parse_fragment(ctx_name, Vec::new()).one(page_string)) + } +} diff --git a/htmlua-parser/src/lib.rs b/htmlua-parser/src/lib.rs index 03e66bd..cd87be2 100644 --- a/htmlua-parser/src/lib.rs +++ b/htmlua-parser/src/lib.rs @@ -1,2 +1,3 @@ pub mod render; pub mod serve; +pub mod helpers; diff --git a/htmlua-parser/src/render.rs b/htmlua-parser/src/render.rs index fe0b64f..1ea99a0 100644 --- a/htmlua-parser/src/render.rs +++ b/htmlua-parser/src/render.rs @@ -1,14 +1,15 @@ use std::cell::RefCell; use std::fmt::Write; -use std::fs::read_to_string; use std::path::PathBuf; use std::rc::Rc; use anyhow::Result; use anyhow::anyhow; -use kuchikiki::{NodeRef, traits::TendrilSink}; +use kuchikiki::NodeRef; use mlua::{Lua, Table}; +use crate::helpers::read_doc_from_file; + fn create_htmlua_stdlib(l: &Lua, stdout: &Rc>) -> mlua::Result { let t = l.create_table()?; @@ -79,13 +80,14 @@ pub fn expand_template(document: NodeRef, component_path: &PathBuf, include_from let exported = from_node .select_first(format!("exportelement.{name}").as_str()) .map_err(|()| anyhow!("Error finding exportelement"))?; - exported.as_node().children().for_each(|c| i.as_node().insert_after(c)); + exported.as_node().children().rev().for_each(|c| i.as_node().insert_after(c)); } } while let Ok(i) = document.select_first("includeelement") { i.as_node().detach(); } } + for i in document .select("include") .map_err(|()| anyhow!("Error finding include"))? @@ -97,10 +99,8 @@ pub fn expand_template(document: NodeRef, component_path: &PathBuf, include_from if let Some(include_path) = attrs.get("path") { let mut item_path = component_path.clone(); item_path.push(include_path); - let component_text = read_to_string(item_path)?; - let new_doc = kuchikiki::parse_html().one(component_text); - let new_node = new_doc.select_first("body").map_err(|()| anyhow!("Failed to get body"))?; - let replaced_node = expand_template(new_node.as_node().clone(), component_path, Some(i.as_node()))?; + let new_node = read_doc_from_file(item_path)?; + let replaced_node = expand_template(new_node, component_path, Some(i.as_node()))?; i.as_node().insert_before(replaced_node); i.as_node().detach(); } diff --git a/htmlua-parser/src/serve.rs b/htmlua-parser/src/serve.rs index 134cc13..370d2e9 100644 --- a/htmlua-parser/src/serve.rs +++ b/htmlua-parser/src/serve.rs @@ -1,8 +1,8 @@ +use crate::helpers::read_doc_from_file; + use super::render::execute_lua; use super::render::expand_template; use anyhow::Result; -use kuchikiki::traits::TendrilSink; -use std::fs::read_to_string; use std::path::{Path, PathBuf}; pub fn serve_content(request_uri: &str) -> Result { @@ -13,9 +13,7 @@ pub fn serve_content(request_uri: &str) -> Result { let safe_path = Path::new(request_uri).strip_prefix("/")?; let page_path = pages.join(safe_path); - let page_string = read_to_string(&page_path)?; - - let doc = kuchikiki::parse_html().one(page_string); + let doc = read_doc_from_file(page_path)?; let full_doc = expand_template(doc, &components, None)?; let executed_doc = execute_lua(full_doc)?;