rumdl 0.0.115__tar.gz → 0.0.116__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.

Potentially problematic release.


This version of rumdl might be problematic. Click here for more details.

Files changed (384) hide show
  1. {rumdl-0.0.115 → rumdl-0.0.116}/CHANGELOG.md +16 -1
  2. {rumdl-0.0.115 → rumdl-0.0.116}/Cargo.lock +1 -1
  3. {rumdl-0.0.115 → rumdl-0.0.116}/Cargo.toml +1 -1
  4. {rumdl-0.0.115 → rumdl-0.0.116}/PKG-INFO +1 -1
  5. {rumdl-0.0.115 → rumdl-0.0.116}/scripts/pre-release.sh +29 -6
  6. {rumdl-0.0.115 → rumdl-0.0.116}/src/lint_context.rs +57 -11
  7. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md020_no_missing_space_closed_atx.rs +15 -10
  8. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md026_no_trailing_punctuation/md026_config.rs +6 -1
  9. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md026_no_trailing_punctuation.rs +32 -148
  10. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md034_no_bare_urls.rs +9 -10
  11. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md051_link_fragments.rs +7 -1
  12. {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/kramdown_utils.rs +38 -1
  13. rumdl-0.0.116/tests/rules/md020_test.rs +267 -0
  14. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md026_kramdown_test.rs +45 -17
  15. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md026_test.rs +39 -92
  16. rumdl-0.0.116/tests/rules/md029_issue42_test.rs +320 -0
  17. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md034_test.rs +41 -0
  18. rumdl-0.0.115/tests/rules/md020_test.rs +0 -130
  19. {rumdl-0.0.115 → rumdl-0.0.116}/.config/nextest.toml +0 -0
  20. {rumdl-0.0.115 → rumdl-0.0.116}/.mise.toml +0 -0
  21. {rumdl-0.0.115 → rumdl-0.0.116}/.pre-commit-config.yaml +0 -0
  22. {rumdl-0.0.115 → rumdl-0.0.116}/.rumdl.toml +0 -0
  23. {rumdl-0.0.115 → rumdl-0.0.116}/.rustfmt.toml +0 -0
  24. {rumdl-0.0.115 → rumdl-0.0.116}/LICENSE +0 -0
  25. {rumdl-0.0.115 → rumdl-0.0.116}/MANIFEST.in +0 -0
  26. {rumdl-0.0.115 → rumdl-0.0.116}/Makefile +0 -0
  27. {rumdl-0.0.115 → rumdl-0.0.116}/README.md +0 -0
  28. {rumdl-0.0.115 → rumdl-0.0.116}/assets/logo.png +0 -0
  29. {rumdl-0.0.115 → rumdl-0.0.116}/benches/fix_performance.rs +0 -0
  30. {rumdl-0.0.115 → rumdl-0.0.116}/benches/range_performance.rs +0 -0
  31. {rumdl-0.0.115 → rumdl-0.0.116}/benches/range_utils_benchmark.rs +0 -0
  32. {rumdl-0.0.115 → rumdl-0.0.116}/benches/rule_performance.rs +0 -0
  33. {rumdl-0.0.115 → rumdl-0.0.116}/benches/simple_fix_bench.rs +0 -0
  34. {rumdl-0.0.115 → rumdl-0.0.116}/benchmark/bin/bench_lint_context.rs +0 -0
  35. {rumdl-0.0.115 → rumdl-0.0.116}/benchmark/bin/benchmark.rs +0 -0
  36. {rumdl-0.0.115 → rumdl-0.0.116}/benchmark/bin/benchmark_rule.rs +0 -0
  37. {rumdl-0.0.115 → rumdl-0.0.116}/benchmark/bin/file_parallel_benchmark.rs +0 -0
  38. {rumdl-0.0.115 → rumdl-0.0.116}/benchmark/bin/measure_code_span_performance.rs +0 -0
  39. {rumdl-0.0.115 → rumdl-0.0.116}/docs/RULES.md +0 -0
  40. {rumdl-0.0.115 → rumdl-0.0.116}/docs/global-settings.md +0 -0
  41. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md001.md +0 -0
  42. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md002.md +0 -0
  43. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md003.md +0 -0
  44. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md004.md +0 -0
  45. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md005.md +0 -0
  46. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md006.md +0 -0
  47. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md007.md +0 -0
  48. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md009.md +0 -0
  49. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md010.md +0 -0
  50. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md011.md +0 -0
  51. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md012.md +0 -0
  52. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md013.md +0 -0
  53. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md014.md +0 -0
  54. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md018.md +0 -0
  55. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md019.md +0 -0
  56. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md020.md +0 -0
  57. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md021.md +0 -0
  58. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md022.md +0 -0
  59. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md023.md +0 -0
  60. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md024.md +0 -0
  61. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md025.md +0 -0
  62. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md026.md +0 -0
  63. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md027.md +0 -0
  64. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md028.md +0 -0
  65. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md029.md +0 -0
  66. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md030.md +0 -0
  67. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md031.md +0 -0
  68. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md032.md +0 -0
  69. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md033.md +0 -0
  70. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md034.md +0 -0
  71. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md035.md +0 -0
  72. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md036.md +0 -0
  73. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md037.md +0 -0
  74. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md038.md +0 -0
  75. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md039.md +0 -0
  76. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md040.md +0 -0
  77. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md041.md +0 -0
  78. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md042.md +0 -0
  79. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md043.md +0 -0
  80. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md044.md +0 -0
  81. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md045.md +0 -0
  82. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md046.md +0 -0
  83. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md047.md +0 -0
  84. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md048.md +0 -0
  85. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md049.md +0 -0
  86. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md050.md +0 -0
  87. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md051.md +0 -0
  88. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md052.md +0 -0
  89. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md053.md +0 -0
  90. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md054.md +0 -0
  91. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md055.md +0 -0
  92. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md056.md +0 -0
  93. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md057.md +0 -0
  94. {rumdl-0.0.115 → rumdl-0.0.116}/docs/md058.md +0 -0
  95. {rumdl-0.0.115 → rumdl-0.0.116}/docs/vscode-extension.md +0 -0
  96. {rumdl-0.0.115 → rumdl-0.0.116}/parity_check.py +0 -0
  97. {rumdl-0.0.115 → rumdl-0.0.116}/pyproject.toml +0 -0
  98. {rumdl-0.0.115 → rumdl-0.0.116}/python/MANIFEST.in +0 -0
  99. {rumdl-0.0.115 → rumdl-0.0.116}/python/PYTHON-README.md +0 -0
  100. {rumdl-0.0.115 → rumdl-0.0.116}/python/rumdl/__init__.py +0 -0
  101. {rumdl-0.0.115 → rumdl-0.0.116}/python/rumdl/__main__.py +0 -0
  102. {rumdl-0.0.115 → rumdl-0.0.116}/python/rumdl/py.typed +0 -0
  103. {rumdl-0.0.115 → rumdl-0.0.116}/rumdl.toml.example +0 -0
  104. {rumdl-0.0.115 → rumdl-0.0.116}/rust-toolchain.toml +0 -0
  105. {rumdl-0.0.115 → rumdl-0.0.116}/scripts/extract-changelog.sh +0 -0
  106. {rumdl-0.0.115 → rumdl-0.0.116}/scripts/generate-downloads-table.sh +0 -0
  107. {rumdl-0.0.115 → rumdl-0.0.116}/scripts/prepare-release.sh +0 -0
  108. {rumdl-0.0.115 → rumdl-0.0.116}/scripts/setup-pre-commit.sh +0 -0
  109. {rumdl-0.0.115 → rumdl-0.0.116}/scripts/update-pre-commit-docs.sh +0 -0
  110. {rumdl-0.0.115 → rumdl-0.0.116}/src/config.rs +0 -0
  111. {rumdl-0.0.115 → rumdl-0.0.116}/src/exit_codes.rs +0 -0
  112. {rumdl-0.0.115 → rumdl-0.0.116}/src/inline_config.rs +0 -0
  113. {rumdl-0.0.115 → rumdl-0.0.116}/src/lib.rs +0 -0
  114. {rumdl-0.0.115 → rumdl-0.0.116}/src/lsp/mod.rs +0 -0
  115. {rumdl-0.0.115 → rumdl-0.0.116}/src/lsp/server.rs +0 -0
  116. {rumdl-0.0.115 → rumdl-0.0.116}/src/lsp/types.rs +0 -0
  117. {rumdl-0.0.115 → rumdl-0.0.116}/src/main.rs +0 -0
  118. {rumdl-0.0.115 → rumdl-0.0.116}/src/markdownlint_config.rs +0 -0
  119. {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/azure.rs +0 -0
  120. {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/concise.rs +0 -0
  121. {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/github.rs +0 -0
  122. {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/gitlab.rs +0 -0
  123. {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/grouped.rs +0 -0
  124. {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/json.rs +0 -0
  125. {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/json_lines.rs +0 -0
  126. {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/junit.rs +0 -0
  127. {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/mod.rs +0 -0
  128. {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/pylint.rs +0 -0
  129. {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/sarif.rs +0 -0
  130. {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/text.rs +0 -0
  131. {rumdl-0.0.115 → rumdl-0.0.116}/src/output/mod.rs +0 -0
  132. {rumdl-0.0.115 → rumdl-0.0.116}/src/parallel.rs +0 -0
  133. {rumdl-0.0.115 → rumdl-0.0.116}/src/performance.rs +0 -0
  134. {rumdl-0.0.115 → rumdl-0.0.116}/src/profiling.rs +0 -0
  135. {rumdl-0.0.115 → rumdl-0.0.116}/src/python.rs +0 -0
  136. {rumdl-0.0.115 → rumdl-0.0.116}/src/rule.rs +0 -0
  137. {rumdl-0.0.115 → rumdl-0.0.116}/src/rule_config.rs +0 -0
  138. {rumdl-0.0.115 → rumdl-0.0.116}/src/rule_config_serde.rs +0 -0
  139. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/blockquote_utils.rs +0 -0
  140. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/code_block_utils.rs +0 -0
  141. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/code_fence_utils.rs +0 -0
  142. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/emphasis_style.rs +0 -0
  143. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/front_matter_utils.rs +0 -0
  144. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/heading_utils.rs +0 -0
  145. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/list_utils.rs +0 -0
  146. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md001_heading_increment.rs +0 -0
  147. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md002_first_heading_h1/md002_config.rs +0 -0
  148. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md002_first_heading_h1.rs +0 -0
  149. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md003_heading_style/md003_config.rs +0 -0
  150. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md003_heading_style.rs +0 -0
  151. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md004_unordered_list_style/md004_config.rs +0 -0
  152. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md004_unordered_list_style.rs +0 -0
  153. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md005_list_indent.rs +0 -0
  154. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md006_start_bullets.rs +0 -0
  155. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md007_ul_indent/md007_config.rs +0 -0
  156. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md007_ul_indent.rs +0 -0
  157. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md009_trailing_spaces/md009_config.rs +0 -0
  158. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md009_trailing_spaces.rs +0 -0
  159. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md010_no_hard_tabs/md010_config.rs +0 -0
  160. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md010_no_hard_tabs.rs +0 -0
  161. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md011_no_reversed_links.rs +0 -0
  162. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md012_no_multiple_blanks/md012_config.rs +0 -0
  163. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md012_no_multiple_blanks.rs +0 -0
  164. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md013_line_length/md013_config.rs +0 -0
  165. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md013_line_length.rs +0 -0
  166. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md014_commands_show_output/md014_config.rs +0 -0
  167. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md014_commands_show_output.rs +0 -0
  168. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md018_no_missing_space_atx.rs +0 -0
  169. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md019_no_multiple_space_atx.rs +0 -0
  170. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md021_no_multiple_space_closed_atx.rs +0 -0
  171. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md022_blanks_around_headings/md022_config.rs +0 -0
  172. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md022_blanks_around_headings.rs +0 -0
  173. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md023_heading_start_left.rs +0 -0
  174. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md024_no_duplicate_heading/md024_config.rs +0 -0
  175. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md024_no_duplicate_heading.rs +0 -0
  176. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md025_single_title/md025_config.rs +0 -0
  177. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md025_single_title.rs +0 -0
  178. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md027_multiple_spaces_blockquote.rs +0 -0
  179. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md028_no_blanks_blockquote.rs +0 -0
  180. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md029_ordered_list_prefix/md029_config.rs +0 -0
  181. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md029_ordered_list_prefix.rs +0 -0
  182. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md030_list_marker_space/md030_config.rs +0 -0
  183. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md030_list_marker_space.rs +0 -0
  184. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md031_blanks_around_fences.rs +0 -0
  185. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md032_blanks_around_lists.rs +0 -0
  186. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md033_no_inline_html/md033_config.rs +0 -0
  187. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md033_no_inline_html.rs +0 -0
  188. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md035_hr_style/md035_config.rs +0 -0
  189. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md035_hr_style.rs +0 -0
  190. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md036_no_emphasis_only_first/md036_config.rs +0 -0
  191. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md036_no_emphasis_only_first.rs +0 -0
  192. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md037_spaces_around_emphasis.rs +0 -0
  193. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md038_no_space_in_code.rs +0 -0
  194. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md039_no_space_in_links.rs +0 -0
  195. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md040_fenced_code_language.rs +0 -0
  196. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md041_first_line_heading.rs +0 -0
  197. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md042_no_empty_links.rs +0 -0
  198. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md043_required_headings.rs +0 -0
  199. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md044_proper_names/md044_config.rs +0 -0
  200. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md044_proper_names.rs +0 -0
  201. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md045_no_alt_text/md045_config.rs +0 -0
  202. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md045_no_alt_text.rs +0 -0
  203. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md046_code_block_style/md046_config.rs +0 -0
  204. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md046_code_block_style.rs +0 -0
  205. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md047_single_trailing_newline.rs +0 -0
  206. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md048_code_fence_style/md048_config.rs +0 -0
  207. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md048_code_fence_style.rs +0 -0
  208. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md049_emphasis_style/md049_config.rs +0 -0
  209. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md049_emphasis_style.rs +0 -0
  210. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md050_strong_style/md050_config.rs +0 -0
  211. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md050_strong_style.rs +0 -0
  212. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md052_reference_links_images.rs +0 -0
  213. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md053_link_image_reference_definitions.rs +0 -0
  214. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md054_link_image_style/md054_config.rs +0 -0
  215. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md054_link_image_style.rs +0 -0
  216. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md055_table_pipe_style/md055_config.rs +0 -0
  217. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md055_table_pipe_style.rs +0 -0
  218. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md056_table_column_count.rs +0 -0
  219. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md057_existing_relative_links/md057_config.rs +0 -0
  220. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md057_existing_relative_links.rs +0 -0
  221. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md058_blanks_around_tables.rs +0 -0
  222. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/mod.rs +0 -0
  223. {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/strong_style.rs +0 -0
  224. {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/ast_utils.rs +0 -0
  225. {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/code_block_utils.rs +0 -0
  226. {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/document_structure.rs +0 -0
  227. {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/early_returns.rs +0 -0
  228. {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/element_cache.rs +0 -0
  229. {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/emphasis_utils.rs +0 -0
  230. {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/fix_utils.rs +0 -0
  231. {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/markdown_elements.rs +0 -0
  232. {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/mod.rs +0 -0
  233. {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/range_utils.rs +0 -0
  234. {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/regex_cache.rs +0 -0
  235. {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/string_interner.rs +0 -0
  236. {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/table_utils.rs +0 -0
  237. {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/text_reflow.rs +0 -0
  238. {rumdl-0.0.115 → rumdl-0.0.116}/src/vscode.rs +0 -0
  239. {rumdl-0.0.115 → rumdl-0.0.116}/tests/advanced_integration_tests.rs +0 -0
  240. {rumdl-0.0.115 → rumdl-0.0.116}/tests/character_ranges/additional_tests.rs +0 -0
  241. {rumdl-0.0.115 → rumdl-0.0.116}/tests/character_ranges/basic_tests.rs +0 -0
  242. {rumdl-0.0.115 → rumdl-0.0.116}/tests/character_ranges/comprehensive_tests.rs +0 -0
  243. {rumdl-0.0.115 → rumdl-0.0.116}/tests/character_ranges/extended_tests.rs +0 -0
  244. {rumdl-0.0.115 → rumdl-0.0.116}/tests/character_ranges/mod.rs +0 -0
  245. {rumdl-0.0.115 → rumdl-0.0.116}/tests/character_ranges/unicode_utils.rs +0 -0
  246. {rumdl-0.0.115 → rumdl-0.0.116}/tests/cli_duplication_test.rs +0 -0
  247. {rumdl-0.0.115 → rumdl-0.0.116}/tests/cli_explain_test.rs +0 -0
  248. {rumdl-0.0.115 → rumdl-0.0.116}/tests/cli_flag_precedence_test.rs +0 -0
  249. {rumdl-0.0.115 → rumdl-0.0.116}/tests/cli_integration_tests.rs +0 -0
  250. {rumdl-0.0.115 → rumdl-0.0.116}/tests/cli_lsp_fix_consistency.rs +0 -0
  251. {rumdl-0.0.115 → rumdl-0.0.116}/tests/cli_statistics_test.rs +0 -0
  252. {rumdl-0.0.115 → rumdl-0.0.116}/tests/common/cli_test_utils.rs +0 -0
  253. {rumdl-0.0.115 → rumdl-0.0.116}/tests/common/fixtures.rs +0 -0
  254. {rumdl-0.0.115 → rumdl-0.0.116}/tests/common/mod.rs +0 -0
  255. {rumdl-0.0.115 → rumdl-0.0.116}/tests/common/test_utils.rs +0 -0
  256. {rumdl-0.0.115 → rumdl-0.0.116}/tests/commonmark_compliance_tests.rs +0 -0
  257. {rumdl-0.0.115 → rumdl-0.0.116}/tests/comprehensive_integration_tests.rs +0 -0
  258. {rumdl-0.0.115 → rumdl-0.0.116}/tests/comprehensive_output_format_tests.rs +0 -0
  259. {rumdl-0.0.115 → rumdl-0.0.116}/tests/config_application_tests.rs +0 -0
  260. {rumdl-0.0.115 → rumdl-0.0.116}/tests/config_file_command_test.rs +0 -0
  261. {rumdl-0.0.115 → rumdl-0.0.116}/tests/config_tests.rs +0 -0
  262. {rumdl-0.0.115 → rumdl-0.0.116}/tests/configuration_inheritance_tests.rs +0 -0
  263. {rumdl-0.0.115 → rumdl-0.0.116}/tests/consistency_regression_tests.rs +0 -0
  264. {rumdl-0.0.115 → rumdl-0.0.116}/tests/cross_platform_compatibility_tests.rs +0 -0
  265. {rumdl-0.0.115 → rumdl-0.0.116}/tests/deeply_nested_lists_performance_test.rs +0 -0
  266. {rumdl-0.0.115 → rumdl-0.0.116}/tests/escaped_brackets_test.rs +0 -0
  267. {rumdl-0.0.115 → rumdl-0.0.116}/tests/final_confidence_assessment.rs +0 -0
  268. {rumdl-0.0.115 → rumdl-0.0.116}/tests/fixable_unfixable_config_test.rs +0 -0
  269. {rumdl-0.0.115 → rumdl-0.0.116}/tests/init_command_test.rs +0 -0
  270. {rumdl-0.0.115 → rumdl-0.0.116}/tests/init_tests.rs +0 -0
  271. {rumdl-0.0.115 → rumdl-0.0.116}/tests/inline_config_blocks_test.rs +0 -0
  272. {rumdl-0.0.115 → rumdl-0.0.116}/tests/inline_config_test.rs +0 -0
  273. {rumdl-0.0.115 → rumdl-0.0.116}/tests/integration_tests.rs +0 -0
  274. {rumdl-0.0.115 → rumdl-0.0.116}/tests/json_output_test.rs +0 -0
  275. {rumdl-0.0.115 → rumdl-0.0.116}/tests/kramdown_integration_test.rs +0 -0
  276. {rumdl-0.0.115 → rumdl-0.0.116}/tests/lib.rs +0 -0
  277. {rumdl-0.0.115 → rumdl-0.0.116}/tests/lsp_editor_integration_tests.rs +0 -0
  278. {rumdl-0.0.115 → rumdl-0.0.116}/tests/lsp_integration_tests.rs +0 -0
  279. {rumdl-0.0.115 → rumdl-0.0.116}/tests/lsp_memory_leak_tests.rs +0 -0
  280. {rumdl-0.0.115 → rumdl-0.0.116}/tests/lsp_tests.rs +0 -0
  281. {rumdl-0.0.115 → rumdl-0.0.116}/tests/malformed_markdown_stress_tests.rs +0 -0
  282. {rumdl-0.0.115 → rumdl-0.0.116}/tests/markdownlint_cli_integration.rs +0 -0
  283. {rumdl-0.0.115 → rumdl-0.0.116}/tests/markdownlint_config_test.rs +0 -0
  284. {rumdl-0.0.115 → rumdl-0.0.116}/tests/markdownlintignore_test.rs +0 -0
  285. {rumdl-0.0.115 → rumdl-0.0.116}/tests/md013_reflow_integration_test.rs +0 -0
  286. {rumdl-0.0.115 → rumdl-0.0.116}/tests/nested_code_block_test.rs +0 -0
  287. {rumdl-0.0.115 → rumdl-0.0.116}/tests/output_format_integration_tests.rs +0 -0
  288. {rumdl-0.0.115 → rumdl-0.0.116}/tests/output_format_tests.rs +0 -0
  289. {rumdl-0.0.115 → rumdl-0.0.116}/tests/perf_check.rs +0 -0
  290. {rumdl-0.0.115 → rumdl-0.0.116}/tests/performance_validation_tests.rs +0 -0
  291. {rumdl-0.0.115 → rumdl-0.0.116}/tests/pyproject_config_tests.rs +0 -0
  292. {rumdl-0.0.115 → rumdl-0.0.116}/tests/python_bindings_test.rs +0 -0
  293. {rumdl-0.0.115 → rumdl-0.0.116}/tests/real_world_repository_tests.rs +0 -0
  294. {rumdl-0.0.115 → rumdl-0.0.116}/tests/regression_prevention_tests.rs +0 -0
  295. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/emphasis_edge_cases_test.rs +0 -0
  296. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/heading_edge_cases_test.rs +0 -0
  297. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/inline_content_edge_cases_test.rs +0 -0
  298. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/link_edge_cases_test.rs +0 -0
  299. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/list_rules_integration_test.rs +0 -0
  300. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md001_test.rs +0 -0
  301. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md001_unicode_test.rs +0 -0
  302. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md002_test.rs +0 -0
  303. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md003_test.rs +0 -0
  304. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md004_test.rs +0 -0
  305. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md005_test.rs +0 -0
  306. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md005_unicode_test.rs +0 -0
  307. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md006_test.rs +0 -0
  308. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md006_unicode_test.rs +0 -0
  309. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md007_test.rs +0 -0
  310. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md009_test.rs +0 -0
  311. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md010_test.rs +0 -0
  312. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md011_test.rs +0 -0
  313. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md012_test.rs +0 -0
  314. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md013_test.rs +0 -0
  315. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md014_test.rs +0 -0
  316. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md018_test.rs +0 -0
  317. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md019_test.rs +0 -0
  318. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md021_test.rs +0 -0
  319. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md022_test.rs +0 -0
  320. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md023_extended_test.rs +0 -0
  321. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md023_test.rs +0 -0
  322. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md024_test.rs +0 -0
  323. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md025_test.rs +0 -0
  324. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md027_test.rs +0 -0
  325. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md028_test.rs +0 -0
  326. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md029_test.rs +0 -0
  327. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md029_unicode_test.rs +0 -0
  328. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md030_test.rs +0 -0
  329. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md031_kramdown_test.rs +0 -0
  330. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md031_test.rs +0 -0
  331. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md032_test.rs +0 -0
  332. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md033_extended_test.rs +0 -0
  333. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md033_kramdown_test.rs +0 -0
  334. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md033_test.rs +0 -0
  335. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md034_ipv6_test.rs +0 -0
  336. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md035_test.rs +0 -0
  337. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md036_test.rs +0 -0
  338. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md037_kramdown_test.rs +0 -0
  339. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md037_test.rs +0 -0
  340. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md038_nested_backticks_test.rs +0 -0
  341. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md038_test.rs +0 -0
  342. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md039_test.rs +0 -0
  343. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md040_test.rs +0 -0
  344. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md041_test.rs +0 -0
  345. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md042_test.rs +0 -0
  346. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md043_test.rs +0 -0
  347. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md044_test.rs +0 -0
  348. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md045_test.rs +0 -0
  349. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md046_test.rs +0 -0
  350. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md047_test.rs +0 -0
  351. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md048_test.rs +0 -0
  352. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md049_test.rs +0 -0
  353. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md050_test.rs +0 -0
  354. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md051_test.rs +0 -0
  355. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md051_unicode_test.rs +0 -0
  356. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md052_test.rs +0 -0
  357. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md053_additional_test.rs +0 -0
  358. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md053_proptest.rs +0 -0
  359. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md053_test.rs +0 -0
  360. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md054_test.rs +0 -0
  361. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md054_unicode_test.rs +0 -0
  362. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md055_test.rs +0 -0
  363. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md056_test.rs +0 -0
  364. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md057_test.rs +0 -0
  365. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md058_kramdown_test.rs +0 -0
  366. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md058_test.rs +0 -0
  367. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/mod.rs +0 -0
  368. {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules_mod_test.rs +0 -0
  369. {rumdl-0.0.115 → rumdl-0.0.116}/tests/thread_safety_tests.rs +0 -0
  370. {rumdl-0.0.115 → rumdl-0.0.116}/tests/unicode_edge_case_tests.rs +0 -0
  371. {rumdl-0.0.115 → rumdl-0.0.116}/tests/utils/blockquote_utils_test.rs +0 -0
  372. {rumdl-0.0.115 → rumdl-0.0.116}/tests/utils/code_block_utils_extended_test.rs +0 -0
  373. {rumdl-0.0.115 → rumdl-0.0.116}/tests/utils/code_block_utils_test.rs +0 -0
  374. {rumdl-0.0.115 → rumdl-0.0.116}/tests/utils/core_utils_test.rs +0 -0
  375. {rumdl-0.0.115 → rumdl-0.0.116}/tests/utils/front_matter_utils_test.rs +0 -0
  376. {rumdl-0.0.115 → rumdl-0.0.116}/tests/utils/line_index_test.rs +0 -0
  377. {rumdl-0.0.115 → rumdl-0.0.116}/tests/utils/mod.rs +0 -0
  378. {rumdl-0.0.115 → rumdl-0.0.116}/tests/utils_markdown_edge_cases.rs +0 -0
  379. {rumdl-0.0.115 → rumdl-0.0.116}/tests/utils_tests.rs +0 -0
  380. {rumdl-0.0.115 → rumdl-0.0.116}/tests/vscode_extension_fixes.rs +0 -0
  381. {rumdl-0.0.115 → rumdl-0.0.116}/tests/vscode_test.rs +0 -0
  382. {rumdl-0.0.115 → rumdl-0.0.116}/tests/vscode_tests.rs +0 -0
  383. {rumdl-0.0.115 → rumdl-0.0.116}/tests/vscode_windows_comprehensive_test.rs +0 -0
  384. {rumdl-0.0.115 → rumdl-0.0.116}/tests/vscode_windows_test.rs +0 -0
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.0.116] - 2025-08-13
11
+
12
+ ### Added
13
+ - Kramdown-style custom header IDs support (#44)
14
+ - Headers can now have custom IDs using the `{#custom-id}` syntax
15
+ - Custom IDs are preserved when fixing MD051 (link fragments)
16
+ - MD026 (trailing punctuation) now ignores headers with custom IDs
17
+ - Safe character validation: accepts Unicode letters/numbers, hyphens, underscores, and colons
18
+ - Rejects problematic characters like spaces, quotes, brackets, and HTML/CSS special chars
19
+
20
+ ### Fixed
21
+ - Pre-release script now correctly handles dynamic versioning in pyproject.toml
22
+ - Added Cargo.lock validation and `cargo publish --dry-run` checks to prevent release failures
23
+
10
24
  ## [0.0.115] - 2025-08-12
11
25
 
12
26
  ## [0.0.114] - 2025-08-09
@@ -310,7 +324,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
310
324
 
311
325
  - Initial implementation of remaining rules for markdownlint parity
312
326
 
313
- [Unreleased]: https://github.com/rvben/rumdl/compare/v0.0.115...HEAD
327
+ [Unreleased]: https://github.com/rvben/rumdl/compare/v0.0.116...HEAD
328
+ [0.0.116]: https://github.com/rvben/rumdl/compare/v0.0.115...v0.0.116
314
329
  [0.0.115]: https://github.com/rvben/rumdl/compare/v0.0.114...v0.0.115
315
330
  [0.0.114]: https://github.com/rvben/rumdl/compare/v0.0.113...v0.0.114
316
331
  [0.0.113]: https://github.com/rvben/rumdl/compare/v0.0.112...v0.0.113
@@ -1493,7 +1493,7 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
1493
1493
 
1494
1494
  [[package]]
1495
1495
  name = "rumdl"
1496
- version = "0.0.115"
1496
+ version = "0.0.116"
1497
1497
  dependencies = [
1498
1498
  "anyhow",
1499
1499
  "assert_cmd",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "rumdl"
3
- version = "0.0.115"
3
+ version = "0.0.116"
4
4
  edition = "2024"
5
5
  rust-version = "1.89.0"
6
6
  description = "A fast Markdown linter written in Rust (Ru(st) MarkDown Linter)"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rumdl
3
- Version: 0.0.115
3
+ Version: 0.0.116
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -73,15 +73,24 @@ run_check "Release build" "cargo build --release"
73
73
  echo "6. Checking documentation..."
74
74
  run_check "Documentation" "cargo doc --no-deps"
75
75
 
76
- # 7. Verify Cargo.toml version
76
+ # 7. Verify Cargo.toml version (pyproject.toml uses dynamic versioning from Cargo.toml)
77
77
  echo "7. Checking version consistency..."
78
78
  CARGO_VERSION=$(grep '^version' Cargo.toml | head -1 | cut -d'"' -f2)
79
- PY_VERSION=$(grep '^version' pyproject.toml | head -1 | cut -d'"' -f2)
80
- if [ "$CARGO_VERSION" != "$PY_VERSION" ]; then
81
- echo -e "${RED}Version mismatch: Cargo.toml ($CARGO_VERSION) vs pyproject.toml ($PY_VERSION)${NC}"
82
- FAILED=1
79
+ # pyproject.toml uses dynamic = ["version"] to read from Cargo.toml
80
+ if grep -q 'dynamic = \["version"\]' pyproject.toml; then
81
+ echo -e "${GREEN}✓${NC} Version $CARGO_VERSION (pyproject.toml uses dynamic versioning)"
83
82
  else
84
- echo -e "${GREEN}✓${NC} Version $CARGO_VERSION is consistent"
83
+ # Fallback: check if there's a static version in pyproject.toml
84
+ PY_VERSION=$(grep '^version' pyproject.toml | head -1 | cut -d'"' -f2)
85
+ if [ -z "$PY_VERSION" ]; then
86
+ echo -e "${YELLOW}⚠${NC} pyproject.toml should use dynamic = [\"version\"] for version"
87
+ # Not a failure, just a warning
88
+ elif [ "$CARGO_VERSION" != "$PY_VERSION" ]; then
89
+ echo -e "${RED}Version mismatch: Cargo.toml ($CARGO_VERSION) vs pyproject.toml ($PY_VERSION)${NC}"
90
+ FAILED=1
91
+ else
92
+ echo -e "${GREEN}✓${NC} Version $CARGO_VERSION is consistent"
93
+ fi
85
94
  fi
86
95
 
87
96
  # 8. Check for uncommitted changes
@@ -111,6 +120,20 @@ else
111
120
  echo -e "${GREEN}✓${NC} Tag $TAG_VERSION is available"
112
121
  fi
113
122
 
123
+ # 11. Verify Cargo.lock is up to date
124
+ echo "11. Verifying Cargo.lock is up to date..."
125
+ if cargo update --workspace --dry-run 2>&1 | grep -q "Updating"; then
126
+ echo -e "${RED}✗ Cargo.lock needs updating${NC}"
127
+ echo " Run: cargo update --workspace"
128
+ FAILED=1
129
+ else
130
+ echo -e "${GREEN}✓${NC} Cargo.lock is up to date"
131
+ fi
132
+
133
+ # 12. Test cargo publish with --dry-run
134
+ echo "12. Testing cargo publish (dry run)..."
135
+ run_check "Cargo publish dry-run" "cargo publish --dry-run --locked"
136
+
114
137
  echo ""
115
138
  echo "====================================="
116
139
  if [ $FAILED -eq 0 ]; then
@@ -197,8 +197,12 @@ pub struct HeadingInfo {
197
197
  pub marker_column: usize,
198
198
  /// Column where heading text starts
199
199
  pub content_column: usize,
200
- /// The heading text (without markers)
200
+ /// The heading text (without markers and without custom ID syntax)
201
201
  pub text: String,
202
+ /// Custom header ID if present (e.g., from {#custom-id} syntax)
203
+ pub custom_id: Option<String>,
204
+ /// Original heading text including custom ID syntax
205
+ pub raw_text: String,
202
206
  /// Whether it has a closing sequence (for ATX)
203
207
  pub has_closing_sequence: bool,
204
208
  /// The closing sequence if present
@@ -1088,10 +1092,23 @@ impl<'a> LintContext<'a> {
1088
1092
  let level = hashes.len() as u8;
1089
1093
  let marker_column = leading_spaces.len();
1090
1094
 
1091
- // Check for closing sequence
1095
+ // Check for closing sequence, but handle custom IDs that might come after
1092
1096
  let (text, has_closing, closing_seq) = {
1093
- // Find the start of a potential closing sequence
1094
- let trimmed_rest = rest.trim_end();
1097
+ // First check if there's a custom ID at the end
1098
+ let (rest_without_id, custom_id_part) = if let Some(id_start) = rest.rfind(" {#") {
1099
+ // Check if this looks like a valid custom ID (ends with })
1100
+ if rest[id_start..].trim_end().ends_with('}') {
1101
+ // Split off the custom ID
1102
+ (&rest[..id_start], &rest[id_start..])
1103
+ } else {
1104
+ (rest, "")
1105
+ }
1106
+ } else {
1107
+ (rest, "")
1108
+ };
1109
+
1110
+ // Now look for closing hashes in the part before the custom ID
1111
+ let trimmed_rest = rest_without_id.trim_end();
1095
1112
  if let Some(last_hash_pos) = trimmed_rest.rfind('#') {
1096
1113
  // Look for the start of the hash sequence
1097
1114
  let mut start_of_hashes = last_hash_pos;
@@ -1099,32 +1116,55 @@ impl<'a> LintContext<'a> {
1099
1116
  start_of_hashes -= 1;
1100
1117
  }
1101
1118
 
1102
- // Check if this is a valid closing sequence (all hashes to end of line)
1119
+ // Check if there's at least one space before the closing hashes
1120
+ let has_space_before = start_of_hashes == 0
1121
+ || trimmed_rest
1122
+ .chars()
1123
+ .nth(start_of_hashes - 1)
1124
+ .is_some_and(|c| c.is_whitespace());
1125
+
1126
+ // Check if this is a valid closing sequence (all hashes to end of trimmed part)
1103
1127
  let potential_closing = &trimmed_rest[start_of_hashes..];
1104
1128
  let is_all_hashes = potential_closing.chars().all(|c| c == '#');
1105
1129
 
1106
- if is_all_hashes {
1107
- // This is a closing sequence, regardless of spacing
1130
+ if is_all_hashes && has_space_before {
1131
+ // This is a closing sequence
1108
1132
  let closing_hashes = potential_closing.to_string();
1109
- let text_part = rest[..start_of_hashes].trim_end();
1110
- (text_part.to_string(), true, closing_hashes)
1133
+ // The text is everything before the closing hashes
1134
+ // Don't include the custom ID here - it will be extracted later
1135
+ let text_part = if !custom_id_part.is_empty() {
1136
+ // If we have a custom ID, append it back to get the full rest
1137
+ // This allows the extract_header_id function to handle it properly
1138
+ format!("{}{}", rest_without_id[..start_of_hashes].trim_end(), custom_id_part)
1139
+ } else {
1140
+ rest_without_id[..start_of_hashes].trim_end().to_string()
1141
+ };
1142
+ (text_part, true, closing_hashes)
1111
1143
  } else {
1144
+ // Not a valid closing sequence, return the full content
1112
1145
  (rest.to_string(), false, String::new())
1113
1146
  }
1114
1147
  } else {
1148
+ // No hashes found, return the full content
1115
1149
  (rest.to_string(), false, String::new())
1116
1150
  }
1117
1151
  };
1118
1152
 
1119
1153
  let content_column = marker_column + hashes.len() + spaces_after.len();
1120
1154
 
1155
+ // Extract custom header ID if present
1156
+ let raw_text = text.trim().to_string();
1157
+ let (clean_text, custom_id) = crate::utils::kramdown_utils::extract_header_id(&raw_text);
1158
+
1121
1159
  lines[i].heading = Some(HeadingInfo {
1122
1160
  level,
1123
1161
  style: HeadingStyle::ATX,
1124
1162
  marker: hashes.to_string(),
1125
1163
  marker_column,
1126
1164
  content_column,
1127
- text: text.trim().to_string(),
1165
+ text: clean_text,
1166
+ custom_id,
1167
+ raw_text,
1128
1168
  has_closing_sequence: has_closing,
1129
1169
  closing_sequence: closing_seq,
1130
1170
  });
@@ -1146,13 +1186,19 @@ impl<'a> LintContext<'a> {
1146
1186
  HeadingStyle::Setext2
1147
1187
  };
1148
1188
 
1189
+ // Extract custom header ID if present
1190
+ let raw_text = line.trim().to_string();
1191
+ let (clean_text, custom_id) = crate::utils::kramdown_utils::extract_header_id(&raw_text);
1192
+
1149
1193
  lines[i].heading = Some(HeadingInfo {
1150
1194
  level,
1151
1195
  style,
1152
1196
  marker: underline.to_string(),
1153
1197
  marker_column: next_line.len() - next_line.trim_start().len(),
1154
1198
  content_column: lines[i].indent,
1155
- text: line.trim().to_string(),
1199
+ text: clean_text,
1200
+ custom_id,
1201
+ raw_text,
1156
1202
  has_closing_sequence: false,
1157
1203
  closing_sequence: String::new(),
1158
1204
  });
@@ -7,9 +7,10 @@ use lazy_static::lazy_static;
7
7
  use regex::Regex;
8
8
 
9
9
  lazy_static! {
10
- static ref CLOSED_ATX_NO_SPACE_PATTERN: Regex = Regex::new(r"^(\s*)(#+)([^#\s].*?)([^#\s])(#+)\s*$").unwrap();
11
- static ref CLOSED_ATX_NO_SPACE_START_PATTERN: Regex = Regex::new(r"^(\s*)(#+)([^#\s].*?)\s(#+)\s*$").unwrap();
12
- static ref CLOSED_ATX_NO_SPACE_END_PATTERN: Regex = Regex::new(r"^(\s*)(#+)\s(.*?)([^#\s])(#+)\s*$").unwrap();
10
+ // Updated patterns to handle optional custom IDs like {#custom-id} after closing hashes
11
+ static ref CLOSED_ATX_NO_SPACE_PATTERN: Regex = Regex::new(r"^(\s*)(#+)([^#\s].*?)([^#\s])(#+)(\s*(?:\{#[^}]+\})?\s*)$").unwrap();
12
+ static ref CLOSED_ATX_NO_SPACE_START_PATTERN: Regex = Regex::new(r"^(\s*)(#+)([^#\s].*?)\s(#+)(\s*(?:\{#[^}]+\})?\s*)$").unwrap();
13
+ static ref CLOSED_ATX_NO_SPACE_END_PATTERN: Regex = Regex::new(r"^(\s*)(#+)\s(.*?)([^#\s])(#+)(\s*(?:\{#[^}]+\})?\s*)$").unwrap();
13
14
  }
14
15
 
15
16
  #[derive(Clone)]
@@ -39,20 +40,23 @@ impl MD020NoMissingSpaceClosedAtx {
39
40
  let content = &captures[3];
40
41
  let last_char = &captures[4];
41
42
  let closing_hashes = &captures[5];
42
- format!("{indentation}{opening_hashes} {content}{last_char} {closing_hashes}")
43
+ let custom_id = &captures[6];
44
+ format!("{indentation}{opening_hashes} {content}{last_char} {closing_hashes}{custom_id}")
43
45
  } else if let Some(captures) = CLOSED_ATX_NO_SPACE_START_PATTERN.captures(line) {
44
46
  let indentation = &captures[1];
45
47
  let opening_hashes = &captures[2];
46
48
  let content = &captures[3];
47
49
  let closing_hashes = &captures[4];
48
- format!("{indentation}{opening_hashes} {content} {closing_hashes}")
50
+ let custom_id = &captures[5];
51
+ format!("{indentation}{opening_hashes} {content} {closing_hashes}{custom_id}")
49
52
  } else if let Some(captures) = CLOSED_ATX_NO_SPACE_END_PATTERN.captures(line) {
50
53
  let indentation = &captures[1];
51
54
  let opening_hashes = &captures[2];
52
55
  let content = &captures[3];
53
56
  let last_char = &captures[4];
54
57
  let closing_hashes = &captures[5];
55
- format!("{indentation}{opening_hashes} {content}{last_char} {closing_hashes}")
58
+ let custom_id = &captures[6];
59
+ format!("{indentation}{opening_hashes} {content}{last_char} {closing_hashes}{custom_id}")
56
60
  } else {
57
61
  line.to_string()
58
62
  }
@@ -79,11 +83,13 @@ impl Rule for MD020NoMissingSpaceClosedAtx {
79
83
  continue;
80
84
  }
81
85
 
82
- // Only check closed ATX headings
83
- if matches!(heading.style, crate::lint_context::HeadingStyle::ATX) && heading.has_closing_sequence {
86
+ // Check all ATX headings (both properly closed and malformed)
87
+ if matches!(heading.style, crate::lint_context::HeadingStyle::ATX) {
84
88
  let line = &line_info.content;
85
89
 
86
90
  // Check if line matches closed ATX pattern without space
91
+ // This will detect both properly closed headings with missing space
92
+ // and malformed attempts at closed headings like "# Heading#"
87
93
  if self.is_closed_atx_heading_without_space(line) {
88
94
  let line_index = LineIndex::new(ctx.content.to_string());
89
95
  let line_range = line_index.line_content_range(line_num + 1);
@@ -162,9 +168,8 @@ impl Rule for MD020NoMissingSpaceClosedAtx {
162
168
  continue;
163
169
  }
164
170
 
165
- // Fix closed ATX headings without space
171
+ // Fix ATX headings without space (both properly closed and malformed)
166
172
  if matches!(heading.style, crate::lint_context::HeadingStyle::ATX)
167
- && heading.has_closing_sequence
168
173
  && self.is_closed_atx_heading_without_space(&line_info.content)
169
174
  {
170
175
  lines.push(self.fix_closed_atx_heading(&line_info.content));
@@ -1,6 +1,11 @@
1
1
  use crate::rule_config_serde::RuleConfig;
2
2
  use serde::{Deserialize, Serialize};
3
3
 
4
+ /// Default punctuation to check for MD026
5
+ /// Matches markdownlint's default: ".,;:!。,;:!"
6
+ /// We only include ASCII punctuation for now
7
+ pub const DEFAULT_PUNCTUATION: &str = ".,;:!";
8
+
4
9
  #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
5
10
  pub struct MD026Config {
6
11
  #[serde(default = "default_punctuation")]
@@ -16,7 +21,7 @@ impl Default for MD026Config {
16
21
  }
17
22
 
18
23
  fn default_punctuation() -> String {
19
- ".,;".to_string()
24
+ DEFAULT_PUNCTUATION.to_string()
20
25
  }
21
26
 
22
27
  impl RuleConfig for MD026Config {
@@ -2,7 +2,6 @@
2
2
  ///
3
3
  /// See [docs/md026.md](../../docs/md026.md) for full documentation, configuration, and examples.
4
4
  use crate::rule::{Fix, LintError, LintResult, LintWarning, Rule, Severity};
5
- use crate::utils::kramdown_utils::has_header_id;
6
5
  use crate::utils::range_utils::calculate_match_range;
7
6
  use lazy_static::lazy_static;
8
7
  use regex::Regex;
@@ -11,14 +10,14 @@ use std::ops::Range;
11
10
  use std::sync::RwLock;
12
11
 
13
12
  mod md026_config;
14
- use md026_config::MD026Config;
13
+ use md026_config::{DEFAULT_PUNCTUATION, MD026Config};
15
14
 
16
15
  lazy_static! {
17
16
  // Optimized single regex for all ATX heading types (normal, closed, indented 1-3 spaces)
18
17
  static ref ATX_HEADING_UNIFIED: Regex = Regex::new(r"^( {0,3})(#{1,6})(\s+)(.+?)(\s+#{1,6})?$").unwrap();
19
18
 
20
- // Fast check patterns for early returns - more restrictive
21
- static ref QUICK_PUNCTUATION_CHECK: Regex = Regex::new(r"[.,;]").unwrap();
19
+ // Fast check patterns for early returns - match defaults
20
+ static ref QUICK_PUNCTUATION_CHECK: Regex = Regex::new(&format!(r"[{}]", regex::escape(DEFAULT_PUNCTUATION))).unwrap();
22
21
 
23
22
  // Regex cache for punctuation patterns
24
23
  static ref PUNCTUATION_REGEX_CACHE: RwLock<HashMap<String, Regex>> = RwLock::new(HashMap::new());
@@ -34,7 +33,7 @@ impl MD026NoTrailingPunctuation {
34
33
  pub fn new(punctuation: Option<String>) -> Self {
35
34
  Self {
36
35
  config: MD026Config {
37
- punctuation: punctuation.unwrap_or_else(|| ".,;".to_string()), // More restrictive by default
36
+ punctuation: punctuation.unwrap_or_else(|| DEFAULT_PUNCTUATION.to_string()),
38
37
  },
39
38
  }
40
39
  }
@@ -68,16 +67,6 @@ impl MD026NoTrailingPunctuation {
68
67
  #[inline]
69
68
  fn has_trailing_punctuation(&self, text: &str, re: &Regex) -> bool {
70
69
  let trimmed = text.trim();
71
-
72
- // Only apply lenient rules for the default punctuation setting
73
- // When users specify custom punctuation, they want strict behavior
74
- if self.config.punctuation == ".,;" {
75
- // Check for common legitimate punctuation patterns before applying the rule
76
- if self.is_legitimate_punctuation(trimmed) {
77
- return false;
78
- }
79
- }
80
-
81
70
  re.is_match(trimmed)
82
71
  }
83
72
 
@@ -102,85 +91,6 @@ impl MD026NoTrailingPunctuation {
102
91
  }
103
92
  }
104
93
 
105
- /// Check if punctuation in a heading is legitimate and should be allowed
106
- #[inline]
107
- fn is_legitimate_punctuation(&self, text: &str) -> bool {
108
- let text = text.trim();
109
-
110
- // Allow question marks in question headings
111
- if text.ends_with('?') {
112
- // Check if it's likely a genuine question
113
- let question_words = [
114
- "what", "why", "how", "when", "where", "who", "which", "can", "should", "would", "could", "is", "are",
115
- "do", "does", "did",
116
- ];
117
- let lower_text = text.to_lowercase();
118
- if question_words.iter().any(|&word| lower_text.starts_with(word)) {
119
- return true;
120
- }
121
- }
122
-
123
- // Allow colons in common categorical/labeling patterns
124
- if text.ends_with(':') {
125
- // Common patterns that legitimately use colons
126
- let colon_patterns = [
127
- "faq",
128
- "api",
129
- "note",
130
- "warning",
131
- "error",
132
- "info",
133
- "tip",
134
- "chapter",
135
- "step",
136
- "version",
137
- "part",
138
- "section",
139
- "method",
140
- "function",
141
- "class",
142
- "module",
143
- "reference",
144
- "guide",
145
- "tutorial",
146
- "example",
147
- "demo",
148
- "usage",
149
- "syntax",
150
- ];
151
-
152
- let lower_text = text.to_lowercase();
153
-
154
- // Check if it starts with any of these patterns
155
- if colon_patterns.iter().any(|&pattern| lower_text.starts_with(pattern)) {
156
- return true;
157
- }
158
-
159
- // Check for numbered items like "Step 1:", "Chapter 2:", "Version 1.0:"
160
- if regex::Regex::new(r"^(step|chapter|part|section|version)\s*\d")
161
- .unwrap()
162
- .is_match(&lower_text)
163
- {
164
- return true;
165
- }
166
- }
167
-
168
- // Allow exclamation marks in specific contexts (less common, but sometimes legitimate)
169
- if text.ends_with('!') {
170
- // Only allow for very specific patterns like "Important!", "New!", "Warning!"
171
- let exclamation_patterns = ["important", "new", "warning", "alert", "notice", "attention"];
172
- let lower_text = text.to_lowercase();
173
- if exclamation_patterns
174
- .iter()
175
- .any(|&pattern| lower_text.starts_with(pattern))
176
- {
177
- return true;
178
- }
179
- }
180
-
181
- false
182
- }
183
-
184
94
  // Remove trailing punctuation from text
185
95
  #[inline]
186
96
  fn remove_trailing_punctuation(&self, text: &str, re: &Regex) -> String {
@@ -196,17 +106,18 @@ impl MD026NoTrailingPunctuation {
196
106
  let space = captures.get(3).unwrap().as_str();
197
107
  let content = captures.get(4).unwrap().as_str();
198
108
 
199
- // If content has a valid Kramdown header ID, don't fix it
200
- if has_header_id(content) {
201
- // Return the line unchanged
202
- if let Some(trailing) = captures.get(5) {
203
- return format!("{}{}{}{}{}", indentation, hashes, space, content, trailing.as_str());
204
- }
205
- return format!("{indentation}{hashes}{space}{content}");
206
- }
207
-
208
- // Otherwise, remove trailing punctuation
209
- let fixed_content = self.remove_trailing_punctuation(content, re);
109
+ // Check if content ends with a custom header ID like {#my-id}
110
+ // If so, we need to fix punctuation before the ID
111
+ let fixed_content = if let Some(id_pos) = content.rfind(" {#") {
112
+ // Has a custom ID - fix punctuation before it
113
+ let before_id = &content[..id_pos];
114
+ let id_part = &content[id_pos..];
115
+ let fixed_before = self.remove_trailing_punctuation(before_id, re);
116
+ format!("{fixed_before}{id_part}")
117
+ } else {
118
+ // No custom ID - just remove trailing punctuation
119
+ self.remove_trailing_punctuation(content, re)
120
+ };
210
121
 
211
122
  // Preserve any trailing hashes if present
212
123
  if let Some(trailing) = captures.get(5) {
@@ -276,7 +187,7 @@ impl Rule for MD026NoTrailingPunctuation {
276
187
 
277
188
  // Quick check for any punctuation we care about
278
189
  // For custom punctuation, we need to check differently
279
- if self.config.punctuation == ".,;" {
190
+ if self.config.punctuation == DEFAULT_PUNCTUATION {
280
191
  if !QUICK_PUNCTUATION_CHECK.is_match(content) {
281
192
  return Ok(Vec::new());
282
193
  }
@@ -308,22 +219,10 @@ impl Rule for MD026NoTrailingPunctuation {
308
219
  continue;
309
220
  }
310
221
 
311
- // For headers with potential Kramdown syntax, we need to be more careful
312
- let text_to_check = if has_header_id(&heading.text) {
313
- // Valid Kramdown ID - skip this header entirely
314
- continue;
315
- } else if heading.text.contains("{") && heading.text.trim().ends_with("}") {
316
- // Has curly braces but not a valid Kramdown ID
317
- // Check for punctuation before the opening brace
318
- if let Some(brace_pos) = heading.text.rfind('{') {
319
- heading.text[..brace_pos].trim().to_string()
320
- } else {
321
- heading.text.clone()
322
- }
323
- } else {
324
- // Regular header without Kramdown syntax
325
- heading.text.clone()
326
- };
222
+ // LintContext already strips Kramdown IDs from heading.text
223
+ // So we just check the heading text directly for trailing punctuation
224
+ // This correctly flags "# Heading." even if it has {#id}
225
+ let text_to_check = heading.text.clone();
327
226
 
328
227
  if self.has_trailing_punctuation(&text_to_check, &re) {
329
228
  // Find the trailing punctuation
@@ -379,7 +278,7 @@ impl Rule for MD026NoTrailingPunctuation {
379
278
 
380
279
  // Quick check for punctuation
381
280
  // For custom punctuation, we need to check differently
382
- if self.config.punctuation == ".,;" {
281
+ if self.config.punctuation == DEFAULT_PUNCTUATION {
383
282
  if !QUICK_PUNCTUATION_CHECK.is_match(content) {
384
283
  return Ok(content.to_string());
385
284
  }
@@ -413,22 +312,9 @@ impl Rule for MD026NoTrailingPunctuation {
413
312
  continue;
414
313
  }
415
314
 
416
- // Handle headers with potential Kramdown syntax
417
- let text_to_check = if has_header_id(&heading.text) {
418
- // Valid Kramdown ID - skip this header entirely
419
- continue;
420
- } else if heading.text.contains("{") && heading.text.trim().ends_with("}") {
421
- // Has curly braces but not a valid Kramdown ID
422
- // Check for punctuation before the opening brace
423
- if let Some(brace_pos) = heading.text.rfind('{') {
424
- heading.text[..brace_pos].trim().to_string()
425
- } else {
426
- heading.text.clone()
427
- }
428
- } else {
429
- // Regular header without Kramdown syntax
430
- heading.text.clone()
431
- };
315
+ // LintContext already strips custom header IDs from heading.text
316
+ // So we just check the heading text directly for trailing punctuation
317
+ let text_to_check = heading.text.clone();
432
318
 
433
319
  // Check and fix trailing punctuation
434
320
  if self.has_trailing_punctuation(&text_to_check, &re) {
@@ -544,26 +430,24 @@ mod tests {
544
430
  }
545
431
 
546
432
  #[test]
547
- fn test_default_legitimate_question() {
433
+ fn test_question_marks_not_in_default() {
548
434
  let rule = MD026NoTrailingPunctuation::new(None);
549
435
  let content = "# What is Rust?\n# How does it work?\n# Is it fast?";
550
436
  let ctx = LintContext::new(content);
551
437
  let result = rule.check(&ctx).unwrap();
552
- assert!(
553
- result.is_empty(),
554
- "Question marks in questions should be allowed by default"
555
- );
438
+ assert!(result.is_empty(), "Question marks are not in default punctuation list");
556
439
  }
557
440
 
558
441
  #[test]
559
- fn test_legitimate_colons() {
442
+ fn test_colons_in_default() {
560
443
  let rule = MD026NoTrailingPunctuation::new(None);
561
444
  let content = "# FAQ:\n# API Reference:\n# Step 1:\n# Version 2.0:";
562
445
  let ctx = LintContext::new(content);
563
446
  let result = rule.check(&ctx).unwrap();
564
- assert!(
565
- result.is_empty(),
566
- "Colons in categorical headings should be allowed by default"
447
+ assert_eq!(
448
+ result.len(),
449
+ 4,
450
+ "Colons are in default punctuation list and should be flagged"
567
451
  );
568
452
  }
569
453
 
@@ -57,9 +57,6 @@ lazy_static! {
57
57
  // Updated to support IPv6 addresses
58
58
  static ref REFERENCE_DEF_RE: Regex = Regex::new(r"^\s*\[[^\]]+\]:\s*(?:https?|ftps?)://\S+$").unwrap();
59
59
 
60
- // Pattern to match URLs inside HTML attributes (src, href, srcset, etc.)
61
- static ref HTML_ATTRIBUTE_URL: Regex = Regex::new(r#"(?:src|href|srcset|content|data-\w+)\s*=\s*["']([^"']*)["']"#).unwrap();
62
-
63
60
  // Pattern to match HTML comments
64
61
  static ref HTML_COMMENT_PATTERN: Regex = Regex::new(r#"<!--[\s\S]*?-->"#).unwrap();
65
62
  }
@@ -114,14 +111,18 @@ impl MD034NoBareUrls {
114
111
  // First, find all markdown link ranges across the entire content
115
112
  let mut excluded_ranges: Vec<(usize, usize)> = Vec::new();
116
113
 
117
- // Markdown links: [text](url) - handle multi-line
114
+ // Markdown links: [text](url) - exclude both destination and entire link text
118
115
  for cap in MARKDOWN_LINK_PATTERN.captures_iter(content) {
119
116
  if let Some(dest) = cap.get(1) {
120
117
  excluded_ranges.push((dest.start(), dest.end()));
121
118
  }
119
+ // Also exclude the entire link to handle URLs in link text
120
+ if let Some(full_match) = cap.get(0) {
121
+ excluded_ranges.push((full_match.start(), full_match.end()));
122
+ }
122
123
  }
123
124
 
124
- // Markdown images: ![alt](url) - handle multi-line
125
+ // Markdown images: ![alt](url)
125
126
  for cap in MARKDOWN_IMAGE_PATTERN.captures_iter(content) {
126
127
  if let Some(dest) = cap.get(2) {
127
128
  excluded_ranges.push((dest.start(), dest.end()));
@@ -135,11 +136,9 @@ impl MD034NoBareUrls {
135
136
  }
136
137
  }
137
138
 
138
- // HTML attribute URLs: src="url", href="url", etc.
139
- for cap in HTML_ATTRIBUTE_URL.captures_iter(content) {
140
- if let Some(url_attr) = cap.get(1) {
141
- excluded_ranges.push((url_attr.start(), url_attr.end()));
142
- }
139
+ // HTML tags: exclude everything inside them
140
+ for html_tag in ctx.html_tags().iter() {
141
+ excluded_ranges.push((html_tag.byte_offset, html_tag.byte_end));
143
142
  }
144
143
 
145
144
  // HTML comments: <!-- url -->