This repository has been archived on 2026-06-01. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
template-compiler/src/compiler/models_impl.rs
T
2026-05-22 09:20:30 +02:00

192 lines
6.6 KiB
Rust

use indoc::indoc;
use serde_json;
use crate::css::scope_css;
use crate::compiler::models::{PageRoute, Project, Template};
use crate::js::minify_javascript;
impl Project {
pub fn compile_script(&self) -> String {
let template = indoc! { r#"
(function() {
if (typeof Handlebars === 'undefined') {
const script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/handlebars@latest/dist/handlebars.js';
document.head.appendChild(script);
}
const tempDefine = window.define;
window.define = undefined;
const script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/handlebars@latest/dist/handlebars.js';
script.onload = function() {
window.define = tempDefine;
{pages_script}
const domReadyEvent = new Event('DOMContentLoaded', {
bubbles: true,
cancelable: true,
});
document.dispatchEvent(domReadyEvent);
window.dispatchEvent(domReadyEvent);
};
document.head.appendChild(script);
})()
"# };
let mut script = String::new();
for page in &self.pages {
let template_script = indoc! { r#"
if (eval({page_route})) {
{content_script}
}
"# };
let route_script = page.route.as_script();
let content_script = page
.content
.iter()
.map(|template| template.as_script())
.collect::<Vec<String>>()
.join("\n");
script.push_str(
&template_script
.replace(
"{page_route}",
&serde_json::to_string(&minify_javascript(&route_script)).unwrap(),
)
.replace("{content_script}", &content_script),
);
}
minify_javascript(&template.replace("{pages_script}", &script))
}
}
impl PageRoute {
fn as_script(&self) -> String {
match self {
PageRoute::Regexpr(expr) => {
let template = indoc! { r#"
(function() {
const regex = new RegExp({expr});
return regex.test(window.location.pathname);
})()
"# };
template.replace("{expr}", &serde_json::to_string(&expr.trim()).unwrap())
}
PageRoute::Static(route) => {
let template = indoc! { r#"
(function() {
return window.location.pathname === {route};
})()
"# };
template.replace("{route}", &serde_json::to_string(&route).unwrap())
}
PageRoute::CustomScript(script) => script.clone(),
}
}
}
impl Template {
pub fn as_script(&self) -> String {
match self {
Template::CustomScript { script, style } => {
if style.is_none() || style.as_ref().unwrap().trim().is_empty() {
return script.clone();
}
let style_script = style.as_ref().map_or(String::new(), |s| {
format!(
r#"
const styleElement = document.createElement('style');
styleElement.textContent = {style};
document.head.appendChild(styleElement);
"#,
style = serde_json::to_string(s).unwrap()
)
});
format!("{}\n{}", style_script, script)
}
Template::TemplateInjector {
template,
replace_selector,
scraper,
style,
} => {
let scope_class = format!("template-style-{}", rand::random::<u32>());
let style_script = if let Some(style) = style {
if style.trim().is_empty() {
String::new()
} else {
format!(
indoc! {r#"
const styleElement = document.createElement('style');
styleElement.textContent = {style};
document.head.appendChild(styleElement);
"# },
style =
&serde_json::to_string(&scope_css(&style, &scope_class)).unwrap()
)
}
} else {
String::new()
};
let script_template = indoc! { r#"
(function() {
{style_script}
const parsedData = eval({scraper} || "(() => ({}))");
const template = Handlebars.compile({template});
const rendered = template(parsedData);
const targetElement = document.querySelector({replace_selector});
const temp = document.createElement('template');
temp.innerHTML = rendered;
const newElement = temp.content.firstElementChild;
targetElement.replaceWith(newElement);
newElement.classList.add({scope_class});
})();
"# };
script_template
.replace("{style_script}", &style_script)
.replace(
"{template}",
&serde_json::to_string(&template.trim()).unwrap(),
)
.replace(
"{replace_selector}",
&serde_json::to_string(&replace_selector).unwrap(),
)
.replace(
"{scope_class}",
&serde_json::to_string(&scope_class).unwrap(),
)
.replace(
"{scraper}",
&serde_json::to_string(&minify_javascript(
scraper.as_deref().unwrap_or(""),
))
.unwrap(),
)
}
}
}
}