1pub mod error;
2pub mod frontmatter;
3pub mod model;
4pub mod parser;
5pub mod render;
6pub mod resolve;
7pub mod signatures;
8pub mod style;
9
10use std::path::{Path, PathBuf};
11
12use error::{Diagnostic, Result};
13use model::{Document, Status};
14use signatures::SignatureBlock;
15use style::StyleConfig;
16
17pub fn parse(input: &str) -> Result<Document> {
18 parser::parse(input)
19}
20
21pub fn resolve(doc: &mut Document) {
22 resolve::resolve(doc);
23}
24
25pub fn render_docx(
26 doc: &Document,
27 style: &StyleConfig,
28 input_dir: Option<&Path>,
29 signature_blocks: &[SignatureBlock],
30) -> Result<Vec<u8>> {
31 render::docx::render_docx(doc, style, input_dir, signature_blocks)
32}
33
34pub fn resolve_config_path(filename: &str, input_dir: Option<&Path>) -> Option<PathBuf> {
40 if let Some(dir) = input_dir {
42 let local = dir.join(filename);
43 if local.exists() {
44 return Some(local);
45 }
46 }
47
48 let config_dir = std::env::var("XDG_CONFIG_HOME")
50 .map(PathBuf::from)
51 .unwrap_or_else(|_| {
52 let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string());
53 PathBuf::from(home).join(".config")
54 })
55 .join("lexicon");
56
57 let global = config_dir.join(filename);
58 if global.exists() {
59 return Some(global);
60 }
61
62 None
63}
64
65pub fn process(
66 input: &str,
67 style: &StyleConfig,
68 input_dir: Option<&Path>,
69 signatures_path: Option<&Path>,
70) -> Result<(Vec<u8>, Vec<Diagnostic>)> {
71 let mut doc = parse(input)?;
72 resolve(&mut doc);
73
74 let mut sig_diagnostics = Vec::new();
76 let signature_blocks = if style.signatures.enabled {
77 let definitions = match signatures_path {
78 Some(path) => signatures::load_definitions(path, &mut sig_diagnostics),
79 None => {
80 sig_diagnostics.push(Diagnostic {
81 level: error::DiagLevel::Warning,
82 message: "Signatures enabled but no definitions file found (searched input directory and $XDG_CONFIG_HOME/lexicon/)".to_string(),
83 location: None,
84 });
85 None
86 }
87 };
88
89 signatures::resolve_signature_blocks(
90 &doc.meta.parties,
91 doc.meta.doc_type.as_deref(),
92 style,
93 &definitions,
94 &mut sig_diagnostics,
95 )
96 } else {
97 vec![]
98 };
99
100 doc.diagnostics.extend(sig_diagnostics);
101
102 let mut bytes = render_docx(&doc, style, input_dir, &signature_blocks)?;
103 if doc.meta.status == Some(Status::Draft) {
104 bytes = render::watermark::inject_watermark(bytes, "DRAFT")?;
105 }
106 Ok((bytes, doc.diagnostics))
107}