You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

82 lines
2.4KB

  1. use std::collections::{HashMap, HashSet};
  2. use elasticlunr::{Index, Language};
  3. use lazy_static::lazy_static;
  4. use errors::{bail, Result};
  5. use library::{Library, Section};
  6. pub const ELASTICLUNR_JS: &str = include_str!("elasticlunr.min.js");
  7. lazy_static! {
  8. static ref AMMONIA: ammonia::Builder<'static> = {
  9. let mut clean_content = HashSet::new();
  10. clean_content.insert("script");
  11. clean_content.insert("style");
  12. let mut builder = ammonia::Builder::new();
  13. builder
  14. .tags(HashSet::new())
  15. .tag_attributes(HashMap::new())
  16. .generic_attributes(HashSet::new())
  17. .link_rel(None)
  18. .allowed_classes(HashMap::new())
  19. .clean_content_tags(clean_content);
  20. builder
  21. };
  22. }
  23. /// Returns the generated JSON index with all the documents of the site added using
  24. /// the language given
  25. /// Errors if the language given is not available in Elasticlunr
  26. /// TODO: is making `in_search_index` apply to subsections of a `false` section useful?
  27. pub fn build_index(lang: &str, library: &Library) -> Result<String> {
  28. let language = match Language::from_code(lang) {
  29. Some(l) => l,
  30. None => {
  31. bail!("Tried to build search index for language {} which is not supported", lang);
  32. }
  33. };
  34. let mut index = Index::with_language(language, &["title", "body"]);
  35. for section in library.sections_values() {
  36. if section.lang == lang {
  37. add_section_to_index(&mut index, section, library);
  38. }
  39. }
  40. Ok(index.to_json())
  41. }
  42. fn add_section_to_index(index: &mut Index, section: &Section, library: &Library) {
  43. if !section.meta.in_search_index {
  44. return;
  45. }
  46. // Don't index redirecting sections
  47. if section.meta.redirect_to.is_none() {
  48. index.add_doc(
  49. &section.permalink,
  50. &[
  51. &section.meta.title.clone().unwrap_or_default(),
  52. &AMMONIA.clean(&section.content).to_string(),
  53. ],
  54. );
  55. }
  56. for key in &section.pages {
  57. let page = library.get_page_by_key(*key);
  58. if !page.meta.in_search_index {
  59. continue;
  60. }
  61. index.add_doc(
  62. &page.permalink,
  63. &[
  64. &page.meta.title.clone().unwrap_or_default(),
  65. &AMMONIA.clean(&page.content).to_string(),
  66. ],
  67. );
  68. }
  69. }