rumdl 0.0.70__tar.gz → 0.0.72__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 (263) hide show
  1. {rumdl-0.0.70 → rumdl-0.0.72}/Cargo.lock +1 -1
  2. {rumdl-0.0.70 → rumdl-0.0.72}/Cargo.toml +1 -1
  3. {rumdl-0.0.70 → rumdl-0.0.72}/PKG-INFO +1 -1
  4. {rumdl-0.0.70 → rumdl-0.0.72}/src/lib.rs +1 -1
  5. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md001_heading_increment.rs +1 -1
  6. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md006_start_bullets.rs +55 -35
  7. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md009_trailing_spaces.rs +2 -2
  8. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md011_no_reversed_links.rs +85 -0
  9. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md014_commands_show_output.rs +19 -4
  10. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md022_blanks_around_headings.rs +6 -6
  11. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md025_single_title.rs +58 -1
  12. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md026_no_trailing_punctuation.rs +2 -2
  13. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md028_no_blanks_blockquote.rs +1 -1
  14. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md029_ordered_list_prefix.rs +46 -2
  15. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md030_list_marker_space.rs +10 -2
  16. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md032_blanks_around_lists.rs +9 -9
  17. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md033_no_inline_html.rs +20 -26
  18. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md034_no_bare_urls.rs +12 -6
  19. rumdl-0.0.72/src/rules/md037_spaces_around_emphasis.rs +620 -0
  20. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md039_no_space_in_links.rs +1 -1
  21. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md040_fenced_code_language.rs +3 -2
  22. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md045_no_alt_text.rs +1 -1
  23. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md046_code_block_style.rs +4 -4
  24. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md048_code_fence_style.rs +2 -2
  25. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md055_table_pipe_style.rs +24 -1
  26. {rumdl-0.0.70 → rumdl-0.0.72}/src/utils/regex_cache.rs +6 -4
  27. {rumdl-0.0.70 → rumdl-0.0.72}/tests/output_format_tests.rs +2 -2
  28. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md001_test.rs +1 -1
  29. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md001_unicode_test.rs +1 -1
  30. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md009_test.rs +1 -4
  31. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md030_test.rs +35 -7
  32. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md032_test.rs +3 -5
  33. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md034_test.rs +3 -3
  34. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md037_test.rs +205 -12
  35. rumdl-0.0.70/src/rules/md037_spaces_around_emphasis.rs +0 -595
  36. {rumdl-0.0.70 → rumdl-0.0.72}/.rumdl.toml +0 -0
  37. {rumdl-0.0.70 → rumdl-0.0.72}/MANIFEST.in +0 -0
  38. {rumdl-0.0.70 → rumdl-0.0.72}/Makefile +0 -0
  39. {rumdl-0.0.70 → rumdl-0.0.72}/README.md +0 -0
  40. {rumdl-0.0.70 → rumdl-0.0.72}/assets/logo.png +0 -0
  41. {rumdl-0.0.70 → rumdl-0.0.72}/benches/fix_performance.rs +0 -0
  42. {rumdl-0.0.70 → rumdl-0.0.72}/benches/range_performance.rs +0 -0
  43. {rumdl-0.0.70 → rumdl-0.0.72}/benches/range_utils_benchmark.rs +0 -0
  44. {rumdl-0.0.70 → rumdl-0.0.72}/benches/rule_performance.rs +0 -0
  45. {rumdl-0.0.70 → rumdl-0.0.72}/benches/simple_fix_bench.rs +0 -0
  46. {rumdl-0.0.70 → rumdl-0.0.72}/docs/RULES.md +0 -0
  47. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md001.md +0 -0
  48. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md002.md +0 -0
  49. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md003.md +0 -0
  50. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md004.md +0 -0
  51. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md005.md +0 -0
  52. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md006.md +0 -0
  53. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md007.md +0 -0
  54. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md009.md +0 -0
  55. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md010.md +0 -0
  56. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md011.md +0 -0
  57. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md012.md +0 -0
  58. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md013.md +0 -0
  59. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md014.md +0 -0
  60. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md018.md +0 -0
  61. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md019.md +0 -0
  62. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md020.md +0 -0
  63. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md021.md +0 -0
  64. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md022.md +0 -0
  65. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md023.md +0 -0
  66. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md024.md +0 -0
  67. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md025.md +0 -0
  68. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md026.md +0 -0
  69. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md027.md +0 -0
  70. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md028.md +0 -0
  71. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md029.md +0 -0
  72. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md030.md +0 -0
  73. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md031.md +0 -0
  74. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md032.md +0 -0
  75. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md033.md +0 -0
  76. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md034.md +0 -0
  77. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md035.md +0 -0
  78. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md036.md +0 -0
  79. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md037.md +0 -0
  80. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md038.md +0 -0
  81. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md039.md +0 -0
  82. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md040.md +0 -0
  83. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md041.md +0 -0
  84. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md042.md +0 -0
  85. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md043.md +0 -0
  86. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md044.md +0 -0
  87. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md045.md +0 -0
  88. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md046.md +0 -0
  89. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md047.md +0 -0
  90. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md048.md +0 -0
  91. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md049.md +0 -0
  92. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md050.md +0 -0
  93. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md051.md +0 -0
  94. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md052.md +0 -0
  95. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md053.md +0 -0
  96. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md054.md +0 -0
  97. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md055.md +0 -0
  98. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md056.md +0 -0
  99. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md057.md +0 -0
  100. {rumdl-0.0.70 → rumdl-0.0.72}/docs/md058.md +0 -0
  101. {rumdl-0.0.70 → rumdl-0.0.72}/issues/plan-rule-parity-with-markdownlint.md +0 -0
  102. {rumdl-0.0.70 → rumdl-0.0.72}/parity_check.py +0 -0
  103. {rumdl-0.0.70 → rumdl-0.0.72}/pyproject.toml +0 -0
  104. {rumdl-0.0.70 → rumdl-0.0.72}/python/MANIFEST.in +0 -0
  105. {rumdl-0.0.70 → rumdl-0.0.72}/python/PYTHON-README.md +0 -0
  106. {rumdl-0.0.70 → rumdl-0.0.72}/python/rumdl/__init__.py +0 -0
  107. {rumdl-0.0.70 → rumdl-0.0.72}/python/rumdl/__main__.py +0 -0
  108. {rumdl-0.0.70 → rumdl-0.0.72}/python/rumdl/py.typed +0 -0
  109. {rumdl-0.0.70 → rumdl-0.0.72}/rumdl.toml.example +0 -0
  110. {rumdl-0.0.70 → rumdl-0.0.72}/src/config.rs +0 -0
  111. {rumdl-0.0.70 → rumdl-0.0.72}/src/init.rs +0 -0
  112. {rumdl-0.0.70 → rumdl-0.0.72}/src/lint_context.rs +0 -0
  113. {rumdl-0.0.70 → rumdl-0.0.72}/src/lsp/mod.rs +0 -0
  114. {rumdl-0.0.70 → rumdl-0.0.72}/src/lsp/server.rs +0 -0
  115. {rumdl-0.0.70 → rumdl-0.0.72}/src/lsp/types.rs +0 -0
  116. {rumdl-0.0.70 → rumdl-0.0.72}/src/main.rs +0 -0
  117. {rumdl-0.0.70 → rumdl-0.0.72}/src/markdownlint_config.rs +0 -0
  118. {rumdl-0.0.70 → rumdl-0.0.72}/src/parallel.rs +0 -0
  119. {rumdl-0.0.70 → rumdl-0.0.72}/src/performance.rs +0 -0
  120. {rumdl-0.0.70 → rumdl-0.0.72}/src/profiling.rs +0 -0
  121. {rumdl-0.0.70 → rumdl-0.0.72}/src/python.rs +0 -0
  122. {rumdl-0.0.70 → rumdl-0.0.72}/src/rule.rs +0 -0
  123. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/blockquote_utils.rs +0 -0
  124. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/code_block_utils.rs +0 -0
  125. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/code_fence_utils.rs +0 -0
  126. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/emphasis_style.rs +0 -0
  127. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/front_matter_utils.rs +0 -0
  128. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/heading_utils.rs +0 -0
  129. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/list_utils.rs +0 -0
  130. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md002_first_heading_h1.rs +0 -0
  131. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md003_heading_style.rs +0 -0
  132. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md004_unordered_list_style.rs +0 -0
  133. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md005_list_indent.rs +0 -0
  134. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md007_ul_indent.rs +0 -0
  135. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md010_no_hard_tabs.rs +0 -0
  136. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md012_no_multiple_blanks.rs +0 -0
  137. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md013_line_length.rs +0 -0
  138. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md018_no_missing_space_atx.rs +0 -0
  139. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md019_no_multiple_space_atx.rs +0 -0
  140. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md020_no_missing_space_closed_atx.rs +0 -0
  141. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md021_no_multiple_space_closed_atx.rs +0 -0
  142. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md023_heading_start_left.rs +0 -0
  143. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md024_no_duplicate_heading.rs +0 -0
  144. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md027_multiple_spaces_blockquote.rs +0 -0
  145. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md031_blanks_around_fences.rs +0 -0
  146. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md035_hr_style.rs +0 -0
  147. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md036_no_emphasis_only_first.rs +0 -0
  148. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md038_no_space_in_code.rs +0 -0
  149. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md041_first_line_heading.rs +0 -0
  150. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md042_no_empty_links.rs +0 -0
  151. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md043_required_headings.rs +0 -0
  152. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md044_proper_names.rs +0 -0
  153. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md047_single_trailing_newline.rs +0 -0
  154. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md049_emphasis_style.rs +0 -0
  155. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md050_strong_style.rs +0 -0
  156. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md051_link_fragments.rs +0 -0
  157. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md052_reference_links_images.rs +0 -0
  158. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md053_link_image_reference_definitions.rs +0 -0
  159. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md054_link_image_style.rs +0 -0
  160. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md056_table_column_count.rs +0 -0
  161. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md057_existing_relative_links.rs +0 -0
  162. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/md058_blanks_around_tables.rs +0 -0
  163. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/mod.rs +0 -0
  164. {rumdl-0.0.70 → rumdl-0.0.72}/src/rules/strong_style.rs +0 -0
  165. {rumdl-0.0.70 → rumdl-0.0.72}/src/utils/ast_utils.rs +0 -0
  166. {rumdl-0.0.70 → rumdl-0.0.72}/src/utils/code_block_utils.rs +0 -0
  167. {rumdl-0.0.70 → rumdl-0.0.72}/src/utils/document_structure.rs +0 -0
  168. {rumdl-0.0.70 → rumdl-0.0.72}/src/utils/early_returns.rs +0 -0
  169. {rumdl-0.0.70 → rumdl-0.0.72}/src/utils/element_cache.rs +0 -0
  170. {rumdl-0.0.70 → rumdl-0.0.72}/src/utils/markdown_elements.rs +0 -0
  171. {rumdl-0.0.70 → rumdl-0.0.72}/src/utils/mod.rs +0 -0
  172. {rumdl-0.0.70 → rumdl-0.0.72}/src/utils/range_utils.rs +0 -0
  173. {rumdl-0.0.70 → rumdl-0.0.72}/src/utils/string_interner.rs +0 -0
  174. {rumdl-0.0.70 → rumdl-0.0.72}/src/utils/table_utils.rs +0 -0
  175. {rumdl-0.0.70 → rumdl-0.0.72}/tests/advanced_integration_tests.rs +0 -0
  176. {rumdl-0.0.70 → rumdl-0.0.72}/tests/character_ranges/additional_tests.rs +0 -0
  177. {rumdl-0.0.70 → rumdl-0.0.72}/tests/character_ranges/basic_tests.rs +0 -0
  178. {rumdl-0.0.70 → rumdl-0.0.72}/tests/character_ranges/comprehensive_tests.rs +0 -0
  179. {rumdl-0.0.70 → rumdl-0.0.72}/tests/character_ranges/extended_tests.rs +0 -0
  180. {rumdl-0.0.70 → rumdl-0.0.72}/tests/character_ranges/mod.rs +0 -0
  181. {rumdl-0.0.70 → rumdl-0.0.72}/tests/character_ranges/unicode_utils.rs +0 -0
  182. {rumdl-0.0.70 → rumdl-0.0.72}/tests/cli_duplication_test.rs +0 -0
  183. {rumdl-0.0.70 → rumdl-0.0.72}/tests/cli_integration_tests.rs +0 -0
  184. {rumdl-0.0.70 → rumdl-0.0.72}/tests/commonmark_compliance_tests.rs +0 -0
  185. {rumdl-0.0.70 → rumdl-0.0.72}/tests/comprehensive_integration_tests.rs +0 -0
  186. {rumdl-0.0.70 → rumdl-0.0.72}/tests/config_application_tests.rs +0 -0
  187. {rumdl-0.0.70 → rumdl-0.0.72}/tests/config_tests.rs +0 -0
  188. {rumdl-0.0.70 → rumdl-0.0.72}/tests/init_command_test.rs +0 -0
  189. {rumdl-0.0.70 → rumdl-0.0.72}/tests/init_tests.rs +0 -0
  190. {rumdl-0.0.70 → rumdl-0.0.72}/tests/integration_tests.rs +0 -0
  191. {rumdl-0.0.70 → rumdl-0.0.72}/tests/json_output_test.rs +0 -0
  192. {rumdl-0.0.70 → rumdl-0.0.72}/tests/lib.rs +0 -0
  193. {rumdl-0.0.70 → rumdl-0.0.72}/tests/lsp_integration_tests.rs +0 -0
  194. {rumdl-0.0.70 → rumdl-0.0.72}/tests/lsp_tests.rs +0 -0
  195. {rumdl-0.0.70 → rumdl-0.0.72}/tests/markdownlint_cli_integration.rs +0 -0
  196. {rumdl-0.0.70 → rumdl-0.0.72}/tests/markdownlint_config_test.rs +0 -0
  197. {rumdl-0.0.70 → rumdl-0.0.72}/tests/md030_edge_cases.md +0 -0
  198. {rumdl-0.0.70 → rumdl-0.0.72}/tests/perf_check.rs +0 -0
  199. {rumdl-0.0.70 → rumdl-0.0.72}/tests/pyproject_config_tests.rs +0 -0
  200. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md002_test.rs +0 -0
  201. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md003_test.rs +0 -0
  202. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md004_test.rs +0 -0
  203. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md005_test.rs +0 -0
  204. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md006_test.rs +0 -0
  205. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md006_unicode_test.rs +0 -0
  206. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md007_test.rs +0 -0
  207. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md010_test.rs +0 -0
  208. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md011_test.rs +0 -0
  209. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md012_test.rs +0 -0
  210. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md013_test.rs +0 -0
  211. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md014_test.rs +0 -0
  212. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md018_test.rs +0 -0
  213. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md019_test.rs +0 -0
  214. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md020_test.rs +0 -0
  215. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md021_test.rs +0 -0
  216. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md022_test.rs +0 -0
  217. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md023_extended_test.rs +0 -0
  218. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md023_test.rs +0 -0
  219. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md024_test.rs +0 -0
  220. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md025_test.rs +0 -0
  221. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md026_test.rs +0 -0
  222. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md027_test.rs +0 -0
  223. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md028_test.rs +0 -0
  224. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md029_test.rs +0 -0
  225. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md031_test.rs +0 -0
  226. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md033_extended_test.rs +0 -0
  227. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md033_test.rs +0 -0
  228. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md035_test.rs +0 -0
  229. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md036_test.rs +0 -0
  230. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md038_test.rs +0 -0
  231. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md039_test.rs +0 -0
  232. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md040_test.rs +0 -0
  233. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md041_test.rs +0 -0
  234. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md042_test.rs +0 -0
  235. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md043_test.rs +0 -0
  236. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md044_test.rs +0 -0
  237. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md045_test.rs +0 -0
  238. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md046_test.rs +0 -0
  239. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md047_test.rs +0 -0
  240. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md048_test.rs +0 -0
  241. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md049_test.rs +0 -0
  242. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md050_test.rs +0 -0
  243. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md051_test.rs +0 -0
  244. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md052_test.rs +0 -0
  245. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md053_additional_test.rs +0 -0
  246. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md053_proptest.rs +0 -0
  247. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md053_test.rs +0 -0
  248. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md054_test.rs +0 -0
  249. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md054_unicode_test.rs +0 -0
  250. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md055_test.rs +0 -0
  251. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md056_test.rs +0 -0
  252. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md057_test.rs +0 -0
  253. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/md058_test.rs +0 -0
  254. {rumdl-0.0.70 → rumdl-0.0.72}/tests/rules/mod.rs +0 -0
  255. {rumdl-0.0.70 → rumdl-0.0.72}/tests/utils/blockquote_utils_test.rs +0 -0
  256. {rumdl-0.0.70 → rumdl-0.0.72}/tests/utils/code_block_utils_extended_test.rs +0 -0
  257. {rumdl-0.0.70 → rumdl-0.0.72}/tests/utils/code_block_utils_test.rs +0 -0
  258. {rumdl-0.0.70 → rumdl-0.0.72}/tests/utils/core_utils_test.rs +0 -0
  259. {rumdl-0.0.70 → rumdl-0.0.72}/tests/utils/front_matter_utils_test.rs +0 -0
  260. {rumdl-0.0.70 → rumdl-0.0.72}/tests/utils/line_index_test.rs +0 -0
  261. {rumdl-0.0.70 → rumdl-0.0.72}/tests/utils/mod.rs +0 -0
  262. {rumdl-0.0.70 → rumdl-0.0.72}/tests/utils_markdown_edge_cases.rs +0 -0
  263. {rumdl-0.0.70 → rumdl-0.0.72}/tests/utils_tests.rs +0 -0
