Skip to main content

formal_ai/
document_formats.rs

1//! Document-format conversion through link-foundation/meta-language.
2//!
3//! formal-ai keeps document structure and cross-format conversion behind the
4//! upstream meta-language links network. This module is the local boundary used
5//! by natural-language document workflows: it exposes the supported formats,
6//! their fidelity profiles, and a small conversion helper over
7//! `LinkNetwork::reconstruct_text_as`.
8
9#[cfg(feature = "meta-language")]
10use meta_language::{
11    canonical_document_format, document_format_profile, docx_package_is_recognized,
12    docx_profile_is_recognized, parse_markup_document, pdf_profile_is_recognized,
13    render_docx_package, LinkNetwork, ParseConfiguration, CROSS_FORMAT_CONCEPTS, DOCUMENT_FORMATS,
14};
15
16/// The engine recorded in traces for document-format CST/concept conversion.
17pub const DOCUMENT_FORMAT_ENGINE: &str = "meta_language";
18
19/// Fidelity profile for one document format supported by meta-language.
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct DocumentFormatCapabilities {
22    /// Canonical format label (`txt`, `Markdown`, `HTML`, `PDF`, or `DOCX`).
23    pub format: String,
24    /// Cross-format concepts the target profile represents natively.
25    pub native_concepts: Vec<String>,
26    /// Declared lossy fallbacks for concepts the target cannot represent.
27    pub fallbacks: Vec<(String, String)>,
28}
29
30/// Result of reconstructing one document format as another.
31#[derive(Debug, Clone, PartialEq, Eq)]
32pub struct DocumentConversion {
33    /// Canonical source format label.
34    pub source_format: String,
35    /// Canonical target format label.
36    pub target_format: String,
37    /// Text representation rendered by `LinkNetwork::reconstruct_text_as`.
38    pub output: String,
39    /// Target fidelity profile used for the conversion.
40    pub target_capabilities: DocumentFormatCapabilities,
41    /// Optional real package bytes when the target format has a package layer.
42    ///
43    /// For meta-language 0.45 this is populated for `DOCX` with a stored-entry
44    /// OPC ZIP package that contains the rendered `word/document.xml` part.
45    pub package_bytes: Option<Vec<u8>>,
46}
47
48/// Document formats available through the upstream cross-format layer.
49#[must_use]
50pub const fn supported_document_formats() -> &'static [&'static str] {
51    #[cfg(feature = "meta-language")]
52    {
53        DOCUMENT_FORMATS
54    }
55    #[cfg(not(feature = "meta-language"))]
56    {
57        &[]
58    }
59}
60
61/// Shared formatting concepts considered by the upstream fidelity profiles.
62#[must_use]
63pub const fn cross_format_document_concepts() -> &'static [&'static str] {
64    #[cfg(feature = "meta-language")]
65    {
66        CROSS_FORMAT_CONCEPTS
67    }
68    #[cfg(not(feature = "meta-language"))]
69    {
70        &[]
71    }
72}
73
74/// Canonicalizes a format alias to the upstream document-format label.
75#[must_use]
76pub fn canonical_document_format_label(format: &str) -> Option<&'static str> {
77    #[cfg(feature = "meta-language")]
78    {
79        canonical_document_format(format)
80    }
81    #[cfg(not(feature = "meta-language"))]
82    {
83        let _ = format;
84        None
85    }
86}
87
88/// Returns the meta-language fidelity profile for a document format.
89#[must_use]
90pub fn document_format_capabilities(format: &str) -> Option<DocumentFormatCapabilities> {
91    #[cfg(not(feature = "meta-language"))]
92    {
93        let _ = format;
94        return None;
95    }
96    #[cfg(feature = "meta-language")]
97    {
98        let canonical = canonical_document_format(format)?;
99        let profile = document_format_profile(canonical)?;
100        let native_concepts = CROSS_FORMAT_CONCEPTS
101            .iter()
102            .copied()
103            .filter(|concept| profile.supports_concept(concept))
104            .map(str::to_owned)
105            .collect();
106        let fallbacks = CROSS_FORMAT_CONCEPTS
107            .iter()
108            .copied()
109            .filter_map(|concept| {
110                profile
111                    .concept_fallback(concept)
112                    .map(|fallback| (concept.to_owned(), fallback.to_owned()))
113            })
114            .collect();
115
116        Some(DocumentFormatCapabilities {
117            format: canonical.to_owned(),
118            native_concepts,
119            fallbacks,
120        })
121    }
122}
123
124/// Whether text is recognized by meta-language's constrained profile for a format.
125///
126/// Markdown, HTML, and txt recognition is based on parsing into a non-empty
127/// concept-layer document. PDF and DOCX use the explicit profile recognizers
128/// exported by meta-language.
129#[must_use]
130pub fn document_profile_is_recognized(format: &str, text: &str) -> bool {
131    #[cfg(not(feature = "meta-language"))]
132    {
133        let _ = (format, text);
134        return false;
135    }
136    #[cfg(feature = "meta-language")]
137    {
138        match canonical_document_format(format) {
139            Some("PDF") => pdf_profile_is_recognized(text),
140            Some("DOCX") => docx_profile_is_recognized(text),
141            Some(canonical) => parse_markup_document(canonical, text)
142                .is_some_and(|document| !document.blocks.is_empty()),
143            None => false,
144        }
145    }
146}
147
148/// Whether package bytes are recognized by the format's package layer.
149///
150/// meta-language 0.45 exposes an OPC ZIP package profile for DOCX. Other
151/// document formats currently have no separate package wrapper in the upstream
152/// API, so they return `false`.
153#[must_use]
154pub fn document_package_is_recognized(format: &str, bytes: &[u8]) -> bool {
155    #[cfg(not(feature = "meta-language"))]
156    {
157        let _ = (format, bytes);
158        return false;
159    }
160    #[cfg(feature = "meta-language")]
161    {
162        match canonical_document_format(format) {
163            Some("DOCX") => docx_package_is_recognized(bytes),
164            _ => false,
165        }
166    }
167}
168
169/// Converts a document through meta-language's shared concept layer.
170#[must_use]
171pub fn convert_document_format(
172    source_format: &str,
173    target_format: &str,
174    source_text: &str,
175) -> Option<DocumentConversion> {
176    #[cfg(not(feature = "meta-language"))]
177    {
178        let _ = (source_format, target_format, source_text);
179        return None;
180    }
181    #[cfg(feature = "meta-language")]
182    {
183        let source = canonical_document_format(source_format)?;
184        let target = canonical_document_format(target_format)?;
185        let network = LinkNetwork::parse(source_text, source, ParseConfiguration::default());
186        let output = network.reconstruct_text_as(target, ParseConfiguration::default());
187        let target_capabilities = document_format_capabilities(target)?;
188        let package_bytes = package_bytes_for_target(source, target, source_text);
189
190        Some(DocumentConversion {
191            source_format: source.to_owned(),
192            target_format: target.to_owned(),
193            output,
194            target_capabilities,
195            package_bytes,
196        })
197    }
198}
199
200#[cfg(feature = "meta-language")]
201fn package_bytes_for_target(
202    source_format: &str,
203    target_format: &str,
204    source_text: &str,
205) -> Option<Vec<u8>> {
206    if target_format != "DOCX" {
207        return None;
208    }
209    let document = parse_markup_document(source_format, source_text)?;
210    (!document.blocks.is_empty()).then(|| render_docx_package(&document))
211}