rumdl 0.0.93__tar.gz → 0.0.94__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 (346) hide show
  1. {rumdl-0.0.93 → rumdl-0.0.94}/CHANGELOG.md +4 -1
  2. {rumdl-0.0.93 → rumdl-0.0.94}/Cargo.lock +3 -3
  3. {rumdl-0.0.93 → rumdl-0.0.94}/Cargo.toml +1 -1
  4. {rumdl-0.0.93 → rumdl-0.0.94}/PKG-INFO +1 -1
  5. rumdl-0.0.94/src/bin/benchmark_rule.rs +156 -0
  6. {rumdl-0.0.93 → rumdl-0.0.94}/src/bin/measure_code_span_performance.rs +1 -1
  7. {rumdl-0.0.93 → rumdl-0.0.94}/src/lint_context.rs +22 -6
  8. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md009_trailing_spaces.rs +10 -12
  9. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md013_line_length.rs +121 -36
  10. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md034_no_bare_urls.rs +98 -119
  11. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md038_no_space_in_code.rs +32 -11
  12. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md044_proper_names.rs +93 -89
  13. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md047_single_trailing_newline.rs +36 -21
  14. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md052_reference_links_images.rs +7 -3
  15. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md053_link_image_reference_definitions.rs +62 -48
  16. {rumdl-0.0.93 → rumdl-0.0.94}/.config/nextest.toml +0 -0
  17. {rumdl-0.0.93 → rumdl-0.0.94}/.mise.toml +0 -0
  18. {rumdl-0.0.93 → rumdl-0.0.94}/.rumdl.toml +0 -0
  19. {rumdl-0.0.93 → rumdl-0.0.94}/.rustfmt.toml +0 -0
  20. {rumdl-0.0.93 → rumdl-0.0.94}/LICENSE +0 -0
  21. {rumdl-0.0.93 → rumdl-0.0.94}/MANIFEST.in +0 -0
  22. {rumdl-0.0.93 → rumdl-0.0.94}/Makefile +0 -0
  23. {rumdl-0.0.93 → rumdl-0.0.94}/README.md +0 -0
  24. {rumdl-0.0.93 → rumdl-0.0.94}/assets/logo.png +0 -0
  25. {rumdl-0.0.93 → rumdl-0.0.94}/benches/fix_performance.rs +0 -0
  26. {rumdl-0.0.93 → rumdl-0.0.94}/benches/range_performance.rs +0 -0
  27. {rumdl-0.0.93 → rumdl-0.0.94}/benches/range_utils_benchmark.rs +0 -0
  28. {rumdl-0.0.93 → rumdl-0.0.94}/benches/rule_performance.rs +0 -0
  29. {rumdl-0.0.93 → rumdl-0.0.94}/benches/simple_fix_bench.rs +0 -0
  30. {rumdl-0.0.93 → rumdl-0.0.94}/docs/RULES.md +0 -0
  31. {rumdl-0.0.93 → rumdl-0.0.94}/docs/global-settings.md +0 -0
  32. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md001.md +0 -0
  33. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md002.md +0 -0
  34. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md003.md +0 -0
  35. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md004.md +0 -0
  36. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md005.md +0 -0
  37. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md006.md +0 -0
  38. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md007.md +0 -0
  39. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md009.md +0 -0
  40. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md010.md +0 -0
  41. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md011.md +0 -0
  42. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md012.md +0 -0
  43. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md013.md +0 -0
  44. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md014.md +0 -0
  45. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md018.md +0 -0
  46. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md019.md +0 -0
  47. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md020.md +0 -0
  48. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md021.md +0 -0
  49. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md022.md +0 -0
  50. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md023.md +0 -0
  51. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md024.md +0 -0
  52. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md025.md +0 -0
  53. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md026.md +0 -0
  54. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md027.md +0 -0
  55. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md028.md +0 -0
  56. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md029.md +0 -0
  57. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md030.md +0 -0
  58. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md031.md +0 -0
  59. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md032.md +0 -0
  60. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md033.md +0 -0
  61. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md034.md +0 -0
  62. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md035.md +0 -0
  63. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md036.md +0 -0
  64. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md037.md +0 -0
  65. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md038.md +0 -0
  66. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md039.md +0 -0
  67. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md040.md +0 -0
  68. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md041.md +0 -0
  69. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md042.md +0 -0
  70. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md043.md +0 -0
  71. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md044.md +0 -0
  72. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md045.md +0 -0
  73. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md046.md +0 -0
  74. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md047.md +0 -0
  75. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md048.md +0 -0
  76. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md049.md +0 -0
  77. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md050.md +0 -0
  78. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md051.md +0 -0
  79. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md052.md +0 -0
  80. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md053.md +0 -0
  81. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md054.md +0 -0
  82. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md055.md +0 -0
  83. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md056.md +0 -0
  84. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md057.md +0 -0
  85. {rumdl-0.0.93 → rumdl-0.0.94}/docs/md058.md +0 -0
  86. {rumdl-0.0.93 → rumdl-0.0.94}/docs/vscode-extension.md +0 -0
  87. {rumdl-0.0.93 → rumdl-0.0.94}/parity_check.py +0 -0
  88. {rumdl-0.0.93 → rumdl-0.0.94}/pyproject.toml +0 -0
  89. {rumdl-0.0.93 → rumdl-0.0.94}/python/MANIFEST.in +0 -0
  90. {rumdl-0.0.93 → rumdl-0.0.94}/python/PYTHON-README.md +0 -0
  91. {rumdl-0.0.93 → rumdl-0.0.94}/python/rumdl/__init__.py +0 -0
  92. {rumdl-0.0.93 → rumdl-0.0.94}/python/rumdl/__main__.py +0 -0
  93. {rumdl-0.0.93 → rumdl-0.0.94}/python/rumdl/py.typed +0 -0
  94. {rumdl-0.0.93 → rumdl-0.0.94}/rumdl.toml.example +0 -0
  95. {rumdl-0.0.93 → rumdl-0.0.94}/rust-toolchain.toml +0 -0
  96. {rumdl-0.0.93 → rumdl-0.0.94}/scripts/extract-changelog.sh +0 -0
  97. {rumdl-0.0.93 → rumdl-0.0.94}/scripts/prepare-release.sh +0 -0
  98. {rumdl-0.0.93 → rumdl-0.0.94}/src/bin/benchmark.rs +0 -0
  99. {rumdl-0.0.93 → rumdl-0.0.94}/src/bin/file_parallel_benchmark.rs +0 -0
  100. {rumdl-0.0.93 → rumdl-0.0.94}/src/config.rs +0 -0
  101. {rumdl-0.0.93 → rumdl-0.0.94}/src/init.rs +0 -0
  102. {rumdl-0.0.93 → rumdl-0.0.94}/src/inline_config.rs +0 -0
  103. {rumdl-0.0.93 → rumdl-0.0.94}/src/lib.rs +0 -0
  104. {rumdl-0.0.93 → rumdl-0.0.94}/src/lsp/mod.rs +0 -0
  105. {rumdl-0.0.93 → rumdl-0.0.94}/src/lsp/server.rs +0 -0
  106. {rumdl-0.0.93 → rumdl-0.0.94}/src/lsp/types.rs +0 -0
  107. {rumdl-0.0.93 → rumdl-0.0.94}/src/main.rs +0 -0
  108. {rumdl-0.0.93 → rumdl-0.0.94}/src/markdownlint_config.rs +0 -0
  109. {rumdl-0.0.93 → rumdl-0.0.94}/src/output/formatters/azure.rs +0 -0
  110. {rumdl-0.0.93 → rumdl-0.0.94}/src/output/formatters/concise.rs +0 -0
  111. {rumdl-0.0.93 → rumdl-0.0.94}/src/output/formatters/github.rs +0 -0
  112. {rumdl-0.0.93 → rumdl-0.0.94}/src/output/formatters/gitlab.rs +0 -0
  113. {rumdl-0.0.93 → rumdl-0.0.94}/src/output/formatters/grouped.rs +0 -0
  114. {rumdl-0.0.93 → rumdl-0.0.94}/src/output/formatters/json.rs +0 -0
  115. {rumdl-0.0.93 → rumdl-0.0.94}/src/output/formatters/json_lines.rs +0 -0
  116. {rumdl-0.0.93 → rumdl-0.0.94}/src/output/formatters/junit.rs +0 -0
  117. {rumdl-0.0.93 → rumdl-0.0.94}/src/output/formatters/mod.rs +0 -0
  118. {rumdl-0.0.93 → rumdl-0.0.94}/src/output/formatters/pylint.rs +0 -0
  119. {rumdl-0.0.93 → rumdl-0.0.94}/src/output/formatters/sarif.rs +0 -0
  120. {rumdl-0.0.93 → rumdl-0.0.94}/src/output/formatters/text.rs +0 -0
  121. {rumdl-0.0.93 → rumdl-0.0.94}/src/output/mod.rs +0 -0
  122. {rumdl-0.0.93 → rumdl-0.0.94}/src/parallel.rs +0 -0
  123. {rumdl-0.0.93 → rumdl-0.0.94}/src/performance.rs +0 -0
  124. {rumdl-0.0.93 → rumdl-0.0.94}/src/profiling.rs +0 -0
  125. {rumdl-0.0.93 → rumdl-0.0.94}/src/python.rs +0 -0
  126. {rumdl-0.0.93 → rumdl-0.0.94}/src/rule.rs +0 -0
  127. {rumdl-0.0.93 → rumdl-0.0.94}/src/rule_config.rs +0 -0
  128. {rumdl-0.0.93 → rumdl-0.0.94}/src/rule_config_serde.rs +0 -0
  129. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/blockquote_utils.rs +0 -0
  130. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/code_block_utils.rs +0 -0
  131. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/code_fence_utils.rs +0 -0
  132. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/emphasis_style.rs +0 -0
  133. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/front_matter_utils.rs +0 -0
  134. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/heading_utils.rs +0 -0
  135. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/list_utils.rs +0 -0
  136. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md001_heading_increment.rs +0 -0
  137. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md002_first_heading_h1/md002_config.rs +0 -0
  138. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md002_first_heading_h1.rs +0 -0
  139. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md003_heading_style/md003_config.rs +0 -0
  140. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md003_heading_style.rs +0 -0
  141. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md004_unordered_list_style/md004_config.rs +0 -0
  142. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md004_unordered_list_style.rs +0 -0
  143. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md005_list_indent.rs +0 -0
  144. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md006_start_bullets.rs +0 -0
  145. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md007_ul_indent/md007_config.rs +0 -0
  146. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md007_ul_indent.rs +0 -0
  147. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md009_trailing_spaces/md009_config.rs +0 -0
  148. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md010_no_hard_tabs/md010_config.rs +0 -0
  149. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md010_no_hard_tabs.rs +0 -0
  150. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md011_no_reversed_links.rs +0 -0
  151. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md012_no_multiple_blanks/md012_config.rs +0 -0
  152. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md012_no_multiple_blanks.rs +0 -0
  153. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md013_line_length/md013_config.rs +0 -0
  154. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md014_commands_show_output/md014_config.rs +0 -0
  155. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md014_commands_show_output.rs +0 -0
  156. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md018_no_missing_space_atx.rs +0 -0
  157. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md019_no_multiple_space_atx.rs +0 -0
  158. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md020_no_missing_space_closed_atx.rs +0 -0
  159. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md021_no_multiple_space_closed_atx.rs +0 -0
  160. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md022_blanks_around_headings/md022_config.rs +0 -0
  161. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md022_blanks_around_headings.rs +0 -0
  162. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md023_heading_start_left.rs +0 -0
  163. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md024_no_duplicate_heading/md024_config.rs +0 -0
  164. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md024_no_duplicate_heading.rs +0 -0
  165. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md025_single_title/md025_config.rs +0 -0
  166. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md025_single_title.rs +0 -0
  167. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md026_no_trailing_punctuation/md026_config.rs +0 -0
  168. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md026_no_trailing_punctuation.rs +0 -0
  169. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md027_multiple_spaces_blockquote.rs +0 -0
  170. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md028_no_blanks_blockquote.rs +0 -0
  171. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md029_ordered_list_prefix.rs +0 -0
  172. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md030_list_marker_space/md030_config.rs +0 -0
  173. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md030_list_marker_space.rs +0 -0
  174. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md031_blanks_around_fences.rs +0 -0
  175. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md032_blanks_around_lists.rs +0 -0
  176. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md033_no_inline_html/md033_config.rs +0 -0
  177. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md033_no_inline_html.rs +0 -0
  178. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md035_hr_style/md035_config.rs +0 -0
  179. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md035_hr_style.rs +0 -0
  180. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md036_no_emphasis_only_first/md036_config.rs +0 -0
  181. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md036_no_emphasis_only_first.rs +0 -0
  182. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md037_spaces_around_emphasis.rs +0 -0
  183. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md039_no_space_in_links.rs +0 -0
  184. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md040_fenced_code_language.rs +0 -0
  185. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md041_first_line_heading.rs +0 -0
  186. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md042_no_empty_links.rs +0 -0
  187. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md043_required_headings.rs +0 -0
  188. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md044_proper_names/md044_config.rs +0 -0
  189. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md045_no_alt_text/md045_config.rs +0 -0
  190. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md045_no_alt_text.rs +0 -0
  191. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md046_code_block_style/md046_config.rs +0 -0
  192. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md046_code_block_style.rs +0 -0
  193. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md048_code_fence_style/md048_config.rs +0 -0
  194. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md048_code_fence_style.rs +0 -0
  195. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md049_emphasis_style/md049_config.rs +0 -0
  196. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md049_emphasis_style.rs +0 -0
  197. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md050_strong_style/md050_config.rs +0 -0
  198. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md050_strong_style.rs +0 -0
  199. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md051_link_fragments.rs +0 -0
  200. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md054_link_image_style/md054_config.rs +0 -0
  201. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md054_link_image_style.rs +0 -0
  202. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md055_table_pipe_style/md055_config.rs +0 -0
  203. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md055_table_pipe_style.rs +0 -0
  204. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md056_table_column_count.rs +0 -0
  205. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md057_existing_relative_links/md057_config.rs +0 -0
  206. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md057_existing_relative_links.rs +0 -0
  207. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/md058_blanks_around_tables.rs +0 -0
  208. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/mod.rs +0 -0
  209. {rumdl-0.0.93 → rumdl-0.0.94}/src/rules/strong_style.rs +0 -0
  210. {rumdl-0.0.93 → rumdl-0.0.94}/src/utils/ast_utils.rs +0 -0
  211. {rumdl-0.0.93 → rumdl-0.0.94}/src/utils/code_block_utils.rs +0 -0
  212. {rumdl-0.0.93 → rumdl-0.0.94}/src/utils/document_structure.rs +0 -0
  213. {rumdl-0.0.93 → rumdl-0.0.94}/src/utils/early_returns.rs +0 -0
  214. {rumdl-0.0.93 → rumdl-0.0.94}/src/utils/element_cache.rs +0 -0
  215. {rumdl-0.0.93 → rumdl-0.0.94}/src/utils/emphasis_utils.rs +0 -0
  216. {rumdl-0.0.93 → rumdl-0.0.94}/src/utils/fix_utils.rs +0 -0
  217. {rumdl-0.0.93 → rumdl-0.0.94}/src/utils/markdown_elements.rs +0 -0
  218. {rumdl-0.0.93 → rumdl-0.0.94}/src/utils/mod.rs +0 -0
  219. {rumdl-0.0.93 → rumdl-0.0.94}/src/utils/range_utils.rs +0 -0
  220. {rumdl-0.0.93 → rumdl-0.0.94}/src/utils/regex_cache.rs +0 -0
  221. {rumdl-0.0.93 → rumdl-0.0.94}/src/utils/string_interner.rs +0 -0
  222. {rumdl-0.0.93 → rumdl-0.0.94}/src/utils/table_utils.rs +0 -0
  223. {rumdl-0.0.93 → rumdl-0.0.94}/src/vscode.rs +0 -0
  224. {rumdl-0.0.93 → rumdl-0.0.94}/tests/advanced_integration_tests.rs +0 -0
  225. {rumdl-0.0.93 → rumdl-0.0.94}/tests/character_ranges/additional_tests.rs +0 -0
  226. {rumdl-0.0.93 → rumdl-0.0.94}/tests/character_ranges/basic_tests.rs +0 -0
  227. {rumdl-0.0.93 → rumdl-0.0.94}/tests/character_ranges/comprehensive_tests.rs +0 -0
  228. {rumdl-0.0.93 → rumdl-0.0.94}/tests/character_ranges/extended_tests.rs +0 -0
  229. {rumdl-0.0.93 → rumdl-0.0.94}/tests/character_ranges/mod.rs +0 -0
  230. {rumdl-0.0.93 → rumdl-0.0.94}/tests/character_ranges/unicode_utils.rs +0 -0
  231. {rumdl-0.0.93 → rumdl-0.0.94}/tests/cli_duplication_test.rs +0 -0
  232. {rumdl-0.0.93 → rumdl-0.0.94}/tests/cli_integration_tests.rs +0 -0
  233. {rumdl-0.0.93 → rumdl-0.0.94}/tests/cli_lsp_fix_consistency.rs +0 -0
  234. {rumdl-0.0.93 → rumdl-0.0.94}/tests/cli_statistics_test.rs +0 -0
  235. {rumdl-0.0.93 → rumdl-0.0.94}/tests/commonmark_compliance_tests.rs +0 -0
  236. {rumdl-0.0.93 → rumdl-0.0.94}/tests/comprehensive_integration_tests.rs +0 -0
  237. {rumdl-0.0.93 → rumdl-0.0.94}/tests/comprehensive_output_format_tests.rs +0 -0
  238. {rumdl-0.0.93 → rumdl-0.0.94}/tests/config_application_tests.rs +0 -0
  239. {rumdl-0.0.93 → rumdl-0.0.94}/tests/config_file_command_test.rs +0 -0
  240. {rumdl-0.0.93 → rumdl-0.0.94}/tests/config_tests.rs +0 -0
  241. {rumdl-0.0.93 → rumdl-0.0.94}/tests/configuration_inheritance_tests.rs +0 -0
  242. {rumdl-0.0.93 → rumdl-0.0.94}/tests/consistency_regression_tests.rs +0 -0
  243. {rumdl-0.0.93 → rumdl-0.0.94}/tests/cross_platform_compatibility_tests.rs +0 -0
  244. {rumdl-0.0.93 → rumdl-0.0.94}/tests/final_confidence_assessment.rs +0 -0
  245. {rumdl-0.0.93 → rumdl-0.0.94}/tests/init_command_test.rs +0 -0
  246. {rumdl-0.0.93 → rumdl-0.0.94}/tests/init_tests.rs +0 -0
  247. {rumdl-0.0.93 → rumdl-0.0.94}/tests/inline_config_test.rs +0 -0
  248. {rumdl-0.0.93 → rumdl-0.0.94}/tests/integration_tests.rs +0 -0
  249. {rumdl-0.0.93 → rumdl-0.0.94}/tests/json_output_test.rs +0 -0
  250. {rumdl-0.0.93 → rumdl-0.0.94}/tests/lib.rs +0 -0
  251. {rumdl-0.0.93 → rumdl-0.0.94}/tests/lsp_editor_integration_tests.rs +0 -0
  252. {rumdl-0.0.93 → rumdl-0.0.94}/tests/lsp_integration_tests.rs +0 -0
  253. {rumdl-0.0.93 → rumdl-0.0.94}/tests/lsp_memory_leak_tests.rs +0 -0
  254. {rumdl-0.0.93 → rumdl-0.0.94}/tests/lsp_tests.rs +0 -0
  255. {rumdl-0.0.93 → rumdl-0.0.94}/tests/malformed_markdown_stress_tests.rs +0 -0
  256. {rumdl-0.0.93 → rumdl-0.0.94}/tests/markdownlint_cli_integration.rs +0 -0
  257. {rumdl-0.0.93 → rumdl-0.0.94}/tests/markdownlint_config_test.rs +0 -0
  258. {rumdl-0.0.93 → rumdl-0.0.94}/tests/markdownlintignore_test.rs +0 -0
  259. {rumdl-0.0.93 → rumdl-0.0.94}/tests/nested_code_block_test.rs +0 -0
  260. {rumdl-0.0.93 → rumdl-0.0.94}/tests/output_format_integration_tests.rs +0 -0
  261. {rumdl-0.0.93 → rumdl-0.0.94}/tests/output_format_tests.rs +0 -0
  262. {rumdl-0.0.93 → rumdl-0.0.94}/tests/perf_check.rs +0 -0
  263. {rumdl-0.0.93 → rumdl-0.0.94}/tests/performance_validation_tests.rs +0 -0
  264. {rumdl-0.0.93 → rumdl-0.0.94}/tests/pyproject_config_tests.rs +0 -0
  265. {rumdl-0.0.93 → rumdl-0.0.94}/tests/real_world_repository_tests.rs +0 -0
  266. {rumdl-0.0.93 → rumdl-0.0.94}/tests/regression_prevention_tests.rs +0 -0
  267. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md001_test.rs +0 -0
  268. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md001_unicode_test.rs +0 -0
  269. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md002_test.rs +0 -0
  270. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md003_test.rs +0 -0
  271. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md004_test.rs +0 -0
  272. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md005_test.rs +0 -0
  273. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md006_test.rs +0 -0
  274. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md006_unicode_test.rs +0 -0
  275. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md007_test.rs +0 -0
  276. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md009_test.rs +0 -0
  277. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md010_test.rs +0 -0
  278. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md011_test.rs +0 -0
  279. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md012_test.rs +0 -0
  280. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md013_test.rs +0 -0
  281. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md014_test.rs +0 -0
  282. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md018_test.rs +0 -0
  283. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md019_test.rs +0 -0
  284. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md020_test.rs +0 -0
  285. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md021_test.rs +0 -0
  286. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md022_test.rs +0 -0
  287. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md023_extended_test.rs +0 -0
  288. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md023_test.rs +0 -0
  289. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md024_test.rs +0 -0
  290. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md025_test.rs +0 -0
  291. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md026_test.rs +0 -0
  292. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md027_test.rs +0 -0
  293. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md028_test.rs +0 -0
  294. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md029_test.rs +0 -0
  295. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md030_test.rs +0 -0
  296. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md031_test.rs +0 -0
  297. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md032_test.rs +0 -0
  298. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md033_extended_test.rs +0 -0
  299. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md033_test.rs +0 -0
  300. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md034_ipv6_test.rs +0 -0
  301. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md034_test.rs +0 -0
  302. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md035_test.rs +0 -0
  303. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md036_test.rs +0 -0
  304. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md037_test.rs +0 -0
  305. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md038_nested_backticks_test.rs +0 -0
  306. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md038_test.rs +0 -0
  307. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md039_test.rs +0 -0
  308. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md040_test.rs +0 -0
  309. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md041_test.rs +0 -0
  310. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md042_test.rs +0 -0
  311. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md043_test.rs +0 -0
  312. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md044_test.rs +0 -0
  313. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md045_test.rs +0 -0
  314. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md046_test.rs +0 -0
  315. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md047_test.rs +0 -0
  316. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md048_test.rs +0 -0
  317. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md049_test.rs +0 -0
  318. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md050_test.rs +0 -0
  319. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md051_test.rs +0 -0
  320. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md051_unicode_test.rs +0 -0
  321. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md052_test.rs +0 -0
  322. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md053_additional_test.rs +0 -0
  323. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md053_proptest.rs +0 -0
  324. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md053_test.rs +0 -0
  325. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md054_test.rs +0 -0
  326. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md054_unicode_test.rs +0 -0
  327. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md055_test.rs +0 -0
  328. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md056_test.rs +0 -0
  329. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md057_test.rs +0 -0
  330. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/md058_test.rs +0 -0
  331. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules/mod.rs +0 -0
  332. {rumdl-0.0.93 → rumdl-0.0.94}/tests/rules_mod_test.rs +0 -0
  333. {rumdl-0.0.93 → rumdl-0.0.94}/tests/thread_safety_tests.rs +0 -0
  334. {rumdl-0.0.93 → rumdl-0.0.94}/tests/unicode_edge_case_tests.rs +0 -0
  335. {rumdl-0.0.93 → rumdl-0.0.94}/tests/utils/blockquote_utils_test.rs +0 -0
  336. {rumdl-0.0.93 → rumdl-0.0.94}/tests/utils/code_block_utils_extended_test.rs +0 -0
  337. {rumdl-0.0.93 → rumdl-0.0.94}/tests/utils/code_block_utils_test.rs +0 -0
  338. {rumdl-0.0.93 → rumdl-0.0.94}/tests/utils/core_utils_test.rs +0 -0
  339. {rumdl-0.0.93 → rumdl-0.0.94}/tests/utils/front_matter_utils_test.rs +0 -0
  340. {rumdl-0.0.93 → rumdl-0.0.94}/tests/utils/line_index_test.rs +0 -0
  341. {rumdl-0.0.93 → rumdl-0.0.94}/tests/utils/mod.rs +0 -0
  342. {rumdl-0.0.93 → rumdl-0.0.94}/tests/utils_markdown_edge_cases.rs +0 -0
  343. {rumdl-0.0.93 → rumdl-0.0.94}/tests/utils_tests.rs +0 -0
  344. {rumdl-0.0.93 → rumdl-0.0.94}/tests/vscode_extension_fixes.rs +0 -0
  345. {rumdl-0.0.93 → rumdl-0.0.94}/tests/vscode_test.rs +0 -0
  346. {rumdl-0.0.93 → rumdl-0.0.94}/tests/vscode_tests.rs +0 -0
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.0.94] - 2025-07-04
11
+
10
12
  ## [0.0.93] - 2025-07-03
