tealr_doc_gen 0.4.0

A cli tool to create online documentation for apis made with tealr
use std::{fs::create_dir_all, path::PathBuf};

use anyhow::Context;
use tealr::{
    mlu::{self, ExportInstances},
    TypeWalker,
};

use crate::Paths;

use super::{shared_globals, shared_types};

#[derive(Default)]
struct GlobalsDefFile {
    etlua: String,
    module: TypeWalker,
    template: String,
    is_global: bool,
    name: String,
}
impl ExportInstances for GlobalsDefFile {
    fn add_instances<T: mlu::InstanceCollector>(
        self,
        instance_collector: &mut T,
    ) -> mlu::mlua::Result<()> {
        instance_collector.document_instance("Type and documentation of this module");
        instance_collector.add_instance("module", |_| Ok(self.module))?;
        instance_collector
            .document_instance("Wether it is a local or global record that wraps the module");
        instance_collector.add_instance("global_or_local", |_| {
            Ok(if self.is_global { "global" } else { "local" })
        })?;

        instance_collector.document_instance("name of the module");
        instance_collector.add_instance("name", |_| Ok(self.name))?;
        shared_globals(instance_collector, &self.etlua, &self.template)?;
        Ok(())
    }
}

pub(crate) fn create_d_file(
    walker: TypeWalker,
    path: PathBuf,
    name: &str,
    config: &Paths,
) -> Result<PathBuf, anyhow::Error> {
    let is_global = config.is_global;
    let runner = match &config.def_config.runner {
        crate::app::DefTemplateRunnerKind::Builtin => {
            include_str!("../../base_run_template.lua").to_string()
        }
        crate::app::DefTemplateRunnerKind::Custom(x) => std::fs::read_to_string(x)
            .with_context(|| format!("Failed loading custom runner: {x}"))?,
    };
    let page_path = path.join("definitions");
    for config in config.def_config.templates.values() {
        let template = match &config.template {
            crate::app::DefTemplateKind::Teal => {
                include_str!("../../base_teal_definition_template.etlua").to_string()
            }
            crate::app::DefTemplateKind::Custom(x) => std::fs::read_to_string(x)
                .with_context(|| format!("Failed to load custom template: {x}"))?,
        };
        let lua = unsafe { mlu::mlua::Lua::unsafe_new() };
        let etlua = include_str!("../../etlua.lua").to_string();
        let x = GlobalsDefFile {
            etlua,
            module: walker.clone(),
            template,
            is_global,
            name: name.to_string(),
        };
        mlu::set_global_env(x, &lua)?;

        let document: mlu::mlua::String = lua
            .load(&runner)
            .set_name("template_runner")
            .call(())
            .context("Failed running lua template")?;
        create_dir_all(&page_path).with_context(|| {
            format!(
                "Could not create directories needed for:{}.",
                page_path.to_string_lossy()
            )
        })?;
        let extension = if config.extension.starts_with('.') {
            &config.extension[1..]
        } else {
            &config.extension
        };
        let page_path = page_path.join(format!("{name}.{extension}"));
        std::fs::write(&page_path, document.as_bytes())
            .with_context(|| format!("Could not write file{}", page_path.to_string_lossy()))?;
    }

    Ok(page_path)
}

pub fn generate_self_def() -> Result<TypeWalker, anyhow::Error> {
    let x = tealr::TypeWalker::new();
    shared_types(x)
        .document_global_instance::<GlobalsDefFile>()
        .context("failed to generate global instance")
}