blockwatch-cli 0.14.0__tar.gz → 0.14.2__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.14.0 → blockwatch_cli-0.14.2}/.github/workflows/pypi.yml +2 -2
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/.github/workflows/rust.yml +8 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/.pre-commit-config.yaml +9 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/AGENTS.md +31 -20
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/CHANGELOG.md +50 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/CLAUDE.md +31 -20
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/Cargo.lock +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/Cargo.toml +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/PKG-INFO +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/README.md +6 -2
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/dist-workspace.toml +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/docs/ci.md +2 -2
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/docs/cli.md +106 -6
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/docs/validators/README.md +1 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/docs/validators/check-lua.md +4 -3
- blockwatch_cli-0.14.2/docs/validators/line-count.md +48 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/setup.py +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/block_parser.rs +115 -111
- blockwatch_cli-0.14.2/src/blocks.rs +1208 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/cli.rs +134 -96
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/config.rs +51 -24
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/diff_parser.rs +135 -66
- blockwatch_cli-0.14.2/src/explain.rs +69 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/flags.rs +119 -26
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/fs.rs +53 -78
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/bash.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/c.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/c_sharp.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/cmake.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/cpp.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/css.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/dart.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/dockerfile.rs +10 -9
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/elixir.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/go.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/graphql.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/groovy.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/hcl.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/html.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/java.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/javascript.rs +1 -3
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/json.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/kotlin.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/lean.rs +4 -13
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/lua.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/makefile.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/markdown.rs +21 -17
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/mdx.rs +17 -26
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/mod.rs +134 -30
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/nix.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/ocaml.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/php.rs +9 -10
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/proto.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/python.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/ruby.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/rust.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/scala.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/sql.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/starlark.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/swift.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/toml.rs +7 -7
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/tsx.rs +1 -3
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/typescript.rs +2 -2
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/xml.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/yaml.rs +5 -7
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/lib.rs +90 -55
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/path_arguments.rs +5 -3
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/paths_glob.rs +2 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/repo_path.rs +11 -9
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/report.rs +65 -59
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/sarif.rs +49 -76
- blockwatch_cli-0.14.0/src/blocks.rs → blockwatch_cli-0.14.2/src/scan.rs +512 -1660
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/settings.rs +131 -104
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/skill.md +8 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/symbol_path.rs +3 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/symbols.rs +50 -12
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/tag_parser.rs +18 -28
- blockwatch_cli-0.14.2/src/target_reference.rs +408 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/validators/affects.rs +267 -229
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/validators/check_ai.rs +248 -147
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/validators/check_lua.rs +310 -211
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/validators/keep_sorted.rs +249 -153
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/validators/keep_unique.rs +176 -69
- blockwatch_cli-0.14.2/src/validators/line_count.rs +707 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/validators/line_pattern.rs +161 -73
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/validators/mod.rs +394 -667
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/validators/same_as.rs +580 -198
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/violation_address.rs +49 -36
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/virtual_blocks.rs +50 -45
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/affects.rs +2 -2
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/check_ai.rs +2 -2
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/check_lua.rs +4 -4
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/config.rs +1 -1
- blockwatch_cli-0.14.2/tests/explain.rs +221 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/keep_sorted.rs +4 -4
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/keep_unique.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/line_count.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/line_pattern.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/repository_root.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/same_as.rs +1 -1
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/suppressions.rs +14 -0
- blockwatch_cli-0.14.2/tests/testdata/explain/a.py +16 -0
- blockwatch_cli-0.14.2/tests/testdata/explain/check.lua +3 -0
- blockwatch_cli-0.14.0/docs/validators/line-count.md +0 -29
- blockwatch_cli-0.14.0/src/validators/line_count.rs +0 -441
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/.agents/.claude-plugin/plugin.json +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/.agents/skills/blockwatch/SKILL.md +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/.claude-plugin/marketplace.json +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/.github/dependabot.yml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/.github/workflows/blockwatch.yml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/.github/workflows/codeql.yml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/.github/workflows/markdownlint.yml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/.github/workflows/release.yml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/.github/workflows/trusted-checks.yml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/.gitignore +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/.markdownlint-cli2.yaml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/.pre-commit-hooks.yaml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/LICENSE +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/SECURITY.md +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/blockwatch.toml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/clippy.toml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/codecov.yml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/demo.gif +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/docs/agents.md +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/docs/symbols.md +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/docs/validators/affects.md +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/docs/validators/check-ai.md +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/docs/validators/keep-sorted.md +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/docs/validators/keep-unique.md +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/docs/validators/line-pattern.md +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/docs/validators/same-as.md +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/pypi/pyproject.toml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/pyproject.toml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/release.toml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/scripts/check_language_count.lua +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/scripts/check_latest_gpt_nano_model.lua +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/language_parsers/json.scm +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/src/main.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/common/empty.toml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/common/mod.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/encoding.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/general.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/list.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/path_arguments.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/sarif.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/skill.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/symbol_references.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/cross_file_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/cross_file_target.md +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/custom_ext_source.javascript +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/custom_ext_target.javascript +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/dangling.md +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/missing_symbol.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/more_added_than_deleted.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/multiline_tag_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/multiline_tag_target.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/nested_mapping_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/nested_mapping_target.yaml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/sibling.md +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/symbol_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/symbol_target.json +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/table_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/table_target.toml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/tag_and_content_source.ts +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/tag_and_content_target.ts +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/whole_file_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/affects/whole_file_target.json +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/check_ai/two_blocks.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/check_lua/affects.lua +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/check_lua/affects.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/check_lua/affects_drift.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/check_lua/blocking_io.lua +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/check_lua/blocking_io.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/check_lua/echo.lua +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/check_lua/fail.lua +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/check_lua/mode.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/check_lua/os.lua +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/check_lua/pathfmt/report_path.lua +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/check_lua/pathfmt/source.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/check_lua/pattern.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/check_lua/pattern_many_matches.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/check_lua/pattern_no_match.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/check_lua/success.lua +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/check_lua/success_and_failure.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/config/glob_target/config.toml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/config/glob_target/package.json +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/config/glob_target/plugins/blue/package.json +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/config/glob_target/plugins/green/package.json +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/config/glob_target/plugins/red/package.json +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/general/block_selection.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/general/custom_file_extension.javascript +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/general/custom_file_extension.python +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/general/disable_enable.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/general/paths/invalid.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/general/paths/subdir/nested_invalid.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/general/paths/valid.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/general/severity.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/hidden/.github/workflows/ci.yml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/keep_sorted/orderings.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/keep_unique/basic_and_pattern.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/line_count/equality_and_greater_than.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/line_pattern/forbidden_text.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/line_pattern/hex_and_word_patterns.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/list/.hg/.gitkeep +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/list/a.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/list/b.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/positions/unicode_columns.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/same_as/custom_ext_source.javascript +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/same_as/custom_ext_target.javascript +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/same_as/package.json +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/same_as/paths/alpha/item.txt +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/same_as/paths/beta/item.txt +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/same_as/paths_and_block_source.md +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/same_as/paths_source.md +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/same_as/sibling.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/same_as/source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/same_as/split_table_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/same_as/split_table_target.toml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/same_as/symbol_mismatch_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/same_as/symbol_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/same_as/target.md +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/same_as/whole_file_mismatch_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/same_as/whole_file_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/same_as/whole_file_target.json +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/sarif/advisory.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/sarif/clean.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/sarif/sorted.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/sarif/unnamed.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/suppressions/commit_msg.txt +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/suppressions/commit_msg_gone_a.txt +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/suppressions/commit_msg_gone_b.txt +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/suppressions/commit_msg_lowercase_trailer.txt +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/suppressions/commit_msg_malformed.txt +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/suppressions/commit_msg_with_noise.txt +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/suppressions/dangling.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/suppressions/sorted.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/suppressions/symbol.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/suppressions/symbol_target.json +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/suppressions/two_rules.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/suppressions/unnamed.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/escapes_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/escapes_target.json +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/filter_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/filter_target.yaml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/json_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/json_target.json +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/jsonc_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/jsonc_target.jsonc +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/markdown_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/markdown_target.markdown +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/md_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/md_target.md +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/mdx_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/mdx_target.mdx +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/mixed_list_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/mixed_list_target.json +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/toml_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/toml_target.toml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/yaml_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/yaml_target.yaml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/yml_source.rs +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/symbol_references/yml_target.yml +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/verbosity/affects/pair.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/verbosity/clean/counted.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/verbosity/clean/noop.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/verbosity/clean/notes.txt +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/verbosity/clean/sorted.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/verbosity/diff/two_blocks.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/verbosity/failing/unsorted.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/testdata/verbosity/mixed/both_kinds.py +0 -0
- {blockwatch_cli-0.14.0 → blockwatch_cli-0.14.2}/tests/verbosity.rs +0 -0
|
@@ -24,9 +24,9 @@ jobs:
|
|
|
24
24
|
target: x86_64-unknown-linux-gnu
|
|
25
25
|
- runner: ubuntu-24.04-arm
|
|
26
26
|
target: aarch64-unknown-linux-gnu
|
|
27
|
-
- runner: macos-
|
|
27
|
+
- runner: macos-15
|
|
28
28
|
target: aarch64-apple-darwin
|
|
29
|
-
- runner: macos-
|
|
29
|
+
- runner: macos-15
|
|
30
30
|
target: x86_64-apple-darwin
|
|
31
31
|
- runner: windows-latest
|
|
32
32
|
target: x86_64-pc-windows-msvc
|
|
@@ -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
|
|
@@ -187,16 +193,19 @@ The whole pipeline is in `src/cli.rs`. `src/main.rs` only calls `blockwatch::run
|
|
|
187
193
|
report goes to stdout. The exit code depends on the error-severity violations that are not suppressed.
|
|
188
194
|
|
|
189
195
|
The `list` subcommand stops after step 6 and writes the blocks it found to stdout as JSON. The `skill` subcommand
|
|
190
|
-
prints `src/skill.md` right after step 1.
|
|
196
|
+
prints `src/skill.md` right after step 1. The `explain` subcommand runs like `--only-block` with the file of its
|
|
197
|
+
address as the only path. It then writes that block to stdout as JSON.
|
|
191
198
|
|
|
192
199
|
The main modules:
|
|
193
200
|
|
|
194
|
-
- `src/fs.rs` — the `FileSystem` and
|
|
195
|
-
|
|
201
|
+
- `src/fs.rs` — the `FileSystem` trait and its real implementation, and `PathFilter`, which decides whether a run
|
|
202
|
+
reads a path: it must match an allow glob and no ignore glob. Tests swap in `FakeFileSystem` from `fs::test_utils`.
|
|
203
|
+
They build a real `PathFilter` with `PathFilter::allow_all()`, `allow_only` or `with_ignored_paths`.
|
|
196
204
|
- `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
|
|
205
|
+
the validated and merged result. `RawSettings::parse` is the only place the rules for a setting live, so the flags
|
|
206
|
+
and the config file can't drift apart. It returns the parsed values, so nothing is parsed twice. Its errors quote the
|
|
207
|
+
bad value but don't show a line and column. Tracking where each value is written would cost more code than it saves
|
|
208
|
+
the reader.
|
|
200
209
|
- `src/config.rs` — reads the config file into a `RawSettings` and the virtual blocks, using `toml_edit`'s serde
|
|
201
210
|
support. Only the errors that `toml_edit` raises itself, such as an unknown key, show a line and column. An error
|
|
202
211
|
about a `[[block]]` entry shows the line of its header, which `serde_spanned` gives.
|
|
@@ -217,8 +226,9 @@ The main modules:
|
|
|
217
226
|
always the same map key.
|
|
218
227
|
- `src/language_parsers/` — one tree-sitter grammar for each language. Each language has a `parser()` that returns a
|
|
219
228
|
`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
|
-
|
|
229
|
+
blocks. `language_parsers()` in `language_parsers/mod.rs` returns `LanguageParsers`: the parser of each extension.
|
|
230
|
+
Its `parser_for` picks the parser of a file, using the settings' extension mappings too. **To add a language, add a
|
|
231
|
+
module here and register it in that function.**
|
|
222
232
|
|
|
223
233
|
Some languages also have symbols. Such a language has a `SymbolsParser`, which its `parser()` passes to
|
|
224
234
|
`.with_symbols(...)`:
|
|
@@ -241,12 +251,13 @@ The main modules:
|
|
|
241
251
|
a file with a syntax error, instead of resolving a path through tree-sitter's error recovery. It doesn't check the
|
|
242
252
|
query itself.
|
|
243
253
|
- `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
|
-
|
|
254
|
+
`line_count`, `line_pattern`, `same_as`). Each file exports a `detect` function. `Validator::detect` in
|
|
255
|
+
`validators/mod.rs` calls them from one `match`.
|
|
256
|
+
- `src/diff_parser.rs` — wraps `unidiff` to produce `LineChange`s, kept in `LineChanges` for a file and in
|
|
257
|
+
`DiffChanges` for the whole diff. `LineChanges::touches` decides whether they touch a range of the file, such as a
|
|
258
|
+
block's start tag or a symbol's definition. A block's content has its own check in `blocks.rs`, because a deletion
|
|
259
|
+
right where the content starts removes content. The results end up in `is_content_modified` and
|
|
260
|
+
`is_start_tag_modified` on `BlockWithContext`, which decide which blocks count as changed.
|
|
250
261
|
|
|
251
262
|
A block counts as changed only when its content or its start tag overlaps a `LineChange`. With
|
|
252
263
|
`--diff --only-changed`, only changed blocks are validated. With `--diff` alone, every block is validated, but rules
|
|
@@ -12,6 +12,56 @@ 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.2] - 2026-10-21
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- `line-count-pattern` makes `line-count` count only the lines that match the regex. For example,
|
|
20
|
+
`line-count="<=20" line-count-pattern='^"\w+",$'` skips comments and blank lines in a list. See
|
|
21
|
+
[`line-count`](docs/validators/line-count.md).
|
|
22
|
+
- `blockwatch explain FILE:BLOCK_NAME` checks one named block and prints it as JSON: its attributes, the text its
|
|
23
|
+
validators read and where that text is. For example: `blockwatch explain package.json:version`. The output also lists
|
|
24
|
+
the validators the block asks for but the settings turn off (`"disabled"`). Under `"checks"`, it shows what each
|
|
25
|
+
validator saw:
|
|
26
|
+
- `same-as`: each record the pattern matched, with its line, on both sides, and the reason of each mismatch.
|
|
27
|
+
- `keep-sorted` and `keep-unique`: the value each line gives, up to the first line out of order or repeated.
|
|
28
|
+
- `line-pattern`: what each pattern matched on each line, up to the first line that fails.
|
|
29
|
+
- `affects`: whether the block changed, and for each target, whether it changed or why it doesn't resolve.
|
|
30
|
+
- `line-count`: the value each line gives, how many lines count, and the rule they were checked against.
|
|
31
|
+
- `check-lua`: the `content` and `ctx.affects` the script got, and the message it returned.
|
|
32
|
+
- `check-ai`: the model, the prompt it was sent and its answer.
|
|
33
|
+
|
|
34
|
+
`"with_diff"` says whether `--diff` was given. Without it, no block counts as changed. Violations go to stderr, and
|
|
35
|
+
the exit code is the same as for a normal run. See [The `explain` Command](docs/cli.md#the-explain-command).
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- A message of `affects` or `same-as` about a whole-file target shows the path alone, without `file` in front. For
|
|
40
|
+
example: `Block a.py:b at line 1 is modified, but config.json is not`.
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
|
|
44
|
+
- A `check-lua` script got no `ctx.affects` entry for a block target that the run didn't check, such as with
|
|
45
|
+
`--only-block` or `--diff --only-changed`. Now `ctx.affects` holds the same targets in every run.
|
|
46
|
+
|
|
47
|
+
## [0.14.1] - 2026-10-17
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
|
|
51
|
+
- The error for a wrong `keep-sorted`, `keep-sorted-format`, `same-as-mode`, `same-as-format` or `BLOCKWATCH_LUA_MODE`
|
|
52
|
+
value now has one form, such as `invalid keep-sorted "up" (expected asc or desc)`. It lists the valid values.
|
|
53
|
+
`keep-sorted-format` did not list them before.
|
|
54
|
+
- `same-as-mode`, `same-as-format` and `BLOCKWATCH_LUA_MODE` ignore upper and lower case, so `Numeric` and `Safe` work
|
|
55
|
+
like `numeric` and `safe`. `keep-sorted` and `keep-sorted-format` already did.
|
|
56
|
+
- A message about a block of `keep-sorted`, `keep-unique`, `line-count`, `line-pattern`, `check-ai` or `check-lua` now
|
|
57
|
+
says `at line 3` where it said `defined at line 3`, as the messages of `affects` and `same-as` always did. For
|
|
58
|
+
example: `Block src/a.rs:limits at line 3 has an out-of-order line 5 (asc)`.
|
|
59
|
+
- Every error now starts with a lowercase letter and has no period at the end. Before, about 30 started with a capital
|
|
60
|
+
letter or ended with a period. For example: `failed to read file "a.py"`, `could not find the repository root
|
|
61
|
+
directory` and `malformed block tag at line 1, column 4. If this is not meant as a tag, put it in backticks`. An
|
|
62
|
+
error that gives advice in a second sentence keeps that sentence. An error that starts with a name, such as `API` or
|
|
63
|
+
`Lua`, keeps its capital letter.
|
|
64
|
+
|
|
15
65
|
## [0.14.0] - 2026-10-16
|
|
16
66
|
|
|
17
67
|
### 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
|
|
@@ -187,16 +193,19 @@ The whole pipeline is in `src/cli.rs`. `src/main.rs` only calls `blockwatch::run
|
|
|
187
193
|
report goes to stdout. The exit code depends on the error-severity violations that are not suppressed.
|
|
188
194
|
|
|
189
195
|
The `list` subcommand stops after step 6 and writes the blocks it found to stdout as JSON. The `skill` subcommand
|
|
190
|
-
prints `src/skill.md` right after step 1.
|
|
196
|
+
prints `src/skill.md` right after step 1. The `explain` subcommand runs like `--only-block` with the file of its
|
|
197
|
+
address as the only path. It then writes that block to stdout as JSON.
|
|
191
198
|
|
|
192
199
|
The main modules:
|
|
193
200
|
|
|
194
|
-
- `src/fs.rs` — the `FileSystem` and
|
|
195
|
-
|
|
201
|
+
- `src/fs.rs` — the `FileSystem` trait and its real implementation, and `PathFilter`, which decides whether a run
|
|
202
|
+
reads a path: it must match an allow glob and no ignore glob. Tests swap in `FakeFileSystem` from `fs::test_utils`.
|
|
203
|
+
They build a real `PathFilter` with `PathFilter::allow_all()`, `allow_only` or `with_ignored_paths`.
|
|
196
204
|
- `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
|
|
205
|
+
the validated and merged result. `RawSettings::parse` is the only place the rules for a setting live, so the flags
|
|
206
|
+
and the config file can't drift apart. It returns the parsed values, so nothing is parsed twice. Its errors quote the
|
|
207
|
+
bad value but don't show a line and column. Tracking where each value is written would cost more code than it saves
|
|
208
|
+
the reader.
|
|
200
209
|
- `src/config.rs` — reads the config file into a `RawSettings` and the virtual blocks, using `toml_edit`'s serde
|
|
201
210
|
support. Only the errors that `toml_edit` raises itself, such as an unknown key, show a line and column. An error
|
|
202
211
|
about a `[[block]]` entry shows the line of its header, which `serde_spanned` gives.
|
|
@@ -217,8 +226,9 @@ The main modules:
|
|
|
217
226
|
always the same map key.
|
|
218
227
|
- `src/language_parsers/` — one tree-sitter grammar for each language. Each language has a `parser()` that returns a
|
|
219
228
|
`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
|
-
|
|
229
|
+
blocks. `language_parsers()` in `language_parsers/mod.rs` returns `LanguageParsers`: the parser of each extension.
|
|
230
|
+
Its `parser_for` picks the parser of a file, using the settings' extension mappings too. **To add a language, add a
|
|
231
|
+
module here and register it in that function.**
|
|
222
232
|
|
|
223
233
|
Some languages also have symbols. Such a language has a `SymbolsParser`, which its `parser()` passes to
|
|
224
234
|
`.with_symbols(...)`:
|
|
@@ -241,12 +251,13 @@ The main modules:
|
|
|
241
251
|
a file with a syntax error, instead of resolving a path through tree-sitter's error recovery. It doesn't check the
|
|
242
252
|
query itself.
|
|
243
253
|
- `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
|
-
|
|
254
|
+
`line_count`, `line_pattern`, `same_as`). Each file exports a `detect` function. `Validator::detect` in
|
|
255
|
+
`validators/mod.rs` calls them from one `match`.
|
|
256
|
+
- `src/diff_parser.rs` — wraps `unidiff` to produce `LineChange`s, kept in `LineChanges` for a file and in
|
|
257
|
+
`DiffChanges` for the whole diff. `LineChanges::touches` decides whether they touch a range of the file, such as a
|
|
258
|
+
block's start tag or a symbol's definition. A block's content has its own check in `blocks.rs`, because a deletion
|
|
259
|
+
right where the content starts removes content. The results end up in `is_content_modified` and
|
|
260
|
+
`is_start_tag_modified` on `BlockWithContext`, which decide which blocks count as changed.
|
|
250
261
|
|
|
251
262
|
A block counts as changed only when its content or its start tag overlaps a `LineChange`. With
|
|
252
263
|
`--diff --only-changed`, only changed blocks are validated. With `--diff` alone, every block is validated, but rules
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: blockwatch-cli
|
|
3
|
-
Version: 0.14.
|
|
3
|
+
Version: 0.14.2
|
|
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 |
|
|
@@ -103,7 +104,7 @@ you'd otherwise have to nitpick in code review.
|
|
|
103
104
|
| [`keep-sorted`](docs/validators/keep-sorted.md) | Enforces alphabetical or numerical ordering on list items | `keep-sorted`, `keep-sorted-pattern`, `keep-sorted-format` |
|
|
104
105
|
| [`keep-unique`](docs/validators/keep-unique.md) | Prevents duplicate lines within a block | `keep-unique` |
|
|
105
106
|
| [`line-pattern`](docs/validators/line-pattern.md) | Enforces that every line matches a regex, or that no line matches a forbidden one | `line-pattern`, `line-pattern-forbidden` |
|
|
106
|
-
| [`line-count`](docs/validators/line-count.md) | Enforces lower or upper bounds on the number of lines in a block | `line-count`
|
|
107
|
+
| [`line-count`](docs/validators/line-count.md) | Enforces lower or upper bounds on the number of lines in a block | `line-count`, `line-count-pattern` |
|
|
107
108
|
| [`check-ai`](docs/validators/check-ai.md) | Validates content against natural language rules using an LLM | `check-ai`, `check-ai-pattern` |
|
|
108
109
|
| [`check-lua`](docs/validators/check-lua.md) | Runs custom validation logic written in Lua | `check-lua`, `check-lua-pattern`, `check-lua-timeout` |
|
|
109
110
|
|
|
@@ -172,6 +173,9 @@ git diff --patch HEAD | blockwatch --diff --only-changed
|
|
|
172
173
|
|
|
173
174
|
# Dump all discovered blocks as JSON
|
|
174
175
|
blockwatch list
|
|
176
|
+
|
|
177
|
+
# Show what each validator of one named block read
|
|
178
|
+
blockwatch explain src/lib.rs:languages
|
|
175
179
|
```
|
|
176
180
|
|
|
177
181
|
Rules live in comments, next to the code they describe. Settings that apply to the whole project, such as ignored
|
|
@@ -214,7 +218,7 @@ exclusions, and custom extension mappings.
|
|
|
214
218
|
|
|
215
219
|
```yaml
|
|
216
220
|
- repo: https://github.com/mennanov/blockwatch
|
|
217
|
-
rev: v0.14.
|
|
221
|
+
rev: v0.14.2 # Use latest release
|
|
218
222
|
hooks:
|
|
219
223
|
- id: blockwatch
|
|
220
224
|
```
|
|
@@ -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.14.
|
|
22
|
+
rev: v0.14.2 # 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.14.
|
|
62
|
+
rev: v0.14.2 # Use latest release
|
|
63
63
|
hooks:
|
|
64
64
|
- id: blockwatch-commit-msg
|
|
65
65
|
```
|
|
@@ -14,6 +14,8 @@ For command-line flag documentation directly in your terminal, run `blockwatch -
|
|
|
14
14
|
every block in the repository.
|
|
15
15
|
- **List Blocks**: `blockwatch list` outputs a JSON report of all discovered blocks. It takes `--diff`,
|
|
16
16
|
`--only-changed`, `--config`, `-E` and `--ignore`.
|
|
17
|
+
- **Explain a Block**: `blockwatch explain FILE:BLOCK_NAME` checks one named block and prints what each of its
|
|
18
|
+
validators read, as JSON. See [The `explain` Command](#the-explain-command).
|
|
17
19
|
- **Print the Agent Skill**: `blockwatch skill` prints the [skill for AI agents](#the-skill-command), as a `SKILL.md`
|
|
18
20
|
- **Config File**: `blockwatch --config FILE` reads the project's settings from FILE instead of `blockwatch.toml`
|
|
19
21
|
- **Custom Extensions**: Map custom file extensions: `blockwatch -E ino=cpp` (config key: `extensions`)
|
|
@@ -172,7 +174,7 @@ describe the input rather than the command that produced it, since a diff need n
|
|
|
172
174
|
|
|
173
175
|
```console
|
|
174
176
|
$ git diff --no-prefix | blockwatch --diff
|
|
175
|
-
Error: diff target "rules.py" has no recognized path prefix (a/, b/, i/, w/, c/, o/)
|
|
177
|
+
Error: diff target "rules.py" has no recognized path prefix (a/, b/, i/, w/, c/, o/)
|
|
176
178
|
```
|
|
177
179
|
|
|
178
180
|
With Git, that means `--no-prefix`, `diff.noprefix`, or a custom `diff.srcPrefix` / `diff.dstPrefix`. To produce
|
|
@@ -555,15 +557,15 @@ Nothing else about the run changes: the same violations are found, and the exit
|
|
|
555
557
|
"tool": {
|
|
556
558
|
"driver": {
|
|
557
559
|
"name": "blockwatch",
|
|
558
|
-
"version": "0.14.
|
|
559
|
-
"semanticVersion": "0.14.
|
|
560
|
+
"version": "0.14.2",
|
|
561
|
+
"semanticVersion": "0.14.2",
|
|
560
562
|
"informationUri": "https://github.com/mennanov/blockwatch",
|
|
561
563
|
"rules": [
|
|
562
564
|
{
|
|
563
565
|
"id": "keep-sorted",
|
|
564
566
|
"name": "keep-sorted",
|
|
565
567
|
"shortDescription": { "text": "Requires the lines of a block to stay in order." },
|
|
566
|
-
"helpUri": "https://github.com/mennanov/blockwatch/blob/v0.14.
|
|
568
|
+
"helpUri": "https://github.com/mennanov/blockwatch/blob/v0.14.2/docs/validators/keep-sorted.md"
|
|
567
569
|
}
|
|
568
570
|
]
|
|
569
571
|
}
|
|
@@ -574,7 +576,7 @@ Nothing else about the run changes: the same violations are found, and the exit
|
|
|
574
576
|
"ruleId": "keep-sorted",
|
|
575
577
|
"ruleIndex": 0,
|
|
576
578
|
"level": "error",
|
|
577
|
-
"message": { "text": "Block fruits.py:fruits
|
|
579
|
+
"message": { "text": "Block fruits.py:fruits at line 2 has an out-of-order line 4 (asc)" },
|
|
578
580
|
"locations": [
|
|
579
581
|
{
|
|
580
582
|
"physicalLocation": {
|
|
@@ -617,7 +619,7 @@ What to expect from the log:
|
|
|
617
619
|
- **Lines and columns are 1-based, with an exclusive end column.** A column counts characters, which the run declares as
|
|
618
620
|
`"columnKind": "unicodeCodePoints"` so that a consumer does not count UTF-16 code units instead.
|
|
619
621
|
|
|
620
|
-
`--format` cannot be combined with the `list`
|
|
622
|
+
`--format` cannot be combined with the `list` and `explain` subcommands, which write JSON of their own. To upload a log
|
|
621
623
|
to GitHub code scanning, see [CI Integration](ci.md#github-code-scanning).
|
|
622
624
|
|
|
623
625
|
## The `list` Command
|
|
@@ -701,6 +703,104 @@ block's attributes are sorted by name; the files themselves are not ordered, and
|
|
|
701
703
|
emit them differently. Sort by key downstream if you need to diff one run against another — or use
|
|
702
704
|
[`--verbosity full`](#full-reports), which does order its files.
|
|
703
705
|
|
|
706
|
+
## The `explain` Command
|
|
707
|
+
|
|
708
|
+
`blockwatch explain FILE:BLOCK_NAME` checks one named block and prints what each of its validators read, as JSON. Run it
|
|
709
|
+
after you write a rule, to see that the rule matches what you meant. A rule can be wrong and still pass. For example, a
|
|
710
|
+
`same-as-pattern` can take the same wrong part of each line on both sides.
|
|
711
|
+
|
|
712
|
+
```shell
|
|
713
|
+
blockwatch explain src/colors.py:colors
|
|
714
|
+
blockwatch explain package.json:version # a block from blockwatch.toml
|
|
715
|
+
git diff --patch | blockwatch explain --diff src/colors.py:colors # affects needs the diff
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
- It takes one address, as `--only-block` does. A block without a `name` can't be explained, so give it one first.
|
|
719
|
+
- It takes `--diff`, `--config`, `-E` and `--ignore`, and rejects the other flags.
|
|
720
|
+
- `only-blocks` and `skip-blocks` in `blockwatch.toml` play no part, because the address already picks the block.
|
|
721
|
+
`enable` and `disable` still apply.
|
|
722
|
+
- The explanation goes to stdout. Violations go to stderr, and the [exit code](#exit-codes) is the one a normal run
|
|
723
|
+
gives. `check-ai` calls the API, as in a normal run.
|
|
724
|
+
|
|
725
|
+
### Explain Output Example
|
|
726
|
+
|
|
727
|
+
For this block:
|
|
728
|
+
|
|
729
|
+
```python
|
|
730
|
+
COLORS = [
|
|
731
|
+
# <block name="colors" keep-sorted="asc" keep-sorted-pattern='"(?P<value>\w+)"'>
|
|
732
|
+
"blue",
|
|
733
|
+
"red",
|
|
734
|
+
# </block>
|
|
735
|
+
]
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
`blockwatch explain src/colors.py:colors` prints:
|
|
739
|
+
|
|
740
|
+
[//]: # (<block name="explain-output-example">)
|
|
741
|
+
|
|
742
|
+
```json
|
|
743
|
+
{
|
|
744
|
+
"block": {
|
|
745
|
+
"attributes": {
|
|
746
|
+
"keep-sorted": "asc",
|
|
747
|
+
"keep-sorted-pattern": "\"(?P<value>\\w+)\"",
|
|
748
|
+
"name": "colors"
|
|
749
|
+
},
|
|
750
|
+
"column": 7,
|
|
751
|
+
"is_content_modified": false,
|
|
752
|
+
"line": 2,
|
|
753
|
+
"name": "colors"
|
|
754
|
+
},
|
|
755
|
+
"checks": {
|
|
756
|
+
"keep-sorted": {
|
|
757
|
+
"format": "lexicographic",
|
|
758
|
+
"lines": [
|
|
759
|
+
{ "line": 3, "text": "\"blue\",", "value": "blue" },
|
|
760
|
+
{ "line": 4, "text": "\"red\",", "value": "red" }
|
|
761
|
+
],
|
|
762
|
+
"order": "asc"
|
|
763
|
+
}
|
|
764
|
+
},
|
|
765
|
+
"content": {
|
|
766
|
+
"start": { "line": 2, "character": 85 },
|
|
767
|
+
"end": { "line": 5, "character": 5 },
|
|
768
|
+
"text": "\n \"blue\",\n \"red\",\n "
|
|
769
|
+
},
|
|
770
|
+
"disabled": [],
|
|
771
|
+
"file": "src/colors.py",
|
|
772
|
+
"with_diff": false
|
|
773
|
+
}
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
[//]: # (</block>)
|
|
777
|
+
|
|
778
|
+
| Key | What it holds |
|
|
779
|
+
|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
780
|
+
| `block` | The block, as [`list`](#the-list-command) writes it. |
|
|
781
|
+
| `checks` | What each validator read, by validator. See [What Each Validator Shows](#what-each-validator-shows). |
|
|
782
|
+
| `content` | The text the validators read. `start` is its first character, and `end` is the first character after it. The column is `character`, as in the `range` of a violation. For a [virtual block](#blocks-in-the-config-file) around a quoted or escaped value, `text` is the decoded value. |
|
|
783
|
+
| `disabled` | The validators that the block asks for, but the settings turn off. They have no entry in `checks`. |
|
|
784
|
+
| `file` | The block's file. |
|
|
785
|
+
| `with_diff` | Whether `--diff` was given. Without it, no block counts as changed, so `affects` can't fire. |
|
|
786
|
+
|
|
787
|
+
### What Each Validator Shows
|
|
788
|
+
|
|
789
|
+
A trace stops where its validator stops, such as at the first line out of order. A `line` is a line of the block's
|
|
790
|
+
file, and `text` is that line trimmed, as the validator compares it. A key that holds what a violation reports has the
|
|
791
|
+
name the violation's `data` gives it, such as `reason`.
|
|
792
|
+
|
|
793
|
+
| Validator | What it shows |
|
|
794
|
+
|----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
795
|
+
| `same-as` | `records`: each match of `same-as-pattern` in the block, with its `line`, the text the regex matched (`match`), and each named group after `same-as-format` (`groups`). `targets`: the `records` of each target, and the `reason` of its violation, or `null` when the two agree. `paths`: with `same-as-paths`, the `glob`, the paths it `matched`, their `records` and the `reason`. |
|
|
796
|
+
| `keep-sorted` | `lines`: each line read, with the `value` it compares, or `null` when `keep-sorted-pattern` skips the line. `format` and `order`. |
|
|
797
|
+
| `keep-unique` | `lines`, as for `keep-sorted`. A repeated value has `duplicate_of`: the line where it first appeared. |
|
|
798
|
+
| `line-pattern` | `lines`: each line read, with the text `line-pattern` matched (`match`). A line that fails has `fails`: the check it fails. `forbidden_match` is the text `line-pattern-forbidden` found. |
|
|
799
|
+
| `line-count` | `lines`, as for `keep-sorted`. A line counts when its `value` isn't `null`. The number of lines counted (`actual`), and the rule (`op` and `expected`). |
|
|
800
|
+
| `affects` | Whether the diff changed the block (`block_changed`). For each target: whether the diff `changed` it, or the `reason` it doesn't resolve. |
|
|
801
|
+
| `check-lua` | The `content` and the `affects` the script got, and the message it returned (`lua_error`), or `null` when it passed. `affects` is `ctx.affects` without the content of each target. |
|
|
802
|
+
| `check-ai` | The `model`, the `prompt` sent and the `response`. Both are `null` when `check-ai-pattern` matched nothing, so no request was sent. |
|
|
803
|
+
|
|
704
804
|
## Run Reports
|
|
705
805
|
|
|
706
806
|
By default `blockwatch` prints nothing when a run succeeds. That makes a check that passed look exactly like a check
|
|
@@ -26,6 +26,7 @@ between two references is fine.
|
|
|
26
26
|
<!-- <block name="validators-index"
|
|
27
27
|
affects="src/skill.md#/blockwatch/Annotating a new project/Where blocks add value (catalog)"
|
|
28
28
|
same-as="src/validators/mod.rs:validator-registry, README.md:available-validators"
|
|
29
|
+
same-as-format="identifier"
|
|
29
30
|
same-as-pattern='\[`(?P<value>[a-z-]+)`\]\('> -->
|
|
30
31
|
|
|
31
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,
|