11
13
 
12
14
  ## [0.0.92] - 2025-07-02
@@ -133,7 +135,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
133
135
 
134
136
  - Initial implementation of remaining rules for markdownlint parity
135
137
 
136
- [Unreleased]: https://github.com/rvben/rumdl/compare/v0.0.93...HEAD
138
+ [Unreleased]: https://github.com/rvben/rumdl/compare/v0.0.94...HEAD
139
+ [0.0.94]: https://github.com/rvben/rumdl/compare/v0.0.93...v0.0.94
137
140
  [0.0.93]: https://github.com/rvben/rumdl/compare/v0.0.92...v0.0.93
138
141
  [0.0.92]: https://github.com/rvben/rumdl/compare/v0.0.91...v0.0.92
139
142
  [0.0.91]: https://github.com/rvben/rumdl/compare/v0.0.90...v0.0.91
@@ -220,9 +220,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
220
220
 
221
221
  [[package]]
222
222
  name = "cc"
223
- version = "1.2.27"
223
+ version = "1.2.28"
224
224
  source = "registry+https://github.com/rust-lang/crates.io-index"
225
- checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc"
225
+ checksum = "4ad45f4f74e4e20eaa392913b7b33a7091c87e59628f4dd27888205ad888843c"
226
226
  dependencies = [
227
227
  "shlex",
228
228
  ]
