use super::js_runtime_scripts::MathJaxRuntimeScripts;
use crate::markdown::color_preset::DiagramColorPreset;
use crate::markdown::diagram_js_runtime::DiagramV8Runtime;
use serde::Deserialize;
use std::path::Path;
pub(super) struct MathJaxJsRuntimeOps;
#[derive(Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
enum MathJaxRuntimeResponse {
Svg { svg: String },
Error { message: String },
}
impl MathJaxJsRuntimeOps {
pub(super) fn render(
source: &str,
mathjax_js: &Path,
preset: &DiagramColorPreset,
display: bool,
) -> Result<String, String> {
let mathjax_source = runtime_source_from(mathjax_js)?;
let request = MathJaxRenderRequest::new(source, preset, display);
let request_json = request.to_json_value().to_string();
let scripts = MathJaxRuntimeScripts::build(mathjax_source, &request_json);
let output = DiagramV8Runtime::render(&scripts)?;
match parse_response(&output)? {
MathJaxRuntimeResponse::Svg { svg } => Ok(svg),
MathJaxRuntimeResponse::Error { message } => Err(message),
}
}
}
fn runtime_source_from(mathjax_js: &Path) -> Result<String, String> {
match std::fs::read_to_string(mathjax_js) {
Ok(source) => Ok(source),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => Err(format!(
"MathJax runtime asset is not installed: {}",
mathjax_js.display()
)),
Err(error) => Err(format!(
"MathJax runtime asset could not be read: {}: {error}",
mathjax_js.display()
)),
}
}
struct MathJaxRenderRequest<'a> {
source: &'a str,
display: bool,
text: &'a str,
dark_mode: bool,
}
impl<'a> MathJaxRenderRequest<'a> {
fn new(source: &'a str, preset: &'a DiagramColorPreset, display: bool) -> Self {
Self {
source,
display,
text: preset.text.as_ref(),
dark_mode: preset.dark_mode,
}
}
fn to_json_value(&self) -> serde_json::Value {
serde_json::json!({
"source": self.source,
"display": self.display,
"text": self.text,
"darkMode": self.dark_mode,
})
}
}
fn parse_response(output: &str) -> Result<MathJaxRuntimeResponse, String> {
serde_json::from_str(output).map_err(|err| format!("Invalid MathJax runtime response: {err}"))
}