obsidian_parser/note/mod.rs
1//! Represents an Obsidian note file with frontmatter properties and content
2
3pub mod note_aliases;
4pub mod note_default;
5pub mod note_in_memory;
6pub mod note_is_todo;
7pub mod note_on_disk;
8pub mod note_once_cell;
9pub mod note_once_lock;
10pub mod note_read;
11pub mod parser;
12
13#[cfg(not(target_family = "wasm"))]
14pub mod note_write;
15
16use std::{borrow::Cow, collections::HashMap, fs::OpenOptions, path::Path};
17
18pub use note_default::NoteDefault;
19pub use note_read::{NoteFromReader, NoteFromString};
20
21#[cfg(not(target_family = "wasm"))]
22pub use note_read::NoteFromFile;
23
24#[cfg(not(target_family = "wasm"))]
25pub use note_write::NoteWrite;
26
27pub(crate) type DefaultProperties = HashMap<String, serde_yml::Value>;
28
29/// Represents an Obsidian note file with frontmatter properties and content
30///
31/// This trait provides a standardized interface for working with Obsidian markdown files,
32/// handling frontmatter parsing, content extraction, and file operations.
33///
34/// # Example
35/// ```no_run
36/// use obsidian_parser::prelude::*;
37/// use serde::Deserialize;
38///
39/// #[derive(Deserialize, Clone)]
40/// struct NoteProperties {
41/// topic: String,
42/// created: String,
43/// }
44///
45/// let note: NoteInMemory<NoteProperties> = NoteFromFile::from_file("note.md").unwrap();
46/// let properties = note.properties().unwrap().unwrap();
47/// println!("Note topic: {}", properties.topic);
48/// ```
49///
50/// # Other
51/// * To open and read [`Note`] to a file, see [`note_read`] module.
52/// * To write and modify [`Note`] to a file, use the [`NoteWrite`] trait.
53pub trait Note: Sized {
54 /// Frontmatter properties type
55 type Properties: Clone;
56
57 /// Error type
58 type Error: std::error::Error;
59
60 /// Returns the parsed properties of frontmatter
61 ///
62 /// Returns [`None`] if the note has no properties
63 fn properties(&self) -> Result<Option<Cow<'_, Self::Properties>>, Self::Error>;
64
65 /// Returns the main content body of the note (excluding frontmatter)
66 ///
67 /// # Implementation Notes
68 /// - Strips YAML frontmatter if present
69 /// - Preserves original formatting and whitespace
70 fn content(&self) -> Result<Cow<'_, str>, Self::Error>;
71
72 /// Returns the source file path if available
73 ///
74 /// Returns [`None`] for in-memory notes without physical storage
75 fn path(&self) -> Option<Cow<'_, Path>>;
76
77 /// Get note name
78 fn note_name(&self) -> Option<String> {
79 self.path().as_ref().map(|path| {
80 path.file_stem()
81 .expect("Path is not file")
82 .to_string_lossy()
83 .to_string()
84 })
85 }
86}
87
88#[cfg(test)]
89pub(crate) mod impl_tests {
90 macro_rules! impl_test_for_note {
91 ($name_test:ident, $fn_test:ident, $impl_note:path) => {
92 #[cfg_attr(feature = "tracing", tracing_test::traced_test)]
93 #[test]
94 fn $name_test() {
95 $fn_test::<$impl_note>().unwrap();
96 }
97 };
98 }
99
100 pub(crate) use impl_test_for_note;
101}