@@ -1465,7 +1465,7 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
1465
1465
 
1466
1466
  [[package]]
1467
1467
  name = "rumdl"
1468
- version = "0.0.93"
1468
+ version = "0.0.94"
1469
1469
  dependencies = [
1470
1470
  "anyhow",
1471
1471
  "assert_cmd",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "rumdl"
3
- version = "0.0.93"
3
+ version = "0.0.94"
4
4
  edition = "2024"
5
5
  rust-version = "1.88.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.93
3
+ Version: 0.0.94
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -0,0 +1,156 @@
1
+ use rumdl::config::Config;
2
+ use rumdl::lint_context::LintContext;
3
+ use rumdl::rule::Rule;
4
+ use rumdl::rules::all_rules;
5
+ use std::env;
6
+ use std::time::Instant;
7
+
8
+ fn benchmark_rule(rule: &dyn Rule, test_cases: &[(&str, &str)], iterations: u32) -> Vec<(String, u64, u64)> {
9
+ let mut results = Vec::new();
10
+
11
+ for (name, content) in test_cases {
12
+ // Warm up
13
+ for _ in 0..10 {
14
+ let ctx = LintContext::new(content);
15
+ let _ = rule.check(&ctx);
16
+ let _ = rule.fix(&ctx);
17
+ }
18
+
19
+ // Benchmark check
20
+ let start = Instant::now();
21
+ for _ in 0..iterations {
22
+ let ctx = LintContext::new(content);
23
+ let _ = rule.check(&ctx);
24
+ }
25
+ let check_time = start.elapsed().as_micros() as u64 / iterations as u64;
26
+
27
+ // Benchmark fix
28
+ let start = Instant::now();
29
+ for _ in 0..iterations {
30
+ let ctx = LintContext::new(content);
31
+ let _ = rule.fix(&ctx);
32
+ }
33
+ let fix_time = start.elapsed().as_micros() as u64 / iterations as u64;
34
+
35
+ results.push((name.to_string(), check_time, fix_time));
36
+ }
37
+
38
+ results
39
+ }
40
+
41
+ fn generate_test_content(rule_name: &str) -> Vec<(&'static str, String)> {
42
+ match rule_name {
43
+ "MD009" => vec![
44
+ ("No trailing spaces", "Line without trailing spaces\n".repeat(100)),
45
+ ("With trailing spaces", "Line with trailing spaces \n".repeat(100)),
46
+ ("Mixed content", "Normal line\nLine with spaces \nAnother normal\n".repeat(50)),
47
+ ("Empty lines", "\n\n\n".repeat(100)),
48
+ ],
49
+ "MD013" => vec![
50
+ ("Short lines", "Short line\n".repeat(1000)),
51
+ ("Long lines", "This is a very long line that exceeds the default line length limit of 80 characters and should trigger MD013\n".repeat(500)),
52
+ ("Mixed lengths", "Short\nThis is a very long line that exceeds the limit\nShort again\n".repeat(300)),
53
+ ("Code blocks", "```\nThis is a very long line in a code block that should be ignored by MD013\n```\n".repeat(100)),
54
+ ],
55
+ "MD047" => vec![
56
+ ("Correct ending", "Content with proper ending\n".to_string()),
57
+ ("Missing newline", "Content without newline at end".to_string()),
58
+ ("Multiple newlines", "Content with multiple newlines\n\n\n".to_string()),
59
+ ("Empty file", "".to_string()),
60
+ ("Large file correct", "Line\n".repeat(1000)),
61
+ ("Large file incorrect", format!("{}\n\n", "Line\n".repeat(1000))),
62
+ ],
63
+ "MD038" => vec![
64
+ ("No code spans", "Regular text without code\n".repeat(100)),
65
+ ("Correct code spans", "Text with `correct code` spans\n".repeat(100)),
66
+ ("Spaces in code", "Text with ` spaced code ` spans\n".repeat(100)),
67
+ ("Multiple backticks", "Text with ``code with ` backtick`` spans\n".repeat(100)),
68
+ ("Mixed content", "Normal text\n`good code`\n` bad code `\n".repeat(100)),
69
+ ],
70
+ "MD044" => vec![
71
+ ("No proper names", "regular text without any proper names\n".repeat(100)),
72
+ ("Correct names", "Using JavaScript and Python correctly\n".repeat(100)),
73
+ ("Incorrect names", "Using javascript and python incorrectly\n".repeat(100)),
74
+ ("Mixed case", "JavaScript is good, but javascript is bad\n".repeat(100)),
75
+ ("Many names", "JavaScript Python TypeScript Ruby Go Rust Java\n".repeat(100)),
76
+ ],
77
+ "MD034" => vec![
78
+ ("No URLs", "Simple text without any URLs or links\n".repeat(100)),
79
+ ("Markdown links", "[link](http://example.com) and [another](https://test.com)\n".repeat(100)),
80
+ ("Bare URLs", "Check out http://example.com and https://test.com for more\n".repeat(100)),
81
+ ("Mixed URLs", "Visit [site](http://a.com) or just go to http://b.com directly\n".repeat(100)),
82
+ ("Complex URLs", "IPv6: http://[2001:db8::1]/path and port: http://example.com:8080/path?query=1\n".repeat(50)),
83
+ ("Many URLs", {
84
+ let mut content = String::new();
85
+ for i in 0..200 {
86
+ content.push_str(&format!("URL {}: http://example{}.com/path/{}/file?id={}\n", i, i, i, i));
87
+ }
88
+ content
89
+ }),
90
+ ],
91
+ "MD053" => vec![
92
+ ("No references", "Simple text without any links or references\n".repeat(100)),
93
+ ("Used references", "[link1][ref1] and [link2][ref2]\n\n[ref1]: http://example1.com\n[ref2]: http://example2.com\n".repeat(50)),
94
+ ("Unused references", "Some text here\n\n[unused1]: http://unused1.com\n[unused2]: http://unused2.com\n".repeat(50)),
95
+ ("Mixed references", "[used][ref1]\n\n[ref1]: http://used.com\n[unused]: http://unused.com\n".repeat(100)),
96
+ ("Many references", {
97
+ let mut content = String::new();
98
+ for i in 0..100 {
99
+ content.push_str(&format!("[link{}][ref{}]\n", i, i));
100
+ }
101
+ content.push_str("\n");
102
+ for i in 0..200 {
103
+ content.push_str(&format!("[ref{}]: http://example{}.com\n", i, i));
104
+ }
105
+ content
106
+ }),
107
+ ],
108
+ _ => vec![
109
+ ("Default test", "Default test content\n".repeat(100)),
110
+ ],
111
+ }
112
+ }
113
+
114
+ fn main() {
115
+ let args: Vec<String> = env::args().collect();
116
+ if args.len() != 2 {
117
+ eprintln!("Usage: {} <rule_name>", args[0]);
118
+ std::process::exit(1);
119
+ }
120
+
121
+ let rule_name = &args[1];
122
+ let config = Config::default();
123
+ let rules = all_rules(&config);
124
+
125
+ let rule = rules.into_iter()
126
+ .find(|r| r.name() == rule_name)
127
+ .unwrap_or_else(|| {
128
+ eprintln!("Rule {} not found", rule_name);
129
+ std::process::exit(1);
130
+ });
131
+
132
+ let test_cases_vec = generate_test_content(rule_name);
133
+ let test_cases: Vec<(&str, &str)> = test_cases_vec.iter()
134
+ .map(|(name, content)| (*name, content.as_str()))
135
+ .collect();
136
+
137
+ println!("Benchmarking {} Rule", rule_name);
138
+ println!("{}", "=".repeat(50));
139
+ println!();
140
+
141
+ let results = benchmark_rule(rule.as_ref(), &test_cases, 100);
142
+
143
+ let mut total_check = 0u64;
144
+ let mut total_fix = 0u64;
145
+
146
+ for (test_name, check_time, fix_time) in &results {
147
+ println!("{:<30} Check: {:>6} μs Fix: {:>6} μs", test_name, check_time, fix_time);
148
+ total_check += check_time;
149
+ total_fix += fix_time;
150
+ }
151
+
152
+ println!();
153
+ println!("Average times:");
154
+ println!(" Check: {} μs", total_check / results.len() as u64);
155
+ println!(" Fix: {} μs", total_fix / results.len() as u64);
156
+ }
@@ -28,7 +28,7 @@ fn main() {
28
28
  times.push(elapsed.as_micros());
29
29
 
30
30
  if times.len() == 1 {
31
- println!(" Code spans detected: {}", ctx.code_spans.len());
31
+ println!(" Code spans detected: {}", ctx.code_spans().len());
32
32
  }
33
33
  }
34
34
 
@@ -243,6 +243,8 @@ pub struct ListBlock {
243
243
  pub nesting_level: usize,
244
244
  }
245
245
 
246
+ use std::sync::{Arc, Mutex};
247
+
246
248
  pub struct LintContext<'a> {
247
249
  pub content: &'a str,
248
250
  pub line_offsets: Vec<usize>,
@@ -251,7 +253,7 @@ pub struct LintContext<'a> {
251
253
  pub links: Vec<ParsedLink>, // Pre-parsed links
252
254
  pub images: Vec<ParsedImage>, // Pre-parsed images
253
255
  pub reference_defs: Vec<ReferenceDef>, // Reference definitions
254
- pub code_spans: Vec<CodeSpan>, // Pre-parsed inline code spans
256
+ code_spans_cache: Mutex<Option<Arc<Vec<CodeSpan>>>>, // Lazy-loaded inline code spans
255
257
  pub list_blocks: Vec<ListBlock>, // Pre-parsed list blocks
256
258
  }
