Use a Config struct across the code
This commit is contained in:
parent
5bcc37f32c
commit
50085e8ce2
22
README.md
Normal file
22
README.md
Normal file
@ -0,0 +1,22 @@
|
||||
# MD-DOCS
|
||||
|
||||
All configuration is done via the `md-docs.config.yaml` file.
|
||||
|
||||
## md-docs.config.yaml
|
||||
|
||||
Values:
|
||||
|
||||
```yaml
|
||||
{
|
||||
String input # Path to the input folder
|
||||
String output # Path to the output folder
|
||||
|
||||
?content: {
|
||||
String? h1 # Classes to add to h1 elements
|
||||
String? h2 # Classes to add to h2 elements
|
||||
String? h3 # Classes to add to h3 elements
|
||||
String? h4 # Classes to add to h4 elements
|
||||
String? h5 # Classes to add to h5 elements
|
||||
}
|
||||
}
|
||||
```
|
16
md-docs.md
16
md-docs.md
@ -1,16 +0,0 @@
|
||||
# MD-DOCS
|
||||
|
||||
All configuration is done via the `md-docs.config.yaml` file.
|
||||
|
||||
## md-docs.config.yaml
|
||||
|
||||
Values:
|
||||
|
||||
```yaml
|
||||
{
|
||||
String input # Path to the input folder
|
||||
String output # Path to the output folder
|
||||
|
||||
|
||||
}
|
||||
```
|
124
src/config.rs
Normal file
124
src/config.rs
Normal file
@ -0,0 +1,124 @@
|
||||
use std::path::Path;
|
||||
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
pub const CONFIG_NAME: &str = "md-docs.config.yaml";
|
||||
pub const INPUT_KEY: &str = "input";
|
||||
pub const OUTPUT_KEY: &str = "output";
|
||||
const TEMPLATE_KEY: &str = "template";
|
||||
|
||||
pub struct Config {
|
||||
pub input: String,
|
||||
pub output: String,
|
||||
pub template: String,
|
||||
}
|
||||
|
||||
/// Creates a `YAML::String` from a `&str`
|
||||
macro_rules! ystr {
|
||||
($str:literal) => {
|
||||
&Yaml::String(String::from($str))
|
||||
};
|
||||
}
|
||||
|
||||
pub fn parse(yaml_str: &String) -> Result<Config, String> {
|
||||
let config_yaml = match yaml_rust::YamlLoader::load_from_str(yaml_str) {
|
||||
Ok(y) => {
|
||||
let document = &y[0];
|
||||
let Yaml::Hash(hash) = document
|
||||
else {
|
||||
return Err(format!("{} doesn't contain a hash as first value.", CONFIG_NAME));
|
||||
};
|
||||
|
||||
hash.clone()
|
||||
}
|
||||
Err(error) => {
|
||||
return Err(format!(
|
||||
"{} doesn't contain valid YAML.\n{:?}",
|
||||
CONFIG_NAME, error
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let input_folder = match config_yaml.get(ystr!("input")) {
|
||||
Some(Yaml::String(input)) => input,
|
||||
Some(_) => {
|
||||
return Err(format!(
|
||||
"{}'s `{}` key MUST be a string",
|
||||
CONFIG_NAME, INPUT_KEY
|
||||
));
|
||||
}
|
||||
None => {
|
||||
return Err(format!("{} MUST have a `{}` key", CONFIG_NAME, INPUT_KEY));
|
||||
}
|
||||
};
|
||||
|
||||
let output_folder = match config_yaml.get(ystr!("output")) {
|
||||
Some(Yaml::String(input)) => input,
|
||||
Some(_) => {
|
||||
return Err(format!(
|
||||
"{}'s `{}` key MUST be a string",
|
||||
CONFIG_NAME, OUTPUT_KEY
|
||||
));
|
||||
}
|
||||
None => {
|
||||
return Err(format!("{} MUST have a `{}` key", CONFIG_NAME, OUTPUT_KEY));
|
||||
}
|
||||
};
|
||||
|
||||
// Check that input & output are valid folders
|
||||
match (
|
||||
Path::new(input_folder).is_dir(),
|
||||
Path::new(output_folder).is_dir(),
|
||||
) {
|
||||
(true, true) => {}
|
||||
(false, true) => {
|
||||
return Err(format!(
|
||||
"{}'s `{}` key is not a valid path to a folder",
|
||||
CONFIG_NAME, INPUT_KEY
|
||||
))
|
||||
}
|
||||
(true, false) => {
|
||||
return Err(format!(
|
||||
"{}'s `{}` key is not a valid path to a folder",
|
||||
CONFIG_NAME, OUTPUT_KEY
|
||||
))
|
||||
}
|
||||
(false, false) => {
|
||||
return Err(format!(
|
||||
"{}'s `{}` and `{}` keys are not valid paths to a folder",
|
||||
CONFIG_NAME, INPUT_KEY, OUTPUT_KEY
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
// Get template file
|
||||
let template_file = match config_yaml.get(ystr!("template")) {
|
||||
Some(Yaml::String(v)) => v,
|
||||
Some(_) => {
|
||||
return Err(format!(
|
||||
"{}'s `{}` key MUST be a string",
|
||||
CONFIG_NAME, TEMPLATE_KEY
|
||||
));
|
||||
}
|
||||
None => {
|
||||
return Err(format!(
|
||||
"{} MUST have a `{}` key",
|
||||
CONFIG_NAME, TEMPLATE_KEY
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
// Check template file exists
|
||||
if !(Path::new(template_file).is_file()) {
|
||||
return Err(format!(
|
||||
"{}'s `{}` key MUST point to a file ({})",
|
||||
CONFIG_NAME, TEMPLATE_KEY, template_file
|
||||
));
|
||||
}
|
||||
|
||||
Ok(Config {
|
||||
input: input_folder.clone(),
|
||||
output: output_folder.clone(),
|
||||
template: template_file.clone(),
|
||||
})
|
||||
}
|
78
src/main.rs
78
src/main.rs
@ -1,16 +1,16 @@
|
||||
use config::CONFIG_NAME;
|
||||
use std::{fs, path::Path};
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
use crate::config::{INPUT_KEY, OUTPUT_KEY};
|
||||
|
||||
mod config;
|
||||
mod generator;
|
||||
mod pages;
|
||||
mod processor;
|
||||
mod sidebar;
|
||||
mod utils;
|
||||
|
||||
const CONFIG_NAME: &str = "md-docs.config.yaml";
|
||||
const INPUT_KEY: &str = "input";
|
||||
const OUTPUT_KEY: &str = "output";
|
||||
|
||||
/// Creates a `YAML::String` from a `&str`
|
||||
macro_rules! ystr {
|
||||
($str:literal) => {
|
||||
@ -33,71 +33,13 @@ fn main() {
|
||||
}
|
||||
};
|
||||
|
||||
let config_yaml = match yaml_rust::YamlLoader::load_from_str(&config_str) {
|
||||
Ok(y) => {
|
||||
let document = &y[0];
|
||||
let Yaml::Hash(hash) = document
|
||||
else {
|
||||
eprintln!("{} doesn't contain a hash as first value.", CONFIG_NAME);
|
||||
match config::parse(&config_str) {
|
||||
Ok(config) => {
|
||||
processor::search_config_file(&config);
|
||||
}
|
||||
Err(reason) => {
|
||||
eprintln!("{}", reason);
|
||||
return;
|
||||
};
|
||||
|
||||
hash.clone()
|
||||
}
|
||||
Err(error) => {
|
||||
eprintln!("{} doesn't contain valid YAML.\n{:?}", CONFIG_NAME, error);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let input_folder = match config_yaml.get(ystr!("input")) {
|
||||
Some(Yaml::String(input)) => input,
|
||||
Some(_) => {
|
||||
eprintln!("{}'s `{}` key MUST be a string", CONFIG_NAME, INPUT_KEY);
|
||||
return;
|
||||
}
|
||||
None => {
|
||||
eprintln!("{} MUST have a `{}` key", CONFIG_NAME, INPUT_KEY);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let output_folder = match config_yaml.get(ystr!("output")) {
|
||||
Some(Yaml::String(input)) => input,
|
||||
Some(_) => {
|
||||
eprintln!("{}'s `{}` key MUST be a string", CONFIG_NAME, OUTPUT_KEY);
|
||||
return;
|
||||
}
|
||||
None => {
|
||||
eprintln!("{} MUST have a `{}` key", CONFIG_NAME, OUTPUT_KEY);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let input_folder = Path::new(input_folder);
|
||||
let output_folder = Path::new(output_folder);
|
||||
|
||||
match (input_folder.is_dir(), output_folder.is_dir()) {
|
||||
(true, true) => {
|
||||
processor::search_config_file(&input_folder, input_folder, output_folder);
|
||||
}
|
||||
(false, true) => {
|
||||
eprintln!(
|
||||
"{}'s `{}` key is not a valid path to a folder",
|
||||
CONFIG_NAME, INPUT_KEY
|
||||
)
|
||||
}
|
||||
(true, false) => {
|
||||
eprintln!(
|
||||
"{}'s `{}` key is not a valid path to a folder",
|
||||
CONFIG_NAME, OUTPUT_KEY
|
||||
)
|
||||
}
|
||||
(false, false) => {
|
||||
eprintln!(
|
||||
"{}'s `{}` and `{}` keys are not valid paths to a folder",
|
||||
CONFIG_NAME, INPUT_KEY, OUTPUT_KEY
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,15 +4,17 @@ use std::{
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use crate::{generator::Printable, sidebar::SidebarGenerator};
|
||||
use crate::{generator::Printable, sidebar::SidebarGenerator, config::Config};
|
||||
|
||||
/// ## Parameters
|
||||
///
|
||||
/// - `config`: Config struct with the parsed values
|
||||
/// - `file`: Path to the MD file to compile
|
||||
/// - `input_folder`: Path to the input folder passed as parameter of the program
|
||||
/// - `output_folder`: Path to the output folder passed as parameter of the program
|
||||
/// - `file_tree_html`: HTML code of the file tree to be inserted into the generated HTML
|
||||
pub fn compile(file: &PathBuf, input_folder: &Path, output_folder: &Path, file_tree_html: &String) {
|
||||
pub fn compile(config: &Config,file: &PathBuf, file_tree_html: &String) {
|
||||
let input_folder = Path::new(&config.input);
|
||||
let output_folder = Path::new(&config.output);
|
||||
|
||||
// /home/fernando/misti/docs/markdown
|
||||
let input_folder = input_folder.canonicalize().unwrap();
|
||||
|
||||
|
@ -2,7 +2,7 @@ use std::path::Path;
|
||||
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
use crate::utils;
|
||||
use crate::{utils, config::{self, Config}};
|
||||
|
||||
mod md_compiler;
|
||||
|
||||
@ -133,10 +133,9 @@ pub fn generate_pages_html(file_tree: &Node, current_path: &Path) -> String {
|
||||
}
|
||||
|
||||
pub fn compile_md_to_html(
|
||||
config: &Config,
|
||||
file_tree: &Node,
|
||||
current_path: &Path,
|
||||
input_folder: &Path,
|
||||
output_folder: &Path,
|
||||
file_tree_html: &String,
|
||||
) {
|
||||
match file_tree {
|
||||
@ -144,7 +143,7 @@ pub fn compile_md_to_html(
|
||||
let mut file_path = current_path.canonicalize().unwrap();
|
||||
file_path.push(format!("{}.md", file.path));
|
||||
|
||||
md_compiler::compile(&file_path, input_folder, output_folder, file_tree_html);
|
||||
md_compiler::compile(config, &file_path, file_tree_html);
|
||||
}
|
||||
Node::File(_) => {
|
||||
panic!("YAML: A file cannot have an empty `path` key")
|
||||
@ -152,20 +151,19 @@ pub fn compile_md_to_html(
|
||||
Node::Folder(folder) if folder.path != "" => {
|
||||
let mut new_path = current_path.canonicalize().unwrap();
|
||||
new_path.push(folder.path);
|
||||
utils::ensure_folder_exists(&new_path, input_folder, output_folder)
|
||||
utils::ensure_folder_exists(config, &new_path)
|
||||
.expect("SHOULD be able to create folder");
|
||||
|
||||
for node in folder.children.iter() {
|
||||
compile_md_to_html(node, &new_path, input_folder, output_folder, file_tree_html);
|
||||
compile_md_to_html(config, node, &new_path, file_tree_html);
|
||||
}
|
||||
}
|
||||
Node::Folder(folder) => {
|
||||
for node in folder.children.iter() {
|
||||
compile_md_to_html(
|
||||
config,
|
||||
node,
|
||||
¤t_path,
|
||||
input_folder,
|
||||
output_folder,
|
||||
file_tree_html,
|
||||
);
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::config::Config;
|
||||
use crate::pages::{compile_md_to_html, generate_pages_html, parse_yaml};
|
||||
use crate::utils;
|
||||
use std::{fs, path::Path};
|
||||
@ -9,10 +10,16 @@ enum EntryFound {
|
||||
None,
|
||||
}
|
||||
|
||||
// Traverses the current path searching for a YAML file
|
||||
pub fn search_config_file(current_path: &Path, input_folder: &Path, output_folder: &Path) {
|
||||
pub fn search_config_file(config: &Config) {
|
||||
let current_folder = Path::new(&config.input);
|
||||
|
||||
search_config_file_impl(config, current_folder)
|
||||
}
|
||||
|
||||
// Recursively traverses the current folder searching a YAML file
|
||||
pub fn search_config_file_impl(config: &Config, current_folder: &Path) {
|
||||
// Iterate over all the files searching for a YAML file
|
||||
let result = current_path
|
||||
let result = current_folder
|
||||
.read_dir()
|
||||
.unwrap()
|
||||
.fold(&EntryFound::None, |acc, next| {
|
||||
@ -22,7 +29,11 @@ pub fn search_config_file(current_path: &Path, input_folder: &Path, output_folde
|
||||
|
||||
match (acc, is_file, ext) {
|
||||
(EntryFound::YamlFile, true, Some(x)) if x == "yaml" => {
|
||||
panic!("FOUND A SECOND YAML FILE!!!")
|
||||
panic!(
|
||||
"Inside the folder {} a second YAML file was found ({}).",
|
||||
current_folder.to_str().unwrap(),
|
||||
p.to_str().unwrap()
|
||||
);
|
||||
}
|
||||
(EntryFound::YamlFile, _, _) => acc,
|
||||
(EntryFound::OtherFile, true, Some(x)) if x == "yaml" => &EntryFound::YamlFile,
|
||||
@ -35,26 +46,29 @@ pub fn search_config_file(current_path: &Path, input_folder: &Path, output_folde
|
||||
match result {
|
||||
// If a file other than a YAML file is found, panic
|
||||
EntryFound::OtherFile => panic!(
|
||||
"Found an orphan file without a YAML parent at {:?}",
|
||||
current_path
|
||||
"Found an orphan file without a YAML parent inside folder {}",
|
||||
current_folder.to_str().unwrap()
|
||||
),
|
||||
// Process the YAML file
|
||||
EntryFound::YamlFile => process_yaml(current_path, input_folder, output_folder),
|
||||
EntryFound::YamlFile => process_yaml(config, current_folder),
|
||||
// No files found, recursively read children folders
|
||||
EntryFound::None => {
|
||||
for entry in current_path.read_dir().unwrap() {
|
||||
// Should always succeed, and countain a folder
|
||||
for entry in current_folder.read_dir().unwrap() {
|
||||
// Should always succeed, and contain a folder
|
||||
let x = entry.unwrap();
|
||||
let path = x.path();
|
||||
|
||||
utils::ensure_folder_exists(&path, input_folder, output_folder).unwrap();
|
||||
search_config_file(&path, input_folder, output_folder);
|
||||
utils::ensure_folder_exists(config, &path).unwrap();
|
||||
search_config_file_impl(config, &path);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn process_yaml(current_path: &Path, input_folder: &Path, output_folder: &Path) {
|
||||
fn process_yaml(config: &Config, current_path: &Path) {
|
||||
let input_folder = Path::new(&config.input);
|
||||
let output_folder = Path::new(&config.output);
|
||||
|
||||
//
|
||||
// Read YAML file
|
||||
//
|
||||
@ -88,10 +102,9 @@ fn process_yaml(current_path: &Path, input_folder: &Path, output_folder: &Path)
|
||||
// Compile MD to HTML
|
||||
//
|
||||
compile_md_to_html(
|
||||
config,
|
||||
&file_tree,
|
||||
current_path,
|
||||
input_folder,
|
||||
output_folder,
|
||||
&tree_html,
|
||||
);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use std::{fs, path::Path};
|
||||
|
||||
use markdown::mdast::Node;
|
||||
|
||||
use crate::generator::Printable;
|
||||
use crate::{generator::Printable, config::{self, Config}};
|
||||
|
||||
pub fn to_html_fragment(text: &String) -> String {
|
||||
text.clone().replace(" ", "-")
|
||||
@ -29,10 +29,12 @@ pub fn collect_children_text(vec: &Vec<Node>) -> String {
|
||||
}
|
||||
|
||||
pub fn ensure_folder_exists(
|
||||
config: &Config,
|
||||
folder: &Path,
|
||||
input_folder: &Path,
|
||||
output_folder: &Path,
|
||||
) -> Result<(), String> {
|
||||
let input_folder = Path::new(&config.input);
|
||||
let output_folder = Path::new(&config.output);
|
||||
|
||||
// /home/fernando/misti/docs/markdown
|
||||
let input_folder = input_folder.canonicalize().unwrap();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user