rumdl 0.0.72__tar.gz → 0.0.74__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 (264) hide show
  1. {rumdl-0.0.72 → rumdl-0.0.74}/Cargo.lock +1 -1
  2. {rumdl-0.0.72 → rumdl-0.0.74}/Cargo.toml +1 -1
  3. {rumdl-0.0.72 → rumdl-0.0.74}/PKG-INFO +1 -1
  4. {rumdl-0.0.72 → rumdl-0.0.74}/src/main.rs +7 -10
  5. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md006_start_bullets.rs +19 -8
  6. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md032_blanks_around_lists.rs +36 -2
  7. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md034_no_bare_urls.rs +81 -92
  8. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md042_no_empty_links.rs +7 -49
  9. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md051_link_fragments.rs +74 -51
  10. {rumdl-0.0.72 → rumdl-0.0.74}/src/utils/document_structure.rs +70 -68
  11. rumdl-0.0.74/tests/rules/md006_test.rs +243 -0
  12. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md033_test.rs +321 -0
  13. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md034_test.rs +69 -2
  14. rumdl-0.0.74/tests/rules/md042_test.rs +291 -0
  15. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md051_test.rs +128 -0
  16. rumdl-0.0.72/tests/rules/md006_test.rs +0 -143
  17. rumdl-0.0.72/tests/rules/md042_test.rs +0 -84
  18. {rumdl-0.0.72 → rumdl-0.0.74}/.rumdl.toml +0 -0
  19. {rumdl-0.0.72 → rumdl-0.0.74}/MANIFEST.in +0 -0
  20. {rumdl-0.0.72 → rumdl-0.0.74}/Makefile +0 -0
  21. {rumdl-0.0.72 → rumdl-0.0.74}/README.md +0 -0
  22. {rumdl-0.0.72 → rumdl-0.0.74}/assets/logo.png +0 -0
  23. {rumdl-0.0.72 → rumdl-0.0.74}/benches/fix_performance.rs +0 -0
  24. {rumdl-0.0.72 → rumdl-0.0.74}/benches/range_performance.rs +0 -0
  25. {rumdl-0.0.72 → rumdl-0.0.74}/benches/range_utils_benchmark.rs +0 -0
  26. {rumdl-0.0.72 → rumdl-0.0.74}/benches/rule_performance.rs +0 -0
  27. {rumdl-0.0.72 → rumdl-0.0.74}/benches/simple_fix_bench.rs +0 -0
  28. {rumdl-0.0.72 → rumdl-0.0.74}/docs/RULES.md +0 -0
  29. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md001.md +0 -0
  30. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md002.md +0 -0
  31. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md003.md +0 -0
  32. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md004.md +0 -0
  33. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md005.md +0 -0
  34. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md006.md +0 -0
  35. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md007.md +0 -0
  36. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md009.md +0 -0
  37. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md010.md +0 -0
  38. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md011.md +0 -0
  39. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md012.md +0 -0
  40. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md013.md +0 -0
  41. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md014.md +0 -0
  42. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md018.md +0 -0
  43. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md019.md +0 -0
  44. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md020.md +0 -0
  45. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md021.md +0 -0
  46. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md022.md +0 -0
  47. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md023.md +0 -0
  48. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md024.md +0 -0
  49. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md025.md +0 -0
  50. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md026.md +0 -0
  51. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md027.md +0 -0
  52. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md028.md +0 -0
  53. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md029.md +0 -0
  54. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md030.md +0 -0
  55. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md031.md +0 -0
  56. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md032.md +0 -0
  57. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md033.md +0 -0
  58. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md034.md +0 -0
  59. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md035.md +0 -0
  60. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md036.md +0 -0
  61. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md037.md +0 -0
  62. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md038.md +0 -0
  63. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md039.md +0 -0
  64. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md040.md +0 -0
  65. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md041.md +0 -0
  66. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md042.md +0 -0
  67. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md043.md +0 -0
  68. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md044.md +0 -0
  69. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md045.md +0 -0
  70. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md046.md +0 -0
  71. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md047.md +0 -0
  72. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md048.md +0 -0
  73. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md049.md +0 -0
  74. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md050.md +0 -0
  75. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md051.md +0 -0
  76. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md052.md +0 -0
  77. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md053.md +0 -0
  78. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md054.md +0 -0
  79. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md055.md +0 -0
  80. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md056.md +0 -0
  81. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md057.md +0 -0
  82. {rumdl-0.0.72 → rumdl-0.0.74}/docs/md058.md +0 -0
  83. {rumdl-0.0.72 → rumdl-0.0.74}/issues/plan-rule-parity-with-markdownlint.md +0 -0
  84. {rumdl-0.0.72 → rumdl-0.0.74}/parity_check.py +0 -0
  85. {rumdl-0.0.72 → rumdl-0.0.74}/pyproject.toml +0 -0
  86. {rumdl-0.0.72 → rumdl-0.0.74}/python/MANIFEST.in +0 -0
  87. {rumdl-0.0.72 → rumdl-0.0.74}/python/PYTHON-README.md +0 -0
  88. {rumdl-0.0.72 → rumdl-0.0.74}/python/rumdl/__init__.py +0 -0
  89. {rumdl-0.0.72 → rumdl-0.0.74}/python/rumdl/__main__.py +0 -0
  90. {rumdl-0.0.72 → rumdl-0.0.74}/python/rumdl/py.typed +0 -0
  91. {rumdl-0.0.72 → rumdl-0.0.74}/rumdl.toml.example +0 -0
  92. {rumdl-0.0.72 → rumdl-0.0.74}/src/config.rs +0 -0
  93. {rumdl-0.0.72 → rumdl-0.0.74}/src/init.rs +0 -0
  94. {rumdl-0.0.72 → rumdl-0.0.74}/src/lib.rs +0 -0
  95. {rumdl-0.0.72 → rumdl-0.0.74}/src/lint_context.rs +0 -0
  96. {rumdl-0.0.72 → rumdl-0.0.74}/src/lsp/mod.rs +0 -0
  97. {rumdl-0.0.72 → rumdl-0.0.74}/src/lsp/server.rs +0 -0
  98. {rumdl-0.0.72 → rumdl-0.0.74}/src/lsp/types.rs +0 -0
  99. {rumdl-0.0.72 → rumdl-0.0.74}/src/markdownlint_config.rs +0 -0
  100. {rumdl-0.0.72 → rumdl-0.0.74}/src/parallel.rs +0 -0
  101. {rumdl-0.0.72 → rumdl-0.0.74}/src/performance.rs +0 -0
  102. {rumdl-0.0.72 → rumdl-0.0.74}/src/profiling.rs +0 -0
  103. {rumdl-0.0.72 → rumdl-0.0.74}/src/python.rs +0 -0
  104. {rumdl-0.0.72 → rumdl-0.0.74}/src/rule.rs +0 -0
  105. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/blockquote_utils.rs +0 -0
  106. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/code_block_utils.rs +0 -0
  107. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/code_fence_utils.rs +0 -0
  108. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/emphasis_style.rs +0 -0
  109. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/front_matter_utils.rs +0 -0
  110. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/heading_utils.rs +0 -0
  111. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/list_utils.rs +0 -0
  112. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md001_heading_increment.rs +0 -0
  113. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md002_first_heading_h1.rs +0 -0
  114. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md003_heading_style.rs +0 -0
  115. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md004_unordered_list_style.rs +0 -0
  116. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md005_list_indent.rs +0 -0
  117. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md007_ul_indent.rs +0 -0
  118. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md009_trailing_spaces.rs +0 -0
  119. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md010_no_hard_tabs.rs +0 -0
  120. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md011_no_reversed_links.rs +0 -0
  121. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md012_no_multiple_blanks.rs +0 -0
  122. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md013_line_length.rs +0 -0
  123. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md014_commands_show_output.rs +0 -0
  124. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md018_no_missing_space_atx.rs +0 -0
  125. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md019_no_multiple_space_atx.rs +0 -0
  126. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md020_no_missing_space_closed_atx.rs +0 -0
  127. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md021_no_multiple_space_closed_atx.rs +0 -0
  128. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md022_blanks_around_headings.rs +0 -0
  129. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md023_heading_start_left.rs +0 -0
  130. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md024_no_duplicate_heading.rs +0 -0
  131. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md025_single_title.rs +0 -0
  132. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md026_no_trailing_punctuation.rs +0 -0
  133. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md027_multiple_spaces_blockquote.rs +0 -0
  134. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md028_no_blanks_blockquote.rs +0 -0
  135. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md029_ordered_list_prefix.rs +0 -0
  136. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md030_list_marker_space.rs +0 -0
  137. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md031_blanks_around_fences.rs +0 -0
  138. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md033_no_inline_html.rs +0 -0
  139. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md035_hr_style.rs +0 -0
  140. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md036_no_emphasis_only_first.rs +0 -0
  141. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md037_spaces_around_emphasis.rs +0 -0
  142. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md038_no_space_in_code.rs +0 -0
  143. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md039_no_space_in_links.rs +0 -0
  144. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md040_fenced_code_language.rs +0 -0
  145. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md041_first_line_heading.rs +0 -0
  146. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md043_required_headings.rs +0 -0
  147. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md044_proper_names.rs +0 -0
  148. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md045_no_alt_text.rs +0 -0
  149. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md046_code_block_style.rs +0 -0
  150. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md047_single_trailing_newline.rs +0 -0
  151. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md048_code_fence_style.rs +0 -0
  152. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md049_emphasis_style.rs +0 -0
  153. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md050_strong_style.rs +0 -0
  154. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md052_reference_links_images.rs +0 -0
  155. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md053_link_image_reference_definitions.rs +0 -0
  156. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md054_link_image_style.rs +0 -0
  157. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md055_table_pipe_style.rs +0 -0
  158. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md056_table_column_count.rs +0 -0
  159. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md057_existing_relative_links.rs +0 -0
  160. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/md058_blanks_around_tables.rs +0 -0
  161. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/mod.rs +0 -0
  162. {rumdl-0.0.72 → rumdl-0.0.74}/src/rules/strong_style.rs +0 -0
  163. {rumdl-0.0.72 → rumdl-0.0.74}/src/utils/ast_utils.rs +0 -0
  164. {rumdl-0.0.72 → rumdl-0.0.74}/src/utils/code_block_utils.rs +0 -0
  165. {rumdl-0.0.72 → rumdl-0.0.74}/src/utils/early_returns.rs +0 -0
  166. {rumdl-0.0.72 → rumdl-0.0.74}/src/utils/element_cache.rs +0 -0
  167. {rumdl-0.0.72 → rumdl-0.0.74}/src/utils/markdown_elements.rs +0 -0
  168. {rumdl-0.0.72 → rumdl-0.0.74}/src/utils/mod.rs +0 -0
  169. {rumdl-0.0.72 → rumdl-0.0.74}/src/utils/range_utils.rs +0 -0
  170. {rumdl-0.0.72 → rumdl-0.0.74}/src/utils/regex_cache.rs +0 -0
  171. {rumdl-0.0.72 → rumdl-0.0.74}/src/utils/string_interner.rs +0 -0
  172. {rumdl-0.0.72 → rumdl-0.0.74}/src/utils/table_utils.rs +0 -0
  173. {rumdl-0.0.72 → rumdl-0.0.74}/tests/advanced_integration_tests.rs +0 -0
  174. {rumdl-0.0.72 → rumdl-0.0.74}/tests/character_ranges/additional_tests.rs +0 -0
  175. {rumdl-0.0.72 → rumdl-0.0.74}/tests/character_ranges/basic_tests.rs +0 -0
  176. {rumdl-0.0.72 → rumdl-0.0.74}/tests/character_ranges/comprehensive_tests.rs +0 -0
  177. {rumdl-0.0.72 → rumdl-0.0.74}/tests/character_ranges/extended_tests.rs +0 -0
  178. {rumdl-0.0.72 → rumdl-0.0.74}/tests/character_ranges/mod.rs +0 -0
  179. {rumdl-0.0.72 → rumdl-0.0.74}/tests/character_ranges/unicode_utils.rs +0 -0
  180. {rumdl-0.0.72 → rumdl-0.0.74}/tests/cli_duplication_test.rs +0 -0
  181. {rumdl-0.0.72 → rumdl-0.0.74}/tests/cli_integration_tests.rs +0 -0
  182. {rumdl-0.0.72 → rumdl-0.0.74}/tests/commonmark_compliance_tests.rs +0 -0
  183. {rumdl-0.0.72 → rumdl-0.0.74}/tests/comprehensive_integration_tests.rs +0 -0
  184. {rumdl-0.0.72 → rumdl-0.0.74}/tests/config_application_tests.rs +0 -0
  185. {rumdl-0.0.72 → rumdl-0.0.74}/tests/config_tests.rs +0 -0
  186. {rumdl-0.0.72 → rumdl-0.0.74}/tests/init_command_test.rs +0 -0
  187. {rumdl-0.0.72 → rumdl-0.0.74}/tests/init_tests.rs +0 -0
  188. {rumdl-0.0.72 → rumdl-0.0.74}/tests/integration_tests.rs +0 -0
  189. {rumdl-0.0.72 → rumdl-0.0.74}/tests/json_output_test.rs +0 -0
  190. {rumdl-0.0.72 → rumdl-0.0.74}/tests/lib.rs +0 -0
  191. {rumdl-0.0.72 → rumdl-0.0.74}/tests/lsp_integration_tests.rs +0 -0
  192. {rumdl-0.0.72 → rumdl-0.0.74}/tests/lsp_tests.rs +0 -0
  193. {rumdl-0.0.72 → rumdl-0.0.74}/tests/markdownlint_cli_integration.rs +0 -0
  194. {rumdl-0.0.72 → rumdl-0.0.74}/tests/markdownlint_config_test.rs +0 -0
  195. {rumdl-0.0.72 → rumdl-0.0.74}/tests/md030_edge_cases.md +0 -0
  196. {rumdl-0.0.72 → rumdl-0.0.74}/tests/output_format_tests.rs +0 -0
  197. {rumdl-0.0.72 → rumdl-0.0.74}/tests/perf_check.rs +0 -0
  198. {rumdl-0.0.72 → rumdl-0.0.74}/tests/pyproject_config_tests.rs +0 -0
  199. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md001_test.rs +0 -0
  200. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md001_unicode_test.rs +0 -0
  201. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md002_test.rs +0 -0
  202. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md003_test.rs +0 -0
  203. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md004_test.rs +0 -0
  204. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md005_test.rs +0 -0
  205. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md006_unicode_test.rs +0 -0
  206. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md007_test.rs +0 -0
  207. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md009_test.rs +0 -0
  208. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md010_test.rs +0 -0
  209. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md011_test.rs +0 -0
  210. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md012_test.rs +0 -0
  211. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md013_test.rs +0 -0
  212. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md014_test.rs +0 -0
  213. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md018_test.rs +0 -0
  214. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md019_test.rs +0 -0
  215. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md020_test.rs +0 -0
  216. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md021_test.rs +0 -0
  217. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md022_test.rs +0 -0
  218. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md023_extended_test.rs +0 -0
  219. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md023_test.rs +0 -0
  220. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md024_test.rs +0 -0
  221. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md025_test.rs +0 -0
  222. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md026_test.rs +0 -0
  223. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md027_test.rs +0 -0
  224. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md028_test.rs +0 -0
  225. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md029_test.rs +0 -0
  226. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md030_test.rs +0 -0
  227. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md031_test.rs +0 -0
  228. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md032_test.rs +0 -0
  229. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md033_extended_test.rs +0 -0
  230. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md035_test.rs +0 -0
  231. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md036_test.rs +0 -0
  232. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md037_test.rs +0 -0
  233. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md038_test.rs +0 -0
  234. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md039_test.rs +0 -0
  235. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md040_test.rs +0 -0
  236. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md041_test.rs +0 -0
  237. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md043_test.rs +0 -0
  238. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md044_test.rs +0 -0
  239. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md045_test.rs +0 -0
  240. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md046_test.rs +0 -0
  241. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md047_test.rs +0 -0
  242. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md048_test.rs +0 -0
  243. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md049_test.rs +0 -0
  244. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md050_test.rs +0 -0
  245. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md052_test.rs +0 -0
  246. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md053_additional_test.rs +0 -0
  247. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md053_proptest.rs +0 -0
  248. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md053_test.rs +0 -0
  249. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md054_test.rs +0 -0
  250. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md054_unicode_test.rs +0 -0
  251. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md055_test.rs +0 -0
  252. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md056_test.rs +0 -0
  253. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md057_test.rs +0 -0
  254. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/md058_test.rs +0 -0
  255. {rumdl-0.0.72 → rumdl-0.0.74}/tests/rules/mod.rs +0 -0
  256. {rumdl-0.0.72 → rumdl-0.0.74}/tests/utils/blockquote_utils_test.rs +0 -0
  257. {rumdl-0.0.72 → rumdl-0.0.74}/tests/utils/code_block_utils_extended_test.rs +0 -0
  258. {rumdl-0.0.72 → rumdl-0.0.74}/tests/utils/code_block_utils_test.rs +0 -0
  259. {rumdl-0.0.72 → rumdl-0.0.74}/tests/utils/core_utils_test.rs +0 -0
  260. {rumdl-0.0.72 → rumdl-0.0.74}/tests/utils/front_matter_utils_test.rs +0 -0
  261. {rumdl-0.0.72 → rumdl-0.0.74}/tests/utils/line_index_test.rs +0 -0
  262. {rumdl-0.0.72 → rumdl-0.0.74}/tests/utils/mod.rs +0 -0
  263. {rumdl-0.0.72 → rumdl-0.0.74}/tests/utils_markdown_edge_cases.rs +0 -0
  264. {rumdl-0.0.72 → rumdl-0.0.74}/tests/utils_tests.rs +0 -0
