obsidian_export/
postprocessors.rs1use pulldown_cmark::Event;
4use serde_yaml::Value;
5
6use super::{Context, MarkdownEvents, PostprocessorResult};
7
8pub fn softbreaks_to_hardbreaks(
11 _context: &mut Context,
12 events: &mut MarkdownEvents<'_>,
13) -> PostprocessorResult {
14 for event in events.iter_mut() {
15 if event == &Event::SoftBreak {
16 *event = Event::HardBreak;
17 }
18 }
19 PostprocessorResult::Continue
20}
21
22pub fn filter_by_tags(
23 skip_tags: Vec<String>,
24 only_tags: Vec<String>,
25) -> impl Fn(&mut Context, &mut MarkdownEvents<'_>) -> PostprocessorResult {
26 move |context: &mut Context, _events: &mut MarkdownEvents<'_>| -> PostprocessorResult {
27 match context.frontmatter.get("tags") {
28 None => filter_by_tags_(&[], &skip_tags, &only_tags),
29 Some(Value::Sequence(tags)) => filter_by_tags_(tags, &skip_tags, &only_tags),
30 _ => PostprocessorResult::Continue,
31 }
32 }
33}
34
35fn filter_by_tags_(
36 tags: &[Value],
37 skip_tags: &[String],
38 only_tags: &[String],
39) -> PostprocessorResult {
40 let skip = skip_tags
41 .iter()
42 .any(|tag| tags.contains(&Value::String(tag.to_string())));
43 let include = only_tags.is_empty()
44 || only_tags
45 .iter()
46 .any(|tag| tags.contains(&Value::String(tag.to_string())));
47
48 if skip || !include {
49 PostprocessorResult::StopAndSkipNote
50 } else {
51 PostprocessorResult::Continue
52 }
53}
54
55#[test]
56fn test_filter_tags() {
57 let tags = vec![
58 Value::String("skip".into()),
59 Value::String("publish".into()),
60 ];
61 let empty_tags = vec![];
62 assert_eq!(
63 filter_by_tags_(&empty_tags, &[], &[]),
64 PostprocessorResult::Continue,
65 "When no exclusion & inclusion are specified, files without tags are included"
66 );
67 assert_eq!(
68 filter_by_tags_(&tags, &[], &[]),
69 PostprocessorResult::Continue,
70 "When no exclusion & inclusion are specified, files with tags are included"
71 );
72 assert_eq!(
73 filter_by_tags_(&tags, &["exclude".into()], &[]),
74 PostprocessorResult::Continue,
75 "When exclusion tags don't match files with tags are included"
76 );
77 assert_eq!(
78 filter_by_tags_(&empty_tags, &["exclude".into()], &[]),
79 PostprocessorResult::Continue,
80 "When exclusion tags don't match files without tags are included"
81 );
82 assert_eq!(
83 filter_by_tags_(&tags, &[], &["publish".into()]),
84 PostprocessorResult::Continue,
85 "When exclusion tags don't match files with tags are included"
86 );
87 assert_eq!(
88 filter_by_tags_(&empty_tags, &[], &["include".into()]),
89 PostprocessorResult::StopAndSkipNote,
90 "When inclusion tags are specified files without tags are excluded"
91 );
92 assert_eq!(
93 filter_by_tags_(&tags, &[], &["include".into()]),
94 PostprocessorResult::StopAndSkipNote,
95 "When exclusion tags don't match files with tags are exluded"
96 );
97 assert_eq!(
98 filter_by_tags_(&tags, &["skip".into()], &["skip".into()]),
99 PostprocessorResult::StopAndSkipNote,
100 "When both inclusion and exclusion tags are the same exclusion wins"
101 );
102 assert_eq!(
103 filter_by_tags_(&tags, &["skip".into()], &["publish".into()]),
104 PostprocessorResult::StopAndSkipNote,
105 "When both inclusion and exclusion tags match exclusion wins"
106 );
107}