#![doc = include_str!("../README.md")]
#![warn(clippy::cargo, clippy::pedantic)]
#![warn(
clippy::exit,
clippy::expect_used,
clippy::panic,
clippy::semicolon_inside_block,
clippy::str_to_string,
clippy::implicit_clone,
clippy::unnecessary_self_imports,
clippy::use_debug
)]
#![deny(clippy::print_stderr, clippy::print_stdout)]
#![allow(clippy::must_use_candidate)]
mod angular;
pub(crate) mod codeblock;
pub(crate) mod config;
mod js;
mod markdown;
mod utils;
pub const MDBOOK_ANGULAR_VERSION: &str = env!("CARGO_PKG_VERSION");
pub const EXPECTED_MDBOOK_VERSION: &str = mdbook_renderer::MDBOOK_VERSION;
use std::{env, fs};
pub use angular::stop_background_process;
pub use config::{Builder, Config};
use angular::build;
use log::debug;
use log::warn;
use markdown::process_markdown;
use markdown::ChapterWithCodeBlocks;
use mdbook_html::HtmlHandlebars;
use mdbook_renderer::{RenderContext, Renderer};
fn validate_version(ctx: &RenderContext) -> Result<()> {
let req = semver::VersionReq::parse(EXPECTED_MDBOOK_VERSION).unwrap();
if semver::Version::parse(&ctx.version).is_ok_and(|version| req.matches(&version)) {
Ok(())
} else {
bail!("Invalid mdbook version {}, expected {}", &ctx.version, req);
}
}
pub(crate) use anyhow::{bail, Context, Error, Result};
pub struct AngularRenderer {}
impl Renderer for AngularRenderer {
fn name(&self) -> &'static str {
"angular"
}
#[inline]
fn render(&self, ctx: &RenderContext) -> Result<()> {
self.render_mut(&mut ctx.clone())
}
}
impl AngularRenderer {
pub fn new() -> Self {
Self {}
}
#[allow(clippy::missing_errors_doc)]
pub fn render_mut(&self, ctx: &mut RenderContext) -> Result<()> {
validate_version(ctx)?;
let config = Config::new(ctx)?;
let mut chapters_with_codeblocks = Vec::new();
let mut result: Result<()> = Ok(());
ctx.book.for_each_chapter_mut(|chapter| {
if result.is_err() {
return;
}
debug!("Processing chapter {}", &chapter.name);
match process_markdown(&config, chapter) {
Ok(processed) => {
debug!("Processed chapter {}", &chapter.name);
if let Some(processed) = processed {
chapters_with_codeblocks.push(processed);
}
}
Err(error) => result = Err(error),
}
});
debug!("Processed chapters");
if let Some(html) = &config.html {
ctx.config.set("output.html", html)?;
}
HtmlHandlebars::new().render(ctx)?;
fs::write(
config.target_folder.join("playground-io.min.js"),
crate::js::PLAYGROUND_SCRIPT,
)?;
debug!("Finished rendering");
#[allow(unused_mut)]
let mut run_build = !chapters_with_codeblocks.is_empty();
#[cfg(debug_assertions)]
if env::var("MDBOOK_ANGULAR_SKIP_BUILD").is_ok() {
run_build = false;
}
if run_build {
build(ctx, &config, chapters_with_codeblocks)?;
}
debug!("Finished");
Ok(())
}
}
impl Default for AngularRenderer {
fn default() -> Self {
Self::new()
}
}