257
259
 
@@ -270,11 +272,11 @@ impl<'a> LintContext<'a> {
270
272
  // Pre-compute line information
271
273
  let lines = Self::compute_line_info(content, &line_offsets, &code_blocks);
272
274
 
273
- // Parse links, images, references, code spans, and list blocks
275
+ // Parse links, images, references, and list blocks
276
+ // Skip code spans - they'll be computed lazily
274
277
  let links = Self::parse_links(content, &lines, &code_blocks);
275
278
  let images = Self::parse_images(content, &lines, &code_blocks);
276
279
  let reference_defs = Self::parse_reference_defs(content, &lines);
277
- let code_spans = Self::parse_code_spans(content, &lines);
278
280
  let list_blocks = Self::parse_list_blocks(&lines);
279
281
 
280
282
  Self {
@@ -285,11 +287,25 @@ impl<'a> LintContext<'a> {
285
287
  links,
286
288
  images,
287
289
  reference_defs,
288
- code_spans,
290
+ code_spans_cache: Mutex::new(None),
289
291
  list_blocks,
290
292
  }
291
293
  }
292
294
 
295
+ /// Get code spans - computed lazily on first access
296
+ pub fn code_spans(&self) -> Arc<Vec<CodeSpan>> {
297
+ let mut cache = self.code_spans_cache.lock().unwrap();
298
+
299
+ // Check if we need to compute code spans
300
+ if cache.is_none() {
301
+ let code_spans = Self::parse_code_spans(self.content, &self.lines);
302
+ *cache = Some(Arc::new(code_spans));
303
+ }
304
+
305
+ // Return a reference to the cached code spans
306
+ cache.as_ref().unwrap().clone()
307
+ }
308
+
293
309
  /// Map a byte offset to (line, column)
294
310
  pub fn offset_to_line_col(&self, offset: usize) -> (usize, usize) {
295
311
  match self.line_offsets.binary_search(&offset) {
@@ -308,8 +324,8 @@ impl<'a> LintContext<'a> {
308
324
  return true;
309
325
  }
310
326
 
311
- // Check inline code spans
312
- self.code_spans
327
+ // Check inline code spans (lazy load if needed)
328
+ self.code_spans()
313
329
  .iter()
314
330
  .any(|span| pos >= span.byte_offset && pos < span.byte_end)
315
331
  }
@@ -35,15 +35,7 @@ impl MD009TrailingSpaces {
35
35
  }
36
36
 
37
37
  fn count_trailing_spaces(line: &str) -> usize {
38
- let mut count = 0;
39
- for c in line.chars().rev() {
40
- if c == ' ' {
41
- count += 1;
42
- } else {
43
- break;
44
- }
45
- }
46
- count
38
+ line.chars().rev().take_while(|&c| c == ' ').count()
47
39
  }
48
40
 
49
41
  fn is_empty_list_item_line(line: &str, prev_line: Option<&str>) -> bool {
@@ -224,6 +216,7 @@ impl Rule for MD009TrailingSpaces {
224
216
  }
225
217
 
226
218
  let trimmed = line.trim_end();
219
+ let trailing_spaces = Self::count_trailing_spaces(line);
227
220
 
228
221
  // Handle empty lines - fast regex replacement
229
222
  if trimmed.is_empty() {
@@ -256,20 +249,25 @@ impl Rule for MD009TrailingSpaces {
256
249
  }
257
250
 
258
251
  // Handle lines with trailing spaces
259
- let trailing_spaces = Self::count_trailing_spaces(line);
260
252
  let is_truly_last_line = i == lines.len() - 1 && !content.ends_with('\n');
261
253
 
262
254
  result.push_str(trimmed);
263
255
 
264
256
  // In non-strict mode, preserve line breaks by normalizing to br_spaces
265
257
  if !self.config.strict && !is_truly_last_line && trailing_spaces > 0 {
266
- result.push_str(&" ".repeat(self.config.br_spaces));
258
+ // Optimize for common case of 2 spaces
259
+ match self.config.br_spaces {
260
+ 0 => {},
261
+ 1 => result.push(' '),
262
+ 2 => result.push_str(" "),
263
+ n => result.push_str(&" ".repeat(n)),
264
+ }
267
265
  }
268
266
  result.push('\n');
269
267
  }
270
268
 
271
269
  // Preserve original ending (with or without final newline)
272
- if !content.ends_with('\n') {
270
+ if !content.ends_with('\n') && result.ends_with('\n') {
273
271
  result.pop();
274
272
  }
275
273
 
@@ -135,8 +135,36 @@ impl Rule for MD013LineLength {
135
135
  if content.is_empty() {
136
136
  return Ok(Vec::new());
137
137
  }
138
+
139
+ // Quick check: if total content is shorter than line limit, definitely no violations
140
+ if content.len() <= self.config.line_length {
141
+ return Ok(Vec::new());
142
+ }
143
+
144
+ // More aggressive early return - check if any line could possibly be long
145
+ let has_long_lines = if !ctx.lines.is_empty() {
146
+ ctx.lines.iter().any(|line| line.content.len() > self.config.line_length)
147
+ } else {
148
+ // Fallback: do a quick scan for newlines to estimate max line length
149
+ let mut max_line_len = 0;
150
+ let mut current_line_len = 0;
151
+ for ch in content.chars() {
152
+ if ch == '\n' {
153
+ max_line_len = max_line_len.max(current_line_len);
154
+ current_line_len = 0;
155
+ } else {
156
+ current_line_len += 1;
157
+ }
158
+ }
159
+ max_line_len = max_line_len.max(current_line_len);
160
+ max_line_len > self.config.line_length
161
+ };
162
+
163
+ if !has_long_lines {
164
+ return Ok(Vec::new());
165
+ }
138
166
 
139
- // Fallback path: create structure manually (should rarely be used)
167
+ // Create structure manually
140
168
  let structure = DocumentStructure::new(content);
141
169
  self.check_with_structure(ctx, &structure)
142
170
  }
@@ -149,12 +177,15 @@ impl Rule for MD013LineLength {
149
177
  ) -> LintResult {
150
178
  let content = ctx.content;
151
179
  let mut warnings = Vec::new();
152
- let lines: Vec<&str> = content.lines().collect();
153
-
154
- // Early return if no lines could possibly exceed the limit
155
- if lines.iter().all(|line| line.len() <= self.config.line_length) {
156
- return Ok(Vec::new());
157
- }
180
+
181
+ // Early return was already done in check(), so we know there are long lines
182
+
183
+ // Use ctx.lines if available for better performance
184
+ let lines: Vec<&str> = if !ctx.lines.is_empty() {
185
+ ctx.lines.iter().map(|l| l.content.as_str()).collect()
186
+ } else {
187
+ content.lines().collect()
188
+ };
158
189
 
159
190
  // Pre-compute LineIndex for efficient byte range calculations
160
191
  let line_index = crate::utils::range_utils::LineIndex::new(content.to_string());
@@ -166,9 +197,18 @@ impl Rule for MD013LineLength {
166
197
  let table_lines_set: std::collections::HashSet<usize> = if self.config.tables {
167
198
  let mut table_lines = std::collections::HashSet::new();
168
199
  let mut in_table = false;
200
+
169
201
  for (i, line) in lines.iter().enumerate() {
170
202
  let line_number = i + 1;
171
- if line.contains('|') && !structure.is_in_code_block(line_number) {
203
+
204
+ // Quick check if in code block using pre-computed blocks from context or structure
205
+ let in_code = if !ctx.code_blocks.is_empty() {
206
+ ctx.code_blocks.iter().any(|(start, end)| *start <= line_number && line_number <= *end)
207
+ } else {
208
+ structure.is_in_code_block(line_number)
209
+ };
210
+
211
+ if !in_code && line.contains('|') {
172
212
  in_table = true;
173
213
  table_lines.insert(line_number);
174
214
  } else if in_table && line.trim().is_empty() {
@@ -236,18 +276,25 @@ impl Rule for MD013LineLength {
236
276
  // Generate simplified fix (avoid expensive sentence splitting for now)
237
277
  let fix = if !self.should_skip_line_for_fix(line, line_num, structure) {
238
278
  // First try trimming trailing whitespace
239
- let trimmed = line.trim_end();
240
- if trimmed.len() <= line_limit && trimmed != *line {
241
- let line_start = line_index.line_col_to_byte_range(line_number, 1).start;
242
- let line_end = if line_number < lines.len() {
243
- line_index.line_col_to_byte_range(line_number + 1, 1).start - 1
279
+ let last_char = line.chars().last();
280
+ if last_char == Some(' ') || last_char == Some('\t') {
281
+ let trimmed = line.trim_end();
282
+ // Calculate trimmed length to avoid re-scanning
283
+ let trimmed_len = self.calculate_effective_length(trimmed);
284
+ if trimmed_len <= line_limit {
285
+ let line_start = line_index.line_col_to_byte_range(line_number, 1).start;
286
+ let line_end = if line_number < lines.len() {
287
+ line_index.line_col_to_byte_range(line_number + 1, 1).start - 1
288
+ } else {
289
+ content.len()
290
+ };
291
+ Some(crate::rule::Fix {
292
+ range: line_start..line_end,
293
+ replacement: trimmed.to_string(),
294
+ })
244
295
  } else {
245
- content.len()
246
- };
247
- Some(crate::rule::Fix {
248
- range: line_start..line_end,
249
- replacement: trimmed.to_string(),
250
- })
296
+ None
297
+ }
251
298
  } else {
252
299
  None // Skip expensive sentence splitting for performance
253
300
  }
@@ -289,16 +336,35 @@ impl Rule for MD013LineLength {
289
336
  // Get all warnings with their fixes
290
337
  let warnings = self.check(ctx)?;
291
338
 
292
- // If no warnings, return original content
339
+ // If no warnings, return original content without allocation
293
340
  if warnings.is_empty() {
294
341
  return Ok(ctx.content.to_string());
295
342
  }
296
343
 
297
- // Collect all fixes and sort by range start (descending) to apply from end to beginning
344
+ // Collect all fixes - check if any exist before allocating
345
+ let mut has_any_fix = false;
346
+ for w in &warnings {
347
+ if w.fix.is_some() {
348
+ has_any_fix = true;
349
+ break;
350
+ }
351
+ }
352
+
353
+ if !has_any_fix {
354
+ return Ok(ctx.content.to_string());
355
+ }
356
+
357
+ // Now collect fixes since we know there's at least one
298
358
  let mut fixes: Vec<_> = warnings
299
359
  .iter()
300
360
  .filter_map(|w| w.fix.as_ref().map(|f| (f.range.start, f.range.end, &f.replacement)))
301
361
  .collect();
362
+
363
+ // This should not happen given our check above, but just in case
364
+ if fixes.is_empty() {
365
+ return Ok(ctx.content.to_string());
366
+ }
367
+
302
368
  fixes.sort_by(|a, b| b.0.cmp(&a.0));
303
369
 
304
370
  // Apply fixes from end to beginning to preserve byte offsets
@@ -325,8 +391,18 @@ impl Rule for MD013LineLength {
325
391
  }
326
392
 
327
393
  fn should_skip(&self, ctx: &crate::lint_context::LintContext) -> bool {
328
- // Skip if content is empty or all lines are shorter than the limit
329
- ctx.content.is_empty() || ctx.lines.iter().all(|line| line.content.len() <= self.config.line_length)
394
+ // Skip if content is empty
395
+ if ctx.content.is_empty() {
396
+ return true;
397
+ }
398
+
399
+ // Quick check: if total content is shorter than line limit, definitely skip
400
+ if ctx.content.len() <= self.config.line_length {
401
+ return true;
402
+ }
403
+
404
+ // Use more efficient check - any() with early termination instead of all()
405
+ !ctx.lines.iter().any(|line| line.content.len() > self.config.line_length)
330
406
  }
331
407
 
332
408
  fn default_config_section(&self) -> Option<(String, toml::Value)> {
@@ -399,29 +475,38 @@ impl MD013LineLength {
399
475
  return line.chars().count();
400
476
  }
401
477
 
478
+ // Quick check: if line doesn't contain "http" or "[", it can't have URLs or markdown links
479
+ if !line.contains("http") && !line.contains('[') {
480
+ return line.chars().count();
481
+ }
482
+
402
483
  let mut effective_line = line.to_string();
403
484
 
404
485
  // First handle markdown links to avoid double-counting URLs
405
486
  // Pattern: [text](very-long-url) -> [text](url)
406
- for cap in MARKDOWN_LINK_PATTERN.captures_iter(&effective_line.clone()) {
407
- if let (Some(full_match), Some(text), Some(url)) = (cap.get(0), cap.get(1), cap.get(2)) {
408
- if url.as_str().len() > 15 {
409
- let replacement = format!("[{}](url)", text.as_str());
410
- effective_line = effective_line.replacen(full_match.as_str(), &replacement, 1);
487
+ if line.contains('[') && line.contains("](") {
488
+ for cap in MARKDOWN_LINK_PATTERN.captures_iter(&effective_line.clone()) {
489
+ if let (Some(full_match), Some(text), Some(url)) = (cap.get(0), cap.get(1), cap.get(2)) {
490
+ if url.as_str().len() > 15 {
491
+ let replacement = format!("[{}](url)", text.as_str());
492
+ effective_line = effective_line.replacen(full_match.as_str(), &replacement, 1);
493
+ }
411
494
  }
412
495
  }
413
496
  }
414
497
 
415
498
  // Then replace bare URLs with a placeholder of reasonable length
416
499
  // This allows lines with long URLs to pass if the rest of the content is reasonable
417
- for url_match in URL_IN_TEXT.find_iter(&effective_line.clone()) {
418
- let url = url_match.as_str();
419
- // Skip if this URL is already part of a markdown link we handled
420
- if !effective_line.contains(&format!("({url})")) {
421
- // Replace URL with placeholder that represents a "reasonable" URL length
422
- // Using 15 chars as a reasonable URL placeholder (e.g., "https://ex.com")
423
- let placeholder = "x".repeat(15.min(url.len()));
424
- effective_line = effective_line.replacen(url, &placeholder, 1);
500
+ if effective_line.contains("http") {
501
+ for url_match in URL_IN_TEXT.find_iter(&effective_line.clone()) {
502
+ let url = url_match.as_str();
503
+ // Skip if this URL is already part of a markdown link we handled
504
+ if !effective_line.contains(&format!("({url})")) {
505
+ // Replace URL with placeholder that represents a "reasonable" URL length
506
+ // Using 15 chars as a reasonable URL placeholder (e.g., "https://ex.com")
507
+ let placeholder = "x".repeat(15.min(url.len()));
508
+ effective_line = effective_line.replacen(url, &placeholder, 1);
509
+ }
425
510
  }
426
511
  }
427
512