mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 14:54:47 +00:00
Remove handlebars templating and instead use new html_node() function some string replacement
This commit is contained in:
parent
f16d1619ea
commit
8036220b19
5 changed files with 199 additions and 276 deletions
31
Cargo.lock
generated
31
Cargo.lock
generated
|
@ -991,12 +991,6 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs_extra"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394"
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-cprng"
|
||||
version = "0.1.1"
|
||||
|
@ -1401,20 +1395,6 @@ version = "1.7.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3"
|
||||
|
||||
[[package]]
|
||||
name = "handlebars"
|
||||
version = "3.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb0867bbc5a3da37a753e78021d5fcf8a4db00e18dd2dd90fd36e24190e162d"
|
||||
dependencies = [
|
||||
"log",
|
||||
"pest",
|
||||
"pest_derive",
|
||||
"quick-error",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.9.1"
|
||||
|
@ -2467,12 +2447,6 @@ dependencies = [
|
|||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ac73b1112776fc109b2e61909bc46c7e1bf0d7f690ffb1676553acce16d5cda"
|
||||
|
||||
[[package]]
|
||||
name = "quickcheck"
|
||||
version = "0.8.5"
|
||||
|
@ -3005,8 +2979,6 @@ name = "roc_docs"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"fs_extra",
|
||||
"handlebars",
|
||||
"maplit",
|
||||
"pretty_assertions 0.5.1",
|
||||
"pulldown-cmark",
|
||||
|
@ -3014,9 +2986,6 @@ dependencies = [
|
|||
"roc_can",
|
||||
"roc_collections",
|
||||
"roc_load",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -8,11 +8,6 @@ edition = "2018"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
handlebars = "3.4.0"
|
||||
serde = "1.0.0"
|
||||
serde_json = "1.0.39"
|
||||
serde_derive = "1.0.75"
|
||||
fs_extra = "1.2.0"
|
||||
pulldown-cmark = { version = "0.8", default-features = false }
|
||||
roc_load = { path = "../compiler/load" }
|
||||
roc_builtins = { path = "../compiler/builtins" }
|
||||
|
|
301
docs/src/lib.rs
301
docs/src/lib.rs
|
@ -1,13 +1,8 @@
|
|||
extern crate fs_extra;
|
||||
extern crate serde;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate pulldown_cmark;
|
||||
extern crate serde_json;
|
||||
use roc_builtins::std::StdLib;
|
||||
use roc_can::builtins::builtin_defs_map;
|
||||
use roc_load::docs::DocTypeAnnotation;
|
||||
use roc_load::docs::ModuleDocumentation;
|
||||
use roc_load::docs::{DocTypeAnnotation, Documentation};
|
||||
use roc_load::file::LoadingProblem;
|
||||
|
||||
use std::fs;
|
||||
|
@ -16,37 +11,6 @@ use bumpalo::Bump;
|
|||
use roc_collections::all::MutMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Template {
|
||||
pub package_name: String,
|
||||
pub package_version: String,
|
||||
pub module_name: String,
|
||||
pub module_docs: String,
|
||||
pub module_entries: Vec<ModuleEntry>,
|
||||
pub module_links: Vec<TemplateLink>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone, Debug, PartialEq)]
|
||||
pub struct ModuleEntry {
|
||||
pub name: String,
|
||||
pub type_vars: Vec<String>,
|
||||
pub type_annotation: String,
|
||||
pub docs: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct TemplateLink {
|
||||
pub name: String,
|
||||
pub href: String,
|
||||
pub classes: String,
|
||||
pub entries: Vec<TemplateLinkEntry>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct TemplateLinkEntry {
|
||||
name: String,
|
||||
}
|
||||
|
||||
pub fn generate(filenames: Vec<PathBuf>, std_lib: StdLib, build_dir: &Path) {
|
||||
let files_docs = files_to_documentations(filenames, std_lib);
|
||||
//
|
||||
|
@ -81,28 +45,213 @@ pub fn generate(filenames: Vec<PathBuf>, std_lib: StdLib, build_dir: &Path) {
|
|||
)
|
||||
.expect("TODO gracefully handle failing to make the favicon");
|
||||
|
||||
// Register handlebars template
|
||||
let mut handlebars = handlebars::Handlebars::new();
|
||||
handlebars
|
||||
.register_template_file("page", "./docs/src/templates/page.hbs")
|
||||
.expect("TODO gracefully handle registering template failing");
|
||||
let template_html = include_str!("./static/index.html");
|
||||
|
||||
// Write each package's module docs html file
|
||||
for module in &package.modules {
|
||||
let template = documentation_to_template_data(&package, module);
|
||||
let mut filename = String::new();
|
||||
filename.push_str(module.name.as_str());
|
||||
filename.push_str(".html");
|
||||
|
||||
let handlebars_data = handlebars::to_json(&template);
|
||||
let filepath = build_dir.join(format!("{}.html", module.name));
|
||||
let mut output_file =
|
||||
fs::File::create(filepath).expect("TODO gracefully handle creating file failing");
|
||||
handlebars
|
||||
.render_to_write("page", &handlebars_data, &mut output_file)
|
||||
.expect("TODO gracefully handle writing file failing");
|
||||
let rendered_module = template_html
|
||||
.replace(
|
||||
"<!-- Module links -->",
|
||||
render_module_links(&package.modules).as_str(),
|
||||
)
|
||||
.replace(
|
||||
"<!-- Package Name and Version -->",
|
||||
render_name_and_version(package.name.as_str(), package.version.as_str()).as_str(),
|
||||
)
|
||||
.replace(
|
||||
"<!-- Module Docs -->",
|
||||
render_main_content(&module).as_str(),
|
||||
);
|
||||
|
||||
fs::write(build_dir.join(filename), rendered_module)
|
||||
.expect("TODO gracefully handle failing to write html");
|
||||
}
|
||||
|
||||
println!("🎉 Docs generated in {}", build_dir.display());
|
||||
}
|
||||
|
||||
fn render_main_content(module: &ModuleDocumentation) -> String {
|
||||
let mut buf = String::new();
|
||||
|
||||
buf.push_str(
|
||||
html_node(
|
||||
"h2",
|
||||
vec![("class", "module-name")],
|
||||
html_node("a", vec![("href", "/#")], module.name.as_str()).as_str(),
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
|
||||
buf.push_str(markdown_to_html(module.docs.clone()).as_str());
|
||||
|
||||
for entry in &module.entries {
|
||||
let mut href = String::new();
|
||||
href.push('#');
|
||||
href.push_str(entry.name.as_str());
|
||||
|
||||
let name = entry.name.as_str();
|
||||
|
||||
let mut content = String::new();
|
||||
|
||||
content.push_str(html_node("a", vec![("href", href.as_str())], name).as_str());
|
||||
|
||||
for type_var in &entry.type_vars {
|
||||
content.push(' ');
|
||||
content.push_str(type_var.as_str());
|
||||
}
|
||||
|
||||
if let Some(type_ann) = &entry.type_annotation {
|
||||
content.push_str(" : ");
|
||||
type_annotation_to_html(0, &mut content, &type_ann);
|
||||
}
|
||||
|
||||
buf.push_str(html_node("h3", vec![("id", name)], content.as_str()).as_str());
|
||||
|
||||
if let Some(docs) = &entry.docs {
|
||||
buf.push_str(docs.as_str());
|
||||
}
|
||||
}
|
||||
|
||||
buf
|
||||
}
|
||||
|
||||
fn html_node(tag_name: &str, attrs: Vec<(&str, &str)>, content: &str) -> String {
|
||||
let mut buf = String::new();
|
||||
|
||||
buf.push('<');
|
||||
buf.push_str(tag_name);
|
||||
|
||||
for (key, value) in &attrs {
|
||||
buf.push(' ');
|
||||
buf.push_str(key);
|
||||
buf.push_str("=\"");
|
||||
buf.push_str(value);
|
||||
buf.push('"');
|
||||
}
|
||||
|
||||
if !&attrs.is_empty() {
|
||||
buf.push(' ');
|
||||
}
|
||||
|
||||
buf.push('>');
|
||||
|
||||
buf.push_str(content);
|
||||
|
||||
buf.push_str("</");
|
||||
buf.push_str(tag_name);
|
||||
buf.push('>');
|
||||
|
||||
buf
|
||||
}
|
||||
|
||||
fn render_name_and_version(name: &str, version: &str) -> String {
|
||||
let mut buf = String::new();
|
||||
|
||||
let mut href = String::new();
|
||||
href.push('/');
|
||||
href.push_str(name);
|
||||
|
||||
buf.push_str(
|
||||
html_node(
|
||||
"h1",
|
||||
vec![("class", "pkg-full-name")],
|
||||
html_node("a", vec![("href", href.as_str())], name).as_str(),
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
|
||||
let mut verions_href = String::new();
|
||||
|
||||
verions_href.push('/');
|
||||
verions_href.push_str(name);
|
||||
verions_href.push('/');
|
||||
verions_href.push_str(version);
|
||||
|
||||
buf.push_str(
|
||||
html_node(
|
||||
"a",
|
||||
vec![("class", "version"), ("href", verions_href.as_str())],
|
||||
version,
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
|
||||
buf
|
||||
}
|
||||
|
||||
fn render_module_links(modules: &[ModuleDocumentation]) -> String {
|
||||
let mut buf = String::new();
|
||||
|
||||
for module in modules {
|
||||
let mut sidebar_entry_content = String::new();
|
||||
|
||||
let name = module.name.as_str();
|
||||
|
||||
let href = {
|
||||
let mut href_buf = String::new();
|
||||
href_buf.push_str(name);
|
||||
href_buf.push_str(".html");
|
||||
href_buf
|
||||
};
|
||||
|
||||
sidebar_entry_content.push_str(
|
||||
html_node(
|
||||
"a",
|
||||
vec![("class", "sidebar-module-link"), ("href", href.as_str())],
|
||||
name,
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
|
||||
let entries = {
|
||||
let mut entries_buf = String::new();
|
||||
|
||||
for entry in &module.entries {
|
||||
let mut entry_href = String::new();
|
||||
|
||||
entry_href.push_str(href.as_str());
|
||||
entry_href.push('#');
|
||||
entry_href.push_str(entry.name.as_str());
|
||||
|
||||
entries_buf.push_str(
|
||||
html_node(
|
||||
"a",
|
||||
vec![("href", entry_href.as_str())],
|
||||
entry.name.as_str(),
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
entries_buf
|
||||
};
|
||||
|
||||
sidebar_entry_content.push_str(
|
||||
html_node(
|
||||
"div",
|
||||
vec![("class", "sidebar-sub-entries")],
|
||||
entries.as_str(),
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
|
||||
buf.push_str(
|
||||
html_node(
|
||||
"div",
|
||||
vec![("class", "sidebar-entry")],
|
||||
sidebar_entry_content.as_str(),
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
buf
|
||||
}
|
||||
|
||||
pub fn files_to_documentations(
|
||||
filenames: Vec<PathBuf>,
|
||||
std_lib: StdLib,
|
||||
|
@ -134,58 +283,6 @@ pub fn files_to_documentations(
|
|||
files_docs
|
||||
}
|
||||
|
||||
pub fn documentation_to_template_data(
|
||||
doc: &Documentation,
|
||||
module: &ModuleDocumentation,
|
||||
) -> Template {
|
||||
Template {
|
||||
package_name: doc.name.clone(),
|
||||
package_version: doc.version.clone(),
|
||||
module_name: module.name.clone(),
|
||||
module_docs: markdown_to_html(module.docs.clone()),
|
||||
module_entries: module
|
||||
.entries
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|entry| ModuleEntry {
|
||||
name: entry.name.clone(),
|
||||
type_vars: entry.type_vars,
|
||||
type_annotation: match entry.type_annotation {
|
||||
None => String::new(),
|
||||
Some(type_ann) => {
|
||||
let type_ann_html = &mut String::new();
|
||||
|
||||
type_ann_html.push_str(" : ");
|
||||
|
||||
type_annotation_to_html(0, type_ann_html, &type_ann);
|
||||
|
||||
type_ann_html.to_string()
|
||||
}
|
||||
},
|
||||
docs: match entry.docs {
|
||||
Some(docs) => markdown_to_html(docs),
|
||||
None => String::new(),
|
||||
},
|
||||
})
|
||||
.collect(),
|
||||
module_links: doc
|
||||
.modules
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|module_link| TemplateLink {
|
||||
name: module_link.name.clone(),
|
||||
href: format!("./{}.html", module_link.name),
|
||||
classes: "".to_string(),
|
||||
entries: module_link
|
||||
.entries
|
||||
.into_iter()
|
||||
.map(|entry| TemplateLinkEntry { name: entry.name })
|
||||
.collect(),
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
const INDENT: &str = " ";
|
||||
|
||||
fn indent(buf: &mut String, times: usize) {
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>The Roc Programming Language</title>
|
||||
<meta name="description" content="A language for building fast, reliable software.">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<link rel="icon" href="favicon.svg">
|
||||
<script type="text/javascript" src="search.js" defer></script>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav id="sidebar-nav">
|
||||
<input id="module-search" aria-labelledby="search-link" type="text" placeholder="Search" />
|
||||
<label for="module-search" id="search-link">Search</label>
|
||||
<div class="module-links">
|
||||
{{#each module_links as |link| ~}}
|
||||
<div class="sidebar-entry">
|
||||
<a class="sidebar-module-link" href="{{link.href}}">{{link.name}}</a>
|
||||
<div class="sidebar-sub-entries">
|
||||
{{#each link.entries as |entry| ~}}
|
||||
<a class="{{link.classes}}" href="{{link.href}}#{{entry.name}}">{{entry.name}}</a>
|
||||
{{/each~}}
|
||||
</div>
|
||||
</div>
|
||||
{{/each~}}
|
||||
</div>
|
||||
</nav>
|
||||
<div class="top-header-extension">
|
||||
<!-- if the window gets big, this extends the purple bar on the top header to the left edge of the window -->
|
||||
</div>
|
||||
<header class="top-header">
|
||||
<nav class="pkg-and-logo">
|
||||
<a class="logo" href="/" aria-labelledby="logo-link">
|
||||
<svg viewBox="0 -6 51 58" fill="none" xmlns="http://www.w3.org/2000/svg" aria-labelledby="logo-link" role="img">
|
||||
<title id="logo-link">Return to Roc packages</title>
|
||||
<polygon role="presentation" points="0,0 23.8834,3.21052 37.2438,19.0101 45.9665,16.6324 50.5,22 45,22 44.0315,26.3689 26.4673,39.3424 27.4527,45.2132 17.655,53 23.6751,22.7086" />
|
||||
</svg>
|
||||
</a>
|
||||
<h1 class="pkg-full-name">
|
||||
<a href="/{{package_name}}">{{package_name}}</a>
|
||||
</h1>
|
||||
<a class="version" href="/{{package_name}}/{{package_version}}">{{package_version}}</a>
|
||||
</nav>
|
||||
<div class="top-header-triangle">
|
||||
<!-- if the window gets big, this extends the purple bar on the top header to the left edge of the window -->
|
||||
</div>
|
||||
</header>
|
||||
<main>
|
||||
<h2 class="module-name"><a href="#">{{module_name}}</a></h2>
|
||||
{{{module_docs}}}
|
||||
{{#each module_entries as |entry| ~}}
|
||||
<h3 id="{{entry.name}}">
|
||||
<a href="#{{entry.name}}">{{entry.name}}</a>
|
||||
{{#each entry.type_vars as |type_var| ~}}
|
||||
{{type_var}}
|
||||
{{/each~}}
|
||||
{{{entry.type_annotation}}}
|
||||
</h3>
|
||||
|
||||
{{{entry.docs}}}
|
||||
{{/each~}}
|
||||
</main>
|
||||
<footer>
|
||||
<p>Made by people who like to make nice things.</p>
|
||||
<p>© 2020-present</p>
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,66 +0,0 @@
|
|||
#[macro_use]
|
||||
extern crate pretty_assertions;
|
||||
|
||||
use roc_docs::{documentation_to_template_data, files_to_documentations, ModuleEntry};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_docs {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn internal() {
|
||||
let files_docs = files_to_documentations(
|
||||
vec![PathBuf::from(r"tests/fixtures/Interface.roc")],
|
||||
roc_builtins::std::standard_stdlib(),
|
||||
);
|
||||
|
||||
let package = roc_load::docs::Documentation {
|
||||
name: "roc/builtins".to_string(),
|
||||
version: "1.0.0".to_string(),
|
||||
docs: "Package introduction or README.".to_string(),
|
||||
modules: files_docs,
|
||||
};
|
||||
|
||||
let expected_entries = vec![
|
||||
ModuleEntry {
|
||||
name: "Block".to_string(),
|
||||
type_vars: vec![ "elem".to_string() ],
|
||||
type_annotation: " : <br> [<br> Block elem<br> ]".to_string(),
|
||||
docs: "<p>This is a block</p>\n".to_string(),
|
||||
},
|
||||
ModuleEntry {
|
||||
name: "singleline".to_string(),
|
||||
type_vars: vec![],
|
||||
type_annotation: "".to_string(),
|
||||
docs: "<p>Single line documentation.</p>\n".to_string(),
|
||||
},
|
||||
ModuleEntry {
|
||||
name: "multiline".to_string(),
|
||||
type_vars: vec![],
|
||||
type_annotation: "".to_string(),
|
||||
docs: "<p>Multiline documentation.\nWithout any complex syntax yet!</p>\n".to_string(),
|
||||
}, ModuleEntry {
|
||||
name: "multiparagraph".to_string(),
|
||||
type_vars: vec![],
|
||||
type_annotation: "".to_string(),
|
||||
docs: "<p>Multiparagraph documentation.</p>\n<p>Without any complex syntax yet!</p>\n".to_string(),
|
||||
}, ModuleEntry {
|
||||
name: "codeblock".to_string(),
|
||||
type_vars: vec![],
|
||||
type_annotation: "".to_string(),
|
||||
docs: "<p>Turns >>> into code block for now.</p>\n<pre><code class=\"language-roc\">codeblock</code></pre>\n".to_string(),
|
||||
},
|
||||
];
|
||||
|
||||
for module in &package.modules {
|
||||
let template = documentation_to_template_data(&package, module);
|
||||
assert_eq!(template.module_name, "Test");
|
||||
template
|
||||
.module_entries
|
||||
.iter()
|
||||
.zip(expected_entries.iter())
|
||||
.for_each(|(x, y)| assert_eq!(x, y));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue