Skip to content

Commit

Permalink
feat(ssg:) [Enhancement]: Adding other types of content formats #17
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastienrousseau committed Mar 27, 2023
1 parent 68203ac commit d178cba
Show file tree
Hide file tree
Showing 13 changed files with 901 additions and 138 deletions.
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,12 @@ name = "utilities"
path = "benches/bench_utilities.rs"

[dependencies]
clap = "4.1.11"
clap = "4.1.13"
comrak = "0.16.0"
reqwest = { version = "0.11.15", features = ["blocking", "json"] }
serde_json = "1.0.94"
toml = "0.7.3"
yaml-rust = "0.4.5"
tempfile = "3.4.0"

[dev-dependencies]
Expand Down
1 change: 1 addition & 0 deletions benches/bench_html.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
black_box(content),
black_box("My Title"),
black_box("My Description"),
black_box(None),
);
assert!(result.contains("<h1>My Title</h1>"));
assert!(result.contains("<h2>My Description</h2>"));
Expand Down
12 changes: 12 additions & 0 deletions content/about.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"frontmatter": {
"date": "2023-03-23",
"description": "Description of the about page",
"keywords": "about, page, description",
"layout": "page",
"permalink": "/about/",
"title": "About",
"image": "https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/demo/images/logo.min.svg"
},
"content": "Content of the about page"
}
18 changes: 0 additions & 18 deletions content/about.md

This file was deleted.

11 changes: 11 additions & 0 deletions content/products.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
+++
"date" = "2023-03-23"
"description" = "Description of the products page"
"keywords" = "products, page, description"
"layout" = "page"
"permalink" = "/products/"
"title" = "Products"
"image" = "https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/demo/images/logo.min.svg"
+++

This is the products page.
72 changes: 63 additions & 9 deletions src/frontmatter.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
use serde_json::Value as JsonValue;
use std::collections::HashMap;
use toml::Value as TomlValue;
use yaml_rust::YamlLoader;

/// ## Function: extract - Extracts metadata from the front matter of a Markdown file
///
/// Extracts metadata from the front matter of a Markdown file and
Expand Down Expand Up @@ -62,28 +67,77 @@
///
/// ```
///
use std::collections::HashMap;

/// Extracts metadata from the front matter of a Markdown file and
/// returns it as a tuple. The front matter is defined as any YAML block
/// that appears at the beginning of the file, enclosed by "---" lines.
///

