1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use crate::ast::Ast;
use serde::{Deserialize, Serialize};
use thiserror::Error;

use crate::document::Document;
use crate::processors::exercises::ExercisesConfig;
use crate::processors::{AstPreprocessor, AstPreprocessorConfig, PreprocessorContext};

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct Parser {
    #[serde(default = "default_preprocessors")]
    pub preprocessors: Vec<Box<dyn AstPreprocessorConfig>>,
    #[serde(default)]
    pub settings: ParserSettings,
}

fn default_preprocessors() -> Vec<Box<dyn AstPreprocessorConfig>> {
    vec![Box::new(ExercisesConfig) as Box<dyn AstPreprocessorConfig>]
}

/// Additional parser configuration.
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct ParserSettings {
    /// Include solutions for the [crate::processors::exercises::Exercises] preprocessor.
    #[serde(default)]
    pub solutions: bool,
    /// Include notebook outputs (from cells) in the loaded output.
    #[serde(default)]
    pub notebook_outputs: bool,
}

impl Parser {
    pub fn parse(
        &self,
        doc: &Document<Ast>,
        ctx: &PreprocessorContext,
    ) -> Result<Document<Ast>, anyhow::Error> {
        let doc_ast = self.run_ast_processors(doc.clone(), ctx)?;

        Ok(doc_ast)
    }

    pub fn run_ast_processors(
        &self,
        doc: Document<Ast>,
        ctx: &PreprocessorContext,
    ) -> Result<Document<Ast>, anyhow::Error> {
        let mut built = self
            .preprocessors
            .iter()
            .map(|p| p.build(ctx, &self.settings))
            .collect::<anyhow::Result<Vec<Box<dyn AstPreprocessor>>>>()?;

        let doc = built.iter_mut().fold(Ok(doc), |c, ast_processor| {
            c.and_then(|c| ast_processor.process(c))
        })?;

        Ok(doc)
    }
}

#[allow(unused)]
struct HeadingNode {
    id: String,
    children: Vec<HeadingNode>,
}

#[derive(Error, Debug)]
pub enum ParserError {
    #[error("IO Error: ")]
    IoError(#[from] std::io::Error),

    #[error("Error in template")]
    TemplateError(#[from] tera::Error),

    #[error("JSON Error: ")]
    JSONError(#[from] serde_json::error::Error),

    #[error("Error parsing frontmatter: ")]
    FrontMatter(#[from] serde_yaml::Error),

    #[error(transparent)]
    ExtensionError(#[from] crate::processors::Error),

    #[cfg(feature = "katex")]
    #[error(transparent)]
    KaTeX(#[from] katex::Error),

    #[error(transparent)]
    Std(#[from] Box<dyn std::error::Error>),

    #[error(transparent)]
    Anyhow(#[from] anyhow::Error),
}

#[cfg(test)]
mod tests {

    // #[test]
    // fn test_deserialization() {
    //     let config = r#"
    //         {
    //             "preprocessors": [
    //                 {
    //                     "type": "shortcodes",
    //                     "template": "tp/**",
    //                     "file_ext": ".html"
    //                 }
    //             ],
    //             "event_processors": []
    //         }
    //     "#;
    //
    //     let p: Parser = serde_json::from_str(config).unwrap();
    // }
}