| // 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()); |
| } |