pub fn extract(content: &str) -> HashMap<String, String> {
let mut front_matter = HashMap::new();

if content.starts_with("---\n") {
if let Some(end_pos) = content.find("\n---\n") {
let front_matter_str = &content[4..end_pos]; // Skip the opening `---\n`
for line in front_matter_str.lines() {
if let Some(pos) = line.find(':') {
let key = line[..pos].trim();
let value = line[pos + 1..].trim();
front_matter
.insert(key.to_string(), value.to_string());
let front_matter_str = &content[4..end_pos];
let docs =
YamlLoader::load_from_str(front_matter_str).unwrap();
let doc = &docs[0];
for (key, value) in doc.as_hash().unwrap().iter() {
front_matter.insert(
key.as_str().unwrap().to_string(),
value.as_str().unwrap().to_string(),
);
}
}
} else if content.starts_with("+++\n") {
if let Some(end_pos) = content.find("\n+++\n") {
let front_matter_str = &content[4..end_pos];
let toml_value: TomlValue =
front_matter_str.parse().unwrap();
for (key, value) in toml_value.as_table().unwrap().iter() {
front_matter.insert(
key.to_string(),
value.as_str().unwrap().to_string(),
);
}
}
} else if content.starts_with('{') {
let end_pos = content.rfind('}').unwrap();
let front_matter_str = &content[0..=end_pos];

let json_value: serde_json::Result<JsonValue> =
serde_json::from_str(front_matter_str);
match json_value {
Ok(value) => {
let front_matter_obj = value.get("frontmatter");
match front_matter_obj {
Some(obj) => {
for (key, value) in
obj.as_object().unwrap().iter()
{
front_matter.insert(
key.to_string(),
value.as_str().unwrap().to_string(),
);
}
}
None => {
eprintln!(
"Error: Could not find frontmatter in JSON"
);
}
}
if let Some(content) = value.get("content") {
front_matter.insert(
"content".to_string(),
content.as_str().unwrap_or("").to_string(),
);
}
}
Err(err) => {
eprintln!("Error parsing JSON: {:?}", err);
}
}
}

front_matter
}
20 changes: 19 additions & 1 deletion src/html.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub fn generate_html(
content: &str,
title: &str,
description: &str,
json_content: Option<&str>,
) -> String {
let options = comrak::ComrakOptions::default();
let markdown_content = if content.starts_with("---\n") {
Expand All @@ -44,6 +45,18 @@ pub fn generate_html(
} else {
""
}
} else if content.starts_with("+++\n") {
if let Some(end_pos) = content.find("\n+++\n") {
&content[end_pos + 5..] // Skip the "+++\n\n" that follows the front matter
} else {
""
}
} else if content.starts_with("{\n") {
if let Some(end_pos) = content.find("\n}\n") {
&content[end_pos + 2..]
} else {
""
}
} else {
content
};
Expand All @@ -59,5 +72,10 @@ pub fn generate_html(
};
let markdown_html =
comrak::markdown_to_html(markdown_content, &options);
format!("{}{}{}", header, subheader, markdown_html)
let json_html = if let Some(json_str) = json_content {
format!("<p>{}</p>", json_str)
} else {
"".to_string()
};
format!("{}{}{}{}", header, subheader, json_html, markdown_html)
}
42 changes: 36 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,20 @@ pub fn generate_navigation(files: &[File]) -> String {
files_sorted.sort_by(|a, b| a.name.cmp(&b.name));

let nav_links = files_sorted.iter().filter(|file| {
let file_name = file.name.replace(".md", "");
let file_name = match Path::new(&file.name).extension() {
Some(ext) if ext == "md" => file.name.replace(".md", ""),
Some(ext) if ext == "toml" => file.name.replace(".toml", ""),
Some(ext) if ext == "json" => file.name.replace(".json", ""),
_ => file.name.to_string(),
};
file_name != "index"
}).map(|file| {
let mut dir_name = file.name.replace(".md", "");
let mut dir_name = match Path::new(&file.name).extension() {
Some(ext) if ext == "md" => file.name.replace(".md", ""),
Some(ext) if ext == "toml" => file.name.replace(".toml", ""),
Some(ext) if ext == "json" => file.name.replace(".json", ""),
_ => file.name.to_string(),
};

// Handle special case for files in the same base directory
if let Some((index, _)) = dir_name.match_indices('/').next() {
Expand All @@ -221,7 +231,12 @@ pub fn generate_navigation(files: &[File]) -> String {
format!(
"<li><a href=\"/{}/index.html\" role=\"navigation\">{}</a></li>",
dir_name,
file.name.replace(".md", "")
match Path::new(&file.name).extension() {
Some(ext) if ext == "md" => file.name.replace(".md", ""),
Some(ext) if ext == "toml" => file.name.replace(".toml", ""),
Some(ext) if ext == "json" => file.name.replace(".json", ""),
_ => file.name.to_string(),
}
)
}).collect::<Vec<_>>().join("\n");

Expand Down Expand Up @@ -294,12 +309,18 @@ pub fn compile(
.map(|file| {
// Extract metadata from front matter
let metadata = extract(&file.content);
// println!(" Metadata: {:?}", metadata);
let meta = generate_metatags(&[("url".to_owned(), metadata.get("permalink").unwrap_or(&"".to_string()).to_string())]);

// Generate HTML
let content = render_page(&PageOptions {
banner: metadata.get("banner").unwrap_or(&"".to_string()),
content: &generate_html(&file.content, metadata.get("title").unwrap_or(&"".to_string()), metadata.get("description").unwrap_or(&"".to_string())),
content: &generate_html(
&file.content,
metadata.get("title").unwrap_or(&"".to_string()),
metadata.get("description").unwrap_or(&"".to_string()),
Some(metadata.get("content").unwrap_or(&"".to_string())),
),
copyright: format!("Copyright © {} 2023. All rights reserved.", site_name).as_str(),
css: "style.css",
date: metadata.get("date").unwrap_or(&"".to_string()),
Expand Down Expand Up @@ -349,7 +370,16 @@ pub fn compile(
// Write the compiled files to the output directory
println!("❯ Writing files...");
for file in &files_compiled {
let file_name = file.name.replace(".md", "");
let file_name = match Path::new(&file.name).extension() {
Some(ext) if ext == "md" => file.name.replace(".md", ""),
Some(ext) if ext == "toml" => {
file.name.replace(".toml", "")
}
Some(ext) if ext == "json" => {
file.name.replace(".json", "")
}
_ => file.name.to_string(),
};

// Check if the filename is "index.md" and write it to the root directory
if file_name == "index" {
Expand All @@ -367,7 +397,7 @@ pub fn compile(

let out_file = dir_name.join("index.html");
let out_json_file = dir_name.join("manifest.json");

println!(" - {}", out_file.display());
fs::write(&out_file, &file.content)?;
fs::write(&out_json_file, &file.json)?;

Expand Down
660 changes: 660 additions & 0 deletions tarpaulin-report.html

Large diffs are not rendered by default.

Loading

0 comments on commit d178cba

Please sign in to comment.