@@ -1789,7 +1789,7 @@ dependencies = [
1789
1789
 
1790
1790
  [[package]]
1791
1791
  name = "rumdl"
1792
- version = "0.0.70"
1792
+ version = "0.0.72"
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.70"
3
+ version = "0.0.72"
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.70
3
+ Version: 0.0.72
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -70,7 +70,7 @@ impl ContentCharacteristics {
70
70
  {
71
71
  chars.has_lists = true;
72
72
  }
73
- if !chars.has_links && line.contains('[') {
73
+ if !chars.has_links && (line.contains('[') || line.contains("http://") || line.contains("https://") || line.contains("ftp://")) {
74
74
  chars.has_links = true;
75
75
  }
76
76
  if !chars.has_images && line.contains("![") {
@@ -162,7 +162,7 @@ impl Rule for MD001HeadingIncrement {
162
162
  column: start_col,
163
163
  end_line,
164
164
  end_column: end_col,
165
- message: format!("Heading level should be {} for this level", prev_level + 1),
165
+ message: format!("Expected heading level {}", prev_level + 1),
166
166
  severity: Severity::Warning,
167
167
  fix: Some(Fix {
168
168
  range: line_index.line_col_to_byte_range(line_num, indentation + 1),
@@ -25,14 +25,14 @@ lazy_static! {
25
25
  }
26
26
 
27
27
  impl MD006StartBullets {
28
- /// Check if a line is a bullet list item and return the indentation level
28
+ /// Checks if a line is a bullet list item and returns its indentation level
29
29
  fn is_bullet_list_item(line: &str) -> Option<usize> {
30
- if let Some(caps) = BULLET_PATTERN.captures(line) {
31
- let indent = caps.get(1).unwrap().as_str().len();
32
- Some(indent)
33
- } else {
34
- None
30
+ if let Some(captures) = BULLET_PATTERN.captures(line) {
31
+ if let Some(indent) = captures.get(1) {
32
+ return Some(indent.as_str().len());
33
+ }
35
34
  }
35
+ None
36
36
  }
37
37
 
38
38
  /// Checks if a line is blank (empty or whitespace only)
@@ -46,7 +46,9 @@ impl MD006StartBullets {
46
46
  Some(indent) => indent,
47
47
  None => return None, // Should not happen if called on a bullet item
48
48
  };
49
+
49
50
  let mut i = line_idx;
51
+
50
52
  while i > 0 {
51
53
  i -= 1;
52
54
  if Self::is_blank_line(lines[i]) {
@@ -54,13 +56,36 @@ impl MD006StartBullets {
54
56
  }
55
57
  if let Some(prev_indent) = Self::is_bullet_list_item(lines[i]) {
56
58
  if prev_indent <= current_indent {
57
- return Some((i, prev_indent));
59
+ // Found a potential parent or sibling
60
+ // Check if there's any non-list content between this potential parent and current item
61
+ let mut has_breaking_content = false;
62
+ for check_idx in (i + 1)..line_idx {
63
+ if Self::is_blank_line(lines[check_idx]) {
64
+ continue;
65
+ }
66
+ if Self::is_bullet_list_item(lines[check_idx]).is_none() {
67
+ // Found non-list content - check if it breaks the list structure
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 {
72
+ has_breaking_content = true;
73
+ break;
74
+ }
75
+ }
76
+ }
77
+
78
+ if !has_breaking_content {
79
+ return Some((i, prev_indent));
80
+ } else {
81
+ // Content breaks the list structure
82
+ return None;
83
+ }
58
84
  }
59
85
  // If prev_indent > current_indent, it's a child of a sibling, ignore it and keep searching.
60
- }
61
- // If we hit non-list content, stop searching
62
- if Self::is_bullet_list_item(lines[i]).is_none() {
63
- break;
86
+ } else {
87
+ // Found non-list content - this breaks the search
88
+ return None;
64
89
  }
65
90
  }
66
91
  None
@@ -156,36 +181,25 @@ impl Rule for MD006StartBullets {
156
181
  doc_structure: &DocumentStructure,
157
182
  ) -> LintResult {
158
183
  let content = _ctx.content;
159
-
160
- // Early returns for performance
161
- if content.is_empty() || doc_structure.list_lines.is_empty() {
184
+ if doc_structure.list_lines.is_empty() {
162
185
  return Ok(Vec::new());
163
186
  }
164
-
165
- // Quick check for any list markers before processing
166
187
  if !content.contains('*') && !content.contains('-') && !content.contains('+') {
167
188
  return Ok(Vec::new());
168
189
  }
169
-
170
- // Pre-compute LineIndex once for all operations
171
190
  let line_index = LineIndex::new(content.to_string());
172
191
  let mut result = Vec::new();
173
192
  let lines: Vec<&str> = content.lines().collect();
174
193
  let mut valid_bullet_lines = vec![false; lines.len()];
175
-
176
- // Process list lines in order for better cache locality
177
194
  for &line_num in &doc_structure.list_lines {
178
195
  let line_idx = line_num - 1;
179
196
  if line_idx >= lines.len() {
180
197
  continue;
181
198
  }
182
199
  let line = lines[line_idx];
183
-
184
- // Skip lines in code blocks
185
200
  if doc_structure.is_in_code_block(line_num) {
186
201
  continue;
187
202
  }
188
-
189
203
  if let Some(indent) = Self::is_bullet_list_item(line) {
190
204
  let mut is_valid = false; // Assume invalid initially
191
205
  if indent == 0 {
@@ -220,19 +234,25 @@ impl Rule for MD006StartBullets {
220
234
  } else {
221
235
  fixed_line.to_string()
222
236
  };
237
+
238
+ // Calculate the range to highlight: from first indentation character to end of list marker
239
+ let start_col = if indent > 0 { 2 } else { 1 }; // Start from first indentation space if indented
240
+ let marker_pos = line.find(|c: char| c == '*' || c == '-' || c == '+').unwrap_or(0);
241
+ let end_col = marker_pos + 3; // +1 for the marker itself, +1 for 1-based indexing, +1 for space after marker
242
+
223
243
  result.push(LintWarning {
224
- rule_name: Some(self.name()),
225
- severity: Severity::Warning,
226
- line: line_num,
227
- column: indent,
228
- end_line: line_num,
229
- end_column: indent + 3,
230
- message: "Consider starting bulleted lists at the beginning of the line"
231
- .to_string(),
232
- fix: Some(Fix {
233
- range: line_index.line_col_to_byte_range(line_num, 1),
234
- replacement,
235
- }),
244
+ rule_name: Some(self.name()),
245
+ severity: Severity::Warning,
246
+ line: line_num,
247
+ column: start_col,
248
+ end_line: line_num,
249
+ end_column: end_col,
250
+ message: "List item should start at the beginning of the line (remove indentation)"
251
+ .to_string(),
252
+ fix: Some(Fix {
253
+ range: line_index.line_col_to_byte_range(line_num, 1),
254
+ replacement,
255
+ }),
236
256
  });
237
257
  }
238
258
  }
@@ -100,7 +100,7 @@ impl Rule for MD009TrailingSpaces {
100
100
  column: start_col,
101
101
  end_line,
102
102
  end_column: end_col,
103
- message: "Empty line should not have trailing spaces".to_string(),
103
+ message: "Empty line has trailing spaces".to_string(),
104
104
  severity: Severity::Warning,
105
105
  fix: Some(Fix {
106
106
  range: _line_index.line_col_to_byte_range(line_num + 1, 1),
@@ -134,7 +134,7 @@ impl Rule for MD009TrailingSpaces {
134
134
  column: start_col,
135
135
  end_line,
136
136
  end_column: end_col,
137
- message: "Empty blockquote line should have a space after >".to_string(),
137
+ message: "Empty blockquote line needs a space after >".to_string(),
138
138
  severity: Severity::Warning,
139
139
  fix: Some(Fix {
140
140
  range: _line_index.line_col_to_byte_range(line_num + 1, trimmed.len() + 1),
@@ -146,3 +146,88 @@ impl Rule for MD011NoReversedLinks {
146
146
  Box::new(MD011NoReversedLinks)
147
147
  }
148
148
  }
149
+
150
+ #[cfg(test)]
151
+ mod tests {
152
+ use super::*;
153
+ use crate::lint_context::LintContext;
154
+
155
+ #[test]
156
+ fn test_capture_group_order_fix() {
157
+ // This test confirms that the capture group order bug is fixed
158
+ // The regex pattern \(([^)]+)\)\[([^\]]+)\] captures:
159
+ // cap[1] = URL (inside parentheses)
160
+ // cap[2] = text (inside brackets)
161
+ // So (URL)[text] should become [text](URL)
162
+
163
+ let rule = MD011NoReversedLinks;
164
+
165
+ // Test with reversed link syntax
166
+ let content = "Check out (https://example.com)[this link] for more info.";
167
+ let ctx = LintContext::new(content);
168
+
169
+ // This should detect the reversed syntax
170
+ let result = rule.check(&ctx).unwrap();
171
+ assert_eq!(result.len(), 1);
172
+ assert!(result[0].message.contains("Reversed link syntax"));
173
+
174
+ // Verify the fix produces correct output
175
+ let fix = result[0].fix.as_ref().unwrap();
176
+ assert_eq!(fix.replacement, "[this link](https://example.com)");
177
+ }
178
+
179
+ #[test]
180
+ fn test_multiple_reversed_links() {
181
+ // Test multiple reversed links in the same content
182
+ let rule = MD011NoReversedLinks;
183
+
184
+ let content = "Visit (https://example.com)[Example] and (https://test.com)[Test Site].";
185
+ let ctx = LintContext::new(content);
186
+
187
+ let result = rule.check(&ctx).unwrap();
188
+ assert_eq!(result.len(), 2);
189
+
190
+ // Verify both fixes are correct
191
+ assert_eq!(result[0].fix.as_ref().unwrap().replacement, "[Example](https://example.com)");
192
+ assert_eq!(result[1].fix.as_ref().unwrap().replacement, "[Test Site](https://test.com)");
193
+ }
194
+
195
+ #[test]
196
+ fn test_normal_links_not_flagged() {
197
+ // Test that normal link syntax is not flagged
198
+ let rule = MD011NoReversedLinks;
199
+
200
+ let content = "This is a normal [link](https://example.com) and another [link](https://test.com).";
201
+ let ctx = LintContext::new(content);
202
+
203
+ let result = rule.check(&ctx).unwrap();
204
+ assert_eq!(result.len(), 0);
205
+ }
206
+
207
+ #[test]
208
+ fn debug_capture_groups() {
209
+ // Debug test to understand capture group behavior
210
+ let pattern = r"\(([^)]+)\)\[([^\]]+)\]";
211
+ let regex = Regex::new(pattern).unwrap();
212
+
213
+ let test_text = "(https://example.com)[Click here]";
214
+
215
+ if let Some(cap) = regex.captures(test_text) {
216
+ println!("Full match: {}", &cap[0]);
217
+ println!("cap[1] (first group): {}", &cap[1]);
218
+ println!("cap[2] (second group): {}", &cap[2]);
219
+
220
+ // Current fix format
221
+ let current_fix = format!("[{}]({})", &cap[2], &cap[1]);
222
+ println!("Current fix produces: {}", current_fix);
223
+
224
+ // Test what the actual rule produces
225
+ let rule = MD011NoReversedLinks;
226
+ let ctx = LintContext::new(test_text);
227
+ let result = rule.check(&ctx).unwrap();
228
+ if !result.is_empty() {
229
+ println!("Rule fix produces: {}", result[0].fix.as_ref().unwrap().replacement);
230
+ }
231
+ }
232
+ }
233
+ }
@@ -70,9 +70,7 @@ impl MD014CommandsShowOutput {
70
70
  }
71
71
 
72
72
  let mut has_command = false;
73
-
74
73
  let mut has_output = false;
75
-
76
74
  let mut last_command = String::new();
77
75
 
78
76
  for line in block {
@@ -88,6 +86,16 @@ impl MD014CommandsShowOutput {
88
86
  has_command && !has_output && !self.is_no_output_command(&last_command)
89
87
  }
90
88
 
89
+ fn get_command_from_block(&self, block: &[&str]) -> String {
90
+ for line in block {
91
+ let trimmed = line.trim();
92
+ if self.is_command_line(line) {
93
+ return trimmed[1..].trim().to_string();
94
+ }
95
+ }
96
+ String::new()
97
+ }
98
+
91
99
  fn fix_command_block(&self, block: &[&str]) -> String {
92
100
  block
93
101
  .iter()
@@ -175,14 +183,21 @@ impl Rule for MD014CommandsShowOutput {
175
183
  match_obj.len(),
176
184
  );
177
185
 
186
+ // Get the command for a more helpful message
187
+ let command = self.get_command_from_block(&current_block);
188
+ let message = if command.is_empty() {
189
+ "Command should show output (add example output or remove $ prompt)".to_string()
190
+ } else {
191
+ format!("Command '{}' should show output (add example output or remove $ prompt)", command)
192
+ };
193
+
178
194
  warnings.push(LintWarning {
179
195
  rule_name: Some(self.name()),
180
196
  line: start_line,
181
197
  column: start_col,
182
198
  end_line,
183
199
  end_column: end_col,
184
- message: "Commands in code blocks should show output"
185
- .to_string(),
200
+ message,
186
201
  severity: Severity::Warning,
187
202
  fix: Some(Fix {
188
203
  range: _line_index
@@ -582,7 +582,7 @@ impl Rule for MD022BlanksAroundHeadings {
582
582
  } else {
583
583
  "lines"
584
584
  };
585
- issues.push(format!("Headings should be surrounded by blank lines. Expected at least {} blank {} between headings.", required_blanks, line_word));
585
+ issues.push(format!("Expected {} blank {} between headings", required_blanks, line_word));
586
586
  }
587
587
  }
588
588
 
@@ -604,7 +604,7 @@ impl Rule for MD022BlanksAroundHeadings {
604
604
  "lines"
605
605
  };
606
606
  issues.push(format!(
607
- "Heading should have at least {} blank {} above.",
607
+ "Expected {} blank {} above heading",
608
608
  self.lines_above, line_word
609
609
  ));
610
610
  }
@@ -663,7 +663,7 @@ impl Rule for MD022BlanksAroundHeadings {
663
663
  "lines"
664
664
  };
665
665
  issues.push(format!(
666
- "Heading should have at least {} blank {} below.",
666
+ "Expected {} blank {} below heading",
667
667
  self.lines_below, line_word
668
668
  ));
669
669
  }
@@ -784,7 +784,7 @@ impl Rule for MD022BlanksAroundHeadings {
784
784
  } else {
785
785
  "lines"
786
786
  };
787
- issues.push(format!("Headings should be surrounded by blank lines. Expected at least {} blank {} between headings.", required_blanks, line_word));
787
+ issues.push(format!("Expected {} blank {} between headings", required_blanks, line_word));
788
788
  }
789
789
  }
790
790
 
@@ -806,7 +806,7 @@ impl Rule for MD022BlanksAroundHeadings {
806
806
  "lines"
807
807
  };
808
808
  issues.push(format!(
809
- "Heading should have at least {} blank {} above.",
809
+ "Expected {} blank {} above heading",
810
810
  self.lines_above, line_word
811
811
  ));
812
812
  }
@@ -865,7 +865,7 @@ impl Rule for MD022BlanksAroundHeadings {
865
865
  "lines"
866
866
  };
867
867
  issues.push(format!(
868
- "Heading should have at least {} blank {} below.",
868
+ "Expected {} blank {} below heading",
869
869
  self.lines_below, line_word
870
870
  ));
871
871
  }
@@ -253,7 +253,13 @@ impl Rule for MD025SingleTitle {
253
253
  "{} {}",
254
254
  "#".repeat(self.level + 1),
255
255
  if line_content.trim_start().starts_with('#') {
256
- &line_content[(col + self.level)..]
256
+ // Add bounds checking to prevent panic
257
+ let slice_start = col + self.level;
258
+ if slice_start < line_content.len() {
259
+ &line_content[slice_start..]
260
+ } else {
261
+ "" // If bounds exceeded, use empty string
262
+ }
257
263
  } else {
258
264
  line_content.trim() // For Setext, use the whole line
259
265
  }
@@ -357,4 +363,55 @@ mod tests {
357
363
  "Should not flag a single title after front matter"
358
364
  );
359
365
  }
366
+
367
+ #[test]
368
+ fn test_bounds_checking_bug() {
369
+ // Test case that could trigger bounds error in fix generation
370
+ // When col + self.level exceeds line_content.len()
371
+ let rule = MD025SingleTitle::default();
372
+
373
+ // Create content with very short second heading
374
+ let content = "# First\n#";
375
+ let ctx = crate::lint_context::LintContext::new(content);
376
+
377
+ // This should not panic
378
+ let result = rule.check(&ctx);
379
+ assert!(result.is_ok());
380
+
381
+ // Test the fix as well
382
+ let fix_result = rule.fix(&ctx);
383
+ assert!(fix_result.is_ok());
384
+ }
385
+
386
+ #[test]
387
+ fn test_bounds_checking_edge_case() {
388
+ // Test case that specifically targets the bounds checking fix
389
+ // Create a heading where col + self.level would exceed line length
390
+ let rule = MD025SingleTitle::default();
391
+
392
+ // Create content where the second heading is just "#" (length 1)
393
+ // col will be 0, self.level is 1, so col + self.level = 1
394
+ // This should not exceed bounds for "#" but tests the edge case
395
+ let content = "# First Title\n#";
396
+ let ctx = crate::lint_context::LintContext::new(content);
397
+
398
+ // This should not panic and should handle the edge case gracefully
399
+ let result = rule.check(&ctx);
400
+ assert!(result.is_ok());
401
+
402
+ if let Ok(warnings) = result {
403
+ if !warnings.is_empty() {
404
+ // Check that the fix doesn't cause a panic
405
+ let fix_result = rule.fix(&ctx);
406
+ assert!(fix_result.is_ok());
407
+
408
+ // The fix should produce valid content
409
+ if let Ok(fixed_content) = fix_result {
410
+ assert!(!fixed_content.is_empty());
411
+ // Should convert the second "#" to "##" (or "## " if there's content)
412
+ assert!(fixed_content.contains("##"));
413
+ }
414
+ }
415
+ }
416
+ }
360
417
  }
@@ -292,7 +292,7 @@ impl MD026NoTrailingPunctuation {
292
292
  end_line,
293
293
  end_column: end_col,
294
294
  message: format!(
295
- "Heading '{}' should not end with punctuation '{}'",
295
+ "Heading '{}' ends with punctuation '{}'",
296
296
  heading_text.trim(),
297
297
  last_char
298
298
  ),
@@ -337,7 +337,7 @@ impl MD026NoTrailingPunctuation {
337
337
  end_column: end_col,
338
338
  message: format!(
339
339
  "Heading '{
340
- }' should not end with punctuation '{}'",
340
+ }' ends with punctuation '{}'",
341
341
  lines[heading_line - 1].trim(),
342
342
  last_char
343
343
  ),
@@ -73,7 +73,7 @@ impl Rule for MD028NoBlanksBlockquote {
73
73
 
74
74
  warnings.push(LintWarning {
75
75
  rule_name: Some(self.name()),
76
- message: "Blank line inside blockquote".to_string(),
76
+ message: "Empty blockquote line should contain '>' marker".to_string(),
77
77
  line: start_line,
78
78
  column: start_col,
79
79
  end_line,
@@ -307,9 +307,8 @@ impl MD029OrderedListPrefix {
307
307
 
308
308
  // Check each item in the group for correct sequence
309
309
  for (idx, (line_num, line)) in group.iter().enumerate() {
310
- if Self::get_list_number(line).is_some() {
310
+ if let Some(actual_num) = Self::get_list_number(line) {
311
311
  let expected_num = self.get_expected_number(idx);
312
- let actual_num = Self::get_list_number(line).unwrap();
313
312
 
314
313
  if actual_num != expected_num {
315
314
  warnings.push(LintWarning {
@@ -378,4 +377,49 @@ mod tests {
378
377
  let result = rule.check_with_structure(&ctx, &structure).unwrap();
379
378
  assert!(result.is_empty());
380
379
  }
380
+
381
+ #[test]
382
+ fn test_redundant_computation_fix() {
383
+ // This test confirms that the redundant computation bug is fixed
384
+ // Previously: get_list_number() was called twice (once for is_some(), once for unwrap())
385
+ // Now: get_list_number() is called once with if let pattern
386
+
387
+ let rule = MD029OrderedListPrefix::default();
388
+
389
+ // Test with mixed valid and edge case content
390
+ let content = "1. First item\n3. Wrong number\n2. Another wrong number";
391
+ let structure = DocumentStructure::new(content);
392
+ let ctx = crate::lint_context::LintContext::new(content);
393
+
394
+ // This should not panic and should produce warnings for incorrect numbering
395
+ let result = rule.check_with_structure(&ctx, &structure).unwrap();
396
+ assert_eq!(result.len(), 2); // Should have warnings for items 3 and 2
397
+
398
+ // Verify the warnings have correct content
399
+ assert!(result[0].message.contains("3 does not match style (expected 2)"));
400
+ assert!(result[1].message.contains("2 does not match style (expected 3)"));
401
+ }
402
+
403
+ #[test]
404
+ fn test_performance_improvement() {
405
+ // This test verifies that the fix improves performance by avoiding redundant calls
406
+ let rule = MD029OrderedListPrefix::default();
407
+
408
+ // Create a larger list to test performance
409
+ let mut content = String::new();
410
+ for i in 1..=100 {
411
+ content.push_str(&format!("{}. Item {}\n", i + 1, i)); // All wrong numbers
412
+ }
413
+
414
+ let structure = DocumentStructure::new(&content);
415
+ let ctx = crate::lint_context::LintContext::new(&content);
416
+
417
+ // This should complete without issues and produce warnings for all items
418
+ let result = rule.check_with_structure(&ctx, &structure).unwrap();
419
+ assert_eq!(result.len(), 100); // Should have warnings for all 100 items
420
+
421
+ // Verify first and last warnings
422
+ assert!(result[0].message.contains("2 does not match style (expected 1)"));
423
+ assert!(result[99].message.contains("101 does not match style (expected 100)"));
424
+ }
381
425
  }
@@ -149,7 +149,11 @@ impl Rule for MD030ListMarkerSpace {
149
149
  column: start_col,
150
150
  end_line,
151
151
  end_column: end_col,
152
- message: "Spaces after list markers".to_string(),
152
+ message: format!(
153
+ "Spaces after list markers (Expected: {}; Actual: {})",
154
+ expected_spaces,
155
+ whitespace.len()
156
+ ),
153
157
  fix,
154
158
  });
155
159
  }
@@ -420,7 +424,11 @@ mod tests {
420
424
  "Should flag lines with too many spaces after list marker"
421
425
  );
422
426
  for warning in result {
423
- assert_eq!(warning.message, "Spaces after list markers");
427
+ assert!(
428
+ warning.message.starts_with("Spaces after list markers (Expected:") && warning.message.contains("Actual:"),
429
+ "Warning message should include expected and actual values, got: '{}'",
430
+ warning.message
431
+ );
424
432
  }
425
433
  }
426
434
  }