Skip to main content

weavatrix_rust/report/
mod.rs

1//! Composes repository evidence into a report a person can read and share.
2//!
3//! The composer returns bytes and writes nothing. Publishing a document is an
4//! explicit act by a person at a command line, not a side effect an agent can
5//! trigger through a query, so the read-only operation surface stays read-only
6//! and the only component that touches the filesystem for output is the CLI.
7
8mod html;
9mod layout;
10mod markdown;
11mod sections;
12mod tables;
13
14use crate::engine::Weavatrix;
15use blazingly_json::{Value, json};
16
17/// The engine identity a report states about itself. Read from the package
18/// rather than through the public facade, which depends on this module.
19const ENGINE: &str = env!("CARGO_PKG_VERSION");
20
21/// One composed report in its three renderings.
22pub struct Report {
23    /// The Markdown document.
24    pub markdown: String,
25    /// The self-contained HTML page, including its module map.
26    pub html: String,
27    /// The gathered evidence, for a consumer that renders its own view.
28    pub data: Value,
29}
30
31/// Composes a report from the repository the engine currently targets.
32///
33/// Every section is an ordinary bounded operation from the read-only catalog.
34/// A capability this build did not compile is recorded as absent with its
35/// reason rather than rendered as an empty section.
36///
37/// # Errors
38///
39/// Returns the first operation failure. A missing optional capability is not
40/// a failure; a repository that cannot be analyzed is.
41pub fn compose(engine: &mut Weavatrix) -> Result<Report, String> {
42    let evidence = sections::gather(engine)?;
43    let summary = tables::summary(&evidence);
44    let sections = tables::sections(&evidence);
45    Ok(Report {
46        markdown: markdown::render(&summary, &sections, evidence.depth, ENGINE),
47        html: html::render(&summary, &sections, &evidence, ENGINE),
48        data: data(&evidence),
49    })
50}
51
52fn data(evidence: &sections::Evidence) -> Value {
53    json!({
54        "schema": "weavatrix.report.v1",
55        "engine": ENGINE,
56        "graph_stats": evidence.stats,
57        "verify_architecture": evidence.architecture,
58        "god_nodes": evidence.hubs,
59        "hot_path_review": evidence.hot,
60        "find_dead_code": evidence.dead,
61        "find_duplicates": evidence.duplicates,
62        "list_endpoints": evidence.endpoints,
63        "n8n_inventory": evidence.workflows,
64        "module_map": {
65            "depth": evidence.depth,
66            "modules": evidence.modules.iter().map(|module| json!({
67                "path": module.path,
68                "files": module.files,
69                "symbols": module.symbols,
70                "violations": module.violations,
71                "x": module.position.0,
72                "y": module.position.1
73            })).collect::<Vec<_>>(),
74            "links": evidence.links.iter().map(|(from, to, weight)| json!({
75                "from": from,
76                "to": to,
77                "weight": weight
78            })).collect::<Vec<_>>()
79        }
80    })
81}