1use std::path::Path;
7
8use super::Graph;
9use crate::document::Document;
10use crate::error::{Error, Result};
11use crate::fs::ReadStorage;
12use crate::link;
13
14impl<FS: ReadStorage, Ix> Graph<FS, Ix> {
15 pub async fn load(&self, path: &Path) -> Result<(String, Document)> {
19 if link::escapes_root(path) {
25 return Err(Error::Escape(path.to_path_buf()));
26 }
27 if let Some(hit) = self.memo_hit(path) {
31 return Ok(hit);
32 }
33 let text = self.fs().read_to_string(&self.root().join(path)).await?;
34 let doc = Document::parse(path, &text)?;
35 self.memo_remember(path, &text, &doc);
36 Ok((text, doc))
37 }
38
39 pub async fn document(&self, path: impl AsRef<Path>) -> Result<Document> {
51 let path = link::normalize(path);
52 self.load(&path).await.map(|(_, doc)| doc)
53 }
54}
55
56#[cfg(all(test, feature = "yaml"))]
58mod tests {
59 use std::path::PathBuf;
60
61 use super::*;
62 use crate::exec::block_on;
63 use crate::fs::StdFs;
64 use crate::graph::ReadSettings;
65 use crate::index::NoIndex;
66
67 fn write(dir: &Path, rel: &str, text: &str) {
68 let p = dir.join(rel);
69 std::fs::create_dir_all(p.parent().unwrap()).unwrap();
70 std::fs::write(p, text).unwrap();
71 }
72
73 fn tempdir(tag: &str) -> PathBuf {
74 let dir = std::env::temp_dir().join(format!("prov-load-{tag}-{}", std::process::id()));
75 let _ = std::fs::remove_dir_all(&dir);
76 std::fs::create_dir_all(&dir).unwrap();
77 dir
78 }
79
80 #[test]
81 fn document_reads_full_metadata_for_a_workspace_relative_path() {
82 let dir = tempdir("document");
83 write(
84 &dir,
85 "notes/a.md",
86 "---\ntitle: A\nauthor: Ada\n---\nbody text\n",
87 );
88
89 let ws = Graph::new(StdFs, &dir, NoIndex, ReadSettings::default());
90 let doc = block_on(ws.document("notes/a.md")).unwrap();
91 let meta = fig::Value::from(&doc.meta);
92 assert_eq!(meta.get("title").and_then(fig::Value::as_str), Some("A"));
93 assert_eq!(meta.get("author").and_then(fig::Value::as_str), Some("Ada"));
94 assert_eq!(doc.body, "body text\n");
95 }
96
97 #[test]
98 fn document_surfaces_the_error_for_an_unreadable_path() {
99 let dir = tempdir("document-missing");
100 let ws = Graph::new(StdFs, &dir, NoIndex, ReadSettings::default());
101 assert!(block_on(ws.document("nope.md")).is_err());
102 }
103}