Skip to main content

ailint_core/
lib.rs

1//! # ailint-core
2//!
3//! Core library for `ailint`: discovers AI agent guidance files, parses them,
4//! runs a configurable set of lint rules, and emits reports in multiple
5//! formats.
6//!
7//! Discovers guidance files via [`discovery`], parses them via [`parser`],
8//! runs rules registered in [`rules::registry`], and emits reports via
9//! [`reporter`].
10
11#![deny(rust_2018_idioms)]
12#![warn(missing_debug_implementations)]
13#![warn(missing_docs)]
14
15pub mod config;
16pub mod discovery;
17pub mod file_type;
18pub mod parser;
19pub mod reporter;
20pub mod rules;
21
22use std::path::{Path, PathBuf};
23
24use anyhow::Result;
25
26pub use crate::config::Config;
27pub use crate::file_type::FileType;
28pub use crate::reporter::{Reporter, ReporterKind};
29pub use crate::rules::{RuleId, Severity, Violation};
30
31/// A single discovered guidance file and its detected type.
32#[derive(Debug, Clone)]
33pub struct DiscoveredFile {
34    /// Location on disk.
35    pub path: PathBuf,
36    /// Detected guidance file type.
37    pub file_type: FileType,
38}
39
40/// Top-level entry point: discover files under `root`, run enabled rules, and
41/// return the aggregated violations.
42pub fn lint(root: &Path, config: &Config) -> Result<Vec<Violation>> {
43    let files = discovery::walk(root, config)?;
44    tracing::debug!(root = %root.display(), files = files.len(), "ailint::lint");
45    let mut docs = Vec::with_capacity(files.len());
46    for file in files {
47        docs.push(parser::parse(&file.path, file.file_type)?);
48    }
49    let mut violations = Vec::new();
50    for doc in &docs {
51        violations.extend(rules::registry::run_all(doc, config));
52    }
53    violations.extend(rules::registry::run_all_batch(&docs, config));
54    Ok(violations)
55}
56
57/// Version string embedded from Cargo.
58pub const VERSION: &str = env!("CARGO_PKG_VERSION");