katana-document-viewer 0.1.4

KatanA document viewer artifact, render evaluation, and export foundation.
Documentation
use crate::artifact::{ArtifactBytes, ArtifactFactory};
use crate::export_payload::ExportPayloadFactory;
pub use crate::forge_types::{
    BuildGraph, BuildProfile, BuildRequest, ExportFormat, ExportOutput, ExportRequest,
    ForgeBackend, ForgeDiagnostics, ForgeError, MarkdownEvaluationTarget, RenderedDiagram,
    TransformStep,
};

pub struct ForgePipeline<B> {
    backend: B,
}

impl BuildProfile {
    pub fn markdown_export() -> Self {
        Self {
            evaluation_targets: vec![
                MarkdownEvaluationTarget::CommonMark,
                MarkdownEvaluationTarget::Gfm,
                MarkdownEvaluationTarget::Math,
                MarkdownEvaluationTarget::GitHubAlert,
                MarkdownEvaluationTarget::KatanaCompatibility,
                MarkdownEvaluationTarget::ExternalRendering,
            ],
            transform_steps: vec![
                TransformStep::EvaluateMarkdown,
                TransformStep::RenderDiagrams,
                TransformStep::BuildArtifactManifest,
            ],
        }
    }
}

impl BuildGraph {
    pub fn from_request(request: &BuildRequest) -> Self {
        Self {
            snapshot: request.snapshot.clone(),
            profile: request.profile.clone(),
            theme: request.theme.clone(),
            diagnostics: ForgeDiagnostics {
                messages: Vec::new(),
            },
            rendered_diagrams: Vec::new(),
        }
    }

    pub fn with_rendered_diagrams(mut self, rendered_diagrams: Vec<RenderedDiagram>) -> Self {
        self.rendered_diagrams = rendered_diagrams;
        self
    }
}

impl<B: ForgeBackend> ForgePipeline<B> {
    pub fn new(backend: B) -> Self {
        Self { backend }
    }

    pub fn build(&self, request: &BuildRequest) -> Result<BuildGraph, ForgeError> {
        self.backend.build(request)
    }

    pub fn export(&self, request: &ExportRequest) -> Result<ExportOutput, ForgeError> {
        validate_export_output(self.backend.export(request), request.format)
    }
}

fn validate_export_output(
    result: Result<ExportOutput, ForgeError>,
    format: ExportFormat,
) -> Result<ExportOutput, ForgeError> {
    match result {
        Ok(output) => reject_empty_export_output(output, format),
        Err(error) => Err(error),
    }
}

fn reject_empty_export_output(
    output: ExportOutput,
    format: ExportFormat,
) -> Result<ExportOutput, ForgeError> {
    if output.artifact.bytes.bytes.is_empty() {
        Err(ForgeError::EmptyExportArtifact(format))
    } else {
        Ok(output)
    }
}
pub struct ManifestOnlyBackend;

impl ForgeBackend for ManifestOnlyBackend {
    fn build(&self, request: &BuildRequest) -> Result<BuildGraph, ForgeError> {
        Ok(BuildGraph::from_request(request))
    }

    fn export(&self, request: &ExportRequest) -> Result<ExportOutput, ForgeError> {
        let snapshot = &request.graph.snapshot;
        ExportPayloadFactory::create(&request.graph, request.format, &request.theme).map(|bytes| {
            let artifact = ArtifactFactory::export(
                request.format.artifact_format(),
                snapshot.id.clone(),
                snapshot.revision.clone(),
                ArtifactBytes { bytes },
            );
            ExportOutput {
                artifact,
                diagnostics: request.graph.diagnostics.clone(),
            }
        })
    }
}

#[cfg(test)]
#[path = "forge_tests.rs"]
mod tests;