BlockWatch: Smart language agnostic linter
- Keep your docs up to date with the code
- Enforce formatting rules (sorted lines)
- Ensure unique lines
- Validate each line against a regex pattern
- Enforce number of lines in a block
Why
Have you ever updated a function but forgotten to update the README.md example that uses it? Or changed a list of
supported items in your code but forgot to update the corresponding list in the documentation?
Keeping everything in sync manually is tedious and error-prone.
What
BlockWatch is a language agnostic lint tool that supports multiple types of checks:
- Code consistency: Track dependencies between code blocks - when one block changes, its dependents must be updated
- Sorted lines: Ensure that parts of your codebase stay properly sorted
- More validators are coming soon!
It keeps your codebase consistent by making dependencies and formatting requirements explicit and automatically verifiable.
How It Works
Blocks are declared in the source code comments: e.g. /* <block> */ in C-style languages).
Every block
Tracking Dependencies
Use the affects attribute to create relationships between blocks:
Mark a "source" block of code and give a name to a "dependent" block in another file (like your documentation).
In src/parsers/mod.rs, we define a list of languages. This block is marked as
affects="README.md:supported-grammar-example", creating a dependency link:
pub
In README.md, we define the block that depends on the code above:
- --
Maintaining Lines Order
Use the keep-sorted attribute to ensure content stays properly sorted:
const MONTHS: = ;
Ensuring Unique Lines
Use the keep-unique attribute to ensure there are no duplicate lines inside a block:
- --
Validating Line Patterns
Use the line-pattern attribute to ensure every line in the block matches a Regular Expression:
hello-world
rust-2025
blockwatch
# This command will now fail until README.md is updated
git diff --patch | blockwatch
Validating Block Line Count
Use the line-count attribute to ensure the total number of lines in a block meets a constraint:
- line-count="<50" — strictly less than 50 lines
- line-count=">=3" — at least 3 lines
- line-count="==10" — exactly 10 lines
- --
This simple mechanism ensures your documentation and code never drift apart.
Key Features
- 🔗 Dependency-aware blocks: declare named blocks and link them to keep code, docs, and configs in sync across files.
- 🔤 Sorted segments: enforce stable ordering to prevent drift in lists and indexes.
- 🤖 Git-native workflow: pipe git diff into blockwatch for instant, change-only validation before you commit.
- 🛠️ Pre-commit & CI/CD ready: first-class support for pre-commit hooks and a dedicated GitHub Action.
- 🌍 Broad language coverage: works with 20+ programming and markup languages out of the box.
- 🧩 Flexible extension mapping: map custom file extensions to supported grammars via a simple CLI flag.
- ⚡ Fast, single-binary tool: written in Rust with no runtime dependencies.
Installation
From Source
Requires the Rust toolchain:
cargo install blockwatch
Prebuilt Binary
Download a pre-built binary for your platform from the Releases page.
Usage & Integration
Command Line
The simplest way to run it is by piping a git diff into the command:
git diff --patch | blockwatch
Pre-commit Hook
For automatic checks before each commit, use it with the pre-commit framework.
Add this to your .pre-commit-config.yaml:
repos:
- repo: local
hooks:
- id: blockwatch
name: blockwatch
entry: bash -c 'git diff --patch --unified=0 | blockwatch'
language: system
stages:
pass_filenames: false
GitHub Action
Add to .github/workflows/your_workflow.yml:
#
jobs:
blockwatch:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 2 # Required to diff against the base branch
- uses: mennanov/blockwatch-action@v1
Supported Languages
BlockWatch supports a wide range of common languages.
- Bash (
.sh,.bash) - C# (
.cs) - C/C++ (
.c,.cpp,.cc,.h) - CSS (
.css) - Golang (
.go) - HTML (
.html,.htm) - Java (
.java) - JavaScript (
.js,.jsx) - Kotlin (
.kt,.kts) - Markdown (
.md,.markdown) - PHP (
.php,.phtml) - Python (
.py,.pyi) - Ruby (
.rb) - Rust (
.rs) - SQL (
.sql) - Swift (
.swift) - TOML (
.toml) - TypeScript (+TSX) (
.ts,.d.ts,.tsx) - XML (
.xml) - YAML (
.yaml,.yml)
Have a custom file extension?
You can map it to a supported grammar:
# Treat .xhtml files as .xml
git diff --patch | blockwatch -E xhtml=xml
Examples
Same-File Dependencies
Blocks can affect other blocks in the same file. Just omit the filename in the affects attribute.
// <block name="foo" affects=":bar, :buzz">
// </block>
// <block name="bar">
// Some other piece of code.
// </block>
// <block name="buzz">
// One more.
// </block>
Mutual Dependencies
Blocks can reference each other.
// <block name="alice" affects=":bob">
// </block>
// <block name="bob" affects=":alice">
// </block>
Nested Blocks
Blocks can be nested inside one another.
// <block name="entire-file">
// <block name="small-block">
// </block>
// </block>
Known Limitations
- Deleted blocks are currently ignored.
- Files with unsupported grammar are ignored.
- Multiple blocks cannot be declared on a single line:
<block><block>will not work</block></block>.
Contributing
Contributions are welcome! A good place to start is by adding support for a new grammar.
Run Tests
cargo test