1use aspero_engine::{Reason, Verification};
4use serde_json::{Value, json};
5
6use crate::{merged, work};
7
8pub fn invalid_claim(echo: Value, reason: &str) -> Value {
10 merged(echo, json!({"verdict": "invalid", "reason": reason}))
11}
12
13pub fn verification(echo: Value, v: &Verification, full: bool) -> Value {
15 let mut item = merged(
16 echo,
17 json!({
18 "verdict": v.verdict.as_str(),
19 "reason": v.reason,
20 "why": why(v, full),
21 "read": v.read,
22 }),
23 );
24 if let Some(best) = v.best {
25 item["match"] = work::candidate(&v.report.candidates[best], full);
26 }
27 let failures = v.report.failures();
28 if !failures.is_empty() {
29 let errors: Vec<String> = failures.iter().map(ToString::to_string).collect();
30 item["errors"] = json!(errors);
31 let kinds: Vec<&str> = failures.iter().map(|e| e.kind().as_str()).collect();
32 item["error_kinds"] = json!(kinds);
33 }
34 if full {
35 let all: Vec<Value> = v
36 .report
37 .candidates
38 .iter()
39 .map(|c| work::candidate(c, true))
40 .collect();
41 item["candidates"] = json!(all);
42 }
43 item
44}
45
46fn why(v: &Verification, full: bool) -> Value {
49 let mut out = json!({"code": v.why.as_str()});
50 let differs: Vec<Value> = v
51 .why
52 .differs()
53 .iter()
54 .map(|d| {
55 let mut out = json!({"field": d.field.as_str()});
56 if let Some(actual) = &d.actual {
57 out["actual"] = json!(actual);
58 }
59 if let Some(cited) = &d.cited {
60 out["cited"] = json!(cited);
61 }
62 out
63 })
64 .collect();
65 if !differs.is_empty() {
66 out["differs"] = json!(differs);
67 }
68 if let Reason::IdElsewhere { cited } = v.why {
69 out["cited"] = work::candidate(&v.report.candidates[cited], full);
70 }
71 out
72}