144 lines
4.5 KiB
Rust
144 lines
4.5 KiB
Rust
use std::borrow::Cow;
|
|
use std::collections::HashSet;
|
|
use std::hash::{Hash, Hasher};
|
|
|
|
use serde_derive::Serialize;
|
|
|
|
use config::Config;
|
|
use library::{Library, Taxonomy};
|
|
use std::cmp::Ordering;
|
|
use tera::{Map, Value};
|
|
|
|
/// The sitemap only needs links, potentially date and extra for pages in case of updates
|
|
/// for examples so we trim down all entries to only that
|
|
#[derive(Debug, Serialize)]
|
|
pub struct SitemapEntry<'a> {
|
|
pub permalink: Cow<'a, str>,
|
|
pub date: Option<String>,
|
|
pub extra: Option<&'a Map<String, Value>>,
|
|
}
|
|
|
|
// Hash/Eq is not implemented for tera::Map but in our case we only care about the permalink
|
|
// when comparing/hashing so we implement it manually
|
|
impl<'a> Hash for SitemapEntry<'a> {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
self.permalink.hash(state);
|
|
}
|
|
}
|
|
impl<'a> PartialEq for SitemapEntry<'a> {
|
|
fn eq(&self, other: &SitemapEntry) -> bool {
|
|
self.permalink == other.permalink
|
|
}
|
|
}
|
|
impl<'a> Eq for SitemapEntry<'a> {}
|
|
|
|
impl<'a> SitemapEntry<'a> {
|
|
pub fn new(permalink: Cow<'a, str>, date: Option<String>) -> Self {
|
|
SitemapEntry { permalink, date, extra: None }
|
|
}
|
|
|
|
pub fn add_extra(&mut self, extra: &'a Map<String, Value>) {
|
|
self.extra = Some(extra);
|
|
}
|
|
}
|
|
|
|
impl<'a> PartialOrd for SitemapEntry<'a> {
|
|
fn partial_cmp(&self, other: &SitemapEntry) -> Option<Ordering> {
|
|
Some(self.permalink.as_ref().cmp(other.permalink.as_ref()))
|
|
}
|
|
}
|
|
|
|
impl<'a> Ord for SitemapEntry<'a> {
|
|
fn cmp(&self, other: &SitemapEntry) -> Ordering {
|
|
self.permalink.as_ref().cmp(other.permalink.as_ref())
|
|
}
|
|
}
|
|
|
|
/// Finds out all the links to put in a sitemap from the pages/sections/taxonomies
|
|
/// There are no duplicate permalinks in the output vec
|
|
pub fn find_entries<'a>(
|
|
library: &'a Library,
|
|
taxonomies: &'a [Taxonomy],
|
|
config: &'a Config,
|
|
) -> Vec<SitemapEntry<'a>> {
|
|
let pages = library
|
|
.pages_values()
|
|
.iter()
|
|
.map(|p| {
|
|
let date = match p.meta.date {
|
|
Some(ref d) => Some(d.to_string()),
|
|
None => None,
|
|
};
|
|
let mut entry = SitemapEntry::new(Cow::Borrowed(&p.permalink), date);
|
|
entry.add_extra(&p.meta.extra);
|
|
entry
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
let mut sections = library
|
|
.sections_values()
|
|
.iter()
|
|
.filter(|s| s.meta.render)
|
|
.map(|s| {
|
|
let mut entry = SitemapEntry::new(Cow::Borrowed(&s.permalink), None);
|
|
entry.add_extra(&s.meta.extra);
|
|
entry
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
for section in library.sections_values().iter().filter(|s| s.meta.paginate_by.is_some()) {
|
|
let number_pagers =
|
|
(section.pages.len() as f64 / section.meta.paginate_by.unwrap() as f64).ceil() as isize;
|
|
for i in 1..=number_pagers {
|
|
let permalink = format!("{}{}/{}/", section.permalink, section.meta.paginate_path, i);
|
|
sections.push(SitemapEntry::new(Cow::Owned(permalink), None))
|
|
}
|
|
}
|
|
|
|
let mut taxonomies_entries = vec![];
|
|
for taxonomy in taxonomies {
|
|
let name = &taxonomy.kind.name;
|
|
let mut terms = vec![];
|
|
terms.push(SitemapEntry::new(Cow::Owned(config.make_permalink(name)), None));
|
|
for item in &taxonomy.items {
|
|
terms.push(SitemapEntry::new(
|
|
Cow::Owned(config.make_permalink(&format!("{}/{}", name, item.slug))),
|
|
None,
|
|
));
|
|
|
|
if taxonomy.kind.is_paginated() {
|
|
let number_pagers = (item.pages.len() as f64
|
|
/ taxonomy.kind.paginate_by.unwrap() as f64)
|
|
.ceil() as isize;
|
|
for i in 1..=number_pagers {
|
|
let permalink = config.make_permalink(&format!(
|
|
"{}/{}/{}/{}",
|
|
name,
|
|
item.slug,
|
|
taxonomy.kind.paginate_path(),
|
|
i
|
|
));
|
|
terms.push(SitemapEntry::new(Cow::Owned(permalink), None))
|
|
}
|
|
}
|
|
}
|
|
|
|
taxonomies_entries.push(terms);
|
|
}
|
|
|
|
let mut all_sitemap_entries = HashSet::new();
|
|
for p in pages {
|
|
all_sitemap_entries.insert(p);
|
|
}
|
|
for s in sections {
|
|
all_sitemap_entries.insert(s);
|
|
}
|
|
for terms in taxonomies_entries {
|
|
for term in terms {
|
|
all_sitemap_entries.insert(term);
|
|
}
|
|
}
|
|
|
|
all_sitemap_entries.into_iter().collect::<Vec<_>>()
|
|
}
|