use std::collections::HashMap;
use std::fmt::Debug;
use serde::{Deserialize, Serialize};
use crate::ast::Ast;
use anyhow::{anyhow, Context};
use thiserror::Error;
use crate::document::{split_shortcodes, Document, DocumentMetadata};
use crate::notebook::Notebook;
#[derive(Error, Debug)]
pub enum LoaderError {
#[error(transparent)]
Anyhow(#[from] anyhow::Error),
#[error(transparent)]
Std(#[from] Box<dyn std::error::Error + Send + Sync>),
#[error(transparent)]
Json(#[from] serde_json::Error),
}
#[typetag::serde(tag = "type")]
pub trait Loader: Debug {
fn load(&self, input: &str) -> anyhow::Result<Document<Ast>>;
}
#[derive(Serialize, Deserialize, Debug)]
pub struct NotebookLoader;
#[typetag::serde(name = "notebook_loader")]
impl Loader for NotebookLoader {
fn load(&self, input: &str) -> anyhow::Result<Document<Ast>> {
let nb: Notebook = serde_json::from_str(input)?;
nb.try_into()
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct MarkdownLoader;
#[typetag::serde(name = "markdown_loader")]
impl Loader for MarkdownLoader {
fn load(&self, input: &str) -> anyhow::Result<Document<Ast>> {
let start = input
.find("---")
.ok_or_else(|| anyhow!("Missing frontmatter specifier"))?;
let end = start
+ 3
+ input[start + 3..]
.find("---")
.ok_or_else(|| anyhow!("Missing frontmatter specifier"))?;
let meta: DocumentMetadata =
serde_yaml::from_str(&input[start + 3..end]).context("Could not parse frontmatter")?;
let mut counters = HashMap::new();
let elems = split_shortcodes(&input[end + 3..], &mut counters)?;
Ok(Document::new(Ast(elems), meta, counters))
}
}
#[cfg(test)]
mod tests {
}