blockwatch-cli 0.13.0__tar.gz → 0.14.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/.github/workflows/rust.yml +8 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/.pre-commit-config.yaml +9 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/AGENTS.md +33 -22
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/CHANGELOG.md +39 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/CLAUDE.md +33 -22
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/Cargo.lock +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/Cargo.toml +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/PKG-INFO +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/README.md +2 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/blockwatch.toml +4 -31
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/docs/ci.md +2 -2
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/docs/cli.md +5 -5
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/docs/validators/README.md +3 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/docs/validators/check-lua.md +4 -3
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/docs/validators/same-as.md +79 -16
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/setup.py +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/block_parser.rs +115 -111
- blockwatch_cli-0.14.1/src/blocks.rs +1185 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/cli.rs +87 -93
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/config.rs +51 -24
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/diff_parser.rs +135 -66
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/flags.rs +37 -27
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/fs.rs +53 -78
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/bash.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/c.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/c_sharp.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/cmake.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/cpp.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/css.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/dart.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/dockerfile.rs +10 -9
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/elixir.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/go.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/graphql.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/groovy.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/hcl.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/html.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/java.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/javascript.rs +1 -3
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/json.rs +2 -2
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/kotlin.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/lean.rs +4 -13
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/lua.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/makefile.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/markdown.rs +22 -18
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/mdx.rs +18 -27
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/mod.rs +134 -30
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/nix.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/ocaml.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/php.rs +9 -10
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/proto.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/python.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/ruby.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/rust.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/scala.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/sql.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/starlark.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/swift.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/toml.rs +8 -8
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/tsx.rs +1 -3
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/typescript.rs +2 -2
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/xml.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/yaml.rs +6 -8
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/lib.rs +89 -55
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/path_arguments.rs +5 -3
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/paths_glob.rs +2 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/repo_path.rs +11 -9
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/report.rs +65 -59
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/sarif.rs +49 -76
- blockwatch_cli-0.13.0/src/blocks.rs → blockwatch_cli-0.14.1/src/scan.rs +512 -1660
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/settings.rs +131 -104
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/skill.md +12 -28
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/symbol_path.rs +3 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/symbols.rs +9 -12
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/tag_parser.rs +18 -28
- blockwatch_cli-0.14.1/src/target_reference.rs +408 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/validators/affects.rs +79 -150
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/validators/check_ai.rs +47 -73
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/validators/check_lua.rs +64 -92
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/validators/keep_sorted.rs +124 -155
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/validators/keep_unique.rs +39 -71
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/validators/line_count.rs +33 -71
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/validators/line_pattern.rs +34 -71
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/validators/mod.rs +332 -665
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/validators/same_as.rs +712 -206
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/violation_address.rs +49 -36
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/virtual_blocks.rs +52 -38
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/check_ai.rs +2 -2
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/check_lua.rs +4 -4
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/config.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/keep_sorted.rs +4 -4
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/keep_unique.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/line_count.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/line_pattern.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/repository_root.rs +1 -1
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/suppressions.rs +14 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/.agents/.claude-plugin/plugin.json +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/.agents/skills/blockwatch/SKILL.md +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/.claude-plugin/marketplace.json +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/.github/dependabot.yml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/.github/workflows/blockwatch.yml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/.github/workflows/codeql.yml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/.github/workflows/markdownlint.yml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/.github/workflows/pypi.yml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/.github/workflows/release.yml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/.github/workflows/trusted-checks.yml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/.gitignore +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/.markdownlint-cli2.yaml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/.pre-commit-hooks.yaml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/LICENSE +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/SECURITY.md +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/clippy.toml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/codecov.yml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/demo.gif +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/dist-workspace.toml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/docs/agents.md +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/docs/symbols.md +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/docs/validators/affects.md +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/docs/validators/check-ai.md +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/docs/validators/keep-sorted.md +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/docs/validators/keep-unique.md +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/docs/validators/line-count.md +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/docs/validators/line-pattern.md +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/pypi/pyproject.toml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/pyproject.toml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/release.toml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/scripts/check_language_count.lua +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/scripts/check_latest_gpt_nano_model.lua +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/language_parsers/json.scm +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/src/main.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/affects.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/common/empty.toml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/common/mod.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/encoding.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/general.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/list.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/path_arguments.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/same_as.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/sarif.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/skill.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/symbol_references.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/cross_file_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/cross_file_target.md +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/custom_ext_source.javascript +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/custom_ext_target.javascript +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/dangling.md +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/missing_symbol.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/more_added_than_deleted.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/multiline_tag_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/multiline_tag_target.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/nested_mapping_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/nested_mapping_target.yaml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/sibling.md +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/symbol_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/symbol_target.json +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/table_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/table_target.toml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/tag_and_content_source.ts +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/tag_and_content_target.ts +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/whole_file_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/affects/whole_file_target.json +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/check_ai/two_blocks.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/check_lua/affects.lua +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/check_lua/affects.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/check_lua/affects_drift.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/check_lua/blocking_io.lua +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/check_lua/blocking_io.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/check_lua/echo.lua +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/check_lua/fail.lua +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/check_lua/mode.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/check_lua/os.lua +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/check_lua/pathfmt/report_path.lua +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/check_lua/pathfmt/source.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/check_lua/pattern.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/check_lua/pattern_many_matches.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/check_lua/pattern_no_match.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/check_lua/success.lua +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/check_lua/success_and_failure.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/config/glob_target/config.toml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/config/glob_target/package.json +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/config/glob_target/plugins/blue/package.json +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/config/glob_target/plugins/green/package.json +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/config/glob_target/plugins/red/package.json +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/general/block_selection.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/general/custom_file_extension.javascript +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/general/custom_file_extension.python +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/general/disable_enable.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/general/paths/invalid.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/general/paths/subdir/nested_invalid.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/general/paths/valid.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/general/severity.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/hidden/.github/workflows/ci.yml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/keep_sorted/orderings.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/keep_unique/basic_and_pattern.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/line_count/equality_and_greater_than.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/line_pattern/forbidden_text.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/line_pattern/hex_and_word_patterns.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/list/.hg/.gitkeep +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/list/a.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/list/b.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/positions/unicode_columns.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/same_as/custom_ext_source.javascript +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/same_as/custom_ext_target.javascript +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/same_as/package.json +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/same_as/paths/alpha/item.txt +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/same_as/paths/beta/item.txt +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/same_as/paths_and_block_source.md +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/same_as/paths_source.md +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/same_as/sibling.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/same_as/source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/same_as/split_table_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/same_as/split_table_target.toml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/same_as/symbol_mismatch_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/same_as/symbol_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/same_as/target.md +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/same_as/whole_file_mismatch_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/same_as/whole_file_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/same_as/whole_file_target.json +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/sarif/advisory.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/sarif/clean.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/sarif/sorted.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/sarif/unnamed.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/suppressions/commit_msg.txt +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/suppressions/commit_msg_gone_a.txt +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/suppressions/commit_msg_gone_b.txt +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/suppressions/commit_msg_lowercase_trailer.txt +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/suppressions/commit_msg_malformed.txt +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/suppressions/commit_msg_with_noise.txt +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/suppressions/dangling.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/suppressions/sorted.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/suppressions/symbol.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/suppressions/symbol_target.json +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/suppressions/two_rules.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/suppressions/unnamed.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/escapes_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/escapes_target.json +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/filter_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/filter_target.yaml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/json_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/json_target.json +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/jsonc_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/jsonc_target.jsonc +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/markdown_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/markdown_target.markdown +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/md_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/md_target.md +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/mdx_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/mdx_target.mdx +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/mixed_list_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/mixed_list_target.json +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/toml_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/toml_target.toml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/yaml_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/yaml_target.yaml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/yml_source.rs +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/symbol_references/yml_target.yml +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/verbosity/affects/pair.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/verbosity/clean/counted.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/verbosity/clean/noop.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/verbosity/clean/notes.txt +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/verbosity/clean/sorted.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/verbosity/diff/two_blocks.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/verbosity/failing/unsorted.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/testdata/verbosity/mixed/both_kinds.py +0 -0
- {blockwatch_cli-0.13.0 → blockwatch_cli-0.14.1}/tests/verbosity.rs +0 -0
|
@@ -33,6 +33,14 @@ jobs:
|
|
|
33
33
|
run: cargo fmt --check
|
|
34
34
|
- name: Run Clippy lint
|
|
35
35
|
run: cargo clippy --all-targets -- -D warnings
|
|
36
|
+
- name: Check the doc comments
|
|
37
|
+
# Nearly every item is private, so without the flag rustdoc would skip their docs.
|
|
38
|
+
run: cargo doc --no-deps --document-private-items
|
|
39
|
+
env:
|
|
40
|
+
RUSTDOCFLAGS: -D warnings
|
|
41
|
+
# `cargo llvm-cov` below does not run doctests.
|
|
42
|
+
- name: Run doctests
|
|
43
|
+
run: cargo test --doc
|
|
36
44
|
- name: Run tests
|
|
37
45
|
run: cargo llvm-cov --lcov --output-path coverage.lcov
|
|
38
46
|
- name: Upload coverage report to Codecov
|
|
@@ -34,6 +34,15 @@ repos:
|
|
|
34
34
|
types: [ rust ]
|
|
35
35
|
stages: [ pre-commit ]
|
|
36
36
|
pass_filenames: false
|
|
37
|
+
- id: cargo-doc
|
|
38
|
+
name: cargo doc
|
|
39
|
+
description: Check the doc comments with rustdoc, private items included.
|
|
40
|
+
# Nearly every item is private, so without the flag rustdoc would skip their docs.
|
|
41
|
+
entry: bash -c 'RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --document-private-items'
|
|
42
|
+
language: system
|
|
43
|
+
types: [ rust ]
|
|
44
|
+
stages: [ pre-commit ]
|
|
45
|
+
pass_filenames: false
|
|
37
46
|
|
|
38
47
|
# Rules and the set of files linted live in `.markdownlint-cli2.yaml`, which the tool picks up
|
|
39
48
|
# from the repository root. The hook passes only the staged Markdown files, so a commit is judged
|
|
@@ -15,6 +15,8 @@ only the lines changed in a unified diff piped into it.
|
|
|
15
15
|
cargo run -- list '<path or glob>' # print the blocks parsed from matching files, as JSON
|
|
16
16
|
cargo llvm-cov # run the tests and report coverage
|
|
17
17
|
cargo clippy --all-targets -- -D warnings # lint
|
|
18
|
+
cargo test --doc # run the examples in the doc comments (cargo llvm-cov skips them)
|
|
19
|
+
RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --document-private-items # check the doc comments
|
|
18
20
|
markdownlint-cli2 # lint Markdown (config: .markdownlint-cli2.yaml)
|
|
19
21
|
pre-commit run --all-files # run every hook the repository installs
|
|
20
22
|
```
|
|
@@ -105,6 +107,8 @@ The goal is a test suite that fails when behavior changes. Running every line is
|
|
|
105
107
|
- *Always* mutation-test a new test before you call the work done. For example, flip each comparison or boundary the
|
|
106
108
|
change touched, run the tests, check that one fails, then undo the flip. If the tests pass either way, they are too
|
|
107
109
|
weak.
|
|
110
|
+
- *Always* delete a scratch copy you made for mutation testing, with its own `target/` directory, as soon as the
|
|
111
|
+
mutation run ends. A `target/` directory takes gigabytes.
|
|
108
112
|
- *Always* run the tests with coverage as the last check before you call the work done.
|
|
109
113
|
- *Prefer* to read a coverage report (`cargo llvm-cov`) as a list of questions, not as a number to raise. An uncovered
|
|
110
114
|
branch asks why nobody needed it. The answer is either a case worth testing or code worth deleting. *Never* add a
|
|
@@ -151,12 +155,14 @@ The whole pipeline is in `src/cli.rs`. `src/main.rs` only calls `blockwatch::run
|
|
|
151
155
|
|
|
152
156
|
1. Parse the command-line flags (`flags.rs`, built with clap). The flags that `list` also takes are `global`, so they
|
|
153
157
|
can go before or after `list`. The flags only validation uses are in `ValidationFlags`, so `list --help` doesn't
|
|
154
|
-
show them.
|
|
158
|
+
show them. `Args::validate` rejects them for `list` and `skill`. A validation run then reads the `--suppress-from`
|
|
159
|
+
files, once. Both happen before stdin or the config file is read, so a bad flag is reported first.
|
|
155
160
|
2. Find the repository root and build a `fs::FileSystemImpl` limited to it. Every file read goes through it, so a path
|
|
156
161
|
in a block attribute can't reach outside the repository.
|
|
157
162
|
3. Decide what the run works on. With `--diff`, a unified diff is read from stdin, and
|
|
158
|
-
`diff_parser::line_changes_from_diff` turns it into a `
|
|
159
|
-
limits the run to the files in that diff. Without `--diff`, stdin is never read and no block
|
|
163
|
+
`diff_parser::line_changes_from_diff` turns it into `DiffChanges`: a sorted `LineChanges` for each file.
|
|
164
|
+
`--only-changed` also limits the run to the files in that diff. Without `--diff`, stdin is never read and no block
|
|
165
|
+
counts as changed.
|
|
160
166
|
4. Resolve the run's settings. `config::read` reads `blockwatch.toml` from the repository root, or the file given by
|
|
161
167
|
`--config`. `Args::raw_settings` returns the settings given as flags. `settings::Settings::resolve` validates both
|
|
162
168
|
with the same rules and merges them: the ignore globs, the extension mappings and the validator selection.
|
|
@@ -175,9 +181,9 @@ The whole pipeline is in `src/cli.rs`. `src/main.rs` only calls `blockwatch::run
|
|
|
175
181
|
touches, even when the diff does not touch that file. The result is a `blocks::FileBlocks` for each file, kept in a
|
|
176
182
|
`validators::ValidationContext`. Each path or glob argument must select at least one parsed file, or the run
|
|
177
183
|
stops. Under `--only-changed`, an argument that selects no file in the diff is checked against a walk of the tree.
|
|
178
|
-
7. `validators::detect_validators`
|
|
179
|
-
|
|
180
|
-
|
|
184
|
+
7. `validators::detect_validators` asks `Validator::detect` about each block, once for each validator. It returns
|
|
185
|
+
either `ValidatorType::Sync` or `ValidatorType::Async`. Async validators, such as `check-ai`, run on Tokio. The Tokio
|
|
186
|
+
runtime only starts if at least one async validator is needed.
|
|
181
187
|
8. Validators produce `Violation`s, each with a `ViolationRange` and a `BlockSeverity` (error or warning). A symbol
|
|
182
188
|
reference such as `file#/path` is found with `symbols::resolve`. It searches the symbols that
|
|
183
189
|
`LanguageParser::parse_symbols` finds in the target file, once per file. A missing or ambiguous symbol is a
|
|
@@ -191,12 +197,14 @@ prints `src/skill.md` right after step 1.
|
|
|
191
197
|
|
|
192
198
|
The main modules:
|
|
193
199
|
|
|
194
|
-
- `src/fs.rs` — the `FileSystem` and
|
|
195
|
-
|
|
200
|
+
- `src/fs.rs` — the `FileSystem` trait and its real implementation, and `PathFilter`, which decides whether a run
|
|
201
|
+
reads a path: it must match an allow glob and no ignore glob. Tests swap in `FakeFileSystem` from `fs::test_utils`.
|
|
202
|
+
They build a real `PathFilter` with `PathFilter::allow_all()`, `allow_only` or `with_ignored_paths`.
|
|
196
203
|
- `src/settings.rs` — `RawSettings` holds the settings read from one place: the config file or the flags. `Settings` is
|
|
197
|
-
the validated and merged result. `RawSettings::
|
|
198
|
-
|
|
199
|
-
Tracking where each value is written would cost more code than it saves
|
|
204
|
+
the validated and merged result. `RawSettings::parse` is the only place the rules for a setting live, so the flags
|
|
205
|
+
and the config file can't drift apart. It returns the parsed values, so nothing is parsed twice. Its errors quote the
|
|
206
|
+
bad value but don't show a line and column. Tracking where each value is written would cost more code than it saves
|
|
207
|
+
the reader.
|
|
200
208
|
- `src/config.rs` — reads the config file into a `RawSettings` and the virtual blocks, using `toml_edit`'s serde
|
|
201
209
|
support. Only the errors that `toml_edit` raises itself, such as an unknown key, show a line and column. An error
|
|
202
210
|
about a `[[block]]` entry shows the line of its header, which `serde_spanned` gives.
|
|
@@ -217,8 +225,9 @@ The main modules:
|
|
|
217
225
|
always the same map key.
|
|
218
226
|
- `src/language_parsers/` — one tree-sitter grammar for each language. Each language has a `parser()` that returns a
|
|
219
227
|
`LanguageParser`, which knows which syntax nodes are comments. `src/block_parser.rs` turns those comments into
|
|
220
|
-
blocks. `language_parsers()` in `language_parsers/mod.rs` returns the
|
|
221
|
-
|
|
228
|
+
blocks. `language_parsers()` in `language_parsers/mod.rs` returns `LanguageParsers`: the parser of each extension.
|
|
229
|
+
Its `parser_for` picks the parser of a file, using the settings' extension mappings too. **To add a language, add a
|
|
230
|
+
module here and register it in that function.**
|
|
222
231
|
|
|
223
232
|
Some languages also have symbols. Such a language has a `SymbolsParser`, which its `parser()` passes to
|
|
224
233
|
`.with_symbols(...)`:
|
|
@@ -241,12 +250,13 @@ The main modules:
|
|
|
241
250
|
a file with a syntax error, instead of resolving a path through tree-sitter's error recovery. It doesn't check the
|
|
242
251
|
query itself.
|
|
243
252
|
- `src/validators/` — one file for each validator (`affects`, `check_ai`, `check_lua`, `keep_sorted`, `keep_unique`,
|
|
244
|
-
`line_count`, `line_pattern`, `same_as`). Each file exports a
|
|
245
|
-
|
|
246
|
-
- `src/diff_parser.rs` — wraps `unidiff` to produce `LineChange`s
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
253
|
+
`line_count`, `line_pattern`, `same_as`). Each file exports a `detect` function. `Validator::detect` in
|
|
254
|
+
`validators/mod.rs` calls them from one `match`.
|
|
255
|
+
- `src/diff_parser.rs` — wraps `unidiff` to produce `LineChange`s, kept in `LineChanges` for a file and in
|
|
256
|
+
`DiffChanges` for the whole diff. `LineChanges::touches` decides whether they touch a range of the file, such as a
|
|
257
|
+
block's start tag or a symbol's definition. A block's content has its own check in `blocks.rs`, because a deletion
|
|
258
|
+
right where the content starts removes content. The results end up in `is_content_modified` and
|
|
259
|
+
`is_start_tag_modified` on `BlockWithContext`, which decide which blocks count as changed.
|
|
250
260
|
|
|
251
261
|
A block counts as changed only when its content or its start tag overlaps a `LineChange`. With
|
|
252
262
|
`--diff --only-changed`, only changed blocks are validated. With `--diff` alone, every block is validated, but rules
|
|
@@ -276,9 +286,10 @@ They are not instructions for working on blockwatch, and changing them changes w
|
|
|
276
286
|
guidance for working on blockwatch.
|
|
277
287
|
|
|
278
288
|
`src/skill.md` must not hold block tags. A project that saves the skill parses it too, so each tag would become a block
|
|
279
|
-
in that project. To point a block at a section of the skill,
|
|
280
|
-
|
|
281
|
-
|
|
289
|
+
in that project. To point a block at a section of the skill, use the section's headings, such as
|
|
290
|
+
`src/skill.md#/blockwatch/Symbols/JSON`. To point at only a part of a section, give that part a heading of its own.
|
|
291
|
+
When the section needs a rule of its own, such as a `same-as-pattern`, add a `[[block]]` entry for it to
|
|
292
|
+
`blockwatch.toml`, next to the others for `src/skill.md`.
|
|
282
293
|
|
|
283
294
|
Each agent's local config directory is left out of git on purpose: `.claude/`, `.cursor/`, `.gemini/`, `.windsurf/`,
|
|
284
295
|
`.aider*`, and the others listed in `.gitignore`. Don't commit agent-specific settings. Anything a future contributor
|
|
@@ -12,6 +12,45 @@ Releases up to and including v0.3.11 predate this file. Their notes live on the
|
|
|
12
12
|
|
|
13
13
|
## [Unreleased] - ReleaseDate
|
|
14
14
|
|
|
15
|
+
## [0.14.1] - 2026-10-17
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- The error for a wrong `keep-sorted`, `keep-sorted-format`, `same-as-mode`, `same-as-format` or `BLOCKWATCH_LUA_MODE`
|
|
20
|
+
value now has one form, such as `invalid keep-sorted "up" (expected asc or desc)`. It lists the valid values.
|
|
21
|
+
`keep-sorted-format` did not list them before.
|
|
22
|
+
- `same-as-mode`, `same-as-format` and `BLOCKWATCH_LUA_MODE` ignore upper and lower case, so `Numeric` and `Safe` work
|
|
23
|
+
like `numeric` and `safe`. `keep-sorted` and `keep-sorted-format` already did.
|
|
24
|
+
- A message about a block of `keep-sorted`, `keep-unique`, `line-count`, `line-pattern`, `check-ai` or `check-lua` now
|
|
25
|
+
says `at line 3` where it said `defined at line 3`, as the messages of `affects` and `same-as` always did. For
|
|
26
|
+
example: `Block src/a.rs:limits at line 3 has an out-of-order line 5 (asc)`.
|
|
27
|
+
- Every error now starts with a lowercase letter and has no period at the end. Before, about 30 started with a capital
|
|
28
|
+
letter or ended with a period. For example: `failed to read file "a.py"`, `could not find the repository root
|
|
29
|
+
directory` and `malformed block tag at line 1, column 4. If this is not meant as a tag, put it in backticks`. An
|
|
30
|
+
error that gives advice in a second sentence keeps that sentence. An error that starts with a name, such as `API` or
|
|
31
|
+
`Lua`, keeps its capital letter.
|
|
32
|
+
|
|
33
|
+
## [0.14.0] - 2026-10-16
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- `same-as-pattern` can compare a key with its value. Every named group, such as `(?P<code>\d+)` and
|
|
38
|
+
`(?P<message>.+)`, takes part, and each match is one record. So a message that moves to another code fails, even
|
|
39
|
+
though the messages alone still agree. Both patterns need the same groups. Each group can have its own
|
|
40
|
+
`same-as-format`, such as `name:identifier,value:numeric`. See
|
|
41
|
+
[Compare several groups](docs/validators/same-as.md#compare-several-groups) and
|
|
42
|
+
[A format for each group](docs/validators/same-as.md#a-format-for-each-group)
|
|
43
|
+
([#99](https://github.com/mennanov/blockwatch/issues/99)).
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- A `same-as-pattern` with named groups other than `value` now compares them too. Before, only `value` counted, or the
|
|
48
|
+
whole match when the pattern had no `value` group. To keep comparing only `value`, change the other groups to
|
|
49
|
+
`(?:…)`.
|
|
50
|
+
- An error about the `same-as-mode`, `same-as-format` or `same-as-pattern` of a block with `same-as` or
|
|
51
|
+
`same-as-paths` now shows the block, such as `invalid same-as attributes on block src/config.rs:limits at line 3`.
|
|
52
|
+
Before, it showed only the bad value.
|
|
53
|
+
|
|
15
54
|
## [0.13.0] - 2026-10-15
|
|
16
55
|
|
|
17
56
|
### Added
|
|
@@ -15,6 +15,8 @@ only the lines changed in a unified diff piped into it.
|
|
|
15
15
|
cargo run -- list '<path or glob>' # print the blocks parsed from matching files, as JSON
|
|
16
16
|
cargo llvm-cov # run the tests and report coverage
|
|
17
17
|
cargo clippy --all-targets -- -D warnings # lint
|
|
18
|
+
cargo test --doc # run the examples in the doc comments (cargo llvm-cov skips them)
|
|
19
|
+
RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --document-private-items # check the doc comments
|
|
18
20
|
markdownlint-cli2 # lint Markdown (config: .markdownlint-cli2.yaml)
|
|
19
21
|
pre-commit run --all-files # run every hook the repository installs
|
|
20
22
|
```
|
|
@@ -105,6 +107,8 @@ The goal is a test suite that fails when behavior changes. Running every line is
|
|
|
105
107
|
- *Always* mutation-test a new test before you call the work done. For example, flip each comparison or boundary the
|
|
106
108
|
change touched, run the tests, check that one fails, then undo the flip. If the tests pass either way, they are too
|
|
107
109
|
weak.
|
|
110
|
+
- *Always* delete a scratch copy you made for mutation testing, with its own `target/` directory, as soon as the
|
|
111
|
+
mutation run ends. A `target/` directory takes gigabytes.
|
|
108
112
|
- *Always* run the tests with coverage as the last check before you call the work done.
|
|
109
113
|
- *Prefer* to read a coverage report (`cargo llvm-cov`) as a list of questions, not as a number to raise. An uncovered
|
|
110
114
|
branch asks why nobody needed it. The answer is either a case worth testing or code worth deleting. *Never* add a
|
|
@@ -151,12 +155,14 @@ The whole pipeline is in `src/cli.rs`. `src/main.rs` only calls `blockwatch::run
|
|
|
151
155
|
|
|
152
156
|
1. Parse the command-line flags (`flags.rs`, built with clap). The flags that `list` also takes are `global`, so they
|
|
153
157
|
can go before or after `list`. The flags only validation uses are in `ValidationFlags`, so `list --help` doesn't
|
|
154
|
-
show them.
|
|
158
|
+
show them. `Args::validate` rejects them for `list` and `skill`. A validation run then reads the `--suppress-from`
|
|
159
|
+
files, once. Both happen before stdin or the config file is read, so a bad flag is reported first.
|
|
155
160
|
2. Find the repository root and build a `fs::FileSystemImpl` limited to it. Every file read goes through it, so a path
|
|
156
161
|
in a block attribute can't reach outside the repository.
|
|
157
162
|
3. Decide what the run works on. With `--diff`, a unified diff is read from stdin, and
|
|
158
|
-
`diff_parser::line_changes_from_diff` turns it into a `
|
|
159
|
-
limits the run to the files in that diff. Without `--diff`, stdin is never read and no block
|
|
163
|
+
`diff_parser::line_changes_from_diff` turns it into `DiffChanges`: a sorted `LineChanges` for each file.
|
|
164
|
+
`--only-changed` also limits the run to the files in that diff. Without `--diff`, stdin is never read and no block
|
|
165
|
+
counts as changed.
|
|
160
166
|
4. Resolve the run's settings. `config::read` reads `blockwatch.toml` from the repository root, or the file given by
|
|
161
167
|
`--config`. `Args::raw_settings` returns the settings given as flags. `settings::Settings::resolve` validates both
|
|
162
168
|
with the same rules and merges them: the ignore globs, the extension mappings and the validator selection.
|
|
@@ -175,9 +181,9 @@ The whole pipeline is in `src/cli.rs`. `src/main.rs` only calls `blockwatch::run
|
|
|
175
181
|
touches, even when the diff does not touch that file. The result is a `blocks::FileBlocks` for each file, kept in a
|
|
176
182
|
`validators::ValidationContext`. Each path or glob argument must select at least one parsed file, or the run
|
|
177
183
|
stops. Under `--only-changed`, an argument that selects no file in the diff is checked against a walk of the tree.
|
|
178
|
-
7. `validators::detect_validators`
|
|
179
|
-
|
|
180
|
-
|
|
184
|
+
7. `validators::detect_validators` asks `Validator::detect` about each block, once for each validator. It returns
|
|
185
|
+
either `ValidatorType::Sync` or `ValidatorType::Async`. Async validators, such as `check-ai`, run on Tokio. The Tokio
|
|
186
|
+
runtime only starts if at least one async validator is needed.
|
|
181
187
|
8. Validators produce `Violation`s, each with a `ViolationRange` and a `BlockSeverity` (error or warning). A symbol
|
|
182
188
|
reference such as `file#/path` is found with `symbols::resolve`. It searches the symbols that
|
|
183
189
|
`LanguageParser::parse_symbols` finds in the target file, once per file. A missing or ambiguous symbol is a
|
|
@@ -191,12 +197,14 @@ prints `src/skill.md` right after step 1.
|
|
|
191
197
|
|
|
192
198
|
The main modules:
|
|
193
199
|
|
|
194
|
-
- `src/fs.rs` — the `FileSystem` and
|
|
195
|
-
|
|
200
|
+
- `src/fs.rs` — the `FileSystem` trait and its real implementation, and `PathFilter`, which decides whether a run
|
|
201
|
+
reads a path: it must match an allow glob and no ignore glob. Tests swap in `FakeFileSystem` from `fs::test_utils`.
|
|
202
|
+
They build a real `PathFilter` with `PathFilter::allow_all()`, `allow_only` or `with_ignored_paths`.
|
|
196
203
|
- `src/settings.rs` — `RawSettings` holds the settings read from one place: the config file or the flags. `Settings` is
|
|
197
|
-
the validated and merged result. `RawSettings::
|
|
198
|
-
|
|
199
|
-
Tracking where each value is written would cost more code than it saves
|
|
204
|
+
the validated and merged result. `RawSettings::parse` is the only place the rules for a setting live, so the flags
|
|
205
|
+
and the config file can't drift apart. It returns the parsed values, so nothing is parsed twice. Its errors quote the
|
|
206
|
+
bad value but don't show a line and column. Tracking where each value is written would cost more code than it saves
|
|
207
|
+
the reader.
|
|
200
208
|
- `src/config.rs` — reads the config file into a `RawSettings` and the virtual blocks, using `toml_edit`'s serde
|
|
201
209
|
support. Only the errors that `toml_edit` raises itself, such as an unknown key, show a line and column. An error
|
|
202
210
|
about a `[[block]]` entry shows the line of its header, which `serde_spanned` gives.
|
|
@@ -217,8 +225,9 @@ The main modules:
|
|
|
217
225
|
always the same map key.
|
|
218
226
|
- `src/language_parsers/` — one tree-sitter grammar for each language. Each language has a `parser()` that returns a
|
|
219
227
|
`LanguageParser`, which knows which syntax nodes are comments. `src/block_parser.rs` turns those comments into
|
|
220
|
-
blocks. `language_parsers()` in `language_parsers/mod.rs` returns the
|
|
221
|
-
|
|
228
|
+
blocks. `language_parsers()` in `language_parsers/mod.rs` returns `LanguageParsers`: the parser of each extension.
|
|
229
|
+
Its `parser_for` picks the parser of a file, using the settings' extension mappings too. **To add a language, add a
|
|
230
|
+
module here and register it in that function.**
|
|
222
231
|
|
|
223
232
|
Some languages also have symbols. Such a language has a `SymbolsParser`, which its `parser()` passes to
|
|
224
233
|
`.with_symbols(...)`:
|
|
@@ -241,12 +250,13 @@ The main modules:
|
|
|
241
250
|
a file with a syntax error, instead of resolving a path through tree-sitter's error recovery. It doesn't check the
|
|
242
251
|
query itself.
|
|
243
252
|
- `src/validators/` — one file for each validator (`affects`, `check_ai`, `check_lua`, `keep_sorted`, `keep_unique`,
|
|
244
|
-
`line_count`, `line_pattern`, `same_as`). Each file exports a
|
|
245
|
-
|
|
246
|
-
- `src/diff_parser.rs` — wraps `unidiff` to produce `LineChange`s
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
253
|
+
`line_count`, `line_pattern`, `same_as`). Each file exports a `detect` function. `Validator::detect` in
|
|
254
|
+
`validators/mod.rs` calls them from one `match`.
|
|
255
|
+
- `src/diff_parser.rs` — wraps `unidiff` to produce `LineChange`s, kept in `LineChanges` for a file and in
|
|
256
|
+
`DiffChanges` for the whole diff. `LineChanges::touches` decides whether they touch a range of the file, such as a
|
|
257
|
+
block's start tag or a symbol's definition. A block's content has its own check in `blocks.rs`, because a deletion
|
|
258
|
+
right where the content starts removes content. The results end up in `is_content_modified` and
|
|
259
|
+
`is_start_tag_modified` on `BlockWithContext`, which decide which blocks count as changed.
|
|
250
260
|
|
|
251
261
|
A block counts as changed only when its content or its start tag overlaps a `LineChange`. With
|
|
252
262
|
`--diff --only-changed`, only changed blocks are validated. With `--diff` alone, every block is validated, but rules
|
|
@@ -276,9 +286,10 @@ They are not instructions for working on blockwatch, and changing them changes w
|
|
|
276
286
|
guidance for working on blockwatch.
|
|
277
287
|
|
|
278
288
|
`src/skill.md` must not hold block tags. A project that saves the skill parses it too, so each tag would become a block
|
|
279
|
-
in that project. To point a block at a section of the skill,
|
|
280
|
-
|
|
281
|
-
|
|
289
|
+
in that project. To point a block at a section of the skill, use the section's headings, such as
|
|
290
|
+
`src/skill.md#/blockwatch/Symbols/JSON`. To point at only a part of a section, give that part a heading of its own.
|
|
291
|
+
When the section needs a rule of its own, such as a `same-as-pattern`, add a `[[block]]` entry for it to
|
|
292
|
+
`blockwatch.toml`, next to the others for `src/skill.md`.
|
|
282
293
|
|
|
283
294
|
Each agent's local config directory is left out of git on purpose: `.claude/`, `.cursor/`, `.gemini/`, `.windsurf/`,
|
|
284
295
|
`.aider*`, and the others listed in `.gitignore`. Don't commit agent-specific settings. Anything a future contributor
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: blockwatch-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.14.1
|
|
4
4
|
Summary: Language agnostic linter that keeps your code and documentation in sync and valid
|
|
5
5
|
Keywords: linter,sync,drift,comments,agents
|
|
6
6
|
Home-Page: https://github.com/mennanov/blockwatch
|
|
@@ -94,6 +94,7 @@ you'd otherwise have to nitpick in code review.
|
|
|
94
94
|
|
|
95
95
|
<!-- <block name="available-validators"
|
|
96
96
|
same-as="src/validators/mod.rs:validator-registry, docs/validators/README.md:validators-index"
|
|
97
|
+
same-as-format="identifier"
|
|
97
98
|
same-as-pattern='^\|\s*\[`(?P<value>[a-z-]+)`\]'> -->
|
|
98
99
|
|
|
99
100
|
| Validator | Description | Attributes |
|
|
@@ -214,7 +215,7 @@ exclusions, and custom extension mappings.
|
|
|
214
215
|
|
|
215
216
|
```yaml
|
|
216
217
|
- repo: https://github.com/mennanov/blockwatch
|
|
217
|
-
rev: v0.
|
|
218
|
+
rev: v0.14.1 # Use latest release
|
|
218
219
|
hooks:
|
|
219
220
|
- id: blockwatch
|
|
220
221
|
```
|
|
@@ -40,41 +40,14 @@ same-as = '''.github/workflows/codeql.yml,
|
|
|
40
40
|
same-as-pattern = '(?:actions/checkout@|^)(?P<value>v\d+)$'
|
|
41
41
|
|
|
42
42
|
# `blockwatch skill` prints src/skill.md, and projects save that output. A tag in that file would become a block in
|
|
43
|
-
# every one of those projects. So
|
|
44
|
-
#
|
|
43
|
+
# every one of those projects. So blocks point at its sections by their headings, and these entries hold the pattern
|
|
44
|
+
# that reads a section, which the section can't hold itself.
|
|
45
45
|
[[block]]
|
|
46
|
-
target = 'src/skill.md'
|
|
47
|
-
target-pattern = '(?s)<!-- validator-catalog -->.*<!-- /validator-catalog -->'
|
|
48
|
-
name = 'validator-catalog'
|
|
49
|
-
|
|
50
|
-
[[block]]
|
|
51
|
-
target = 'src/skill.md'
|
|
52
|
-
target-pattern = '(?s)<!-- validator-reference -->.*<!-- /validator-reference -->'
|
|
46
|
+
target = 'src/skill.md#/blockwatch/Validator reference'
|
|
53
47
|
name = 'validator-reference'
|
|
54
48
|
same-as-pattern = '^\|\s*`(?P<value>[a-z-]+)`'
|
|
55
49
|
|
|
56
50
|
[[block]]
|
|
57
|
-
target = 'src/skill.md'
|
|
58
|
-
target-pattern = '(?s)<!-- extensions-with-symbols -->.*<!-- /extensions-with-symbols -->'
|
|
51
|
+
target = 'src/skill.md#/blockwatch/Symbols/Files with symbols'
|
|
59
52
|
name = 'extensions-with-symbols'
|
|
60
53
|
same-as-pattern = '`\.?(?P<value>[A-Za-z]+)`'
|
|
61
|
-
|
|
62
|
-
[[block]]
|
|
63
|
-
target = 'src/skill.md'
|
|
64
|
-
target-pattern = '(?s)<!-- json-paths -->.*<!-- /json-paths -->'
|
|
65
|
-
name = 'json-paths'
|
|
66
|
-
|
|
67
|
-
[[block]]
|
|
68
|
-
target = 'src/skill.md'
|
|
69
|
-
target-pattern = '(?s)<!-- toml-paths -->.*<!-- /toml-paths -->'
|
|
70
|
-
name = 'toml-paths'
|
|
71
|
-
|
|
72
|
-
[[block]]
|
|
73
|
-
target = 'src/skill.md'
|
|
74
|
-
target-pattern = '(?s)<!-- yaml-paths -->.*<!-- /yaml-paths -->'
|
|
75
|
-
name = 'yaml-paths'
|
|
76
|
-
|
|
77
|
-
[[block]]
|
|
78
|
-
target = 'src/skill.md'
|
|
79
|
-
target-pattern = '(?s)<!-- markdown-paths -->.*<!-- /markdown-paths -->'
|
|
80
|
-
name = 'markdown-paths'
|
|
@@ -19,7 +19,7 @@ To use [pre-commit](https://pre-commit.com), add the hook to `.pre-commit-config
|
|
|
19
19
|
|
|
20
20
|
```yaml
|
|
21
21
|
- repo: https://github.com/mennanov/blockwatch
|
|
22
|
-
rev: v0.
|
|
22
|
+
rev: v0.14.1 # Use latest release
|
|
23
23
|
hooks:
|
|
24
24
|
- id: blockwatch
|
|
25
25
|
```
|
|
@@ -59,7 +59,7 @@ The `blockwatch` hook runs before the commit message exists, so it cannot see a
|
|
|
59
59
|
|
|
60
60
|
```yaml
|
|
61
61
|
- repo: https://github.com/mennanov/blockwatch
|
|
62
|
-
rev: v0.
|
|
62
|
+
rev: v0.14.1 # Use latest release
|
|
63
63
|
hooks:
|
|
64
64
|
- id: blockwatch-commit-msg
|
|
65
65
|
```
|
|
@@ -172,7 +172,7 @@ describe the input rather than the command that produced it, since a diff need n
|
|
|
172
172
|
|
|
173
173
|
```console
|
|
174
174
|
$ git diff --no-prefix | blockwatch --diff
|
|
175
|
-
Error: diff target "rules.py" has no recognized path prefix (a/, b/, i/, w/, c/, o/)
|
|
175
|
+
Error: diff target "rules.py" has no recognized path prefix (a/, b/, i/, w/, c/, o/)
|
|
176
176
|
```
|
|
177
177
|
|
|
178
178
|
With Git, that means `--no-prefix`, `diff.noprefix`, or a custom `diff.srcPrefix` / `diff.dstPrefix`. To produce
|
|
@@ -555,15 +555,15 @@ Nothing else about the run changes: the same violations are found, and the exit
|
|
|
555
555
|
"tool": {
|
|
556
556
|
"driver": {
|
|
557
557
|
"name": "blockwatch",
|
|
558
|
-
"version": "0.
|
|
559
|
-
"semanticVersion": "0.
|
|
558
|
+
"version": "0.14.1",
|
|
559
|
+
"semanticVersion": "0.14.1",
|
|
560
560
|
"informationUri": "https://github.com/mennanov/blockwatch",
|
|
561
561
|
"rules": [
|
|
562
562
|
{
|
|
563
563
|
"id": "keep-sorted",
|
|
564
564
|
"name": "keep-sorted",
|
|
565
565
|
"shortDescription": { "text": "Requires the lines of a block to stay in order." },
|
|
566
|
-
"helpUri": "https://github.com/mennanov/blockwatch/blob/v0.
|
|
566
|
+
"helpUri": "https://github.com/mennanov/blockwatch/blob/v0.14.1/docs/validators/keep-sorted.md"
|
|
567
567
|
}
|
|
568
568
|
]
|
|
569
569
|
}
|
|
@@ -574,7 +574,7 @@ Nothing else about the run changes: the same violations are found, and the exit
|
|
|
574
574
|
"ruleId": "keep-sorted",
|
|
575
575
|
"ruleIndex": 0,
|
|
576
576
|
"level": "error",
|
|
577
|
-
"message": { "text": "Block fruits.py:fruits
|
|
577
|
+
"message": { "text": "Block fruits.py:fruits at line 2 has an out-of-order line 4 (asc)" },
|
|
578
578
|
"locations": [
|
|
579
579
|
{
|
|
580
580
|
"physicalLocation": {
|
|
@@ -23,8 +23,10 @@ between two references is fine.
|
|
|
23
23
|
|
|
24
24
|
## Which validator do I want?
|
|
25
25
|
|
|
26
|
-
<!-- <block name="validators-index"
|
|
26
|
+
<!-- <block name="validators-index"
|
|
27
|
+
affects="src/skill.md#/blockwatch/Annotating a new project/Where blocks add value (catalog)"
|
|
27
28
|
same-as="src/validators/mod.rs:validator-registry, README.md:available-validators"
|
|
29
|
+
same-as-format="identifier"
|
|
28
30
|
same-as-pattern='\[`(?P<value>[a-z-]+)`\]\('> -->
|
|
29
31
|
|
|
30
32
|
| I want to... | Use |
|
|
@@ -158,7 +158,7 @@ end
|
|
|
158
158
|
```
|
|
159
159
|
|
|
160
160
|
<!-- <block name="lua-safety-modes" same-as="src/validators/check_lua.rs:lua-safety-modes"
|
|
161
|
-
same-as-pattern='^\|\s*`(?P<value>[a-z]+)`'> -->
|
|
161
|
+
same-as-format="identifier" same-as-pattern='^\|\s*`(?P<value>[a-z]+)`'> -->
|
|
162
162
|
|
|
163
163
|
## Safety modes
|
|
164
164
|
|
|
@@ -182,8 +182,9 @@ BLOCKWATCH_LUA_MODE=unsafe blockwatch
|
|
|
182
182
|
| `safe` | All memory-safe libraries (including `io`, `os`, `package`) | Memory-safe - Allows file/OS access |
|
|
183
183
|
| `unsafe` | All Lua standard libraries with no restrictions (including C modules) | Unsafe - Full system access |
|
|
184
184
|
|
|
185
|
-
An empty value means `sandboxed`, the same as an unset variable.
|
|
186
|
-
checks a `check-lua` block. The error lists the valid
|
|
185
|
+
An empty value means `sandboxed`, the same as an unset variable. Upper and lower case do not matter, so `Safe` works
|
|
186
|
+
like `safe`. Any other value, such as `sandbox`, stops a run that checks a `check-lua` block. The error lists the valid
|
|
187
|
+
values.
|
|
187
188
|
|
|
188
189
|
If a script uses a library that is not available in the selected mode, the run stops with a Lua error. The block is not
|
|
189
190
|
reported as a violation — the whole run fails. So a script that needs `io` or `os` will fail every `sandboxed` run,
|