⎇ d270c5e67457195cd845f783c0b3b7bd66b9add0
crates/ente-brain/src/loader.rs
Historia
Quién tocó qué
crudo
1//! Loader de Cards y Reglas desde archivos JSON.
2//!
3//! Sustituye al antiguo `kcl_loader.rs` (eliminado): la rama KCL invocaba
4//! un subprocess al CLI Go `kcl` que ningún target real tenía instalado y
5//! cuya validación duplicaba `EntityCard::validate()`. La fuente de verdad
6//! del shape de la Card es Rust + serde; en disco se guarda JSON crudo.
7//!
8//! Ergonomía de autoría futura (RON, Dhall, etc.) se añade como ramas
9//! adicionales aquí cuando duela escribir JSON a mano. Hoy: una sola rama.
10
11use crate::rules::Rule;
12use ente_card::EntityCard;
13use std::path::Path;
14use tracing::info;
15
16/// Carga una `EntityCard` desde un archivo JSON. Pasa por
17/// `EntityCard::validate()` antes de devolver — falla rápida.
18pub fn load_card_file(path: &Path) -> anyhow::Result<EntityCard> {
19 info!(path = %path.display(), "cargando Card desde JSON");
20 let raw = std::fs::read_to_string(path)?;
21 let card = extract_card_from_json(&raw)?;
22 card.validate()
23 .map_err(|e| anyhow::anyhow!("Card inválida ({}): {e}", path.display()))?;
24 Ok(card)
25}
26
27/// Extrae una `EntityCard` de JSON. Acepta:
28/// 1. Object directamente serializable como EntityCard.
29/// 2. Object dict con un único valor que sea EntityCard (compat con
30/// salidas de generadores que envuelven en `{"seed": {...}}`).
31pub fn extract_card_from_json(raw: &str) -> anyhow::Result<EntityCard> {
32 let v: serde_json::Value = serde_json::from_str(raw)?;
33 if let Ok(c) = serde_json::from_value::<EntityCard>(v.clone()) {
34 return Ok(c);
35 }
36 if let serde_json::Value::Object(map) = v {
37 for (_, vv) in map {
38 if let Ok(c) = serde_json::from_value::<EntityCard>(vv) {
39 return Ok(c);
40 }
41 }
42 }
43 anyhow::bail!("JSON no contiene una EntityCard válida")
44}
45
46/// Carga reglas desde un archivo JSON.
47pub fn load_rules_file(path: &Path) -> anyhow::Result<Vec<Rule>> {
48 info!(path = %path.display(), "cargando reglas desde JSON");
49 let raw = std::fs::read_to_string(path)?;
50 extract_rules_from_json(&raw)
51}
52
53/// Extrae un `Vec<Rule>` de JSON que puede ser:
54/// 1. Array directo: `[{...}, {...}]`
55/// 2. Object con un campo array: `{"rules": [...]}`
56pub fn extract_rules_from_json(raw: &str) -> anyhow::Result<Vec<Rule>> {
57 let v: serde_json::Value = serde_json::from_str(raw)?;
58 let arr = match v {
59 serde_json::Value::Array(_) => v,
60 serde_json::Value::Object(map) => map
61 .into_values()
62 .find(|x| x.is_array())
63 .ok_or_else(|| anyhow::anyhow!("JSON no contiene ningún array"))?,
64 _ => anyhow::bail!("JSON debe ser array o object con campo array"),
65 };
66 let rules: Vec<Rule> = serde_json::from_value(arr)?;
67 Ok(rules)
68}