normalize-syntax-rules 0.3.1

Syntax-based linting rules with tree-sitter queries
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
# normalize-syntax-rules/src

Source modules for the syntax rules crate.

- `lib.rs` — public API surface: re-exports `Rule`, `Severity`, `BuiltinRule`, and all key functions.
- `builtin/` — 95 embedded builtin `.scm` rule files compiled in via `include_str!` (14 Rust incl. `missing-module-doc`, 10 JS, 5 TS, 12 Python, 9 Go, 9 Ruby, 4 cross-language + 1 Rust-only `hardcoded-secret`).
- `loader.rs` — `load_all_rules()`, `parse_rule_content()`, `RulesConfig`, `RuleOverride`; merges rules from builtins, user global dir, and project dir. `RulesConfig` has `global_allow: Vec<String>` (applied to every rule) and `rules: HashMap<String, RuleOverride>` (per-rule overrides via `#[serde(flatten)]`). Parses the `files` frontmatter field (inclusion filter, complement of `allow`).
- `runner.rs` — `run_rules()`, `apply_fixes()`, `Finding`, `CachedFinding`, `DebugFlags`; executes rules against files using tree-sitter and handles per-line `normalize-syntax-allow:` suppression comments. Findings inside language-specific *test regions* are filtered out per-rule via `test_region_ranges()` (calls `GrammarLoader::get_test_regions()` to load a `{lang}.test_regions.scm` query and collects `@test_region` byte ranges). The runner is language-agnostic — what counts as a test region is defined entirely by the language's `.scm` file (Rust: inline `#[cfg(test)] mod ...`). Filtering is opt-out per rule via the `applies_in_tests` frontmatter field (default `false` = drop findings in test regions; `true` = keep them). Accepts a `PathFilter` parameter to skip non-matching files during `collect_source_files()` (pre-walk scoping for `--only`/`--exclude`). Accepts an optional `files: Option<&[PathBuf]>` parameter to bypass file walking entirely when an explicit file list is provided (e.g. from `--files` flag). Uses a SQLite-backed `FindingsCache` (private impl, stored at `.normalize/findings-cache.sqlite`) keyed by `(path, engine="syntax", mtime_nanos, config_hash=rules_hash)`; replaces the old JSON `SyntaxCache`/`FileCacheEntry`. Nanosecond mtime precision avoids false hits on fast writes (e.g. multi-pass fix application). Grammar loading uses `GrammarLoader::get()` which returns `Result<Option<Language>, GrammarLoadError>`; errors are discarded via `.ok().flatten()` for graceful skip.
- `query.rs` — `run_sexp_query()`, `run_astgrep_query()`, `is_sexp_pattern()`: dual query execution backends (tree-sitter native + ast-grep).
- `sources.rs` — `RuleSource` trait, `SourceRegistry`, `SourceContext`; built-in sources: `PathSource`, `EnvSource`, `GitSource`, `RustSource`, `GoSource`, `PythonSource`, `TypeScriptSource`. `GitSource` uses `gix` (pure-Rust) exclusively: branch via `head().referent_name()`, dirty via `repo.is_dirty()`, staged via index-vs-HEAD blob comparison.
- `main.rs` — binary entry point for the standalone `normalize-syntax-rules` CLI (gated behind `cli` feature)
- `service.rs` — `SyntaxRulesService` with `#[cli]` impl: `run` and `list` subcommands (gated behind `cli` feature)