From 06477109425c400dd37ff3299bbc180285e8428a Mon Sep 17 00:00:00 2001 From: Alexis Beingessner Date: Mon, 3 Jul 2023 16:25:18 -0400 Subject: [PATCH] WIP: rewrite relative links to additional pages this is currently hardcoded to SECURITY.md, and needs a more robust notion of relative links to pages we care about --- README.md | 1 + oranda.json | 5 ++++- src/data/funding.rs | 8 ++++++-- src/site/changelog.rs | 6 +++++- src/site/markdown/mod.rs | 31 ++++++++++++++++++++++++++++--- src/site/mod.rs | 2 +- src/site/page/mod.rs | 22 ++++++++++++++++++---- tests/build/fixtures/page.rs | 14 ++++++++++++-- 8 files changed, 75 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 800a7867..62f4a4e3 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ [![release](https://github.com/axodotdev/oranda/actions/workflows/release.yml/badge.svg)](https://github.com/axodotdev/oranda/actions/workflows/release.yml) [![web](https://github.com/axodotdev/oranda/actions/workflows/web.yml/badge.svg?branch=main)](https://github.com/axodotdev/oranda/actions/workflows/web.yml) +See [security](./SECURITY.md) `oranda` is an opinionated static-site generator that is designed for developers who are publishing projects and would like a website but don't want to build diff --git a/oranda.json b/oranda.json index a0e906ed..706ad4f4 100644 --- a/oranda.json +++ b/oranda.json @@ -1,6 +1,9 @@ { "build": { - "path_prefix": "oranda" + "path_prefix": "oranda", + "additional_pages": { + "security": "SECURITY.md" + } }, "styles": { "theme": "axodark", diff --git a/src/data/funding.rs b/src/data/funding.rs index 8010e474..2849f05f 100644 --- a/src/data/funding.rs +++ b/src/data/funding.rs @@ -41,7 +41,11 @@ pub enum FundingContent { impl Funding { /// Creates a new Funding struct by attempting to read from the FUNDING.yml, and the docs file. - pub fn new(funding_cfg: &FundingConfig, style_cfg: &StyleConfig) -> Result { + pub fn new( + path_prefix: &Option, + funding_cfg: &FundingConfig, + style_cfg: &StyleConfig, + ) -> Result { let mut funding = if let Some(yml_path) = &funding_cfg.yml_path { match LocalAsset::load_string(yml_path) { Ok(res) => { @@ -66,7 +70,7 @@ impl Funding { if let Some(md_path) = &funding_cfg.md_path { let res = LocalAsset::load_string(md_path)?; - let html = to_html(&res, &style_cfg.syntax_theme)?; + let html = to_html(&res, &style_cfg.syntax_theme, path_prefix)?; funding.docs_content = Some(html); } diff --git a/src/site/changelog.rs b/src/site/changelog.rs index 6e890167..a1a4e075 100644 --- a/src/site/changelog.rs +++ b/src/site/changelog.rs @@ -131,7 +131,11 @@ fn build_release_body(release: &Release, config: &Config) -> Result { release.source.body().unwrap_or_default().to_owned() }; - markdown::to_html(&contents, &config.styles.syntax_theme) + markdown::to_html( + &contents, + &config.styles.syntax_theme, + &config.build.path_prefix, + ) } fn build_prerelease_toggle(has_prereleases: bool) -> Option>> { diff --git a/src/site/markdown/mod.rs b/src/site/markdown/mod.rs index 4cadcfe9..cd882c30 100644 --- a/src/site/markdown/mod.rs +++ b/src/site/markdown/mod.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::io::BufWriter; mod syntax_highlight; pub use syntax_highlight::syntax_themes::SyntaxTheme; @@ -8,7 +9,7 @@ use crate::errors::*; use ammonia::Builder; use comrak::adapters::SyntaxHighlighterAdapter; -use comrak::{self, ComrakOptions, ComrakPlugins}; +use comrak::{self, Arena, ComrakOptions, ComrakPlugins}; pub struct Adapters<'a> { syntax_theme: &'a SyntaxTheme, @@ -47,14 +48,38 @@ fn initialize_comrak_options() -> ComrakOptions { options } -pub fn to_html(markdown: &str, syntax_theme: &SyntaxTheme) -> Result { +pub fn to_html( + markdown: &str, + syntax_theme: &SyntaxTheme, + path_prefix: &Option, +) -> Result { let options = initialize_comrak_options(); let mut plugins = ComrakPlugins::default(); let adapter = Adapters { syntax_theme }; plugins.render.codefence_syntax_highlighter = Some(&adapter); - let unsafe_html = comrak::markdown_to_html_with_plugins(markdown, &options, &plugins); + // Build the markdown AST + let arena = Arena::new(); + let root: &comrak::arena_tree::Node<'_, std::cell::RefCell> = + comrak::parse_document(&arena, markdown, &options); + + // Edit links in the markdown AST + for node in root.descendants() { + let mut node = node.data.borrow_mut(); + if let comrak::nodes::NodeValue::Link(link) = &mut node.value { + if link.url.contains("./SECURITY.md") { + link.url = crate::site::link::generate(path_prefix, "SECURITY/"); + } + } + } + + // Render the markdown AST to HTML + let mut bw = BufWriter::new(Vec::new()); + comrak::format_html_with_plugins(root, &options, &mut bw, &plugins).unwrap(); + let unsafe_html = String::from_utf8(bw.into_inner().unwrap()).unwrap(); + + // Sanitize the html let safe_html = Builder::new() .add_generic_attributes(&["style", "class", "id"]) .clean(&unsafe_html) diff --git a/src/site/mod.rs b/src/site/mod.rs index 6ca14b8b..0f16e618 100644 --- a/src/site/mod.rs +++ b/src/site/mod.rs @@ -89,7 +89,7 @@ impl Site { pages.append(&mut changelog_pages); } if let Some(funding_cfg) = &config.components.funding { - let funding = Funding::new(funding_cfg, &config.styles)?; + let funding = Funding::new(&config.build.path_prefix, funding_cfg, &config.styles)?; let body = funding::page(config, &funding)?; let page = Page::new_from_contents(body, "funding.html", &layout_template, config); pages.push(page); diff --git a/src/site/page/mod.rs b/src/site/page/mod.rs index 6b792b98..45392397 100644 --- a/src/site/page/mod.rs +++ b/src/site/page/mod.rs @@ -29,6 +29,7 @@ impl Page { let readme = Self::load_and_render_contents( &config.project.readme_path, &config.styles.syntax_theme, + &config.build.path_prefix, )?; body.push_str(&readme); let os_script = javascript::build_os_script(&config.build.path_prefix); @@ -43,6 +44,7 @@ impl Page { let body = Self::load_and_render_contents( &config.project.readme_path, &config.styles.syntax_theme, + &config.build.path_prefix, )?; let contents = layout.render(body, None); Ok(Page { @@ -52,7 +54,11 @@ impl Page { } pub fn new_from_file(source: &str, layout: &Layout, config: &Config) -> Result { - let body = Self::load_and_render_contents(source, &config.styles.syntax_theme)?; + let body = Self::load_and_render_contents( + source, + &config.styles.syntax_theme, + &config.build.path_prefix, + )?; let contents = layout.render(body, None); Ok(Page { contents, @@ -61,7 +67,11 @@ impl Page { } pub fn new_from_file_with_dir(source: &str, layout: &Layout, config: &Config) -> Result { - let body = Self::load_and_render_contents(source, &config.styles.syntax_theme)?; + let body = Self::load_and_render_contents( + source, + &config.styles.syntax_theme, + &config.build.path_prefix, + )?; let contents = layout.render(body, None); // Try diffing with the execution directory in case the user has provided an absolute-ish // path, in order to obtain the relative-to-dir path segment @@ -90,10 +100,14 @@ impl Page { } } - fn load_and_render_contents(source: &str, syntax_theme: &SyntaxTheme) -> Result { + fn load_and_render_contents( + source: &str, + syntax_theme: &SyntaxTheme, + path_prefix: &Option, + ) -> Result { let source = SourceFile::load_local(source)?; let contents = source.contents(); - markdown::to_html(contents, syntax_theme).map(|html| { + markdown::to_html(contents, syntax_theme, path_prefix).map(|html| { let html: Box> = html!(
{unsafe_text!(html)} diff --git a/tests/build/fixtures/page.rs b/tests/build/fixtures/page.rs index a620c366..54807b92 100644 --- a/tests/build/fixtures/page.rs +++ b/tests/build/fixtures/page.rs @@ -39,7 +39,12 @@ fn reset(dist_dir: &str) { pub fn index(config: &Config, layout: &Layout) -> Page { reset(&config.build.dist_dir); - let body = markdown::to_html(readme(), &config.styles.syntax_theme).unwrap(); + let body = markdown::to_html( + readme(), + &config.styles.syntax_theme, + &config.build.path_prefix, + ) + .unwrap(); Page::new_from_contents(body, "index.html", layout, config) } @@ -60,7 +65,12 @@ pub fn index_with_artifacts(config: &Config, layout: &Layout) -> Page { pub fn index_with_warning(config: &Config, layout: &Layout) -> Page { reset(&config.build.dist_dir); - let body = markdown::to_html(readme_invalid_annotation(), &config.styles.syntax_theme).unwrap(); + let body = markdown::to_html( + readme_invalid_annotation(), + &config.styles.syntax_theme, + &config.build.path_prefix, + ) + .unwrap(); Page::new_from_contents(body, "index.html", layout, config) }