blockwatch

Crates.ioblockwatch
lib.rsblockwatch
version0.2.0
created_at2025-04-07 23:19:47.38736+00
updated_at2025-08-29 23:07:17.781504+00
descriptionLinter that tracks changes between dependent blocks of code
homepagehttps://github.com/mennanov/blockwatch
repositoryhttps://github.com/mennanov/blockwatch
max_upload_size
id1624797
size194,744
Renat (mennanov)

documentation

README

BlockWatch: Never Let Your Code and Docs Go Stale Again

Automatically spot inconsistencies in your documentation, configuration, and code whenever they change.

Build Status codecov Crates.io Downloads

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 dependency tracker for your codebase. You declare relationships between blocks of code, if a block changes, BlockWatch will require that its dependents are also updated, catching inconsistencies before they are committed.

It keeps your codebase consistent by making dependencies between code and documentation explicit and verifiable.

How It Works

It's a simple two-step process:

1. Declare your 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", creating a dependency link.

// src/parsers/mod.rs
// <block affects="README.md:supported-grammar-example">
pub(crate) fn language_parsers() -> anyhow::Result<HashMap<String, Rc<Box<dyn BlocksParser>>>> {
    Ok(HashMap::from([
        ("rs".into(), rust_parser),
        ("js".into(), Rc::clone(&js_parser)),
        ("go".into(), go_parser),
    ]))
}
// </block>

In README.md, we define the block that depends on the code above.

## Supported Languages

[//]: # (<block name="supported-grammar-example">)

- Rust
- JavaScript
- Go

[//]: # (</block>)

2. Run validation

When you make a change, BlockWatch checks the git diff. If you modify the SUPPORTED_LANGUAGES array in src/parsers/mod.rs without also modifying the block in README.md, BlockWatch will exit with an error, helping to prevent a bad commit.

# This command will now fail until README.md is updated
git diff --patch | blockwatch

This simple mechanism ensures your documentation and code never drift apart.


Key Features

  • 🔗 Link Code to Docs: Create explicit, verifiable dependencies between code snippets and your documentation.
  • 🤖 Automated Git Workflow: Integrates seamlessly with git diff to automatically validate changes before you commit.
  • 🛠️ Pre-commit & CI/CD Ready: Includes support for pre-commit hooks and a dedicated GitHub Action for robust CI/CD pipelines.
  • 🌍 Broad Language Support: Works with over 20 programming and markup languages out of the box.
  • Fast and Lightweight: Written in Rust for maximum performance 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: [ pre-commit ]
        pass_filenames: false

GitHub Action

Add the following job to your workflow file to check for inconsistencies in pull requests.

# .github/workflows/main.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)
  • Rust (.rs)
  • SQL (.sql)
  • 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

Advanced Patterns

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">
fn main() {
    println!("Blocks can affect multiple other blocks declared in the same file");
    println!("Just omit the file name in the 'affects' attribute");
}
// </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">
fn foo() {
    println!("Hi, Bob!");
}
// </block>

// <block name="bob" affects=":alice">
fn bar() {
    println!("Hi, Alice!");
}
// </block>

Nested Blocks

Blocks can be nested inside one another.

// <block name="entire-file">
fn foo() {
    println!("Hello");
}

// <block name="small-block">
fn bar() {
    println!("Hi!");
}
// </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
Commit count: 85

cargo fmt