blob: f0f7f90edea8b2e2afe76f5a8b91c7d4084e15e4 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, Error};
use handlebars::{Context, Handlebars, Helper, JsonRender, Output, RenderContext, RenderError};
use lazy_static::lazy_static;
use log::info;
use regex::Regex;
use serde_json::Value;
use std::fs;
use std::fs::File;
use std::path::PathBuf;
use crate::templates::{FidldocTemplate, HandlebarsHelper};
pub struct HtmlTemplate<'a> {
handlebars: Handlebars<'a>,
output_path: PathBuf,
}
impl HtmlTemplate<'_> {
pub fn new(output_path: &PathBuf) -> Result<HtmlTemplate<'_>, Error> {
info!("The HTML template is not ready, please use Markdown");
// Handlebars
let mut handlebars = Handlebars::new();
// Register core templates
for &(name, template, expect) in &[
("main", include_str!("main.hbs"), "Failed to include main"),
("interface", include_str!("interface.hbs"), "Failed to include interface"),
] {
handlebars.register_template_string(name, template).expect(expect);
}
// Register helpers
let helpers: &[(&str, HandlebarsHelper)] = &[
("getLink", crate::templates::get_link_helper),
("rpn", crate::templates::remove_package_name),
("eq", crate::templates::eq),
("ph", package_hash),
("pl", crate::templates::package_link),
];
for &(name, helper) in helpers {
handlebars.register_helper(name, Box::new(helper));
}
Ok(HtmlTemplate { handlebars: handlebars, output_path: output_path.to_path_buf() })
}
}
impl FidldocTemplate for HtmlTemplate<'_> {
fn render_main_page(&self, main_fidl_json: &Value) -> Result<(), Error> {
// Render main page
let main_page_path = self.output_path.join("index.html");
info!("Generating main page documentation {}", main_page_path.display());
let mut main_page_file = File::create(&main_page_path)
.with_context(|| format!("Can't create {}", main_page_path.display()))?;
// Render main page
self.handlebars
.render_to_write("main", &main_fidl_json, &mut main_page_file)
.expect("Unable to render main page");
Ok(())
}
fn render_interface(&self, package: &str, fidl_json: &Value) -> Result<(), Error> {
// Create a directory for interface files
let output_dir = self.output_path.join(package);
fs::create_dir(&output_dir)?;
info!("Created output directory {}", output_dir.display());
let package_index = output_dir.join("index.html");
info!("Generating package documentation {}", package_index.display());
let mut output_file = File::create(&package_index)
.with_context(|| format!("Can't create {}", package_index.display()))?;
// Render files
self.handlebars
.render_to_write("interface", &fidl_json, &mut output_file)
.expect("Unable to render files");
Ok(())
}
fn name(&self) -> String {
return "HTML".to_string();
}
}
fn package_hash(
h: &Helper<'_, '_>,
_: &Handlebars<'_>,
_: &Context,
_: &mut RenderContext<'_, '_>,
out: &mut dyn Output,
) -> Result<(), RenderError> {
// get parameter from helper or throw an error
let package = h.param(0).ok_or(RenderError::new("Param 0 is required for ph helper"))?;
let package_only =
h.param(1).ok_or_else(|| RenderError::new("Param 1 is required for ph helper"))?;
out.write(&ph(&package.value().render(), package_only.value().render() == "true"))?;
Ok(())
}
fn ph(name: &str, package_only: bool) -> String {
lazy_static! {
static ref RE: Regex = Regex::new(r"(.*)/(.*)").unwrap();
}
if package_only {
// Do not add the location hash
RE.replace_all(&name, "../$1/index.html").into_owned()
} else {
// Add a location hash
RE.replace_all(&name, "../$1/index.html#$2").into_owned()
}
}
#[test]
fn ph_test() {
let name = "fuchsia.media/Audio";
let without_hash = "../fuchsia.media/index.html";
assert_eq!(ph(name, true), without_hash.to_string());
let with_hash = "../fuchsia.media/index.html#Audio";
assert_eq!(ph(name, false), with_hash.to_string());
}