Skip to main content

corpora_rules/
lib.rs

1//! Plugin seam #1 — self-validation. A [`Rule`] is pure `&Graph -> diagnostics`;
2//! [`RuleRunner`] fires the registered pack on every `GraphBuilt`.
3
4use corpora_core::subscriber::ek;
5use corpora_core::{Context, Diagnostic, Event, Graph, Interest, RevisionOracle, Subscriber};
6
7pub mod e3;
8pub mod gate_b;
9pub mod held;
10pub mod positional;
11pub mod schema;
12pub mod supersession;
13
14pub use e3::E3;
15pub use gate_b::GateB;
16pub use held::HeldDecision;
17pub use positional::PositionalRef;
18pub use schema::Schema;
19pub use supersession::SupersessionIntegrity;
20
21pub trait Rule {
22    fn code(&self) -> &'static str;
23    fn check(&self, g: &Graph, out: &mut Vec<Diagnostic>);
24}
25
26pub struct RuleRunner {
27    rules: Vec<Box<dyn Rule>>,
28}
29
30impl RuleRunner {
31    pub fn with(rules: Vec<Box<dyn Rule>>) -> Self {
32        RuleRunner { rules }
33    }
34}
35
36impl Subscriber for RuleRunner {
37    fn name(&self) -> &'static str {
38        "rules"
39    }
40
41    fn interest(&self) -> Interest {
42        Interest::only(ek::GRAPH_BUILT)
43    }
44
45    fn handle(&mut self, ev: &Event, cx: &mut Context<'_>) {
46        if let Event::GraphBuilt(g) = ev {
47            let mut ds = Vec::new();
48            for r in &self.rules {
49                r.check(g, &mut ds);
50            }
51            for d in ds {
52                cx.error(d);
53            }
54        }
55    }
56}
57
58/// The default rule pack. `GateB` needs a [`RevisionOracle`] (git); pass a `NullOracle`
59/// to run the pure rules without VCS context.
60pub fn default_rules(oracle: Box<dyn RevisionOracle>) -> Vec<Box<dyn Rule>> {
61    vec![
62        Box::new(Schema),
63        Box::new(SupersessionIntegrity),
64        Box::new(E3),
65        Box::new(HeldDecision),
66        Box::new(PositionalRef),
67        Box::new(GateB::new(oracle)),
68    ]
69}