Skip to main content

cfdi_cli/
lib.rs

1pub mod models;
2pub mod parser;
3pub mod validator;
4
5#[cfg(feature = "cli")]
6pub mod bulk;
7#[cfg(feature = "cli")]
8pub mod formatter;
9
10// WASM bindings
11#[cfg(feature = "wasm")]
12mod wasm {
13    use wasm_bindgen::prelude::*;
14
15    use crate::parser;
16    use crate::validator;
17
18    /// Parse a CFDI XML string and return JSON.
19    #[wasm_bindgen(js_name = "parseCfdi")]
20    pub fn parse_cfdi(xml: &str) -> Result<String, JsValue> {
21        let cfdi = parser::parse_str(xml).map_err(|e| JsValue::from_str(&e.to_string()))?;
22        serde_json::to_string(&cfdi).map_err(|e| JsValue::from_str(&e.to_string()))
23    }
24
25    /// Parse a CFDI XML string and return pretty-printed JSON.
26    #[wasm_bindgen(js_name = "parseCfdiPretty")]
27    pub fn parse_cfdi_pretty(xml: &str) -> Result<String, JsValue> {
28        let cfdi = parser::parse_str(xml).map_err(|e| JsValue::from_str(&e.to_string()))?;
29        serde_json::to_string_pretty(&cfdi).map_err(|e| JsValue::from_str(&e.to_string()))
30    }
31
32    /// Validate a CFDI XML string. Returns JSON with {valid, errors, warnings}.
33    #[wasm_bindgen(js_name = "validateCfdi")]
34    pub fn validate_cfdi(xml: &str) -> Result<String, JsValue> {
35        let cfdi = parser::parse_str(xml).map_err(|e| JsValue::from_str(&e.to_string()))?;
36        let result = validator::validate(&cfdi);
37
38        let output = serde_json::json!({
39            "valid": result.valid,
40            "errors": result.errors,
41            "warnings": result.warnings,
42        });
43
44        serde_json::to_string(&output).map_err(|e| JsValue::from_str(&e.to_string()))
45    }
46
47    /// Quick info extraction: returns JSON with uuid, fecha, tipo, emisor, receptor, total.
48    #[wasm_bindgen(js_name = "infoCfdi")]
49    pub fn info_cfdi(xml: &str) -> Result<String, JsValue> {
50        let cfdi = parser::parse_str(xml).map_err(|e| JsValue::from_str(&e.to_string()))?;
51
52        let output = serde_json::json!({
53            "uuid": cfdi.uuid(),
54            "fecha": cfdi.fecha,
55            "tipo": cfdi.tipo_de_comprobante,
56            "tipoDescripcion": cfdi.tipo_comprobante_str(),
57            "serie": cfdi.serie,
58            "folio": cfdi.folio,
59            "emisorRfc": cfdi.emisor.rfc,
60            "emisorNombre": cfdi.emisor.nombre,
61            "receptorRfc": cfdi.receptor.rfc,
62            "receptorNombre": cfdi.receptor.nombre,
63            "subTotal": cfdi.sub_total,
64            "total": cfdi.total,
65            "moneda": cfdi.moneda,
66        });
67
68        serde_json::to_string(&output).map_err(|e| JsValue::from_str(&e.to_string()))
69    }
70
71    /// Parse multiple CFDI XMLs at once. Input: JSON array of XML strings. Returns JSON array of results.
72    #[wasm_bindgen(js_name = "parseCfdiBulk")]
73    pub fn parse_cfdi_bulk(xmls_json: &str) -> Result<String, JsValue> {
74        let xmls: Vec<String> =
75            serde_json::from_str(xmls_json).map_err(|e| JsValue::from_str(&e.to_string()))?;
76
77        let results: Vec<serde_json::Value> = xmls
78            .iter()
79            .map(|xml| match parser::parse_str(xml) {
80                Ok(cfdi) => serde_json::json!({
81                    "ok": true,
82                    "data": cfdi,
83                }),
84                Err(e) => serde_json::json!({
85                    "ok": false,
86                    "error": e.to_string(),
87                }),
88            })
89            .collect();
90
91        serde_json::to_string(&results).map_err(|e| JsValue::from_str(&e.to_string()))
92    }
93}