-
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
unit tests: add frontmatter unit tests
- Loading branch information
Showing
8 changed files
with
260 additions
and
89 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,61 +1,109 @@ | ||
use std::{ | ||
collections::HashMap, | ||
fs, | ||
path::{Path, PathBuf}, | ||
process::Command, | ||
}; | ||
|
||
use gray_matter::engine::YAML; | ||
use gray_matter::Matter; | ||
use std::fmt; | ||
|
||
use relative_path::RelativePath; | ||
use serde::{Deserialize, Serialize}; | ||
use yaml_front_matter::YamlFrontMatter; | ||
|
||
fn find_repo_root() -> Option<PathBuf> { | ||
let output = Command::new("git") | ||
.args(["rev-parse", "--show-toplevel"]) | ||
.output() | ||
.ok()? | ||
.stdout; | ||
#[derive(Deserialize, Serialize, Debug)] | ||
pub struct Frontmatter { | ||
pub doc_location: Option<String>, | ||
} | ||
|
||
let path_str = String::from_utf8(output).ok()?.trim().to_string(); | ||
Some(PathBuf::from(path_str)) | ||
#[derive(Debug, PartialEq)] | ||
pub enum FrontmatterErrorKind { | ||
InvalidYaml, | ||
DocLocationFileNotFound, | ||
DocLocationNotRelativePath, | ||
} | ||
|
||
#[derive(Deserialize, Serialize, Debug)] | ||
pub struct Matter { | ||
#[serde(flatten)] | ||
pub content: HashMap<String, serde_yaml::Value>, | ||
#[derive(Debug, PartialEq)] | ||
pub struct FrontmatterError { | ||
pub message: String, | ||
pub kind: FrontmatterErrorKind, | ||
} | ||
|
||
impl fmt::Display for FrontmatterError { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
// Write the error message to the formatter | ||
write!(f, "FrontmatterError: {}", self.message) | ||
} | ||
} | ||
|
||
/// Returns the actual content of a markdown file, if the frontmatter has an import field. | ||
pub fn get_imported_content(file_path: &Path, markdown: Option<&String>) -> Option<String> { | ||
markdown?; | ||
|
||
match YamlFrontMatter::parse::<Matter>(markdown.unwrap()) { | ||
Ok(document) => { | ||
let metadata = document.metadata.content; | ||
|
||
let abs_import = metadata.get("import").map(|field| { | ||
let import_val = field | ||
.as_str() | ||
.expect("Frontmatter: import field must be a string"); | ||
match PathBuf::from(import_val).is_relative() { | ||
true => PathBuf::from_iter(vec![ | ||
// Cannot fail because every file has a parent directory | ||
file_path.parent().unwrap().to_path_buf(), | ||
PathBuf::from(import_val), | ||
]), | ||
false => PathBuf::from_iter(vec![ | ||
find_repo_root() | ||
.expect("Could not find root directory of repository. Make sure you have git installed and are in a git repository"), | ||
PathBuf::from(format!(".{import_val}")), | ||
]), | ||
/// Returns the actual content of a markdown file, if the frontmatter has a doc_location field. | ||
/// It returns None if the frontmatter is not present. | ||
/// It returns an error if the frontmatter is present but invalid. This includes: | ||
/// - Invalid yaml frontmatter | ||
/// - Invalid doc_location type | ||
/// - doc_location file is not readable or not found | ||
/// - doc_location field is not a relative path | ||
/// - doc_location file is not utf8 | ||
pub fn get_imported_content( | ||
file_path: &Path, | ||
markdown: &str, | ||
) -> Result<Option<String>, FrontmatterError> { | ||
let matter = Matter::<YAML>::new(); | ||
|
||
let result = matter.parse(markdown); | ||
|
||
// If the frontmatter is not present, we return None | ||
if result.data.is_none() { | ||
return Ok(None); | ||
} | ||
|
||
let pod = result.data.unwrap(); | ||
match pod.deserialize::<Frontmatter>() { | ||
Ok(metadata) => { | ||
let abs_import = match metadata.doc_location { | ||
Some(doc_location) => { | ||
let import_path: PathBuf = PathBuf::from(&doc_location); | ||
let relative_path = RelativePath::from_path(&import_path); | ||
|
||
match relative_path { | ||
Ok(rel) => Ok(Some(rel.to_path(file_path.parent().unwrap()))), | ||
Err(e) => Err(FrontmatterError { | ||
message: format!("{:?}: doc_location: field must be a path relative to the current file. Error: {} - {}", file_path, doc_location, e), | ||
kind: FrontmatterErrorKind::DocLocationNotRelativePath, | ||
}), | ||
} | ||
} | ||
}); | ||
// doc_location: field doesn't exist. Since it is optional, we return None | ||
None => Ok(None), | ||
}; | ||
|
||
match abs_import { | ||
Ok(Some(path)) => match fs::read_to_string(&path) { | ||
Ok(content) => Ok(Some(content)), | ||
Err(e) => Err(FrontmatterError { | ||
message: format!( | ||
"{:?}: Failed to read doc_location file: {:?} {}", | ||
file_path, path, e | ||
), | ||
kind: FrontmatterErrorKind::DocLocationFileNotFound, | ||
}), | ||
}, | ||
Ok(None) => Ok(None), | ||
Err(e) => Err(e), | ||
} | ||
} | ||
|
||
abs_import.map(|path| { | ||
fs::read_to_string(&path) | ||
.expect(format!("Could not read file: {:?}", &path).as_str()) | ||
Err(e) => { | ||
let message = format!( | ||
"{:?}: Failed to parse frontmatter metadata - {} YAML:{}:{}", | ||
file_path, | ||
e, | ||
e.line(), | ||
e.column() | ||
); | ||
Err(FrontmatterError { | ||
message, | ||
kind: FrontmatterErrorKind::InvalidYaml, | ||
}) | ||
} | ||
Err(_) => None, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
src/snapshots/nixdoc__test__frontmatter_doc_location_e2e.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
--- | ||
source: src/test.rs | ||
expression: output | ||
--- | ||
# Debug {#sec-functions-library-debug} | ||
## Imported | ||
|
||
This is be the documentation | ||
|
||
## `lib.debug.item` {#function-library-lib.debug.item} | ||
|
||
### Imported | ||
|
||
This is be the documentation | ||
|
||
## `lib.debug.optional` {#function-library-lib.debug.optional} | ||
|
||
No frontmatter |
Oops, something went wrong.