blockwatch-cli 0.14.2__tar.gz → 0.16.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.
Files changed (270) hide show
  1. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/.pre-commit-config.yaml +8 -0
  2. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/AGENTS.md +9 -8
  3. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/CHANGELOG.md +52 -0
  4. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/CLAUDE.md +9 -8
  5. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/Cargo.lock +1 -12
  6. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/Cargo.toml +1 -2
  7. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/PKG-INFO +1 -1
  8. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/README.md +1 -1
  9. blockwatch_cli-0.16.0/clippy.toml +11 -0
  10. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/docs/ci.md +2 -2
  11. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/docs/cli.md +13 -13
  12. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/docs/validators/check-ai.md +3 -0
  13. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/docs/validators/check-lua.md +3 -0
  14. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/docs/validators/keep-sorted.md +3 -0
  15. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/docs/validators/line-count.md +3 -0
  16. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/docs/validators/same-as.md +46 -26
  17. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/setup.py +1 -1
  18. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/blocks.rs +37 -3
  19. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/config.rs +6 -2
  20. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/fs.rs +5 -1
  21. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/markdown.rs +306 -154
  22. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/mdx.rs +4 -13
  23. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/path_arguments.rs +15 -3
  24. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/paths_glob.rs +66 -1
  25. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/settings.rs +17 -1
  26. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/skill.md +27 -23
  27. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/validators/check_ai.rs +27 -1
  28. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/validators/check_lua.rs +33 -0
  29. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/validators/keep_sorted.rs +37 -1
  30. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/validators/line_count.rs +30 -1
  31. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/validators/mod.rs +49 -0
  32. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/validators/same_as.rs +313 -59
  33. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/explain.rs +13 -5
  34. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/same_as.rs +35 -0
  35. blockwatch_cli-0.14.2/clippy.toml +0 -5
  36. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/.agents/.claude-plugin/plugin.json +0 -0
  37. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/.agents/skills/blockwatch/SKILL.md +0 -0
  38. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/.claude-plugin/marketplace.json +0 -0
  39. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/.github/dependabot.yml +0 -0
  40. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/.github/workflows/blockwatch.yml +0 -0
  41. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/.github/workflows/codeql.yml +0 -0
  42. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/.github/workflows/markdownlint.yml +0 -0
  43. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/.github/workflows/pypi.yml +0 -0
  44. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/.github/workflows/release.yml +0 -0
  45. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/.github/workflows/rust.yml +0 -0
  46. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/.github/workflows/trusted-checks.yml +0 -0
  47. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/.gitignore +0 -0
  48. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/.markdownlint-cli2.yaml +0 -0
  49. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/.pre-commit-hooks.yaml +0 -0
  50. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/LICENSE +0 -0
  51. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/SECURITY.md +0 -0
  52. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/blockwatch.toml +0 -0
  53. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/codecov.yml +0 -0
  54. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/demo.gif +0 -0
  55. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/dist-workspace.toml +0 -0
  56. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/docs/agents.md +0 -0
  57. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/docs/symbols.md +0 -0
  58. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/docs/validators/README.md +0 -0
  59. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/docs/validators/affects.md +0 -0
  60. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/docs/validators/keep-unique.md +0 -0
  61. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/docs/validators/line-pattern.md +0 -0
  62. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/pypi/pyproject.toml +0 -0
  63. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/pyproject.toml +0 -0
  64. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/release.toml +0 -0
  65. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/scripts/check_language_count.lua +0 -0
  66. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/scripts/check_latest_gpt_nano_model.lua +0 -0
  67. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/block_parser.rs +0 -0
  68. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/cli.rs +0 -0
  69. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/diff_parser.rs +0 -0
  70. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/explain.rs +0 -0
  71. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/flags.rs +0 -0
  72. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/bash.rs +0 -0
  73. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/c.rs +0 -0
  74. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/c_sharp.rs +0 -0
  75. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/cmake.rs +0 -0
  76. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/cpp.rs +0 -0
  77. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/css.rs +0 -0
  78. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/dart.rs +0 -0
  79. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/dockerfile.rs +0 -0
  80. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/elixir.rs +0 -0
  81. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/go.rs +0 -0
  82. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/graphql.rs +0 -0
  83. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/groovy.rs +0 -0
  84. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/hcl.rs +0 -0
  85. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/html.rs +0 -0
  86. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/java.rs +0 -0
  87. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/javascript.rs +0 -0
  88. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/json.rs +0 -0
  89. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/json.scm +0 -0
  90. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/kotlin.rs +0 -0
  91. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/lean.rs +0 -0
  92. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/lua.rs +0 -0
  93. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/makefile.rs +0 -0
  94. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/mod.rs +0 -0
  95. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/nix.rs +0 -0
  96. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/ocaml.rs +0 -0
  97. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/php.rs +0 -0
  98. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/proto.rs +0 -0
  99. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/python.rs +0 -0
  100. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/ruby.rs +0 -0
  101. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/rust.rs +0 -0
  102. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/scala.rs +0 -0
  103. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/sql.rs +0 -0
  104. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/starlark.rs +0 -0
  105. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/swift.rs +0 -0
  106. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/toml.rs +0 -0
  107. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/tsx.rs +0 -0
  108. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/typescript.rs +0 -0
  109. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/xml.rs +0 -0
  110. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/language_parsers/yaml.rs +0 -0
  111. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/lib.rs +0 -0
  112. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/main.rs +0 -0
  113. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/repo_path.rs +0 -0
  114. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/report.rs +0 -0
  115. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/sarif.rs +0 -0
  116. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/scan.rs +0 -0
  117. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/symbol_path.rs +0 -0
  118. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/symbols.rs +0 -0
  119. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/tag_parser.rs +0 -0
  120. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/target_reference.rs +0 -0
  121. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/validators/affects.rs +0 -0
  122. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/validators/keep_unique.rs +0 -0
  123. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/validators/line_pattern.rs +0 -0
  124. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/violation_address.rs +0 -0
  125. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/src/virtual_blocks.rs +0 -0
  126. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/affects.rs +0 -0
  127. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/check_ai.rs +0 -0
  128. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/check_lua.rs +0 -0
  129. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/common/empty.toml +0 -0
  130. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/common/mod.rs +0 -0
  131. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/config.rs +0 -0
  132. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/encoding.rs +0 -0
  133. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/general.rs +0 -0
  134. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/keep_sorted.rs +0 -0
  135. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/keep_unique.rs +0 -0
  136. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/line_count.rs +0 -0
  137. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/line_pattern.rs +0 -0
  138. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/list.rs +0 -0
  139. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/path_arguments.rs +0 -0
  140. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/repository_root.rs +0 -0
  141. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/sarif.rs +0 -0
  142. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/skill.rs +0 -0
  143. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/suppressions.rs +0 -0
  144. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/symbol_references.rs +0 -0
  145. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/cross_file_source.rs +0 -0
  146. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/cross_file_target.md +0 -0
  147. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/custom_ext_source.javascript +0 -0
  148. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/custom_ext_target.javascript +0 -0
  149. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/dangling.md +0 -0
  150. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/missing_symbol.rs +0 -0
  151. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/more_added_than_deleted.py +0 -0
  152. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/multiline_tag_source.rs +0 -0
  153. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/multiline_tag_target.rs +0 -0
  154. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/nested_mapping_source.rs +0 -0
  155. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/nested_mapping_target.yaml +0 -0
  156. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/sibling.md +0 -0
  157. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/symbol_source.rs +0 -0
  158. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/symbol_target.json +0 -0
  159. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/table_source.rs +0 -0
  160. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/table_target.toml +0 -0
  161. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/tag_and_content_source.ts +0 -0
  162. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/tag_and_content_target.ts +0 -0
  163. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/whole_file_source.rs +0 -0
  164. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/affects/whole_file_target.json +0 -0
  165. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/check_ai/two_blocks.py +0 -0
  166. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/check_lua/affects.lua +0 -0
  167. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/check_lua/affects.py +0 -0
  168. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/check_lua/affects_drift.py +0 -0
  169. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/check_lua/blocking_io.lua +0 -0
  170. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/check_lua/blocking_io.py +0 -0
  171. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/check_lua/echo.lua +0 -0
  172. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/check_lua/fail.lua +0 -0
  173. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/check_lua/mode.py +0 -0
  174. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/check_lua/os.lua +0 -0
  175. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/check_lua/pathfmt/report_path.lua +0 -0
  176. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/check_lua/pathfmt/source.py +0 -0
  177. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/check_lua/pattern.py +0 -0
  178. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/check_lua/pattern_many_matches.py +0 -0
  179. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/check_lua/pattern_no_match.py +0 -0
  180. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/check_lua/success.lua +0 -0
  181. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/check_lua/success_and_failure.py +0 -0
  182. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/config/glob_target/config.toml +0 -0
  183. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/config/glob_target/package.json +0 -0
  184. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/config/glob_target/plugins/blue/package.json +0 -0
  185. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/config/glob_target/plugins/green/package.json +0 -0
  186. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/config/glob_target/plugins/red/package.json +0 -0
  187. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/explain/a.py +0 -0
  188. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/explain/check.lua +0 -0
  189. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/general/block_selection.py +0 -0
  190. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/general/custom_file_extension.javascript +0 -0
  191. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/general/custom_file_extension.python +0 -0
  192. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/general/disable_enable.py +0 -0
  193. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/general/paths/invalid.py +0 -0
  194. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/general/paths/subdir/nested_invalid.py +0 -0
  195. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/general/paths/valid.py +0 -0
  196. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/general/severity.py +0 -0
  197. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/hidden/.github/workflows/ci.yml +0 -0
  198. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/keep_sorted/orderings.py +0 -0
  199. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/keep_unique/basic_and_pattern.py +0 -0
  200. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/line_count/equality_and_greater_than.py +0 -0
  201. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/line_pattern/forbidden_text.py +0 -0
  202. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/line_pattern/hex_and_word_patterns.py +0 -0
  203. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/list/.hg/.gitkeep +0 -0
  204. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/list/a.py +0 -0
  205. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/list/b.py +0 -0
  206. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/positions/unicode_columns.py +0 -0
  207. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/same_as/custom_ext_source.javascript +0 -0
  208. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/same_as/custom_ext_target.javascript +0 -0
  209. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/same_as/package.json +0 -0
  210. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/same_as/paths/alpha/item.txt +0 -0
  211. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/same_as/paths/beta/item.txt +0 -0
  212. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/same_as/paths_and_block_source.md +0 -0
  213. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/same_as/paths_source.md +0 -0
  214. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/same_as/sibling.rs +0 -0
  215. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/same_as/source.rs +0 -0
  216. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/same_as/split_table_source.rs +0 -0
  217. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/same_as/split_table_target.toml +0 -0
  218. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/same_as/symbol_mismatch_source.rs +0 -0
  219. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/same_as/symbol_source.rs +0 -0
  220. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/same_as/target.md +0 -0
  221. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/same_as/whole_file_mismatch_source.rs +0 -0
  222. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/same_as/whole_file_source.rs +0 -0
  223. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/same_as/whole_file_target.json +0 -0
  224. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/sarif/advisory.py +0 -0
  225. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/sarif/clean.py +0 -0
  226. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/sarif/sorted.py +0 -0
  227. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/sarif/unnamed.py +0 -0
  228. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/suppressions/commit_msg.txt +0 -0
  229. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/suppressions/commit_msg_gone_a.txt +0 -0
  230. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/suppressions/commit_msg_gone_b.txt +0 -0
  231. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/suppressions/commit_msg_lowercase_trailer.txt +0 -0
  232. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/suppressions/commit_msg_malformed.txt +0 -0
  233. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/suppressions/commit_msg_with_noise.txt +0 -0
  234. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/suppressions/dangling.py +0 -0
  235. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/suppressions/sorted.py +0 -0
  236. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/suppressions/symbol.py +0 -0
  237. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/suppressions/symbol_target.json +0 -0
  238. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/suppressions/two_rules.py +0 -0
  239. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/suppressions/unnamed.py +0 -0
  240. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/escapes_source.rs +0 -0
  241. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/escapes_target.json +0 -0
  242. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/filter_source.rs +0 -0
  243. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/filter_target.yaml +0 -0
  244. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/json_source.rs +0 -0
  245. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/json_target.json +0 -0
  246. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/jsonc_source.rs +0 -0
  247. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/jsonc_target.jsonc +0 -0
  248. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/markdown_source.rs +0 -0
  249. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/markdown_target.markdown +0 -0
  250. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/md_source.rs +0 -0
  251. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/md_target.md +0 -0
  252. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/mdx_source.rs +0 -0
  253. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/mdx_target.mdx +0 -0
  254. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/mixed_list_source.rs +0 -0
  255. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/mixed_list_target.json +0 -0
  256. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/toml_source.rs +0 -0
  257. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/toml_target.toml +0 -0
  258. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/yaml_source.rs +0 -0
  259. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/yaml_target.yaml +0 -0
  260. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/yml_source.rs +0 -0
  261. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/symbol_references/yml_target.yml +0 -0
  262. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/verbosity/affects/pair.py +0 -0
  263. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/verbosity/clean/counted.py +0 -0
  264. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/verbosity/clean/noop.py +0 -0
  265. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/verbosity/clean/notes.txt +0 -0
  266. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/verbosity/clean/sorted.py +0 -0
  267. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/verbosity/diff/two_blocks.py +0 -0
  268. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/verbosity/failing/unsorted.py +0 -0
  269. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/testdata/verbosity/mixed/both_kinds.py +0 -0
  270. {blockwatch_cli-0.14.2 → blockwatch_cli-0.16.0}/tests/verbosity.rs +0 -0
