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}