@@ -1789,7 +1789,7 @@ dependencies = [
1789
1789
 
1790
1790
  [[package]]
1791
1791
  name = "rumdl"
1792
- version = "0.0.72"
1792
+ version = "0.0.74"
1793
1793
  dependencies = [
1794
1794
  "anyhow",
1795
1795
  "assert_cmd",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "rumdl"
3
- version = "0.0.72"
3
+ version = "0.0.74"
4
4
  edition = "2021"
5
5
  description = "A fast Markdown linter written in Rust (Ru(st) MarkDown Linter)"
6
6
  authors = ["Ruben J. Jongejan <ruben.jongejan@gmail.com>"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rumdl
3
- Version: 0.0.72
3
+ Version: 0.0.74
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -1297,16 +1297,13 @@ fn process_stdin(rules: &[Box<dyn Rule>], args: &CheckArgs) {
1297
1297
  let has_issues = !all_warnings.is_empty();
1298
1298
  if has_issues {
1299
1299
  for warning in &all_warnings {
1300
+ let rule_name = warning.rule_name.unwrap_or("unknown");
1300
1301
  println!(
1301
- "<stdin>:{}:{}: {}: {} [{}]",
1302
- warning.line,
1303
- warning.column,
1304
- match warning.severity {
1305
- rumdl::rule::Severity::Error => "error".red(),
1306
- rumdl::rule::Severity::Warning => "warning".yellow(),
1307
- },
1308
- warning.message,
1309
- warning.rule_name.unwrap_or("unknown")
1302
+ "<stdin>:{}:{}: {} {}",
1303
+ warning.line.to_string().cyan(),
1304
+ warning.column.to_string().cyan(),
1305
+ format!("[{:5}]", rule_name).yellow(), // Align rule names consistently
1306
+ warning.message
1310
1307
  );
1311
1308
  }
1312
1309
  }
@@ -1611,7 +1608,7 @@ fn process_file(
1611
1608
  file_path.blue().underline(),
1612
1609
  warning.line.to_string().cyan(),
1613
1610
  warning.column.to_string().cyan(),
1614
- format!("[{}]", rule_name).yellow(),
1611
+ format!("[{:5}]", rule_name).yellow(), // Pad rule name to 5 characters for alignment
1615
1612
  warning.message,
1616
1613
  fix_indicator.green()
1617
1614
  );
@@ -66,9 +66,15 @@ impl MD006StartBullets {
66
66
  if Self::is_bullet_list_item(lines[check_idx]).is_none() {
67
67
  // Found non-list content - check if it breaks the list structure
68
68
  let content_indent = lines[check_idx].len() - lines[check_idx].trim_start().len();
69
- // Content is only acceptable if it's indented at least as much as current item
70
- // AND we have a true parent relationship (prev_indent < current_indent)
71
- if content_indent < current_indent || prev_indent >= current_indent {
69
+
70
+ // Content is acceptable if:
71
+ // 1. It's indented at least as much as the current item (continuation of parent)
72
+ // 2. OR it's indented more than the previous bullet (continuation of previous item)
73
+ // 3. AND we have a true parent relationship (prev_indent < current_indent)
74
+ let is_continuation = content_indent >= prev_indent.max(2); // At least 2 spaces for continuation
75
+ let is_valid_nesting = prev_indent < current_indent;
76
+
77
+ if !is_continuation || !is_valid_nesting {
72
78
  has_breaking_content = true;
73
79
  break;
74
80
  }
@@ -78,13 +84,19 @@ impl MD006StartBullets {
78
84
  if !has_breaking_content {
79
85
  return Some((i, prev_indent));
80
86
  } else {
81
- // Content breaks the list structure
82
- return None;
87
+ // Content breaks the list structure, but continue searching for an earlier valid parent
88
+ continue;
83
89
  }
84
90
  }
85
91
  // If prev_indent > current_indent, it's a child of a sibling, ignore it and keep searching.
86
92
  } else {
87
- // Found non-list content - this breaks the search
93
+ // Found non-list content - check if it's a continuation line
94
+ let content_indent = lines[i].len() - lines[i].trim_start().len();
95
+ // If it's indented enough to be a continuation, don't break the search
96
+ if content_indent >= 2 {
97
+ continue;
98
+ }
99
+ // Otherwise, this breaks the search
88
100
  return None;
89
101
  }
90
102
  }
@@ -247,8 +259,7 @@ impl Rule for MD006StartBullets {
247
259
  column: start_col,
248
260
  end_line: line_num,
249
261
  end_column: end_col,
250
- message: "List item should start at the beginning of the line (remove indentation)"
251
- .to_string(),
262
+ message: "List item indentation".to_string(),
252
263
  fix: Some(Fix {
253
264
  range: line_index.line_col_to_byte_range(line_num, 1),
254
265
  replacement,
@@ -103,8 +103,42 @@ impl MD032BlanksAroundLists {
103
103
  if structure.is_in_code_block(current_line_idx_1)
104
104
  || structure.is_in_front_matter(current_line_idx_1)
105
105
  {
106
- current_line_idx_0 += 1;
107
- continue;
106
+ // Special case: Even if a line is in a code block (e.g., tab-indented),
107
+ // if it looks like a list item, the user probably intended it as such.
108
+ // We should warn about spacing issues rather than silently ignore it.
109
+ // But only apply this to INDENTED code blocks, not FENCED code blocks.
110
+ if structure.is_in_code_block(current_line_idx_1) {
111
+ // Check if this is an indented code block (starts with tab or 4+ spaces)
112
+ // vs a fenced code block (enclosed in ``` or ~~~)
113
+ let line_trimmed = line_str.trim_start();
114
+ let leading_whitespace = &line_str[..line_str.len() - line_trimmed.len()];
115
+ let is_indented_code = leading_whitespace.contains('\t') ||
116
+ leading_whitespace.chars().filter(|&c| c == ' ').count() >= 4;
117
+
118
+ if is_indented_code {
119
+ // Check if this "indented code block" line actually looks like a list item
120
+ let blockquote_prefix = BLOCKQUOTE_PREFIX_RE
121
+ .find(line_str)
122
+ .map_or(String::new(), |m| m.as_str().to_string());
123
+ let line_content = line_str.trim_start_matches(&blockquote_prefix);
124
+
125
+ // If it matches our list item pattern, treat it as a list item for linting purposes
126
+ if LIST_ITEM_START_REGEX.is_match(line_content) {
127
+ // Don't skip - process it as a potential list item
128
+ } else {
129
+ current_line_idx_0 += 1;
130
+ continue;
131
+ }
132
+ } else {
133
+ // Fenced code block - always skip
134
+ current_line_idx_0 += 1;
135
+ continue;
136
+ }
137
+ } else {
138
+ // Front matter - always skip
139
+ current_line_idx_0 += 1;
140
+ continue;
141
+ }
108
142
  }
109
143
 
110
144
  // Determine blockquote prefix and content *before* checking for list item
@@ -96,61 +96,53 @@ impl MD034NoBareUrls {
96
96
  &url[..end]
97
97
  }
98
98
 
99
- // Find all bare URLs in a line, using DocumentStructure for code span detection
100
- fn find_bare_urls_with_structure(
99
+ // Uses DocumentStructure for code block and code span detection in check_with_structure.
100
+ pub fn check_with_structure(
101
101
  &self,
102
- line: &str,
103
- line_idx: usize,
102
+ ctx: &crate::lint_context::LintContext,
104
103
  structure: &crate::utils::document_structure::DocumentStructure,
105
- ) -> Vec<LintWarning> {
106
- let mut warnings = Vec::new();
107
-
108
- // Early return: empty lines
109
- if line.trim().is_empty() {
110
- return warnings;
111
- }
112
-
113
- // Fast path - check if line potentially contains a URL
114
- if !URL_QUICK_CHECK.is_match(line) {
115
- return warnings;
116
- }
104
+ ) -> LintResult {
105
+ let content = ctx.content;
117
106
 
118
- // Skip lines that consist only of a badge link
119
- if BADGE_LINK_LINE.is_match(line) {
120
- return warnings;
107
+ // Early return: skip if no URLs or emails
108
+ if self.should_skip(content) {
109
+ return Ok(vec![]);
121
110
  }
122
111
 
123
- // Early return: skip reference definitions
124
- if REFERENCE_DEF_RE.is_match(line) {
125
- return warnings;
126
- }
112
+ // Process the entire content to handle multi-line markdown links
113
+ let mut warnings = Vec::new();
127
114
 
128
- // --- NEW: Collect all link/image destination ranges using regex ---
115
+ // First, find all markdown link ranges across the entire content
129
116
  let mut excluded_ranges: Vec<(usize, usize)> = Vec::new();
130
- // Markdown links: [text](url)
131
- for cap in MARKDOWN_LINK_PATTERN.captures_iter(line) {
117
+
118
+ // Markdown links: [text](url) - handle multi-line
119
+ for cap in MARKDOWN_LINK_PATTERN.captures_iter(content) {
132
120
  if let Some(dest) = cap.get(1) {
133
121
  excluded_ranges.push((dest.start(), dest.end()));
134
122
  }
135
123
  }
136
- // Markdown images: ![alt](url)
137
- for cap in MARKDOWN_IMAGE_PATTERN.captures_iter(line) {
124
+
125
+ // Markdown images: ![alt](url) - handle multi-line
126
+ for cap in MARKDOWN_IMAGE_PATTERN.captures_iter(content) {
138
127
  if let Some(dest) = cap.get(2) {
139
128
  excluded_ranges.push((dest.start(), dest.end()));
140
129
  }
141
130
  }
131
+
142
132
  // Angle-bracket links: <url>
143
- for cap in ANGLE_LINK_PATTERN.captures_iter(line) {
133
+ for cap in ANGLE_LINK_PATTERN.captures_iter(content) {
144
134
  if let Some(m) = cap.get(1) {
145
135
  excluded_ranges.push((m.start(), m.end()));
146
136
  }
147
137
  }
138
+
148
139
  // HTML attribute URLs: src="url", href="url", etc.
149
- for cap in HTML_ATTRIBUTE_URL.captures_iter(line) {
140
+ for cap in HTML_ATTRIBUTE_URL.captures_iter(content) {
150
141
  if let Some(url_attr) = cap.get(1) {
151
142
  excluded_ranges.push((url_attr.start(), url_attr.end()));
152
143
  }
153
144
  }
145
+
154
146
  // Sort and merge overlapping ranges
155
147
  excluded_ranges.sort_by_key(|r| r.0);
156
148
  let mut merged: Vec<(usize, usize)> = Vec::new();
@@ -164,12 +156,13 @@ impl MD034NoBareUrls {
164
156
  merged.push((start, end));
165
157
  }
166
158
 
167
- for url_match in SIMPLE_URL_REGEX.find_iter(line) {
159
+ // Now find all URLs in the content and check if they're excluded
160
+ for url_match in SIMPLE_URL_REGEX.find_iter(content) {
168
161
  let url_start = url_match.start();
169
162
  let mut url_end = url_match.end();
170
163
 
171
164
  // Trim trailing punctuation that's likely sentence punctuation
172
- let raw_url = &line[url_start..url_end];
165
+ let raw_url = &content[url_start..url_end];
173
166
  let trimmed_url = self.trim_trailing_punctuation(raw_url);
174
167
  url_end = url_start + trimmed_url.len();
175
168
 
@@ -182,9 +175,9 @@ impl MD034NoBareUrls {
182
175
  let before = if url_start == 0 {
183
176
  None
184
177
  } else {
185
- line.get(url_start - 1..url_start)
178
+ content.get(url_start - 1..url_start)
186
179
  };
187
- let after = line.get(url_end..url_end + 1);
180
+ let after = content.get(url_end..url_end + 1);
188
181
  let is_valid_boundary = before.map_or(true, |c| {
189
182
  !c.chars().next().unwrap().is_alphanumeric() && c != "_"
190
183
  }) && after.map_or(true, |c| {
@@ -193,45 +186,67 @@ impl MD034NoBareUrls {
193
186
  if !is_valid_boundary {
194
187
  continue;
195
188
  }
196
- // Skip if this URL is within a code span (using DocumentStructure)
197
- if structure.is_in_code_span(line_idx + 1, url_start + 1) {
189
+
190
+ // Convert byte offset to line/column
191
+ let (line_num, col_num) = ctx.offset_to_line_col(url_start);
192
+
193
+ // Skip if this URL is within a code span
194
+ if structure.is_in_code_span(line_num, col_num) {
198
195
  continue;
199
196
  }
200
- // --- NEW: Skip if URL is within any excluded range (link/image dest) ---
197
+
198
+ // Skip if this URL is within a code block
199
+ if structure.is_in_code_block(line_num) {
200
+ continue;
201
+ }
202
+
203
+ // Skip if URL is within any excluded range (link/image dest)
201
204
  let in_any_range = merged
202
205
  .iter()
203
206
  .any(|(start, end)| url_start >= *start && url_end <= *end);
204
207
  if in_any_range {
205
208
  continue;
206
209
  }
210
+
211
+ // Skip reference definitions
212
+ let line_start = content[..url_start].rfind('\n').map(|i| i + 1).unwrap_or(0);
213
+ let line_end = content[url_start..].find('\n').map(|i| url_start + i).unwrap_or(content.len());
214
+ let line = &content[line_start..line_end];
215
+ if REFERENCE_DEF_RE.is_match(line) {
216
+ continue;
217
+ }
218
+
219
+ let url_text = &content[url_start..url_end];
207
220
  let (start_line, start_col, end_line, end_col) =
208
- calculate_url_range(line_idx + 1, line, url_start, url_end - url_start);
221
+ calculate_url_range(line_num, line, col_num - 1, url_text.len());
222
+
209
223
  warnings.push(LintWarning {
210
224
  rule_name: Some(self.name()),
211
225
  line: start_line,
212
226
  column: start_col,
213
227
  end_line,
214
228
  end_column: end_col,
215
- message: format!("Bare URL found (wrap in angle brackets: <URL> or use link syntax: [text](URL))"),
229
+ message: format!("Bare URL found"),
216
230
  severity: Severity::Warning,
217
231
  fix: Some(Fix {
218
232
  range: url_start..url_end,
219
- replacement: format!("<{}>", &line[url_start..url_end]),
233
+ replacement: format!("<{}>", url_text),
220
234
  }),
221
235
  });
222
236
  }
223
237
 
224
238
  // Check for email addresses - similar logic to URLs
225
- for email_match in EMAIL_REGEX.find_iter(line) {
239
+ for email_match in EMAIL_REGEX.find_iter(content) {
226
240
  let email_start = email_match.start();
227
241
  let email_end = email_match.end();
242
+
228
243
  // Manual boundary check: not part of a larger word
229
244
  let before = if email_start == 0 {
230
245
  None
231
246
  } else {
232
- line.get(email_start - 1..email_start)
247
+ content.get(email_start - 1..email_start)
233
248
  };
234
- let after = line.get(email_end..email_end + 1);
249
+ let after = content.get(email_end..email_end + 1);
235
250
  let is_valid_boundary = before.map_or(true, |c| {
236
251
  !c.chars().next().unwrap().is_alphanumeric() && c != "_" && c != "."
237
252
  }) && after.map_or(true, |c| {
@@ -240,10 +255,20 @@ impl MD034NoBareUrls {
240
255
  if !is_valid_boundary {
241
256
  continue;
242
257
  }
243
- // Skip if this email is within a code span (using DocumentStructure)
244
- if structure.is_in_code_span(line_idx + 1, email_start + 1) {
258
+
259
+ // Convert byte offset to line/column
260
+ let (line_num, col_num) = ctx.offset_to_line_col(email_start);
261
+
262
+ // Skip if this email is within a code span
263
+ if structure.is_in_code_span(line_num, col_num) {
264
+ continue;
265
+ }
266
+
267
+ // Skip if this email is within a code block
268
+ if structure.is_in_code_block(line_num) {
245
269
  continue;
246
270
  }
271
+
247
272
  // Skip if email is within any excluded range (link/image dest)
248
273
  let in_any_range = merged
249
274
  .iter()
@@ -251,65 +276,29 @@ impl MD034NoBareUrls {
251
276
  if in_any_range {
252
277
  continue;
253
278
  }
279
+
280
+ let email_text = &content[email_start..email_end];
281
+ let line_start = content[..email_start].rfind('\n').map(|i| i + 1).unwrap_or(0);
282
+ let line_end = content[email_start..].find('\n').map(|i| email_start + i).unwrap_or(content.len());
283
+ let line = &content[line_start..line_end];
254
284
  let (start_line, start_col, end_line, end_col) =
255
- calculate_url_range(line_idx + 1, line, email_start, email_end - email_start);
285
+ calculate_url_range(line_num, line, col_num - 1, email_text.len());
286
+
256
287
  warnings.push(LintWarning {
257
288
  rule_name: Some(self.name()),
258
289
  line: start_line,
259
290
  column: start_col,
260
291
  end_line,
261
292
  end_column: end_col,
262
- message: format!(
263
- "Bare email address found: {}",
264
- &line[email_start..email_end]
265
- ),
293
+ message: format!("Bare email address found"),
266
294
  severity: Severity::Warning,
267
295
  fix: Some(Fix {
268
296
  range: email_start..email_end,
269
- replacement: format!("<{}>", &line[email_start..email_end]),
297
+ replacement: format!("<{}>", email_text),
270
298
  }),
271
299
  });
272
300
  }
273
- warnings
274
- }
275
-
276
- // Uses DocumentStructure for code block and code span detection in check_with_structure.
277
- pub fn check_with_structure(
278
- &self,
279
- ctx: &crate::lint_context::LintContext,
280
- structure: &crate::utils::document_structure::DocumentStructure,
281
- ) -> LintResult {
282
- let content = ctx.content;
283
301
 
284
- // Early return: skip if no URLs or emails
285
- if self.should_skip(content) {
286
- return Ok(vec![]);
287
- }
288
-
289
- let mut warnings = Vec::new();
290
- for (i, line) in content.lines().enumerate() {
291
- // Fast path: Skip empty lines
292
- if line.trim().is_empty() {
293
- continue;
294
- }
295
-
296
- // Fast path: Skip lines without potential URLs or emails
297
- if !line.contains("http") && !line.contains("ftp") && !line.contains('@') {
298
- continue;
299
- }
300
-
301
- // Skip lines in code blocks
302
- if structure.is_in_code_block(i + 1) {
303
- continue;
304
- }
305
-
306
- // Fast path: Skip reference link definitions
307
- if REFERENCE_DEF_RE.is_match(line) {
308
- continue;
309
- }
310
-
311
- warnings.extend(self.find_bare_urls_with_structure(line, i, structure));
312
- }
313
302
  Ok(warnings)
314
303
  }
315
304
 
@@ -368,7 +357,7 @@ impl MD034NoBareUrls {
368
357
  column: start_col,
369
358
  end_line,
370
359
  end_column: end_col,
371
- message: format!("Bare URL found (wrap in angle brackets: <URL> or use link syntax: [text](URL))"),
360
+ message: format!("Bare URL found"),
372
361
  severity: Severity::Warning,
373
362
  fix: Some(Fix {
374
363
  range: offset..(offset + url_text.len()),
@@ -466,7 +455,7 @@ impl MD034NoBareUrls {
466
455
  column: start_col,
467
456
  end_line,
468
457
  end_column: end_col,
469
- message: format!("Bare URL found (wrap in angle brackets: <URL> or use link syntax: [text](URL))"),
458
+ message: format!("Bare URL found"),
470
459
  severity: Severity::Warning,
471
460
  fix: Some(Fix {
472
461
  range: offset..(offset + url_text.len()),
@@ -35,57 +35,15 @@ impl Rule for MD042NoEmptyLinks {
35
35
 
36
36
  fn check(&self, ctx: &crate::lint_context::LintContext) -> LintResult {
37
37
  let content = ctx.content;
38
- let line_index = LineIndex::new(content.to_string());
39
- let mut warnings = Vec::new();
40
-
41
- lazy_static! {
42
- static ref EMPTY_LINK_REGEX: Regex =
43
- Regex::new(r"(?<!\!)\[([^\]]*)\]\(([^\)]*)\)").unwrap();
44
- }
45
38
 
46
- for (line_num, line) in content.lines().enumerate() {
47
- for cap_result in EMPTY_LINK_REGEX.captures_iter(line) {
48
- let cap = match cap_result {
49
- Ok(cap) => cap,
50
- Err(_) => continue,
51
- };
52
-
53
- let full_match = cap.get(0).unwrap();
54
- let text = cap.get(1).map_or("", |m| m.as_str());
55
- let url = cap.get(2).map_or("", |m| m.as_str());
56
-
57
- if text.trim().is_empty() || url.trim().is_empty() {
58
- let replacement = if text.trim().is_empty() && url.trim().is_empty() {
59
- "[Link text](https://example.com)".to_string()
60
- } else if text.trim().is_empty() {
61
- format!("[Link text]({})", url)
62
- } else {
63
- format!("[{}](https://example.com)", text)
64
- };
65
-
66
- warnings.push(LintWarning {
67
- rule_name: Some(self.name()),
68
- message: format!(
69
- "Empty link found: [{
70
- }]({})",
71
- text, url
72
- ),
73
- line: line_num + 1,
74
- column: full_match.start() + 1,
75
- end_line: line_num + 1,
76
- end_column: full_match.end() + 1,
77
- severity: Severity::Warning,
78
- fix: Some(Fix {
79
- range: line_index
80
- .line_col_to_byte_range(line_num + 1, full_match.start() + 1),
81
- replacement,
82
- }),
83
- });
84
- }
85
- }
39
+ // Early return for empty content or content without links
40
+ if content.is_empty() || !content.contains('[') {
41
+ return Ok(Vec::new());
86
42
  }
87
43
 
88
- Ok(warnings)
44
+ // Use document structure for proper code block and code span detection
45
+ let structure = DocumentStructure::new(content);
46
+ self.check_with_structure(ctx, &structure)
89
47
  }
90
48
 
91
49
  /// Optimized check using document structure
@@ -125,7 +83,7 @@ impl Rule for MD042NoEmptyLinks {
125
83
  line: link.line,
126
84
  column: link.start_col,
127
85
  end_line: link.line,
128
- end_column: link.end_col,
86
+ end_column: link.end_col + 1,
129
87
  severity: Severity::Warning,
130
88
  fix: Some(Fix {
131
89
  range: line_index.line_col_to_byte_range(link.line, link.start_col),