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