@@ -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 asks whether a value is one variant, and no new variant could be that
69
- one. For example, every Markdown heading is `mdast::Node::Heading`, so the other node types can go to `_ => None`.
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. `tag_parser` and
177
- `block_parser` turn the comment text into `Block` values, with their attributes and their byte and line ranges.
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
@@ -224,7 +225,8 @@ The main modules:
224
225
  - `src/repo_path.rs` — `RepoPath`, the one way to write a path relative to the repository root. A diff header
225
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
226
227
  always the same map key.
227
- - `src/language_parsers/` — one tree-sitter grammar for each language. Each language has a `parser()` that returns a
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
228
230
  `LanguageParser`, which knows which syntax nodes are comments. `src/block_parser.rs` turns those comments into
229
231
  blocks. `language_parsers()` in `language_parsers/mod.rs` returns `LanguageParsers`: the parser of each extension.
230
232
  Its `parser_for` picks the parser of a file, using the settings' extension mappings too. **To add a language, add a
@@ -238,8 +240,7 @@ The main modules:
238
240
  syntax tree is nested.
239
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
240
242
  express that.
241
- - Markdown finds its sections with the `markdown` crate. The `section` nodes of `tree-sitter-md` don't end at a
242
- heading underlined with `---`.
243
+ - Markdown finds its sections with the `markdown` crate, the same parser that finds its comments.
243
244
 
