blockwatch-cli 0.14.1__tar.gz → 0.15.0__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.1 → blockwatch_cli-0.15.0}/.github/workflows/pypi.yml +2 -2
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/.pre-commit-config.yaml +8 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/AGENTS.md +11 -9
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/CHANGELOG.md +51 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/CLAUDE.md +11 -9
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/Cargo.lock +1 -12
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/Cargo.toml +1 -2
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/PKG-INFO +1 -1
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/README.md +5 -2
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/dist-workspace.toml +1 -1
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/docs/ci.md +2 -2
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/docs/cli.md +104 -4
- blockwatch_cli-0.15.0/docs/validators/line-count.md +48 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/setup.py +1 -1
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/blocks.rs +23 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/cli.rs +49 -5
- blockwatch_cli-0.15.0/src/explain.rs +69 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/flags.rs +86 -3
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/markdown.rs +306 -154
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/mdx.rs +4 -13
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/lib.rs +1 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/skill.md +8 -1
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/symbols.rs +41 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/target_reference.rs +3 -3
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/validators/affects.rs +217 -108
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/validators/check_ai.rs +222 -95
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/validators/check_lua.rs +266 -139
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/validators/keep_sorted.rs +131 -4
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/validators/keep_unique.rs +141 -2
- blockwatch_cli-0.15.0/src/validators/line_count.rs +707 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/validators/line_pattern.rs +129 -4
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/validators/mod.rs +62 -2
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/validators/same_as.rs +476 -79
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/virtual_blocks.rs +1 -10
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/affects.rs +2 -2
- blockwatch_cli-0.15.0/tests/explain.rs +221 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/same_as.rs +1 -1
- blockwatch_cli-0.15.0/tests/testdata/explain/a.py +16 -0
- blockwatch_cli-0.15.0/tests/testdata/explain/check.lua +3 -0
- blockwatch_cli-0.14.1/docs/validators/line-count.md +0 -29
- blockwatch_cli-0.14.1/src/validators/line_count.rs +0 -403
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/.agents/.claude-plugin/plugin.json +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/.agents/skills/blockwatch/SKILL.md +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/.claude-plugin/marketplace.json +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/.github/dependabot.yml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/.github/workflows/blockwatch.yml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/.github/workflows/codeql.yml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/.github/workflows/markdownlint.yml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/.github/workflows/release.yml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/.github/workflows/rust.yml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/.github/workflows/trusted-checks.yml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/.gitignore +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/.markdownlint-cli2.yaml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/.pre-commit-hooks.yaml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/LICENSE +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/SECURITY.md +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/blockwatch.toml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/clippy.toml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/codecov.yml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/demo.gif +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/docs/agents.md +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/docs/symbols.md +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/docs/validators/README.md +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/docs/validators/affects.md +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/docs/validators/check-ai.md +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/docs/validators/check-lua.md +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/docs/validators/keep-sorted.md +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/docs/validators/keep-unique.md +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/docs/validators/line-pattern.md +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/docs/validators/same-as.md +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/pypi/pyproject.toml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/pyproject.toml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/release.toml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/scripts/check_language_count.lua +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/scripts/check_latest_gpt_nano_model.lua +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/block_parser.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/config.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/diff_parser.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/fs.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/bash.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/c.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/c_sharp.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/cmake.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/cpp.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/css.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/dart.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/dockerfile.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/elixir.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/go.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/graphql.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/groovy.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/hcl.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/html.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/java.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/javascript.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/json.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/json.scm +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/kotlin.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/lean.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/lua.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/makefile.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/mod.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/nix.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/ocaml.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/php.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/proto.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/python.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/ruby.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/rust.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/scala.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/sql.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/starlark.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/swift.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/toml.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/tsx.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/typescript.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/xml.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/language_parsers/yaml.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/main.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/path_arguments.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/paths_glob.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/repo_path.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/report.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/sarif.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/scan.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/settings.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/symbol_path.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/tag_parser.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/src/violation_address.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/check_ai.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/check_lua.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/common/empty.toml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/common/mod.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/config.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/encoding.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/general.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/keep_sorted.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/keep_unique.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/line_count.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/line_pattern.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/list.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/path_arguments.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/repository_root.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/sarif.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/skill.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/suppressions.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/symbol_references.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/cross_file_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/cross_file_target.md +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/custom_ext_source.javascript +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/custom_ext_target.javascript +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/dangling.md +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/missing_symbol.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/more_added_than_deleted.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/multiline_tag_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/multiline_tag_target.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/nested_mapping_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/nested_mapping_target.yaml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/sibling.md +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/symbol_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/symbol_target.json +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/table_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/table_target.toml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/tag_and_content_source.ts +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/tag_and_content_target.ts +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/whole_file_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/affects/whole_file_target.json +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/check_ai/two_blocks.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/check_lua/affects.lua +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/check_lua/affects.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/check_lua/affects_drift.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/check_lua/blocking_io.lua +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/check_lua/blocking_io.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/check_lua/echo.lua +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/check_lua/fail.lua +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/check_lua/mode.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/check_lua/os.lua +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/check_lua/pathfmt/report_path.lua +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/check_lua/pathfmt/source.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/check_lua/pattern.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/check_lua/pattern_many_matches.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/check_lua/pattern_no_match.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/check_lua/success.lua +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/check_lua/success_and_failure.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/config/glob_target/config.toml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/config/glob_target/package.json +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/config/glob_target/plugins/blue/package.json +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/config/glob_target/plugins/green/package.json +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/config/glob_target/plugins/red/package.json +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/general/block_selection.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/general/custom_file_extension.javascript +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/general/custom_file_extension.python +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/general/disable_enable.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/general/paths/invalid.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/general/paths/subdir/nested_invalid.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/general/paths/valid.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/general/severity.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/hidden/.github/workflows/ci.yml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/keep_sorted/orderings.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/keep_unique/basic_and_pattern.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/line_count/equality_and_greater_than.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/line_pattern/forbidden_text.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/line_pattern/hex_and_word_patterns.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/list/.hg/.gitkeep +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/list/a.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/list/b.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/positions/unicode_columns.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/same_as/custom_ext_source.javascript +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/same_as/custom_ext_target.javascript +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/same_as/package.json +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/same_as/paths/alpha/item.txt +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/same_as/paths/beta/item.txt +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/same_as/paths_and_block_source.md +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/same_as/paths_source.md +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/same_as/sibling.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/same_as/source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/same_as/split_table_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/same_as/split_table_target.toml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/same_as/symbol_mismatch_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/same_as/symbol_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/same_as/target.md +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/same_as/whole_file_mismatch_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/same_as/whole_file_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/same_as/whole_file_target.json +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/sarif/advisory.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/sarif/clean.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/sarif/sorted.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/sarif/unnamed.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/suppressions/commit_msg.txt +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/suppressions/commit_msg_gone_a.txt +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/suppressions/commit_msg_gone_b.txt +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/suppressions/commit_msg_lowercase_trailer.txt +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/suppressions/commit_msg_malformed.txt +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/suppressions/commit_msg_with_noise.txt +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/suppressions/dangling.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/suppressions/sorted.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/suppressions/symbol.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/suppressions/symbol_target.json +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/suppressions/two_rules.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/suppressions/unnamed.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/escapes_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/escapes_target.json +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/filter_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/filter_target.yaml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/json_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/json_target.json +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/jsonc_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/jsonc_target.jsonc +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/markdown_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/markdown_target.markdown +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/md_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/md_target.md +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/mdx_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/mdx_target.mdx +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/mixed_list_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/mixed_list_target.json +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/toml_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/toml_target.toml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/yaml_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/yaml_target.yaml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/yml_source.rs +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/symbol_references/yml_target.yml +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/verbosity/affects/pair.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/verbosity/clean/counted.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/verbosity/clean/noop.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/verbosity/clean/notes.txt +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/verbosity/clean/sorted.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/verbosity/diff/two_blocks.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/verbosity/failing/unsorted.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/tests/testdata/verbosity/mixed/both_kinds.py +0 -0
- {blockwatch_cli-0.14.1 → blockwatch_cli-0.15.0}/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
|
|
@@ -43,6 +43,14 @@ repos:
|
|
|
43
43
|
types: [ rust ]
|
|
44
44
|
stages: [ pre-commit ]
|
|
45
45
|
pass_filenames: false
|
|
46
|
+
- id: cargo-test
|
|
47
|
+
name: cargo test
|
|
48
|
+
description: Run the unit, integration and doc tests.
|
|
49
|
+
entry: cargo test --quiet
|
|
50
|
+
language: system
|
|
51
|
+
types: [ rust ]
|
|
52
|
+
stages: [ pre-commit ]
|
|
53
|
+
pass_filenames: false
|
|
46
54
|
|
|
47
55
|
# Rules and the set of files linted live in `.markdownlint-cli2.yaml`, which the tool picks up
|
|
48
56
|
# from the repository root. The hook passes only the staged Markdown files, so a commit is judged
|
|
@@ -65,9 +65,9 @@ For example:
|
|
|
65
65
|
- *Always* handle the variants of an enum with an exhaustive `match`. A `let ... else`, or an `if` that handles one
|
|
66
66
|
variant and sends the rest to a single branch, quietly gives any new variant whatever that branch does. With a
|
|
67
67
|
`match`, the compiler makes you decide what to do with each new variant. One exception: a `match` on another
|
|
68
|
-
crate's enum can end with `_` when it only
|
|
69
|
-
|
|
70
|
-
Say why in a comment next to the `_`.
|
|
68
|
+
crate's enum can end with `_` when it only picks out one or a few variants, and no new variant could be one of
|
|
69
|
+
them. For example, every Markdown heading is `mdast::Node::Heading`, so the other node types can go to
|
|
70
|
+
`_ => None`. Say why in a comment next to the `_`.
|
|
71
71
|
- *Always* give an item the narrowest visibility that compiles: private, then `pub(super)`, then `pub(crate)`.
|
|
72
72
|
blockwatch is a program, not a library. Only `run` and `count_rust_blocks` in `lib.rs` are `pub`, for `main.rs` and
|
|
73
73
|
the fuzz target. The `unreachable_pub` lint makes `cargo clippy -- -D warnings` fail on any other `pub`.
|
|
@@ -173,8 +173,9 @@ The whole pipeline is in `src/cli.rs`. `src/main.rs` only calls `blockwatch::run
|
|
|
173
173
|
from the command line select, and that don't match the settings' ignore globs. `PathArguments::resolve` turns an
|
|
174
174
|
existing file or directory into a glob first, so `src` selects `src/**`. Pick each file's language by its
|
|
175
175
|
extension, using the settings' extension mappings too.
|
|
176
|
-
6. For each file, the matching `language_parsers::<lang>` (a tree-sitter grammar) finds the comments.
|
|
177
|
-
`block_parser` turn the comment text into `Block` values, with their attributes and their byte and
|
|
176
|
+
6. For each file, the matching `language_parsers::<lang>` (usually a tree-sitter grammar) finds the comments.
|
|
177
|
+
`tag_parser` and `block_parser` turn the comment text into `Block` values, with their attributes and their byte and
|
|
178
|
+
line ranges.
|
|
178
179
|
`VirtualBlock::resolve` finds each virtual block in the file, by its `Locator`, and adds it as a `Block` too. A file
|
|
179
180
|
without a grammar is read as plain text: it has no tags, only its virtual blocks. A target that does not resolve
|
|
180
181
|
stops the run. `--only-changed` also parses the file of a virtual block whose entry the diff
|
|
@@ -193,7 +194,8 @@ The whole pipeline is in `src/cli.rs`. `src/main.rs` only calls `blockwatch::run
|
|
|
193
194
|
report goes to stdout. The exit code depends on the error-severity violations that are not suppressed.
|
|
194
195
|
|
|
195
196
|
The `list` subcommand stops after step 6 and writes the blocks it found to stdout as JSON. The `skill` subcommand
|
|
196
|
-
prints `src/skill.md` right after step 1.
|
|
197
|
+
prints `src/skill.md` right after step 1. The `explain` subcommand runs like `--only-block` with the file of its
|
|
198
|
+
address as the only path. It then writes that block to stdout as JSON.
|
|
197
199
|
|
|
198
200
|
The main modules:
|
|
199
201
|
|
|
@@ -223,7 +225,8 @@ The main modules:
|
|
|
223
225
|
- `src/repo_path.rs` — `RepoPath`, the one way to write a path relative to the repository root. A diff header
|
|
224
226
|
(`b/src/main.rs`), a path found in the walk and a `file:name` attribute all become a `RepoPath`. So the same file is
|
|
225
227
|
always the same map key.
|
|
226
|
-
- `src/language_parsers/` — one
|
|
228
|
+
- `src/language_parsers/` — one parser for each language, most of them a tree-sitter grammar. Markdown and MDX use
|
|
229
|
+
the `markdown` crate, and Lean has its own scanner. Each language has a `parser()` that returns a
|
|
227
230
|
`LanguageParser`, which knows which syntax nodes are comments. `src/block_parser.rs` turns those comments into
|
|
228
231
|
blocks. `language_parsers()` in `language_parsers/mod.rs` returns `LanguageParsers`: the parser of each extension.
|
|
229
232
|
Its `parser_for` picks the parser of a file, using the settings' extension mappings too. **To add a language, add a
|
|
@@ -237,8 +240,7 @@ The main modules:
|
|
|
237
240
|
syntax tree is nested.
|
|
238
241
|
- YAML walks its syntax tree itself. An alias has a position in a sequence but can't be addressed, and a query can't
|
|
239
242
|
express that.
|
|
240
|
-
- Markdown finds its sections with the `markdown` crate
|
|
241
|
-
heading underlined with `---`.
|
|
243
|
+
- Markdown finds its sections with the `markdown` crate, the same parser that finds its comments.
|
|
242
244
|
|
|
243
245
|
Each language's tests list every symbol it finds. When you give a language symbols, also document its paths in
|
|
244
246
|
`docs/symbols.md` and in the "Symbols" section of the skill, `src/skill.md`. A test in `language_parsers/mod.rs` and the
|
|
@@ -12,6 +12,57 @@ 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.15.0] - 2026-10-21
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- In Markdown, a `<!--` is a comment only where HTML is kept as it is: in an HTML block or in raw HTML in a line of
|
|
20
|
+
text. These were read as comments before and are not now:
|
|
21
|
+
- the alt text of an image: ``;
|
|
22
|
+
- the title of a link: `[Docs](docs.md "<!-- x -->")`;
|
|
23
|
+
- an escaped `<`: `\<!-- x -->`.
|
|
24
|
+
|
|
25
|
+
In a line of text, `<!-->` is now a whole comment, so a tag after it on that line is not read.
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- In Markdown, blockwatch skipped every tag after a fenced code block that holds a line like `` ``` `` indented by 4
|
|
30
|
+
spaces or a tab, or `` echo x``` ``. Such a line closed the code block too early, so the rest of the file became
|
|
31
|
+
code. The run gave no error. Now such a line stays in the code block, as CommonMark says
|
|
32
|
+
([#176](https://github.com/mennanov/blockwatch/issues/176)).
|
|
33
|
+
|
|
34
|
+
## [0.14.2] - 2026-10-21
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
|
|
38
|
+
- `line-count-pattern` makes `line-count` count only the lines that match the regex. For example,
|
|
39
|
+
`line-count="<=20" line-count-pattern='^"\w+",$'` skips comments and blank lines in a list. See
|
|
40
|
+
[`line-count`](docs/validators/line-count.md).
|
|
41
|
+
- `blockwatch explain FILE:BLOCK_NAME` checks one named block and prints it as JSON: its attributes, the text its
|
|
42
|
+
validators read and where that text is. For example: `blockwatch explain package.json:version`. The output also lists
|
|
43
|
+
the validators the block asks for but the settings turn off (`"disabled"`). Under `"checks"`, it shows what each
|
|
44
|
+
validator saw:
|
|
45
|
+
- `same-as`: each record the pattern matched, with its line, on both sides, and the reason of each mismatch.
|
|
46
|
+
- `keep-sorted` and `keep-unique`: the value each line gives, up to the first line out of order or repeated.
|
|
47
|
+
- `line-pattern`: what each pattern matched on each line, up to the first line that fails.
|
|
48
|
+
- `affects`: whether the block changed, and for each target, whether it changed or why it doesn't resolve.
|
|
49
|
+
- `line-count`: the value each line gives, how many lines count, and the rule they were checked against.
|
|
50
|
+
- `check-lua`: the `content` and `ctx.affects` the script got, and the message it returned.
|
|
51
|
+
- `check-ai`: the model, the prompt it was sent and its answer.
|
|
52
|
+
|
|
53
|
+
`"with_diff"` says whether `--diff` was given. Without it, no block counts as changed. Violations go to stderr, and
|
|
54
|
+
the exit code is the same as for a normal run. See [The `explain` Command](docs/cli.md#the-explain-command).
|
|
55
|
+
|
|
56
|
+
### Changed
|
|
57
|
+
|
|
58
|
+
- A message of `affects` or `same-as` about a whole-file target shows the path alone, without `file` in front. For
|
|
59
|
+
example: `Block a.py:b at line 1 is modified, but config.json is not`.
|
|
60
|
+
|
|
61
|
+
### Fixed
|
|
62
|
+
|
|
63
|
+
- A `check-lua` script got no `ctx.affects` entry for a block target that the run didn't check, such as with
|
|
64
|
+
`--only-block` or `--diff --only-changed`. Now `ctx.affects` holds the same targets in every run.
|
|
65
|
+
|
|
15
66
|
## [0.14.1] - 2026-10-17
|
|
16
67
|
|
|
17
68
|
### Changed
|
|
@@ -65,9 +65,9 @@ For example:
|
|
|
65
65
|
- *Always* handle the variants of an enum with an exhaustive `match`. A `let ... else`, or an `if` that handles one
|
|
66
66
|
variant and sends the rest to a single branch, quietly gives any new variant whatever that branch does. With a
|
|
67
67
|
`match`, the compiler makes you decide what to do with each new variant. One exception: a `match` on another
|
|
68
|
-
crate's enum can end with `_` when it only
|
|
69
|
-
|
|
70
|
-
Say why in a comment next to the `_`.
|
|
68
|
+
crate's enum can end with `_` when it only picks out one or a few variants, and no new variant could be one of
|
|
69
|
+
them. For example, every Markdown heading is `mdast::Node::Heading`, so the other node types can go to
|
|
70
|
+
`_ => None`. Say why in a comment next to the `_`.
|
|
71
71
|
- *Always* give an item the narrowest visibility that compiles: private, then `pub(super)`, then `pub(crate)`.
|
|
72
72
|
blockwatch is a program, not a library. Only `run` and `count_rust_blocks` in `lib.rs` are `pub`, for `main.rs` and
|
|
73
73
|
the fuzz target. The `unreachable_pub` lint makes `cargo clippy -- -D warnings` fail on any other `pub`.
|
|
@@ -173,8 +173,9 @@ The whole pipeline is in `src/cli.rs`. `src/main.rs` only calls `blockwatch::run
|
|
|
173
173
|
from the command line select, and that don't match the settings' ignore globs. `PathArguments::resolve` turns an
|
|
174
174
|
existing file or directory into a glob first, so `src` selects `src/**`. Pick each file's language by its
|
|
175
175
|
extension, using the settings' extension mappings too.
|
|
176
|
-
6. For each file, the matching `language_parsers::<lang>` (a tree-sitter grammar) finds the comments.
|
|
177
|
-
`block_parser` turn the comment text into `Block` values, with their attributes and their byte and
|
|
176
|
+
6. For each file, the matching `language_parsers::<lang>` (usually a tree-sitter grammar) finds the comments.
|
|
177
|
+
`tag_parser` and `block_parser` turn the comment text into `Block` values, with their attributes and their byte and
|
|
178
|
+
line ranges.
|
|
178
179
|
`VirtualBlock::resolve` finds each virtual block in the file, by its `Locator`, and adds it as a `Block` too. A file
|
|
179
180
|
without a grammar is read as plain text: it has no tags, only its virtual blocks. A target that does not resolve
|
|
180
181
|
stops the run. `--only-changed` also parses the file of a virtual block whose entry the diff
|
|
@@ -193,7 +194,8 @@ The whole pipeline is in `src/cli.rs`. `src/main.rs` only calls `blockwatch::run
|
|
|
193
194
|
report goes to stdout. The exit code depends on the error-severity violations that are not suppressed.
|
|
194
195
|
|
|
195
196
|
The `list` subcommand stops after step 6 and writes the blocks it found to stdout as JSON. The `skill` subcommand
|
|
196
|
-
prints `src/skill.md` right after step 1.
|
|
197
|
+
prints `src/skill.md` right after step 1. The `explain` subcommand runs like `--only-block` with the file of its
|
|
198
|
+
address as the only path. It then writes that block to stdout as JSON.
|
|
197
199
|
|
|
198
200
|
The main modules:
|
|
199
201
|
|
|
@@ -223,7 +225,8 @@ The main modules:
|
|
|
223
225
|
- `src/repo_path.rs` — `RepoPath`, the one way to write a path relative to the repository root. A diff header
|
|
224
226
|
(`b/src/main.rs`), a path found in the walk and a `file:name` attribute all become a `RepoPath`. So the same file is
|
|
225
227
|
always the same map key.
|
|
226
|
-
- `src/language_parsers/` — one
|
|
228
|
+
- `src/language_parsers/` — one parser for each language, most of them a tree-sitter grammar. Markdown and MDX use
|
|
229
|
+
the `markdown` crate, and Lean has its own scanner. Each language has a `parser()` that returns a
|
|
227
230
|
`LanguageParser`, which knows which syntax nodes are comments. `src/block_parser.rs` turns those comments into
|
|
228
231
|
blocks. `language_parsers()` in `language_parsers/mod.rs` returns `LanguageParsers`: the parser of each extension.
|
|
229
232
|
Its `parser_for` picks the parser of a file, using the settings' extension mappings too. **To add a language, add a
|
|
@@ -237,8 +240,7 @@ The main modules:
|
|
|
237
240
|
syntax tree is nested.
|
|
238
241
|
- YAML walks its syntax tree itself. An alias has a position in a sequence but can't be addressed, and a query can't
|
|
239
242
|
express that.
|
|
240
|
-
- Markdown finds its sections with the `markdown` crate
|
|
241
|
-
heading underlined with `---`.
|
|
243
|
+
- Markdown finds its sections with the `markdown` crate, the same parser that finds its comments.
|
|
242
244
|
|
|
243
245
|
Each language's tests list every symbol it finds. When you give a language symbols, also document its paths in
|
|
244
246
|
`docs/symbols.md` and in the "Symbols" section of the skill, `src/skill.md`. A test in `language_parsers/mod.rs` and the
|
|
@@ -274,7 +274,7 @@ checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06"
|
|
|
274
274
|
|
|
275
275
|
[[package]]
|
|
276
276
|
name = "blockwatch"
|
|
277
|
-
version = "0.
|
|
277
|
+
version = "0.15.0"
|
|
278
278
|
dependencies = [
|
|
279
279
|
"anyhow",
|
|
280
280
|
"assert-json-diff",
|
|
@@ -327,7 +327,6 @@ dependencies = [
|
|
|
327
327
|
"tree-sitter-kotlin-ng",
|
|
328
328
|
"tree-sitter-lua",
|
|
329
329
|
"tree-sitter-make",
|
|
330
|
-
"tree-sitter-md",
|
|
331
330
|
"tree-sitter-nix",
|
|
332
331
|
"tree-sitter-ocaml",
|
|
333
332
|
"tree-sitter-php",
|
|
@@ -2637,16 +2636,6 @@ dependencies = [
|
|
|
2637
2636
|
"tree-sitter-language",
|
|
2638
2637
|
]
|
|
2639
2638
|
|
|
2640
|
-
[[package]]
|
|
2641
|
-
name = "tree-sitter-md"
|
|
2642
|
-
version = "0.5.3"
|
|
2643
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2644
|
-
checksum = "2efd398be546456c814598ee56c0f51769a77241511b4a58077815d120afa882"
|
|
2645
|
-
dependencies = [
|
|
2646
|
-
"cc",
|
|
2647
|
-
"tree-sitter-language",
|
|
2648
|
-
]
|
|
2649
|
-
|
|
2650
2639
|
[[package]]
|
|
2651
2640
|
name = "tree-sitter-nix"
|
|
2652
2641
|
version = "0.3.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "blockwatch"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.15.0"
|
|
4
4
|
edition = "2024"
|
|
5
5
|
repository = "https://github.com/mennanov/blockwatch"
|
|
6
6
|
description = "Language agnostic linter that keeps your code and documentation in sync and valid"
|
|
@@ -62,7 +62,6 @@ tree-sitter-json = "0.24.8"
|
|
|
62
62
|
tree-sitter-kotlin-ng = "1.1"
|
|
63
63
|
tree-sitter-lua = "0.5"
|
|
64
64
|
tree-sitter-make = "1.1"
|
|
65
|
-
tree-sitter-md = "0.5"
|
|
66
65
|
tree-sitter-nix = "0.3.0"
|
|
67
66
|
tree-sitter-ocaml = "0.26"
|
|
68
67
|
tree-sitter-php = "0.25"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: blockwatch-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.0
|
|
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
|
|
@@ -104,7 +104,7 @@ you'd otherwise have to nitpick in code review.
|
|
|
104
104
|
| [`keep-sorted`](docs/validators/keep-sorted.md) | Enforces alphabetical or numerical ordering on list items | `keep-sorted`, `keep-sorted-pattern`, `keep-sorted-format` |
|
|
105
105
|
| [`keep-unique`](docs/validators/keep-unique.md) | Prevents duplicate lines within a block | `keep-unique` |
|
|
106
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` |
|
|
107
|
-
| [`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` |
|
|
108
108
|
| [`check-ai`](docs/validators/check-ai.md) | Validates content against natural language rules using an LLM | `check-ai`, `check-ai-pattern` |
|
|
109
109
|
| [`check-lua`](docs/validators/check-lua.md) | Runs custom validation logic written in Lua | `check-lua`, `check-lua-pattern`, `check-lua-timeout` |
|
|
110
110
|
|
|
@@ -173,6 +173,9 @@ git diff --patch HEAD | blockwatch --diff --only-changed
|
|
|
173
173
|
|
|
174
174
|
# Dump all discovered blocks as JSON
|
|
175
175
|
blockwatch list
|
|
176
|
+
|
|
177
|
+
# Show what each validator of one named block read
|
|
178
|
+
blockwatch explain src/lib.rs:languages
|
|
176
179
|
```
|
|
177
180
|
|
|
178
181
|
Rules live in comments, next to the code they describe. Settings that apply to the whole project, such as ignored
|
|
@@ -215,7 +218,7 @@ exclusions, and custom extension mappings.
|
|
|
215
218
|
|
|
216
219
|
```yaml
|
|
217
220
|
- repo: https://github.com/mennanov/blockwatch
|
|
218
|
-
rev: v0.
|
|
221
|
+
rev: v0.15.0 # Use latest release
|
|
219
222
|
hooks:
|
|
220
223
|
- id: blockwatch
|
|
221
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.
|
|
22
|
+
rev: v0.15.0 # 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.15.0 # 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`)
|
|
@@ -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.
|
|
559
|
-
"semanticVersion": "0.
|
|
560
|
+
"version": "0.15.0",
|
|
561
|
+
"semanticVersion": "0.15.0",
|
|
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.
|
|
568
|
+
"helpUri": "https://github.com/mennanov/blockwatch/blob/v0.15.0/docs/validators/keep-sorted.md"
|
|
567
569
|
}
|
|
568
570
|
]
|
|
569
571
|
}
|
|
@@ -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
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# `line-count`
|
|
2
|
+
|
|
3
|
+
Constrains how many lines a block may contain. Flags unbounded growth in a public API surface, or pins a switch to the
|
|
4
|
+
size of the enum it maps.
|
|
5
|
+
|
|
6
|
+
## Syntax
|
|
7
|
+
|
|
8
|
+
| Attribute | Value | Default |
|
|
9
|
+
|----------------------|--------------------------------------------|--------------------------|
|
|
10
|
+
| `line-count` | `<N`, `<=N`, `==N`, `>=N`, `>N` | — |
|
|
11
|
+
| `line-count-pattern` | regex; a line counts when it gives a value | every line that has text |
|
|
12
|
+
|
|
13
|
+
## Example
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
# <block line-count="<=5">
|
|
17
|
+
"a",
|
|
18
|
+
"b",
|
|
19
|
+
"c"
|
|
20
|
+
# </block>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Counting only some lines
|
|
24
|
+
|
|
25
|
+
`line-count-pattern` counts only the lines it matches:
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
# <block line-count="<=2" line-count-pattern='^"\w+",$'>
|
|
29
|
+
"a",
|
|
30
|
+
# a comment
|
|
31
|
+
"b",
|
|
32
|
+
# </block>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The block above counts 2: the comment line doesn't match.
|
|
36
|
+
|
|
37
|
+
Lines that do not match are skipped, as are lines whose match is empty. So is a line that matches a branch without the
|
|
38
|
+
`value` group: `^(?:none|(?P<value>\w+))$` skips the line `none`. The pattern runs on the trimmed line, so `^` and `$`
|
|
39
|
+
match at the text, not at the indentation.
|
|
40
|
+
|
|
41
|
+
## Notes
|
|
42
|
+
|
|
43
|
+
- **Blank lines are not counted.** The block above counts 3.
|
|
44
|
+
- A malformed comparator is a hard error, not a violation.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
← [Validators](README.md) · [README](../../README.md)
|
|
@@ -6,7 +6,7 @@ setup(
|
|
|
6
6
|
name='blockwatch-pre-commit-placeholder',
|
|
7
7
|
version='0.0.0',
|
|
8
8
|
# <block name="blockwatch-cli-version" same-as-pattern="blockwatch-cli==(?P<value>\d+\.\d+\.\d+)">
|
|
9
|
-
install_requires=['blockwatch-cli==0.
|
|
9
|
+
install_requires=['blockwatch-cli==0.15.0'],
|
|
10
10
|
# </block>
|
|
11
11
|
# Without it, setuptools takes the directories under src/ for Python packages.
|
|
12
12
|
packages=[],
|
|
@@ -184,6 +184,15 @@ impl Content {
|
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
+
/// Describes the content for JSON. `source` must be the text of the block's file.
|
|
188
|
+
pub(crate) fn listing<'a>(&'a self, source: &'a str) -> ContentListing<'a> {
|
|
189
|
+
ContentListing {
|
|
190
|
+
start: self.positions.start,
|
|
191
|
+
end: self.positions.end,
|
|
192
|
+
text: self.text(source),
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
187
196
|
/// Returns the content's text. `source` must be the text of the block's file.
|
|
188
197
|
pub(crate) fn text<'a>(&'a self, source: &'a str) -> &'a str {
|
|
189
198
|
match &self.text {
|
|
@@ -424,6 +433,19 @@ pub(crate) struct BlockListing<'a> {
|
|
|
424
433
|
}
|
|
425
434
|
// </block>
|
|
426
435
|
|
|
436
|
+
/// The content of a block, as it is written in JSON: its text, and where the block's file writes
|
|
437
|
+
/// it.
|
|
438
|
+
#[derive(Serialize, Debug)]
|
|
439
|
+
pub(crate) struct ContentListing<'a> {
|
|
440
|
+
/// The position of the content's first character.
|
|
441
|
+
start: Position,
|
|
442
|
+
/// The first position after the content.
|
|
443
|
+
end: Position,
|
|
444
|
+
/// The text the validators read. For a virtual block around a quoted or escaped value, it is
|
|
445
|
+
/// the decoded value.
|
|
446
|
+
text: &'a str,
|
|
447
|
+
}
|
|
448
|
+
|
|
427
449
|
impl<'a> From<&'a BlockWithContext> for BlockListing<'a> {
|
|
428
450
|
/// Describes the block, with no `checks`.
|
|
429
451
|
fn from(block_with_context: &'a BlockWithContext) -> Self {
|
|
@@ -461,6 +483,7 @@ const RECOGNIZED_ATTRIBUTES: &[&str] = &[
|
|
|
461
483
|
"keep-sorted-pattern",
|
|
462
484
|
"keep-unique",
|
|
463
485
|
"line-count",
|
|
486
|
+
"line-count-pattern",
|
|
464
487
|
"line-pattern",
|
|
465
488
|
"line-pattern-forbidden",
|
|
466
489
|
"name",
|