use std::path::Path;
use sha2::{Digest, Sha256};
use zenith_core::{
Diagnostic, DiagnosticPolicy, Document, KdlAdapter, KdlSource, Severity, apply_policy,
merge_brand_contract, validate_with_policy,
};
use crate::config::{CliPolicyFlags, load_global_and_local, merge_policy};
use super::entry::RenderCmdErr;
pub(super) fn verify_locked_sha256(
id: &str,
kind: &str,
sha256: Option<&str>,
bytes: &[u8],
) -> Result<(), RenderCmdErr> {
let declared = sha256.ok_or_else(|| {
RenderCmdErr::new(format!("--locked: {kind} '{id}' has no declared sha256"), 2)
})?;
let hex = format!("{:x}", Sha256::digest(bytes));
if declared.trim().to_lowercase() != hex {
return Err(RenderCmdErr::new(
format!("--locked: {kind} '{id}' sha256 mismatch (declared {declared}, actual {hex})"),
2,
));
}
Ok(())
}
pub(super) fn parse_validate(
src: &str,
start_dir: Option<&Path>,
flags: &CliPolicyFlags,
) -> Result<(Document, DiagnosticPolicy), RenderCmdErr> {
let (global, local, global_brand, local_brand) = load_global_and_local(start_dir)
.map_err(|msg| RenderCmdErr::new(format!("error[config.error]: {msg}"), 2))?;
let doc = KdlAdapter
.parse(src.as_bytes())
.map_err(|e| RenderCmdErr::new(format!("error[parse.error]: {}", e.message), 2))?;
let merged = merge_policy(&global, &local, &doc.diagnostic_policy, flags);
let effective_brand = merge_brand_contract(
&merge_brand_contract(&global_brand, &local_brand),
&doc.brand_contract,
);
let report = validate_with_policy(&doc, &merged, &effective_brand);
if report.has_errors() {
let msgs: Vec<String> = report
.diagnostics
.iter()
.filter(|d| d.severity == Severity::Error)
.map(crate::commands::format_error_diag)
.collect();
return Err(RenderCmdErr::new(msgs.join("\n"), 1));
}
Ok((doc, merged))
}
pub(super) fn govern_compile_diagnostics(
diagnostics: Vec<Diagnostic>,
policy: &DiagnosticPolicy,
) -> Vec<Diagnostic> {
apply_policy(diagnostics, policy)
}
pub(super) fn resolve_page_index(doc: &Document, page: usize) -> Result<usize, RenderCmdErr> {
let n = doc.body.pages.len();
if doc.body.pages.is_empty() || page < 1 || page > n {
return Err(RenderCmdErr::new(
format!("page {page} out of range; document has {n} page(s)"),
2,
));
}
Ok(page - 1)
}