#![cfg_attr(not(feature = "std"), no_std)]
#![forbid(unsafe_code)]
#![deny(missing_docs)]
#![deny(rustdoc::broken_intra_doc_links)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc = include_str!("../README.md")]
#![doc(
html_favicon_url = "https://cloudcdn.pro/metadata-gen/v1/favicon.ico",
html_logo_url = "https://cloudcdn.pro/metadata-gen/v1/logos/metadata-gen.svg",
html_root_url = "https://docs.rs/metadata-gen"
)]
#![crate_name = "metadata_gen"]
#![crate_type = "lib"]
extern crate alloc;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
pub mod error;
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub mod io;
pub mod metadata;
pub mod metatags;
#[cfg(all(feature = "tokio", not(loom)))]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
pub mod tokio;
pub mod utils;
pub use error::MetadataError;
pub use metadata::{
detect_front_matter, extract_metadata, extract_metadata_with_body,
extract_metadata_with_limits, extract_typed,
extract_typed_borrowed, process_metadata, process_metadata_with,
DateOrder, FrontMatterFormat, Metadata, ParseLimits,
ProcessOptions,
};
pub use metatags::{generate_metatags, MetaTag, MetaTagGroups};
#[cfg(all(feature = "tokio", not(loom)))]
pub use utils::async_extract_metadata_from_file;
pub use utils::{escape_attribute, escape_html};
#[cfg(feature = "std")]
pub type MetadataMap = std::collections::HashMap<String, String>;
#[cfg(not(feature = "std"))]
pub type MetadataMap = alloc::collections::BTreeMap<String, String>;
pub type Keywords = Vec<String>;
pub type MetadataResult =
Result<(MetadataMap, Keywords, MetaTagGroups), MetadataError>;
pub fn extract_and_prepare_metadata(content: &str) -> MetadataResult {
if !content.contains(':') && !content.contains('=') {
return Err(MetadataError::ExtractionError {
message: "No valid front matter found".to_string(),
});
}
let metadata = extract_metadata(content)?;
let metadata_map = metadata.into_inner();
let keywords = extract_keywords(&metadata_map);
let all_meta_tags = generate_metatags(&metadata_map);
Ok((metadata_map, keywords, all_meta_tags))
}
pub fn extract_keywords(metadata: &MetadataMap) -> Vec<String> {
metadata
.get("keywords")
.map(|k| k.split(',').map(|s| s.trim().to_string()).collect())
.unwrap_or_default()
}
#[cfg(all(test, feature = "std", feature = "yaml"))]
mod tests {
use super::*;
use alloc::string::ToString;
use alloc::vec;
#[test]
fn test_extract_and_prepare_metadata() {
let content = r#"---
title: Test Page
description: A test page for metadata extraction
keywords: test, metadata, extraction
---
# Test Content
This is a test file for metadata extraction."#;
let result = extract_and_prepare_metadata(content);
assert!(result.is_ok());
let (metadata, keywords, meta_tags) = result.unwrap();
assert_eq!(
metadata.get("title"),
Some(&"Test Page".to_string())
);
assert_eq!(
metadata.get("description"),
Some(&"A test page for metadata extraction".to_string())
);
assert_eq!(keywords, vec!["test", "metadata", "extraction"]);
assert!(!meta_tags.primary.is_empty());
}
#[test]
fn test_extract_keywords() {
let mut metadata = MetadataMap::new();
metadata.insert(
"keywords".to_string(),
"rust, programming, metadata".to_string(),
);
let keywords = extract_keywords(&metadata);
assert_eq!(keywords, vec!["rust", "programming", "metadata"]);
}
#[test]
fn test_extract_keywords_empty() {
let metadata = MetadataMap::new();
let keywords = extract_keywords(&metadata);
assert!(keywords.is_empty());
}
}