metadata_gen/lib.rs
1#![forbid(unsafe_code)]
2#![deny(missing_docs)]
3#![doc = include_str!("../README.md")]
4#![doc(
5 html_favicon_url = "https://cloudcdn.pro/metadata-gen/v1/favicon.ico",
6 html_logo_url = "https://cloudcdn.pro/metadata-gen/v1/logos/metadata-gen.svg",
7 html_root_url = "https://docs.rs/metadata-gen"
8)]
9#![crate_name = "metadata_gen"]
10#![crate_type = "lib"]
11
12use std::collections::HashMap;
13
14/// The `error` module contains error types for metadata processing.
15pub mod error;
16/// The `metadata` module contains functions for extracting and processing metadata.
17pub mod metadata;
18/// The `metatags` module contains functions for generating meta tags.
19pub mod metatags;
20/// The `utils` module contains utility functions for metadata processing.
21pub mod utils;
22
23pub use error::MetadataError;
24pub use metadata::{
25 detect_front_matter, extract_metadata, extract_metadata_with_body,
26 extract_typed, process_metadata, process_metadata_with,
27 FrontMatterFormat, Metadata, ProcessOptions,
28};
29pub use metatags::{generate_metatags, MetaTagGroups};
30pub use utils::{async_extract_metadata_from_file, escape_html};
31
32/// Type alias for a map of metadata key-value pairs.
33///
34/// # Example
35///
36/// ```
37/// use metadata_gen::MetadataMap;
38///
39/// let mut map = MetadataMap::new();
40/// map.insert("title".to_string(), "My Page".to_string());
41/// assert_eq!(map.get("title"), Some(&"My Page".to_string()));
42/// ```
43pub type MetadataMap = HashMap<String, String>;
44
45/// Type alias for a list of keywords.
46///
47/// # Example
48///
49/// ```
50/// use metadata_gen::Keywords;
51///
52/// let keywords: Keywords = vec!["rust".to_string(), "metadata".to_string()];
53/// assert_eq!(keywords.len(), 2);
54/// ```
55pub type Keywords = Vec<String>;
56
57/// Type alias for the result of metadata extraction and processing.
58///
59/// # Example
60///
61/// ```
62/// use metadata_gen::{MetadataResult, extract_and_prepare_metadata};
63///
64/// let result: MetadataResult = extract_and_prepare_metadata("---\ntitle: Test\n---\n");
65/// assert!(result.is_ok());
66/// ```
67pub type MetadataResult =
68 Result<(MetadataMap, Keywords, MetaTagGroups), MetadataError>;
69
70/// Extracts metadata from the content, generates keywords based on the metadata,
71/// and prepares meta tag groups.
72///
73/// This function performs three key tasks:
74/// 1. It extracts metadata from the front matter of the content.
75/// 2. It generates keywords based on this metadata.
76/// 3. It generates various meta tags required for the page.
77///
78/// # Arguments
79///
80/// * `content` - A string slice representing the content from which to extract metadata.
81///
82/// # Returns
83///
84/// Returns a Result containing a tuple with:
85/// * `HashMap<String, String>`: Extracted metadata
86/// * `Vec<String>`: A list of keywords
87/// * `MetaTagGroups`: A structure containing various meta tags
88///
89/// # Errors
90///
91/// This function will return a `MetadataError` if metadata extraction or processing fails.
92///
93/// # Example
94///
95/// ```
96/// use metadata_gen::extract_and_prepare_metadata;
97///
98/// let content = r#"---
99/// title: My Page
100/// description: A sample page
101/// ---
102/// # Content goes here
103/// "#;
104///
105/// let result = extract_and_prepare_metadata(content);
106/// assert!(result.is_ok());
107/// ```
108pub fn extract_and_prepare_metadata(content: &str) -> MetadataResult {
109 // Ensure the front matter format is correct
110 if !content.contains(':') {
111 return Err(MetadataError::ExtractionError {
112 message: "No valid front matter found".to_string(),
113 });
114 }
115
116 let metadata = extract_metadata(content)?;
117 let metadata_map = metadata.into_inner();
118 let keywords = extract_keywords(&metadata_map);
119 let all_meta_tags = generate_metatags(&metadata_map);
120
121 Ok((metadata_map, keywords, all_meta_tags))
122}
123
124/// Extracts keywords from the metadata.
125///
126/// This function looks for a "keywords" key in the metadata and splits its value into a vector of strings.
127///
128/// # Arguments
129///
130/// * `metadata` - A reference to a HashMap containing the metadata.
131///
132/// # Returns
133///
134/// A vector of strings representing the keywords. Returns an empty vector if no keywords are found.
135///
136/// # Example
137///
138/// ```
139/// use std::collections::HashMap;
140/// use metadata_gen::extract_keywords;
141///
142/// let mut metadata = HashMap::new();
143/// metadata.insert("keywords".to_string(), "rust, metadata, parsing".to_string());
144///
145/// let keywords = extract_keywords(&metadata);
146/// assert_eq!(keywords, vec!["rust", "metadata", "parsing"]);
147/// ```
148pub fn extract_keywords(
149 metadata: &HashMap<String, String>,
150) -> Vec<String> {
151 metadata
152 .get("keywords")
153 .map(|k| k.split(',').map(|s| s.trim().to_string()).collect())
154 .unwrap_or_default()
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160
161 #[test]
162 fn test_extract_and_prepare_metadata() {
163 let content = r#"---
164title: Test Page
165description: A test page for metadata extraction
166keywords: test, metadata, extraction
167---
168# Test Content
169This is a test file for metadata extraction."#;
170
171 let result = extract_and_prepare_metadata(content);
172 assert!(result.is_ok());
173
174 let (metadata, keywords, meta_tags) = result.unwrap();
175 assert_eq!(
176 metadata.get("title"),
177 Some(&"Test Page".to_string())
178 );
179 assert_eq!(
180 metadata.get("description"),
181 Some(&"A test page for metadata extraction".to_string())
182 );
183 assert_eq!(keywords, vec!["test", "metadata", "extraction"]);
184 assert!(!meta_tags.primary.is_empty());
185 }
186
187 #[test]
188 fn test_extract_keywords() {
189 let mut metadata = HashMap::new();
190 metadata.insert(
191 "keywords".to_string(),
192 "rust, programming, metadata".to_string(),
193 );
194
195 let keywords = extract_keywords(&metadata);
196 assert_eq!(keywords, vec!["rust", "programming", "metadata"]);
197 }
198
199 #[test]
200 fn test_extract_keywords_empty() {
201 let metadata = HashMap::new();
202 let keywords = extract_keywords(&metadata);
203 assert!(keywords.is_empty());
204 }
205}