harn_rules/lib.rs
1//! # harn-rules
2//!
3//! The declarative structural rule engine for Harn — the Rust core that
4//! powers `harn rules` / lint / codemod surfaces. A **rule** describes
5//! *what to match* (a pattern snippet, a node kind, or a regex) and
6//! optionally *how to rewrite* it (a `fix`); the engine compiles that rule
7//! against the tree-sitter machinery in [`harn_hostlib::ast`] and produces
8//! [`RuleMatch`]es with metavariable bindings.
9//!
10//! This crate delivers the **atomic matching tier** (issue #2832):
11//!
12//! - [`model`] — the serde rule data model (`id` / `language` / `severity`
13//! / `message` / `rule` block / `fix`).
14//! - [`pattern`] — the snippet → tree-sitter-query compiler (`$VAR`
15//! metavariable lifting + unification).
16//! - [`engine`] — compile a [`Rule`] and run it to produce matches.
17//! - [`loader`] — load rules from a TOML file or a directory.
18//!
19//! Relational/composite matching (#2833) and `where` / `transform` / `fix`
20//! interpolation (#2834) layer onto this surface.
21//!
22//! ```
23//! use harn_rules::{Rule, CompiledRule};
24//!
25//! let rule = Rule::from_toml_str(
26//! r#"
27//! id = "destructure-default"
28//! language = "typescript"
29//! fix = "{ $KEY: $SRC }"
30//! [rule]
31//! pattern = "$SRC?.$KEY ?? $DEFAULT"
32//! "#,
33//! ).unwrap();
34//! let compiled = CompiledRule::compile(&rule).unwrap();
35//! let matches = compiled.run("const a = cfg?.timeout ?? 30;").unwrap();
36//! assert_eq!(matches[0].bindings["KEY"].text, "timeout");
37//! ```
38
39#![forbid(unsafe_code)]
40
41pub mod engine;
42pub mod error;
43pub mod loader;
44pub mod model;
45pub mod pattern;
46
47pub use engine::{Binding, CompiledRule, RuleMatch, Span};
48pub use error::RulesError;
49pub use loader::{load_rule_dir, load_rule_file};
50pub use model::{AtomicMatcher, Matcher, Rule, RuleKind, Severity};
51pub use pattern::{compile_pattern, CompiledPattern};