244
245
  Each language's tests list every symbol it finds. When you give a language symbols, also document its paths in
245
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,58 @@ 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.16.0] - 2026-10-24
16
+
17
+ ### Changed
18
+
19
+ - Without `same-as-pattern`, `same-as` compares each line that isn't blank as one value. Before, the whole block was
20
+ one value, so `same-as-mode` and `same-as-format` didn't work on a block of several lines. For example,
21
+ `same-as-mode="single"` passed with two lines, `subset` failed on a line that the target had, and `numeric` reported
22
+ that `1` and `2` together are not a number ([#179](https://github.com/mennanov/blockwatch/issues/179)).
23
+ - Without `same-as-mode`, a block without `same-as-pattern` compares in `sequence` mode. So it still fails when its
24
+ lines differ from the target's or come in another order. A block with a pattern still compares in `set` mode.
25
+ - A block without `same-as-pattern` now fails when its target's pattern finds a value more than once, or in another
26
+ order: `["1.2.3"] != ["1.2.3", "1.2.3"]`. Before, the default `set` mode ignored this. To keep the old result, add
27
+ `same-as-mode="set"`, or `same-as-mode="subset"` when the target may hold other values too.
28
+ - `same-as` now fails on two empty blocks, as it does on a pattern that matches nothing. The message for both is
29
+ `this block or its target has no values to compare`.
30
+ - `same-as-paths` no longer needs `same-as-pattern`. Without one, each line of the block must be a path, in sorted
31
+ order.
32
+ - An attribute that changes how a validator works now stops the run on a block without the validator's main
33
+ attribute. Before, it did nothing there. For example, `same-as-mode="sequence"` on a target let values in another
34
+ order pass. The attributes are:
35
+ - `same-as-mode` and `same-as-format`, without `same-as` or `same-as-paths`;
36
+ - `same-as-pattern`, without `same-as`, `same-as-paths` or `name`, because only a block with a name can be a target;
37
+ - `keep-sorted-pattern` and `keep-sorted-format`, without `keep-sorted`;
38
+ - `line-count-pattern`, without `line-count`;
39
+ - `check-ai-pattern`, without `check-ai`;
40
+ - `check-lua-pattern` and `check-lua-timeout`, without `check-lua`.
41
+
42
+ ### Fixed
43
+
44
+ - An empty alternative in braces now matches, so `{,sub/}a.yml` matches both `a.yml` and `sub/a.yml`. Before, it
45
+ matched only `sub/a.yml`, with no error. This was true of every glob: a `[[block]]` target, `same-as-paths`, the
46
+ `ignore` setting and `--ignore`, and a path argument ([#177](https://github.com/mennanov/blockwatch/issues/177)).
47
+
48
+ ## [0.15.0] - 2026-10-21
49
+
50
+ ### Changed
51
+
52
+ - 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
53
+ text. These were read as comments before and are not now:
54
+ - the alt text of an image: `![Logo <!-- x -->](logo.png)`;
55
+ - the title of a link: `[Docs](docs.md "<!-- x -->")`;
56
+ - an escaped `<`: `\<!-- x -->`.
57
+
58
+ In a line of text, `<!-->` is now a whole comment, so a tag after it on that line is not read.
59
+
60
+ ### Fixed
61
+
62
+ - In Markdown, blockwatch skipped every tag after a fenced code block that holds a line like `` ``` `` indented by 4
63
+ spaces or a tab, or `` echo x``` ``. Such a line closed the code block too early, so the rest of the file became
64
+ code. The run gave no error. Now such a line stays in the code block, as CommonMark says
65
+ ([#176](https://github.com/mennanov/blockwatch/issues/176)).
66
+
15
67
  ## [0.14.2] - 2026-10-21
16
68
 
17
69
  ### Added
@@ -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 asks whether a value is one variant, and no new variant could be that
69
- one. For example, every Markdown heading is `mdast::Node::Heading`, so the other node types can go to `_ => None`.
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. `tag_parser` and
177
- `block_parser` turn the comment text into `Block` values, with their attributes and their byte and line ranges.
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
@@ -224,7 +225,8 @@ The main modules:
224
225
  - `src/repo_path.rs` — `RepoPath`, the one way to write a path relative to the repository root. A diff header
225
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
226
227
  always the same map key.
227
- - `src/language_parsers/` — one tree-sitter grammar for each language. Each language has a `parser()` that returns a
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
228
230
  `LanguageParser`, which knows which syntax nodes are comments. `src/block_parser.rs` turns those comments into
229
231
  blocks. `language_parsers()` in `language_parsers/mod.rs` returns `LanguageParsers`: the parser of each extension.
230
232
  Its `parser_for` picks the parser of a file, using the settings' extension mappings too. **To add a language, add a
@@ -238,8 +240,7 @@ The main modules:
238
240
  syntax tree is nested.
239
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
240
242
  express that.
241
- - Markdown finds its sections with the `markdown` crate. The `section` nodes of `tree-sitter-md` don't end at a
242
- heading underlined with `---`.
243
+ - Markdown finds its sections with the `markdown` crate, the same parser that finds its comments.
243
244
 
244
245
  Each language's tests list every symbol it finds. When you give a language symbols, also document its paths in
245
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.14.2"
277
+ version = "0.16.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.14.2"
3
+ version = "0.16.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.14.2
3
+ Version: 0.16.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
@@ -218,7 +218,7 @@ exclusions, and custom extension mappings.
218
218
 
219
219
  ```yaml
220
220
  - repo: https://github.com/mennanov/blockwatch
221
- rev: v0.14.2 # Use latest release
221
+ rev: v0.16.0 # Use latest release
222
222
  hooks:
223
223
  - id: blockwatch
224
224
  ```
@@ -0,0 +1,11 @@
1
+ # The integration tests run inside this repository, so a run would read its blockwatch.toml, which
2
+ # skips tests/testdata.
3
+ disallowed-macros = [
4
+ { path = "assert_cmd::cargo_bin_cmd", reason = "use common::cargo_bin_cmd!, which passes an empty config" },
5
+ ]
6
+ # globset drops an empty alternative in braces by default, so `{,sub/}a.yml` would not match
7
+ # `a.yml`.
8
+ disallowed-methods = [
9
+ { path = "globset::Glob::new", reason = "use paths_glob::glob_builder, which keeps an empty alternative" },
10
+ { path = "globset::GlobBuilder::new", reason = "use paths_glob::glob_builder, which keeps an empty alternative" },
11
+ ]
@@ -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.2 # Use latest release
22
+ rev: v0.16.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.14.2 # Use latest release
62
+ rev: v0.16.0 # Use latest release
63
63
  hooks:
64
64
  - id: blockwatch-commit-msg
65
65
  ```
@@ -557,15 +557,15 @@ Nothing else about the run changes: the same violations are found, and the exit
557
557
  "tool": {
558
558
  "driver": {
559
559
  "name": "blockwatch",
560
- "version": "0.14.2",
561
- "semanticVersion": "0.14.2",
560
+ "version": "0.16.0",
561
+ "semanticVersion": "0.16.0",
562
562
  "informationUri": "https://github.com/mennanov/blockwatch",
563
563
  "rules": [
564
564
  {
565
565
  "id": "keep-sorted",
566
566
  "name": "keep-sorted",
567
567
  "shortDescription": { "text": "Requires the lines of a block to stay in order." },
568
- "helpUri": "https://github.com/mennanov/blockwatch/blob/v0.14.2/docs/validators/keep-sorted.md"
568
+ "helpUri": "https://github.com/mennanov/blockwatch/blob/v0.16.0/docs/validators/keep-sorted.md"
569
569
  }
570
570
  ]
571
571
  }
@@ -790,16 +790,16 @@ A trace stops where its validator stops, such as at the first line out of order.
790
790
  file, and `text` is that line trimmed, as the validator compares it. A key that holds what a violation reports has the
791
791
  name the violation's `data` gives it, such as `reason`.
792
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. |
793
+ | Validator | What it shows |
794
+ |----------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
795
+ | `same-as` | `records`: each match of `same-as-pattern` in the block, or each line without a pattern, with its `line`, the text the regex matched (`match`), and each named group after `same-as-format` (`groups`). `mode`: the `same-as-mode` it compared with. `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
803
 
804
804
  ## Run Reports
805
805
 
@@ -10,6 +10,9 @@ mention the company name", "no TODOs left", "the tone matches the rest of the pa
10
10
  | `check-ai` | the condition, in natural language | — |
11
11
  | `check-ai-pattern` | regex; every match's `(?P<value>…)` group, or whole match | whole block |
12
12
 
13
+ `check-ai-pattern` works only next to `check-ai`. On a block without it, it stops the run, because it would do nothing
14
+ there.
15
+
13
16
  ## Example
14
17
 
15
18
  ```html
@@ -19,6 +19,9 @@ string when it fails.
19
19
 
20
20
  <!-- </block> -->
21
21
 
22
+ `check-lua-pattern` and `check-lua-timeout` work only next to `check-lua`. On a block without it, they stop the run,
23
+ because they would do nothing there.
24
+
22
25
  The script path must point to a file inside the repository. Paths that escape it — absolute paths outside the project,
23
26
  `../` traversal, or symlinks pointing outward — are rejected.
24
27
 
@@ -10,6 +10,9 @@ Keeps a list ordered. Eliminates "please sort this" review nits.
10
10
  | `keep-sorted-pattern` | regex; the `(?P<value>…)` group, or the whole match | whole line |
11
11
  | `keep-sorted-format` | `numeric` | text |
12
12
 
13
+ `keep-sorted-pattern` and `keep-sorted-format` work only next to `keep-sorted`. On a block without it, they stop the
14
+ run, because they would do nothing there.
15
+
13
16
  ## Example
14
17
 
15
18
  ```python
@@ -10,6 +10,9 @@ size of the enum it maps.
10
10
  | `line-count` | `<N`, `<=N`, `==N`, `>=N`, `>N` | — |
11
11
  | `line-count-pattern` | regex; a line counts when it gives a value | every line that has text |
12
12
 
13
+ `line-count-pattern` works only next to `line-count`. On a block without it, it stops the run, because it would do
14
+ nothing there.
15
+
13
16
  ## Example
14
17
 
15
18
  ```python
@@ -8,13 +8,17 @@ It runs on every scan, with or without a diff.
8
8
 
9
9
  ## Syntax
10
10
 
11
- | Attribute | Value | Default |
12
- |-------------------|--------------------------------------------------------------------------------------|-------------------|
13
- | `same-as` | One or more [targets](#targets), comma-separated | — |
14
- | `same-as-paths` | A [glob](#paths-as-targets) of paths to compare | — |
15
- | `same-as-pattern` | A regex that picks the values to compare | the whole content |
16
- | `same-as-mode` | `set`, `sequence`, `single` or `subset` | `set` |
17
- | `same-as-format` | `numeric`, `identifier` or `flat`, or [one for each group](#a-format-for-each-group) | text |
11
+ | Attribute | Value | Default |
12
+ |-------------------|--------------------------------------------------------------------------------------|------------------------------------------|
13
+ | `same-as` | One or more [targets](#targets), comma-separated | — |
14
+ | `same-as-paths` | A [glob](#paths-as-targets) of paths to compare | — |
15
+ | `same-as-pattern` | A regex that picks the values to compare | each line |
16
+ | `same-as-mode` | `set`, `sequence`, `single` or `subset` | [`sequence` or `set`](#comparison-modes) |
17
+ | `same-as-format` | `numeric`, `identifier` or `flat`, or [one for each group](#a-format-for-each-group) | text |
18
+
19
+ `same-as-mode` and `same-as-format` work only next to `same-as` or `same-as-paths`. `same-as-pattern` also works next
20
+ to `name`, because a block with a name can be a target. On any other block, they stop the run, because they would do
21
+ nothing there.
18
22
 
19
23
  ## Targets
20
24
 
@@ -28,7 +32,8 @@ It runs on every scan, with or without a diff.
28
32
 
29
33
  ## Example
30
34
 
31
- With no other attributes, both blocks must hold **identical** text. Blank lines and indentation don't count. This suits
35
+ With no other attributes, both blocks must hold **identical** text: the same lines in the same order. Blank lines and
36
+ indentation don't count. This suits
32
37
  text you can't share any other way, such as a command shown in two docs:
33
38
 
34
39
  **README.md**:
@@ -145,7 +150,8 @@ pub const NODE_VERSION: &str = "20.11.1";
145
150
  ```
146
151
 
147
152
  The file has no block of its own, so the referencing block's pattern reads both sides. For anything longer than one
148
- line, you will want a pattern: without one, the block must equal the entire file.
153
+ line, you will want a pattern: without one, the block must equal the entire file. Or add `same-as-mode="subset"`: then
154
+ each line of the block must be a line of the file.
149
155
 
150
156
  ## Symbols as targets
151
157
 
@@ -187,10 +193,10 @@ show every entry of a directory, such as the services in a README:
187
193
  The glob lists `services/auth/`, `services/billing/` and `services/search/`. The pattern picks `auth`, `billing` and
188
194
  `search` from them, and `billing` and `search` from the block. So the run reports that `auth` is missing.
189
195
 
190
- - **`same-as-pattern` is required.** It reads both the block and the paths. To compare whole lines, use
191
- `same-as-pattern=".+"`.
192
- - **The paths are sorted, and each one is listed once.** So `same-as-mode="sequence"` also checks that the block
193
- lists them in that order.
196
+ - **The block's `same-as-pattern` reads both the block and the paths.** Without a pattern, each line of the block must
197
+ be a path, such as `services/billing/`.
198
+ - **The paths are sorted, and each one is listed once.** Without a pattern, or with `same-as-mode="sequence"`, the
199
+ block must list them in that order. To allow any order, add `same-as-mode="set"`.
194
200
  - **A trailing `/` lists directories.** A directory is listed when it holds a file, and `services/billing/` is listed
195
201
  once however many files it holds. Without the `/`, the glob lists files: `crates/*/AGENTS.md`.
196
202
  - **`*` stops at `/`.** `services/*/` lists `services/billing/`, but not `services/billing/src/`. `**` matches any
@@ -205,12 +211,22 @@ A block can have both `same-as` and `same-as-paths`. Each target is compared wit
205
211
 
206
212
  ## Comparison modes
207
213
 
208
- | `same-as-mode` | Passes when |
209
- |-----------------|-------------------------------------------------------------------|
210
- | `set` (default) | both sides hold the same values, in any order, ignoring repeats |
211
- | `sequence` | both sides hold the same values in the same order |
212
- | `single` | each side holds exactly one value, and the two are equal |
213
- | `subset` | every value in this block also appears in the target |
214
+ | `same-as-mode` | Passes when |
215
+ |----------------|-----------------------------------------------------------------|
216
+ | `set` | both sides hold the same values, in any order, ignoring repeats |
217
+ | `sequence` | both sides hold the same values in the same order |
218
+ | `single` | each side holds exactly one value, and the two are equal |
219
+ | `subset` | every value in this block also appears in the target |
220
+
221
+ Without `same-as-mode`, the mode depends on the block's own `same-as-pattern`. A target's pattern doesn't change it.
222
+
223
+ - **The block has no pattern:** `sequence`. Each line that isn't blank is a value, so the two sides must hold the same
224
+ lines in the same order, as in the [example](#example).
225
+ - **The block has a pattern:** `set`.
226
+
227
+ So adding a pattern stops order from mattering. To keep the order, add `same-as-mode="sequence"` too. And a block
228
+ without a pattern fails when its target's pattern finds a value twice: `["1.2.3"] != ["1.2.3", "1.2.3"]`. To allow
229
+ repeats, add `same-as-mode="set"` or `same-as-mode="subset"`.
214
230
 
215
231
  `subset` checks one direction only. Use it when one side should hold part of the other, like a test that uses only
216
232
  some of the environment variables:
@@ -356,14 +372,18 @@ const TIMEOUT_SECS: f64 = 2.0;
356
372
  ## Notes
357
373
 
358
374
  - **Which block's attributes count.** The referencing block's `same-as-mode` and `same-as-format` decide how to compare.
359
- Each block's `same-as-pattern` reads only that block. A whole file, a symbol or a list of paths has no block, so the
360
- referencing block's pattern reads it too.
375
+ On a target, or any block without `same-as` or `same-as-paths`, they stop the run, because they would do nothing
376
+ there. Each block's `same-as-pattern` reads only that block. A whole file, a symbol or a list of paths has no block,
377
+ so the referencing block's pattern reads it too. Only a block with a name can be a target, so `same-as-pattern` on a
378
+ block without `same-as`, `same-as-paths` or `name` stops the run.
361
379
  - **Violations:** a missing block, a missing or repeated key, a value that is not a number under `numeric`, a `single`
362
- side without exactly one value, a pattern that matches nothing on either side, two patterns with different groups,
363
- and a `same-as-paths` glob that matches no path. Two empty sides do not count as equal.
364
- - **Errors that stop the run:** an unknown `same-as-mode` or `same-as-format`, a `same-as-format` entry for a group
365
- that the pattern doesn't have, an invalid regex or glob, `same-as-paths` without `same-as-pattern`, a missing target
366
- file, and a symbol in a file with a syntax error, without symbols, or with several YAML documents.
380
+ side without exactly one value, a side with no values (such as an empty block, or a pattern that matches nothing),
381
+ two patterns with different groups, and a `same-as-paths` glob that matches no path. Two empty sides do not count as
382
+ equal.
383
+ - **Errors that stop the run:** an unknown `same-as-mode` or `same-as-format`, either of them on a block without
384
+ `same-as` or `same-as-paths`, `same-as-pattern` on a block without `same-as`, `same-as-paths` or `name`, a
385
+ `same-as-format` entry for a group that the pattern doesn't have, an invalid regex or glob, a missing target file,
386
+ and a symbol in a file with a syntax error, without symbols, or with several YAML documents.
367
387
  - **Run it on the whole tree now and then.** `same-as` needs no diff, so a plain `blockwatch` run catches drift that
368
388
  `--only-changed` misses. See [CI integration](../ci.md).
369
389
  - **A rename alone goes unnoticed in a diff.** Renaming a target file without changing it (a plain `git mv`) gives
@@ -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.14.2'],
9
+ install_requires=['blockwatch-cli==0.16.0'],
10
10
  # </block>
11
11
  # Without it, setuptools takes the directories under src/ for Python packages.
12
12
  packages=[],
@@ -13,6 +13,7 @@ use std::collections::{BTreeMap, BTreeSet, HashMap};
13
13
  use std::fmt;
14
14
  use std::ops::Range;
15
15
  use std::str::FromStr;
16
+ use strum::IntoEnumIterator;
16
17
  use strum_macros::EnumString;
17
18
 
18
19
  const UNNAMED_BLOCK_LABEL: &str = "(unnamed)";
@@ -496,11 +497,12 @@ const RECOGNIZED_ATTRIBUTES: &[&str] = &[
496
497
  // </block>
497
498
  ];
498
499
 
499
- /// Checks that each attribute of a block is recognized. It does not check the values: see
500
+ /// Checks that each attribute of a block is recognized, and that each validator accepts the
501
+ /// attributes it reads (see [`Validator::check_attributes`]). It does not check the values: see
500
502
  /// [`BlockSeverity::from_attributes`] for `severity`.
501
503
  ///
502
504
  /// # Errors
503
- /// Returns an error that quotes the attribute that is not recognized, such as
505
+ /// Returns an error that quotes the first attribute found to be wrong, such as
504
506
  /// ``unrecognized attribute `keep-sortd` ``.
505
507
  pub(crate) fn validate_attributes(attributes: &HashMap<String, String>) -> anyhow::Result<()> {
506
508
  if let Some(name) = attributes
@@ -509,7 +511,39 @@ pub(crate) fn validate_attributes(attributes: &HashMap<String, String>) -> anyho
509
511
  {
510
512
  bail!("unrecognized attribute `{name}`");
511
513
  }
512
- Ok(())
514
+ // A block can be in a file that the run reads only to find a target, and no validator runs on
515
+ // such a block. Every parsed block passes here.
516
+ Validator::iter().try_for_each(|validator| validator.check_attributes(attributes))
517
+ }
518
+
519
+ #[cfg(test)]
520
+ mod validate_attributes_tests {
521
+ use crate::blocks::{RECOGNIZED_ATTRIBUTES, validate_attributes};
522
+ use crate::validators::Validator;
523
+ use std::collections::HashMap;
524
+ use strum::IntoEnumIterator;
525
+
526
+ #[test]
527
+ fn single_attribute_returns_an_error_only_when_it_needs_another() {
528
+ // A new attribute must either work alone or stop the run alone. Otherwise a block with
529
+ // only that attribute would pass without being checked.
530
+ let needs_no_other: Vec<&str> = Validator::iter()
531
+ .map(Validator::as_str)
532
+ .chain([
533
+ "line-pattern-forbidden",
534
+ "name",
535
+ "same-as-paths",
536
+ "severity",
537
+ ])
538
+ .collect();
539
+ for name in RECOGNIZED_ATTRIBUTES {
540
+ let attributes = HashMap::from([(name.to_string(), String::new())]);
541
+
542
+ let result = validate_attributes(&attributes);
543
+
544
+ assert_eq!(result.is_ok(), needs_no_other.contains(name), "{name}");
545
+ }
546
+ }
513
547
  }
514
548
 
515
549
  #[cfg(test)]
@@ -272,7 +272,9 @@ fn is_entry_modified(
272
272
  /// - the target's file is a glob that is not valid or that matches no file;
273
273
  /// - `target-pattern` comes with a symbol, or is not a valid regex;
274
274
  /// - an attribute is not one a tag can have, or has a value that is not a string, `true` or an
275
- /// integer.
275
+ /// integer;
276
+ /// - an attribute comes without the attribute its validator needs, such as `check-lua-timeout`
277
+ /// without `check-lua`.
276
278
  fn entry_blocks(
277
279
  block_entry: BlockEntry,
278
280
  entry: ConfigEntry,
@@ -433,6 +435,7 @@ mod tests {
433
435
  target = 'package.json#/version'
434
436
  name = 'version'
435
437
  keep-unique = true
438
+ check-lua = 'check.lua'
436
439
  check-lua-timeout = 30
437
440
 
438
441
  [[block]]
@@ -450,6 +453,7 @@ target = 'a.yaml#/b'
450
453
  attributes: HashMap::from([
451
454
  ("name".to_string(), "version".to_string()),
452
455
  ("keep-unique".to_string(), String::new()),
456
+ ("check-lua".to_string(), "check.lua".to_string()),
453
457
  ("check-lua-timeout".to_string(), "30".to_string()),
454
458
  ]),
455
459
  entry: ConfigEntry {
@@ -465,7 +469,7 @@ target = 'a.yaml#/b'
465
469
  attributes: HashMap::new(),
466
470
  entry: ConfigEntry {
467
471
  file: PathBuf::from(DEFAULT_FILE),
468
- line: 9,
472
+ line: 10,
469
473
  },
470
474
  is_entry_modified: false,
471
475
  severity: BlockSeverity::Error,
@@ -263,7 +263,11 @@ impl PathFilter {
263
263
  fn glob_set(globs: impl IntoIterator<Item = impl AsRef<str>>) -> GlobSet {
264
264
  let mut builder = GlobSet::builder();
265
265
  for glob in globs {
266
- builder.add(globset::Glob::new(glob.as_ref()).expect("malformed test glob"));
266
+ builder.add(
267
+ crate::paths_glob::glob_builder(glob.as_ref())
268
+ .build()
269
+ .expect("malformed test glob"),
270
+ );
267
271
  }
268
272
  builder.build().expect("failed to build test glob set")
269
273
  }