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.3KB

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