rumdl 0.0.89__tar.gz → 0.0.90__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 (341) hide show
  1. {rumdl-0.0.89 → rumdl-0.0.90}/CHANGELOG.md +4 -1
  2. {rumdl-0.0.89 → rumdl-0.0.90}/Cargo.lock +1 -1
  3. {rumdl-0.0.89 → rumdl-0.0.90}/Cargo.toml +1 -1
  4. {rumdl-0.0.89 → rumdl-0.0.90}/PKG-INFO +11 -2
  5. {rumdl-0.0.89 → rumdl-0.0.90}/README.md +10 -1
  6. {rumdl-0.0.89 → rumdl-0.0.90}/src/lib.rs +1 -1
  7. {rumdl-0.0.89 → rumdl-0.0.90}/src/lint_context.rs +22 -369
  8. {rumdl-0.0.89 → rumdl-0.0.90}/src/main.rs +12 -1
  9. {rumdl-0.0.89 → rumdl-0.0.90}/src/rule.rs +1 -0
  10. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md009_trailing_spaces.rs +1 -0
  11. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md010_no_hard_tabs.rs +1 -0
  12. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md012_no_multiple_blanks.rs +1 -0
  13. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md037_spaces_around_emphasis.rs +6 -249
  14. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md047_single_trailing_newline.rs +1 -0
  15. rumdl-0.0.90/src/rules/md049_emphasis_style.rs +266 -0
  16. rumdl-0.0.90/src/utils/emphasis_utils.rs +374 -0
  17. {rumdl-0.0.89 → rumdl-0.0.90}/src/utils/mod.rs +1 -0
  18. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md034_test.rs +5 -5
  19. rumdl-0.0.89/src/rules/md049_emphasis_style.rs +0 -278
  20. {rumdl-0.0.89 → rumdl-0.0.90}/.config/nextest.toml +0 -0
  21. {rumdl-0.0.89 → rumdl-0.0.90}/.mise.toml +0 -0
  22. {rumdl-0.0.89 → rumdl-0.0.90}/.rumdl.toml +0 -0
  23. {rumdl-0.0.89 → rumdl-0.0.90}/.rustfmt.toml +0 -0
  24. {rumdl-0.0.89 → rumdl-0.0.90}/LICENSE +0 -0
  25. {rumdl-0.0.89 → rumdl-0.0.90}/MANIFEST.in +0 -0
  26. {rumdl-0.0.89 → rumdl-0.0.90}/Makefile +0 -0
  27. {rumdl-0.0.89 → rumdl-0.0.90}/assets/logo.png +0 -0
  28. {rumdl-0.0.89 → rumdl-0.0.90}/benches/fix_performance.rs +0 -0
  29. {rumdl-0.0.89 → rumdl-0.0.90}/benches/range_performance.rs +0 -0
  30. {rumdl-0.0.89 → rumdl-0.0.90}/benches/range_utils_benchmark.rs +0 -0
  31. {rumdl-0.0.89 → rumdl-0.0.90}/benches/rule_performance.rs +0 -0
  32. {rumdl-0.0.89 → rumdl-0.0.90}/benches/simple_fix_bench.rs +0 -0
  33. {rumdl-0.0.89 → rumdl-0.0.90}/docs/RULES.md +0 -0
  34. {rumdl-0.0.89 → rumdl-0.0.90}/docs/global-settings.md +0 -0
  35. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md001.md +0 -0
  36. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md002.md +0 -0
  37. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md003.md +0 -0
  38. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md004.md +0 -0
  39. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md005.md +0 -0
  40. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md006.md +0 -0
  41. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md007.md +0 -0
  42. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md009.md +0 -0
  43. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md010.md +0 -0
  44. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md011.md +0 -0
  45. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md012.md +0 -0
  46. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md013.md +0 -0
  47. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md014.md +0 -0
  48. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md018.md +0 -0
  49. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md019.md +0 -0
  50. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md020.md +0 -0
  51. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md021.md +0 -0
  52. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md022.md +0 -0
  53. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md023.md +0 -0
  54. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md024.md +0 -0
  55. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md025.md +0 -0
  56. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md026.md +0 -0
  57. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md027.md +0 -0
  58. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md028.md +0 -0
  59. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md029.md +0 -0
  60. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md030.md +0 -0
  61. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md031.md +0 -0
  62. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md032.md +0 -0
  63. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md033.md +0 -0
  64. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md034.md +0 -0
  65. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md035.md +0 -0
  66. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md036.md +0 -0
  67. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md037.md +0 -0
  68. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md038.md +0 -0
  69. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md039.md +0 -0
  70. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md040.md +0 -0
  71. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md041.md +0 -0
  72. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md042.md +0 -0
  73. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md043.md +0 -0
  74. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md044.md +0 -0
  75. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md045.md +0 -0
  76. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md046.md +0 -0
  77. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md047.md +0 -0
  78. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md048.md +0 -0
  79. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md049.md +0 -0
  80. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md050.md +0 -0
  81. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md051.md +0 -0
  82. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md052.md +0 -0
  83. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md053.md +0 -0
  84. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md054.md +0 -0
  85. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md055.md +0 -0
  86. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md056.md +0 -0
  87. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md057.md +0 -0
  88. {rumdl-0.0.89 → rumdl-0.0.90}/docs/md058.md +0 -0
  89. {rumdl-0.0.89 → rumdl-0.0.90}/docs/vscode-extension.md +0 -0
  90. {rumdl-0.0.89 → rumdl-0.0.90}/issues/plan-rule-parity-with-markdownlint.md +0 -0
  91. {rumdl-0.0.89 → rumdl-0.0.90}/parity_check.py +0 -0
  92. {rumdl-0.0.89 → rumdl-0.0.90}/pyproject.toml +0 -0
  93. {rumdl-0.0.89 → rumdl-0.0.90}/python/MANIFEST.in +0 -0
  94. {rumdl-0.0.89 → rumdl-0.0.90}/python/PYTHON-README.md +0 -0
  95. {rumdl-0.0.89 → rumdl-0.0.90}/python/rumdl/__init__.py +0 -0
  96. {rumdl-0.0.89 → rumdl-0.0.90}/python/rumdl/__main__.py +0 -0
  97. {rumdl-0.0.89 → rumdl-0.0.90}/python/rumdl/py.typed +0 -0
  98. {rumdl-0.0.89 → rumdl-0.0.90}/rumdl.toml.example +0 -0
  99. {rumdl-0.0.89 → rumdl-0.0.90}/rust-toolchain.toml +0 -0
  100. {rumdl-0.0.89 → rumdl-0.0.90}/scripts/extract-changelog.sh +0 -0
  101. {rumdl-0.0.89 → rumdl-0.0.90}/scripts/prepare-release.sh +0 -0
  102. {rumdl-0.0.89 → rumdl-0.0.90}/src/bin/benchmark.rs +0 -0
  103. {rumdl-0.0.89 → rumdl-0.0.90}/src/bin/file_parallel_benchmark.rs +0 -0
  104. {rumdl-0.0.89 → rumdl-0.0.90}/src/bin/measure_code_span_performance.rs +0 -0
  105. {rumdl-0.0.89 → rumdl-0.0.90}/src/config.rs +0 -0
  106. {rumdl-0.0.89 → rumdl-0.0.90}/src/init.rs +0 -0
  107. {rumdl-0.0.89 → rumdl-0.0.90}/src/inline_config.rs +0 -0
  108. {rumdl-0.0.89 → rumdl-0.0.90}/src/lsp/mod.rs +0 -0
  109. {rumdl-0.0.89 → rumdl-0.0.90}/src/lsp/server.rs +0 -0
  110. {rumdl-0.0.89 → rumdl-0.0.90}/src/lsp/types.rs +0 -0
  111. {rumdl-0.0.89 → rumdl-0.0.90}/src/markdownlint_config.rs +0 -0
  112. {rumdl-0.0.89 → rumdl-0.0.90}/src/output/formatters/azure.rs +0 -0
  113. {rumdl-0.0.89 → rumdl-0.0.90}/src/output/formatters/concise.rs +0 -0
  114. {rumdl-0.0.89 → rumdl-0.0.90}/src/output/formatters/github.rs +0 -0
  115. {rumdl-0.0.89 → rumdl-0.0.90}/src/output/formatters/gitlab.rs +0 -0
  116. {rumdl-0.0.89 → rumdl-0.0.90}/src/output/formatters/grouped.rs +0 -0
  117. {rumdl-0.0.89 → rumdl-0.0.90}/src/output/formatters/json.rs +0 -0
  118. {rumdl-0.0.89 → rumdl-0.0.90}/src/output/formatters/json_lines.rs +0 -0
  119. {rumdl-0.0.89 → rumdl-0.0.90}/src/output/formatters/junit.rs +0 -0
  120. {rumdl-0.0.89 → rumdl-0.0.90}/src/output/formatters/mod.rs +0 -0
  121. {rumdl-0.0.89 → rumdl-0.0.90}/src/output/formatters/pylint.rs +0 -0
  122. {rumdl-0.0.89 → rumdl-0.0.90}/src/output/formatters/sarif.rs +0 -0
  123. {rumdl-0.0.89 → rumdl-0.0.90}/src/output/formatters/text.rs +0 -0
  124. {rumdl-0.0.89 → rumdl-0.0.90}/src/output/mod.rs +0 -0
  125. {rumdl-0.0.89 → rumdl-0.0.90}/src/parallel.rs +0 -0
  126. {rumdl-0.0.89 → rumdl-0.0.90}/src/performance.rs +0 -0
  127. {rumdl-0.0.89 → rumdl-0.0.90}/src/profiling.rs +0 -0
  128. {rumdl-0.0.89 → rumdl-0.0.90}/src/python.rs +0 -0
  129. {rumdl-0.0.89 → rumdl-0.0.90}/src/rule_config.rs +0 -0
  130. {rumdl-0.0.89 → rumdl-0.0.90}/src/rule_config_serde.rs +0 -0
  131. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/blockquote_utils.rs +0 -0
  132. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/code_block_utils.rs +0 -0
  133. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/code_fence_utils.rs +0 -0
  134. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/emphasis_style.rs +0 -0
  135. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/front_matter_utils.rs +0 -0
  136. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/heading_utils.rs +0 -0
  137. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/list_utils.rs +0 -0
  138. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md001_heading_increment.rs +0 -0
  139. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md002_first_heading_h1/md002_config.rs +0 -0
  140. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md002_first_heading_h1.rs +0 -0
  141. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md003_heading_style/md003_config.rs +0 -0
  142. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md003_heading_style.rs +0 -0
  143. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md004_unordered_list_style/md004_config.rs +0 -0
  144. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md004_unordered_list_style.rs +0 -0
  145. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md005_list_indent.rs +0 -0
  146. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md006_start_bullets.rs +0 -0
  147. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md007_ul_indent/md007_config.rs +0 -0
  148. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md007_ul_indent.rs +0 -0
  149. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md009_trailing_spaces/md009_config.rs +0 -0
  150. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md010_no_hard_tabs/md010_config.rs +0 -0
  151. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md011_no_reversed_links.rs +0 -0
  152. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md012_no_multiple_blanks/md012_config.rs +0 -0
  153. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md013_line_length/md013_config.rs +0 -0
  154. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md013_line_length.rs +0 -0
  155. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md014_commands_show_output/md014_config.rs +0 -0
  156. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md014_commands_show_output.rs +0 -0
  157. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md018_no_missing_space_atx.rs +0 -0
  158. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md019_no_multiple_space_atx.rs +0 -0
  159. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md020_no_missing_space_closed_atx.rs +0 -0
  160. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md021_no_multiple_space_closed_atx.rs +0 -0
  161. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md022_blanks_around_headings/md022_config.rs +0 -0
  162. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md022_blanks_around_headings.rs +0 -0
  163. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md023_heading_start_left.rs +0 -0
  164. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md024_no_duplicate_heading/md024_config.rs +0 -0
  165. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md024_no_duplicate_heading.rs +0 -0
  166. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md025_single_title/md025_config.rs +0 -0
  167. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md025_single_title.rs +0 -0
  168. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md026_no_trailing_punctuation/md026_config.rs +0 -0
  169. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md026_no_trailing_punctuation.rs +0 -0
  170. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md027_multiple_spaces_blockquote.rs +0 -0
  171. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md028_no_blanks_blockquote.rs +0 -0
  172. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md029_ordered_list_prefix.rs +0 -0
  173. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md030_list_marker_space/md030_config.rs +0 -0
  174. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md030_list_marker_space.rs +0 -0
  175. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md031_blanks_around_fences.rs +0 -0
  176. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md032_blanks_around_lists.rs +0 -0
  177. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md033_no_inline_html/md033_config.rs +0 -0
  178. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md033_no_inline_html.rs +0 -0
  179. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md034_no_bare_urls.rs +0 -0
  180. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md035_hr_style/md035_config.rs +0 -0
  181. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md035_hr_style.rs +0 -0
  182. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md036_no_emphasis_only_first/md036_config.rs +0 -0
  183. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md036_no_emphasis_only_first.rs +0 -0
  184. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md038_no_space_in_code.rs +0 -0
  185. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md039_no_space_in_links.rs +0 -0
  186. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md040_fenced_code_language.rs +0 -0
  187. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md041_first_line_heading.rs +0 -0
  188. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md042_no_empty_links.rs +0 -0
  189. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md043_required_headings.rs +0 -0
  190. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md044_proper_names/md044_config.rs +0 -0
  191. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md044_proper_names.rs +0 -0
  192. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md045_no_alt_text.rs +0 -0
  193. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md046_code_block_style/md046_config.rs +0 -0
  194. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md046_code_block_style.rs +0 -0
  195. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md048_code_fence_style/md048_config.rs +0 -0
  196. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md048_code_fence_style.rs +0 -0
  197. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md049_emphasis_style/md049_config.rs +0 -0
  198. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md050_strong_style/md050_config.rs +0 -0
  199. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md050_strong_style.rs +0 -0
  200. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md051_link_fragments.rs +0 -0
  201. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md052_reference_links_images.rs +0 -0
  202. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md053_link_image_reference_definitions.rs +0 -0
  203. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md054_link_image_style/md054_config.rs +0 -0
  204. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md054_link_image_style.rs +0 -0
  205. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md055_table_pipe_style/md055_config.rs +0 -0
  206. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md055_table_pipe_style.rs +0 -0
  207. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md056_table_column_count.rs +0 -0
  208. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md057_existing_relative_links/md057_config.rs +0 -0
  209. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md057_existing_relative_links.rs +0 -0
  210. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/md058_blanks_around_tables.rs +0 -0
  211. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/mod.rs +0 -0
  212. {rumdl-0.0.89 → rumdl-0.0.90}/src/rules/strong_style.rs +0 -0
  213. {rumdl-0.0.89 → rumdl-0.0.90}/src/utils/ast_utils.rs +0 -0
  214. {rumdl-0.0.89 → rumdl-0.0.90}/src/utils/code_block_utils.rs +0 -0
  215. {rumdl-0.0.89 → rumdl-0.0.90}/src/utils/document_structure.rs +0 -0
  216. {rumdl-0.0.89 → rumdl-0.0.90}/src/utils/early_returns.rs +0 -0
  217. {rumdl-0.0.89 → rumdl-0.0.90}/src/utils/element_cache.rs +0 -0
  218. {rumdl-0.0.89 → rumdl-0.0.90}/src/utils/fix_utils.rs +0 -0
  219. {rumdl-0.0.89 → rumdl-0.0.90}/src/utils/markdown_elements.rs +0 -0
  220. {rumdl-0.0.89 → rumdl-0.0.90}/src/utils/range_utils.rs +0 -0
  221. {rumdl-0.0.89 → rumdl-0.0.90}/src/utils/regex_cache.rs +0 -0
  222. {rumdl-0.0.89 → rumdl-0.0.90}/src/utils/string_interner.rs +0 -0
  223. {rumdl-0.0.89 → rumdl-0.0.90}/src/utils/table_utils.rs +0 -0
  224. {rumdl-0.0.89 → rumdl-0.0.90}/src/vscode.rs +0 -0
  225. {rumdl-0.0.89 → rumdl-0.0.90}/tests/advanced_integration_tests.rs +0 -0
  226. {rumdl-0.0.89 → rumdl-0.0.90}/tests/character_ranges/additional_tests.rs +0 -0
  227. {rumdl-0.0.89 → rumdl-0.0.90}/tests/character_ranges/basic_tests.rs +0 -0
  228. {rumdl-0.0.89 → rumdl-0.0.90}/tests/character_ranges/comprehensive_tests.rs +0 -0
  229. {rumdl-0.0.89 → rumdl-0.0.90}/tests/character_ranges/extended_tests.rs +0 -0
  230. {rumdl-0.0.89 → rumdl-0.0.90}/tests/character_ranges/mod.rs +0 -0
  231. {rumdl-0.0.89 → rumdl-0.0.90}/tests/character_ranges/unicode_utils.rs +0 -0
  232. {rumdl-0.0.89 → rumdl-0.0.90}/tests/cli_duplication_test.rs +0 -0
  233. {rumdl-0.0.89 → rumdl-0.0.90}/tests/cli_integration_tests.rs +0 -0
  234. {rumdl-0.0.89 → rumdl-0.0.90}/tests/cli_lsp_fix_consistency.rs +0 -0
  235. {rumdl-0.0.89 → rumdl-0.0.90}/tests/cli_statistics_test.rs +0 -0
  236. {rumdl-0.0.89 → rumdl-0.0.90}/tests/commonmark_compliance_tests.rs +0 -0
  237. {rumdl-0.0.89 → rumdl-0.0.90}/tests/comprehensive_integration_tests.rs +0 -0
  238. {rumdl-0.0.89 → rumdl-0.0.90}/tests/comprehensive_output_format_tests.rs +0 -0
  239. {rumdl-0.0.89 → rumdl-0.0.90}/tests/config_application_tests.rs +0 -0
  240. {rumdl-0.0.89 → rumdl-0.0.90}/tests/config_file_command_test.rs +0 -0
  241. {rumdl-0.0.89 → rumdl-0.0.90}/tests/config_tests.rs +0 -0
  242. {rumdl-0.0.89 → rumdl-0.0.90}/tests/configuration_inheritance_tests.rs +0 -0
  243. {rumdl-0.0.89 → rumdl-0.0.90}/tests/consistency_regression_tests.rs +0 -0
  244. {rumdl-0.0.89 → rumdl-0.0.90}/tests/cross_platform_compatibility_tests.rs +0 -0
  245. {rumdl-0.0.89 → rumdl-0.0.90}/tests/final_confidence_assessment.rs +0 -0
  246. {rumdl-0.0.89 → rumdl-0.0.90}/tests/init_command_test.rs +0 -0
  247. {rumdl-0.0.89 → rumdl-0.0.90}/tests/init_tests.rs +0 -0
  248. {rumdl-0.0.89 → rumdl-0.0.90}/tests/inline_config_test.rs +0 -0
  249. {rumdl-0.0.89 → rumdl-0.0.90}/tests/integration_tests.rs +0 -0
  250. {rumdl-0.0.89 → rumdl-0.0.90}/tests/json_output_test.rs +0 -0
  251. {rumdl-0.0.89 → rumdl-0.0.90}/tests/lib.rs +0 -0
  252. {rumdl-0.0.89 → rumdl-0.0.90}/tests/lsp_editor_integration_tests.rs +0 -0
  253. {rumdl-0.0.89 → rumdl-0.0.90}/tests/lsp_integration_tests.rs +0 -0
  254. {rumdl-0.0.89 → rumdl-0.0.90}/tests/lsp_memory_leak_tests.rs +0 -0
  255. {rumdl-0.0.89 → rumdl-0.0.90}/tests/lsp_tests.rs +0 -0
  256. {rumdl-0.0.89 → rumdl-0.0.90}/tests/malformed_markdown_stress_tests.rs +0 -0
  257. {rumdl-0.0.89 → rumdl-0.0.90}/tests/markdownlint_cli_integration.rs +0 -0
  258. {rumdl-0.0.89 → rumdl-0.0.90}/tests/markdownlint_config_test.rs +0 -0
  259. {rumdl-0.0.89 → rumdl-0.0.90}/tests/markdownlintignore_test.rs +0 -0
  260. {rumdl-0.0.89 → rumdl-0.0.90}/tests/md030_edge_cases.md +0 -0
  261. {rumdl-0.0.89 → rumdl-0.0.90}/tests/output_format_integration_tests.rs +0 -0
  262. {rumdl-0.0.89 → rumdl-0.0.90}/tests/output_format_tests.rs +0 -0
  263. {rumdl-0.0.89 → rumdl-0.0.90}/tests/perf_check.rs +0 -0
  264. {rumdl-0.0.89 → rumdl-0.0.90}/tests/performance_validation_tests.rs +0 -0
  265. {rumdl-0.0.89 → rumdl-0.0.90}/tests/pyproject_config_tests.rs +0 -0
  266. {rumdl-0.0.89 → rumdl-0.0.90}/tests/real_world_repository_tests.rs +0 -0
  267. {rumdl-0.0.89 → rumdl-0.0.90}/tests/regression_prevention_tests.rs +0 -0
  268. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md001_test.rs +0 -0
  269. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md001_unicode_test.rs +0 -0
  270. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md002_test.rs +0 -0
  271. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md003_test.rs +0 -0
  272. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md004_test.rs +0 -0
  273. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md005_test.rs +0 -0
  274. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md006_test.rs +0 -0
  275. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md006_unicode_test.rs +0 -0
  276. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md007_test.rs +0 -0
  277. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md009_test.rs +0 -0
  278. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md010_test.rs +0 -0
  279. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md011_test.rs +0 -0
  280. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md012_test.rs +0 -0
  281. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md013_test.rs +0 -0
  282. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md014_test.rs +0 -0
  283. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md018_test.rs +0 -0
  284. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md019_test.rs +0 -0
  285. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md020_test.rs +0 -0
  286. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md021_test.rs +0 -0
  287. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md022_test.rs +0 -0
  288. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md023_extended_test.rs +0 -0
  289. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md023_test.rs +0 -0
  290. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md024_test.rs +0 -0
  291. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md025_test.rs +0 -0
  292. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md026_test.rs +0 -0
  293. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md027_test.rs +0 -0
  294. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md028_test.rs +0 -0
  295. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md029_test.rs +0 -0
  296. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md030_test.rs +0 -0
  297. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md031_test.rs +0 -0
  298. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md032_test.rs +0 -0
  299. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md033_extended_test.rs +0 -0
  300. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md033_test.rs +0 -0
  301. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md035_test.rs +0 -0
  302. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md036_test.rs +0 -0
  303. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md037_test.rs +0 -0
  304. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md038_test.rs +0 -0
  305. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md039_test.rs +0 -0
  306. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md040_test.rs +0 -0
  307. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md041_test.rs +0 -0
  308. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md042_test.rs +0 -0
  309. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md043_test.rs +0 -0
  310. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md044_test.rs +0 -0
  311. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md045_test.rs +0 -0
  312. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md046_test.rs +0 -0
  313. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md047_test.rs +0 -0
  314. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md048_test.rs +0 -0
  315. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md049_test.rs +0 -0
  316. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md050_test.rs +0 -0
  317. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md051_test.rs +0 -0
  318. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md052_test.rs +0 -0
  319. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md053_additional_test.rs +0 -0
  320. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md053_proptest.rs +0 -0
  321. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md053_test.rs +0 -0
  322. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md054_test.rs +0 -0
  323. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md054_unicode_test.rs +0 -0
  324. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md055_test.rs +0 -0
  325. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md056_test.rs +0 -0
  326. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md057_test.rs +0 -0
  327. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/md058_test.rs +0 -0
  328. {rumdl-0.0.89 → rumdl-0.0.90}/tests/rules/mod.rs +0 -0
  329. {rumdl-0.0.89 → rumdl-0.0.90}/tests/thread_safety_tests.rs +0 -0
  330. {rumdl-0.0.89 → rumdl-0.0.90}/tests/unicode_edge_case_tests.rs +0 -0
  331. {rumdl-0.0.89 → rumdl-0.0.90}/tests/utils/blockquote_utils_test.rs +0 -0
  332. {rumdl-0.0.89 → rumdl-0.0.90}/tests/utils/code_block_utils_extended_test.rs +0 -0
  333. {rumdl-0.0.89 → rumdl-0.0.90}/tests/utils/code_block_utils_test.rs +0 -0
  334. {rumdl-0.0.89 → rumdl-0.0.90}/tests/utils/core_utils_test.rs +0 -0
  335. {rumdl-0.0.89 → rumdl-0.0.90}/tests/utils/front_matter_utils_test.rs +0 -0
  336. {rumdl-0.0.89 → rumdl-0.0.90}/tests/utils/line_index_test.rs +0 -0
  337. {rumdl-0.0.89 → rumdl-0.0.90}/tests/utils/mod.rs +0 -0
  338. {rumdl-0.0.89 → rumdl-0.0.90}/tests/utils_markdown_edge_cases.rs +0 -0
  339. {rumdl-0.0.89 → rumdl-0.0.90}/tests/utils_tests.rs +0 -0
  340. {rumdl-0.0.89 → rumdl-0.0.90}/tests/vscode_extension_fixes.rs +0 -0
  341. {rumdl-0.0.89 → rumdl-0.0.90}/tests/vscode_test.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.90] - 2025-07-01
11
+
10
12
  ## [0.0.89] - 2025-07-01
11
13
 
12
14
  ### Added
@@ -107,7 +109,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
107
109
  ### Added
108
110
  - Initial implementation of remaining rules for markdownlint parity
109
111
 
110
- [Unreleased]: https://github.com/rvben/rumdl/compare/v0.0.89...HEAD
112
+ [Unreleased]: https://github.com/rvben/rumdl/compare/v0.0.90...HEAD
113
+ [0.0.90]: https://github.com/rvben/rumdl/compare/v0.0.89...v0.0.90
111
114
  [0.0.89]: https://github.com/rvben/rumdl/compare/v0.0.88...v0.0.89
112
115
  [0.0.88]: https://github.com/rvben/rumdl/compare/v0.0.87...v0.0.88
113
116
  [0.0.87]: https://github.com/rvben/rumdl/compare/v0.0.86...v0.0.87
@@ -1454,7 +1454,7 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
1454
1454
 
1455
1455
  [[package]]
1456
1456
  name = "rumdl"
1457
- version = "0.0.89"
1457
+ version = "0.0.90"
1458
1458
  dependencies = [
1459
1459
  "anyhow",
1460
1460
  "assert_cmd",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "rumdl"
3
- version = "0.0.89"
3
+ version = "0.0.90"
4
4
  edition = "2024"
5
5
  rust-version = "1.87.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.89
3
+ Version: 0.0.90
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -55,6 +55,7 @@ Project-URL: Repository, https://github.com/rvben/rumdl.git
55
55
  - [Table of Contents](#table-of-contents)
56
56
  - [Quick Start](#quick-start)
57
57
  - [Overview](#overview)
58
+ - [Performance](#performance)
58
59
  - [Installation](#installation)
59
60
  - [Using Cargo (Rust)](#using-cargo-rust)
60
61
  - [Using pip (Python)](#using-pip-python)
@@ -102,7 +103,7 @@ rumdl init
102
103
 
103
104
  rumdl is a high-performance Markdown linter and fixer that helps ensure consistency and best practices in your Markdown files. It offers:
104
105
 
105
- - ⚡️ **Built for speed** with Rust
106
+ - ⚡️ **Built for speed** with Rust - significantly faster than alternatives
106
107
  - 🔍 **54 lint rules** covering common Markdown issues
107
108
  - 🛠️ **Automatic fixing** with `--fix` for most rules
108
109
  - 📦 **Zero dependencies** - single binary with no runtime requirements
@@ -112,6 +113,14 @@ rumdl is a high-performance Markdown linter and fixer that helps ensure consiste
112
113
  - 📏 **Modern CLI** with detailed error reporting
113
114
  - 🔄 **CI/CD friendly** with non-zero exit code on errors
114
115
 
116
+ ## Performance
117
+
118
+ rumdl is designed for speed and efficiency:
119
+
120
+ ![Performance Comparison](assets/performance_overview.png)
121
+
122
+ rumdl is **4.3x faster** on average than markdownlint for typical markdown files, with performance improvements ranging from 3.4x to 5.4x depending on project size.
123
+
115
124
  ## Installation
116
125
 
117
126
  Choose the installation method that works best for you:
@@ -24,6 +24,7 @@
24
24
  - [Table of Contents](#table-of-contents)
25
25
  - [Quick Start](#quick-start)
26
26
  - [Overview](#overview)
27
+ - [Performance](#performance)
27
28
  - [Installation](#installation)
28
29
  - [Using Cargo (Rust)](#using-cargo-rust)
29
30
  - [Using pip (Python)](#using-pip-python)
@@ -71,7 +72,7 @@ rumdl init
71
72
 
72
73
  rumdl is a high-performance Markdown linter and fixer that helps ensure consistency and best practices in your Markdown files. It offers:
73
74
 
74
- - ⚡️ **Built for speed** with Rust
75
+ - ⚡️ **Built for speed** with Rust - significantly faster than alternatives
75
76
  - 🔍 **54 lint rules** covering common Markdown issues
76
77
  - 🛠️ **Automatic fixing** with `--fix` for most rules
77
78
  - 📦 **Zero dependencies** - single binary with no runtime requirements
@@ -81,6 +82,14 @@ rumdl is a high-performance Markdown linter and fixer that helps ensure consiste
81
82
  - 📏 **Modern CLI** with detailed error reporting
82
83
  - 🔄 **CI/CD friendly** with non-zero exit code on errors
83
84
 
85
+ ## Performance
86
+
87
+ rumdl is designed for speed and efficiency:
88
+
89
+ ![Performance Comparison](assets/performance_overview.png)
90
+
91
+ rumdl is **4.3x faster** on average than markdownlint for typical markdown files, with performance improvements ranging from 3.4x to 5.4x depending on project size.
92
+
84
93
  ## Installation
85
94
 
86
95
  Choose the installation method that works best for you:
@@ -23,7 +23,7 @@ pub mod python;
23
23
  pub use rules::heading_utils::{Heading, HeadingStyle};
24
24
  pub use rules::*;
25
25
 
26
- pub use crate::lint_context::{BareUrl, LineInfo, LintContext, ListItemInfo};
26
+ pub use crate::lint_context::{LineInfo, LintContext, ListItemInfo};
27
27
  use crate::rule::{LintResult, Rule, RuleCategory};
28
28
  use crate::utils::document_structure::DocumentStructure;
29
29
  use std::time::Instant;
@@ -1,8 +1,6 @@
1
1
  use crate::utils::code_block_utils::CodeBlockUtils;
2
2
  use lazy_static::lazy_static;
3
- use markdown::{mdast::Node, to_mdast, ParseOptions};
4
3
  use regex::Regex;
5
- use std::panic;
6
4
 
7
5
  lazy_static! {
8
6
  // Comprehensive link pattern that captures both inline and reference links
@@ -223,24 +221,6 @@ pub struct BlockquoteInfo {
223
221
  pub needs_md028_fix: bool,
224
222
  }
225
223
 
226
- /// Information about a bare URL or email
227
- #[derive(Debug, Clone)]
228
- pub struct BareUrl {
229
- /// Line number (1-indexed)
230
- pub line: usize,
231
- /// Start column (0-indexed) in the line
232
- pub start_col: usize,
233
- /// End column (0-indexed) in the line
234
- pub end_col: usize,
235
- /// Byte offset in document
236
- pub byte_offset: usize,
237
- /// End byte offset in document
238
- pub byte_end: usize,
239
- /// The URL or email text
240
- pub text: String,
241
- /// Whether this is an email (true) or URL (false)
242
- pub is_email: bool,
243
- }
244
224
 
245
225
  /// Information about a list block
246
226
  #[derive(Debug, Clone)]
@@ -263,7 +243,6 @@ pub struct ListBlock {
263
243
 
264
244
  pub struct LintContext<'a> {
265
245
  pub content: &'a str,
266
- pub ast: Node, // The root of the AST
267
246
  pub line_offsets: Vec<usize>,
268
247
  pub code_blocks: Vec<(usize, usize)>, // Cached code block ranges (not including inline code spans)
269
248
  pub lines: Vec<LineInfo>, // Pre-computed line information
@@ -272,79 +251,10 @@ pub struct LintContext<'a> {
272
251
  pub reference_defs: Vec<ReferenceDef>, // Reference definitions
273
252
  pub code_spans: Vec<CodeSpan>, // Pre-parsed inline code spans
274
253
  pub list_blocks: Vec<ListBlock>, // Pre-parsed list blocks
275
- pub bare_urls: Vec<BareUrl>, // Pre-parsed bare URLs and emails
276
254
  }
277
255
 
278
256
  impl<'a> LintContext<'a> {
279
257
  pub fn new(content: &'a str) -> Self {
280
- // Check for problematic patterns that cause the markdown crate to panic
281
- if content_has_problematic_lists(content) {
282
- log::debug!("Detected problematic list patterns in LintContext, skipping AST parsing");
283
- let ast = Node::Root(markdown::mdast::Root {
284
- children: vec![],
285
- position: None,
286
- });
287
-
288
- let mut line_offsets = vec![0];
289
- for (i, c) in content.char_indices() {
290
- if c == '\n' {
291
- line_offsets.push(i + 1);
292
- }
293
- }
294
-
295
- // Detect code blocks once and cache them
296
- let code_blocks = CodeBlockUtils::detect_code_blocks(content);
297
-
298
- // Pre-compute line information
299
- let lines = Self::compute_line_info(content, &line_offsets, &code_blocks);
300
-
301
- // Parse links, images, references, code spans, and list blocks
302
- let links = Self::parse_links(content, &lines, &code_blocks);
303
- let images = Self::parse_images(content, &lines, &code_blocks);
304
- let reference_defs = Self::parse_reference_defs(content, &lines);
305
- let code_spans = Self::parse_code_spans(content, &lines);
306
- let list_blocks = Self::parse_list_blocks(&lines);
307
- let bare_urls = Self::parse_bare_urls(content, &lines, &code_blocks, &links, &images, &reference_defs);
308
-
309
- return Self {
310
- content,
311
- ast,
312
- line_offsets,
313
- code_blocks,
314
- lines,
315
- links,
316
- images,
317
- reference_defs,
318
- code_spans,
319
- list_blocks,
320
- bare_urls,
321
- };
322
- }
323
-
324
- // Try to parse AST, but handle panics from the markdown crate
325
- let ast = match panic::catch_unwind(std::panic::AssertUnwindSafe(|| to_mdast(content, &ParseOptions::gfm()))) {
326
- Ok(Ok(ast)) => {
327
- // Successfully parsed AST
328
- ast
329
- }
330
- Ok(Err(err)) => {
331
- // Parsing failed with an error
332
- log::debug!("Failed to parse markdown AST: {:?}", err);
333
- Node::Root(markdown::mdast::Root {
334
- children: vec![],
335
- position: None,
336
- })
337
- }
338
- Err(_) => {
339
- // Parsing panicked
340
- log::debug!("Markdown AST parsing panicked, falling back to empty AST");
341
- Node::Root(markdown::mdast::Root {
342
- children: vec![],
343
- position: None,
344
- })
345
- }
346
- };
347
-
348
258
  let mut line_offsets = vec![0];
349
259
  for (i, c) in content.char_indices() {
350
260
  if c == '\n' {
@@ -364,11 +274,9 @@ impl<'a> LintContext<'a> {
364
274
  let reference_defs = Self::parse_reference_defs(content, &lines);
365
275
  let code_spans = Self::parse_code_spans(content, &lines);
366
276
  let list_blocks = Self::parse_list_blocks(&lines);
367
- let bare_urls = Self::parse_bare_urls(content, &lines, &code_blocks, &links, &images, &reference_defs);
368
277
 
369
278
  Self {
370
279
  content,
371
- ast,
372
280
  line_offsets,
373
281
  code_blocks,
374
282
  lines,
@@ -377,7 +285,6 @@ impl<'a> LintContext<'a> {
377
285
  reference_defs,
378
286
  code_spans,
379
287
  list_blocks,
380
- bare_urls,
381
288
  }
382
289
  }
383
290
 
@@ -665,28 +572,30 @@ impl<'a> LintContext<'a> {
665
572
 
666
573
  /// Pre-compute line information
667
574
  fn compute_line_info(content: &str, line_offsets: &[usize], code_blocks: &[(usize, usize)]) -> Vec<LineInfo> {
668
- let mut lines = Vec::new();
669
- let content_lines: Vec<&str> = content.lines().collect();
670
-
671
- // Regex for list detection - allow any whitespace including no space (to catch malformed lists)
672
- let unordered_regex = regex::Regex::new(r"^(\s*)([-*+])([ \t]*)(.*)").unwrap();
673
- let ordered_regex = regex::Regex::new(r"^(\s*)(\d+)([.)])([ \t]*)(.*)").unwrap();
575
+ lazy_static! {
576
+ // Regex for list detection - allow any whitespace including no space (to catch malformed lists)
577
+ static ref UNORDERED_REGEX: regex::Regex = regex::Regex::new(r"^(\s*)([-*+])([ \t]*)(.*)").unwrap();
578
+ static ref ORDERED_REGEX: regex::Regex = regex::Regex::new(r"^(\s*)(\d+)([.)])([ \t]*)(.*)").unwrap();
674
579
 
675
- // Regex for blockquote prefix
676
- let blockquote_regex = regex::Regex::new(r"^(\s*>\s*)(.*)").unwrap();
580
+ // Regex for blockquote prefix
581
+ static ref BLOCKQUOTE_REGEX: regex::Regex = regex::Regex::new(r"^(\s*>\s*)(.*)").unwrap();
677
582
 
678
- // Regex for heading detection
679
- let atx_heading_regex = regex::Regex::new(r"^(\s*)(#{1,6})(\s*)(.*)$").unwrap();
680
- let setext_underline_regex = regex::Regex::new(r"^(\s*)(=+|-+)\s*$").unwrap();
583
+ // Regex for heading detection
584
+ static ref ATX_HEADING_REGEX: regex::Regex = regex::Regex::new(r"^(\s*)(#{1,6})(\s*)(.*)$").unwrap();
585
+ static ref SETEXT_UNDERLINE_REGEX: regex::Regex = regex::Regex::new(r"^(\s*)(=+|-+)\s*$").unwrap();
681
586
 
682
- // Regex for blockquote detection
683
- let blockquote_regex_full = regex::Regex::new(r"^(\s*)(>+)(\s*)(.*)$").unwrap();
587
+ // Regex for blockquote detection
588
+ static ref BLOCKQUOTE_REGEX_FULL: regex::Regex = regex::Regex::new(r"^(\s*)(>+)(\s*)(.*)$").unwrap();
589
+ }
590
+
591
+ let mut lines = Vec::new();
592
+ let content_lines: Vec<&str> = content.lines().collect();
684
593
 
685
594
  for (i, line) in content_lines.iter().enumerate() {
686
595
  let byte_offset = line_offsets.get(i).copied().unwrap_or(0);
687
596
  let indent = line.len() - line.trim_start().len();
688
597
  // For blank detection, consider blockquote context
689
- let is_blank = if let Some(caps) = blockquote_regex.captures(line) {
598
+ let is_blank = if let Some(caps) = BLOCKQUOTE_REGEX.captures(line) {
690
599
  // In blockquote context, check if content after prefix is blank
691
600
  let after_prefix = caps.get(2).map_or("", |m| m.as_str());
692
601
  after_prefix.trim().is_empty()
@@ -712,7 +621,7 @@ impl<'a> LintContext<'a> {
712
621
  // Detect list items
713
622
  let list_item = if !in_code_block && !is_blank {
714
623
  // Strip blockquote prefix if present for list detection
715
- let (line_for_list_check, blockquote_prefix_len) = if let Some(caps) = blockquote_regex.captures(line) {
624
+ let (line_for_list_check, blockquote_prefix_len) = if let Some(caps) = BLOCKQUOTE_REGEX.captures(line) {
716
625
  let prefix = caps.get(1).unwrap().as_str();
717
626
  let content = caps.get(2).unwrap().as_str();
718
627
  (content, prefix.len())
@@ -720,7 +629,7 @@ impl<'a> LintContext<'a> {
720
629
  (&**line, 0)
721
630
  };
722
631
 
723
- if let Some(caps) = unordered_regex.captures(line_for_list_check) {
632
+ if let Some(caps) = UNORDERED_REGEX.captures(line_for_list_check) {
724
633
  let leading_spaces = caps.get(1).map_or("", |m| m.as_str());
725
634
  let marker = caps.get(2).map_or("", |m| m.as_str());
726
635
  let spacing = caps.get(3).map_or("", |m| m.as_str());
@@ -766,7 +675,7 @@ impl<'a> LintContext<'a> {
766
675
  content_column,
767
676
  })
768
677
  }
769
- } else if let Some(caps) = ordered_regex.captures(line_for_list_check) {
678
+ } else if let Some(caps) = ORDERED_REGEX.captures(line_for_list_check) {
770
679
  let leading_spaces = caps.get(1).map_or("", |m| m.as_str());
771
680
  let number_str = caps.get(2).map_or("", |m| m.as_str());
772
681
  let delimiter = caps.get(3).map_or("", |m| m.as_str());
@@ -836,7 +745,7 @@ impl<'a> LintContext<'a> {
836
745
  let line = content_lines[i];
837
746
 
838
747
  // Check for blockquotes (even on blank lines within blockquotes)
839
- if let Some(caps) = blockquote_regex_full.captures(line) {
748
+ if let Some(caps) = BLOCKQUOTE_REGEX_FULL.captures(line) {
840
749
  let indent_str = caps.get(1).map_or("", |m| m.as_str());
841
750
  let markers = caps.get(2).map_or("", |m| m.as_str());
842
751
  let spaces_after = caps.get(3).map_or("", |m| m.as_str());
@@ -873,7 +782,7 @@ impl<'a> LintContext<'a> {
873
782
  }
874
783
 
875
784
  // Check for ATX headings
876
- if let Some(caps) = atx_heading_regex.captures(line) {
785
+ if let Some(caps) = ATX_HEADING_REGEX.captures(line) {
877
786
  let leading_spaces = caps.get(1).map_or("", |m| m.as_str());
878
787
  let hashes = caps.get(2).map_or("", |m| m.as_str());
879
788
  let spaces_after = caps.get(3).map_or("", |m| m.as_str());
@@ -926,7 +835,7 @@ impl<'a> LintContext<'a> {
926
835
  // Check for Setext headings (need to look at next line)
927
836
  else if i + 1 < content_lines.len() {
928
837
  let next_line = content_lines[i + 1];
929
- if !lines[i + 1].in_code_block && setext_underline_regex.is_match(next_line) {
838
+ if !lines[i + 1].in_code_block && SETEXT_UNDERLINE_REGEX.is_match(next_line) {
930
839
  // Skip if next line is front matter delimiter
931
840
  if in_front_matter && i < front_matter_end {
932
841
  continue;
@@ -1287,218 +1196,6 @@ impl<'a> LintContext<'a> {
1287
1196
 
1288
1197
  list_blocks
1289
1198
  }
1290
-
1291
- /// Parse all bare URLs and emails in the content
1292
- fn parse_bare_urls(
1293
- content: &str,
1294
- lines: &[LineInfo],
1295
- code_blocks: &[(usize, usize)],
1296
- links: &[ParsedLink],
1297
- images: &[ParsedImage],
1298
- reference_defs: &[ReferenceDef],
1299
- ) -> Vec<BareUrl> {
1300
- let mut bare_urls = Vec::new();
1301
-
1302
- // Quick check - if no URLs or emails, return empty
1303
- if !content.contains("http://")
1304
- && !content.contains("https://")
1305
- && !content.contains("ftp://")
1306
- && !content.contains('@')
1307
- {
1308
- return bare_urls;
1309
- }
1310
-
1311
- // Build exclusion ranges from links, images, and angle bracket links
1312
- let mut excluded_ranges: Vec<(usize, usize)> = Vec::new();
1313
-
1314
- // Exclude link URLs
1315
- for link in links {
1316
- if !link.url.is_empty() {
1317
- excluded_ranges.push((link.byte_offset, link.byte_end));
1318
- }
1319
- }
1320
-
1321
- // Exclude image URLs
1322
- for image in images {
1323
- if !image.url.is_empty() {
1324
- excluded_ranges.push((image.byte_offset, image.byte_end));
1325
- }
1326
- }
1327
-
1328
- // Exclude angle bracket links <url> or <email>
1329
- for angle_match in ANGLE_BRACKET_PATTERN.find_iter(content) {
1330
- excluded_ranges.push((angle_match.start(), angle_match.end()));
1331
- }
1332
-
1333
- // Sort and merge overlapping ranges
1334
- excluded_ranges.sort_by_key(|r| r.0);
1335
- let mut merged: Vec<(usize, usize)> = Vec::new();
1336
- for (start, end) in excluded_ranges {
1337
- if let Some((_, last_end)) = merged.last_mut() {
1338
- if *last_end >= start {
1339
- *last_end = (*last_end).max(end);
1340
- continue;
1341
- }
1342
- }
1343
- merged.push((start, end));
1344
- }
1345
-
1346
- // Find bare URLs
1347
- for url_match in BARE_URL_PATTERN.find_iter(content) {
1348
- let url_start = url_match.start();
1349
- let mut url_end = url_match.end();
1350
-
1351
- // Skip if in code block or code span
1352
- if CodeBlockUtils::is_in_code_block_or_span(code_blocks, url_start) {
1353
- continue;
1354
- }
1355
-
1356
- // Skip if within any excluded range (link/image)
1357
- let in_any_range = merged.iter().any(|(start, end)| url_start >= *start && url_end <= *end);
1358
- if in_any_range {
1359
- continue;
1360
- }
1361
-
1362
- // Check if it's in a reference definition line
1363
- let mut is_ref_def = false;
1364
- for ref_def in reference_defs {
1365
- if let Some(line_info) = lines.get(ref_def.line - 1) {
1366
- let line_start = line_info.byte_offset;
1367
- let line_end = if ref_def.line < lines.len() {
1368
- lines[ref_def.line].byte_offset
1369
- } else {
1370
- content.len()
1371
- };
1372
- if url_start >= line_start && url_start < line_end {
1373
- is_ref_def = true;
1374
- break;
1375
- }
1376
- }
1377
- }
1378
- if is_ref_def {
1379
- continue;
1380
- }
1381
-
1382
- // Trim trailing punctuation
1383
- let raw_url = &content[url_start..url_end];
1384
- let trailing_punct = ['.', ',', ';', ':', '!', '?'];
1385
- while url_end > url_start {
1386
- if let Some(last_char) = raw_url.chars().last() {
1387
- if trailing_punct.contains(&last_char) {
1388
- url_end -= last_char.len_utf8();
1389
- } else {
1390
- break;
1391
- }
1392
- } else {
1393
- break;
1394
- }
1395
- }
1396
-
1397
- // Manual boundary check
1398
- let before = if url_start == 0 {
1399
- None
1400
- } else {
1401
- content.get(url_start - 1..url_start)
1402
- };
1403
- let after = content.get(url_end..url_end + 1);
1404
- let is_valid_boundary = before.is_none_or(|c| !c.chars().next().unwrap().is_alphanumeric() && c != "_")
1405
- && after.is_none_or(|c| !c.chars().next().unwrap().is_alphanumeric() && c != "_");
1406
- if !is_valid_boundary {
1407
- continue;
1408
- }
1409
-
1410
- // Find which line this URL is on
1411
- let mut line_num = 1;
1412
- let mut col_start = url_start;
1413
- for (idx, line_info) in lines.iter().enumerate() {
1414
- if url_start >= line_info.byte_offset {
1415
- line_num = idx + 1;
1416
- col_start = url_start - line_info.byte_offset;
1417
- } else {
1418
- break;
1419
- }
1420
- }
1421
-
1422
- // Calculate end column
1423
- let mut col_end = col_start + (url_end - url_start);
1424
- if let Some(line_info) = lines.get(line_num - 1) {
1425
- // For single-line URLs
1426
- col_end = url_end - line_info.byte_offset;
1427
- }
1428
-
1429
- bare_urls.push(BareUrl {
1430
- line: line_num,
1431
- start_col: col_start,
1432
- end_col: col_end,
1433
- byte_offset: url_start,
1434
- byte_end: url_end,
1435
- text: content[url_start..url_end].to_string(),
1436
- is_email: false,
1437
- });
1438
- }
1439
-
1440
- // Find bare emails
1441
- for email_match in BARE_EMAIL_PATTERN.find_iter(content) {
1442
- let email_start = email_match.start();
1443
- let email_end = email_match.end();
1444
-
1445
- // Skip if in code block or code span
1446
- if CodeBlockUtils::is_in_code_block_or_span(code_blocks, email_start) {
1447
- continue;
1448
- }
1449
-
1450
- // Skip if within any excluded range (link/image)
1451
- let in_any_range = merged
1452
- .iter()
1453
- .any(|(start, end)| email_start >= *start && email_end <= *end);
1454
- if in_any_range {
1455
- continue;
1456
- }
1457
-
1458
- // Manual boundary check
1459
- let before = if email_start == 0 {
1460
- None
1461
- } else {
1462
- content.get(email_start - 1..email_start)
1463
- };
1464
- let after = content.get(email_end..email_end + 1);
1465
- let is_valid_boundary = before.is_none_or(|c| {
1466
- !c.chars().next().unwrap().is_alphanumeric() && c != "_" && c != "."
1467
- }) && after.is_none_or(|c| {
1468
- !c.chars().next().unwrap().is_alphanumeric() && c != "_" && c != "."
1469
- });
1470
- if !is_valid_boundary {
1471
- continue;
1472
- }
1473
-
1474
- // Find which line this email is on
1475
- let mut line_num = 1;
1476
- let mut col_start = email_start;
1477
- for (idx, line_info) in lines.iter().enumerate() {
1478
- if email_start >= line_info.byte_offset {
1479
- line_num = idx + 1;
1480
- col_start = email_start - line_info.byte_offset;
1481
- } else {
1482
- break;
1483
- }
1484
- }
1485
-
1486
- // Calculate end column
1487
- let col_end = email_end - lines[line_num - 1].byte_offset;
1488
-
1489
- bare_urls.push(BareUrl {
1490
- line: line_num,
1491
- start_col: col_start,
1492
- end_col: col_end,
1493
- byte_offset: email_start,
1494
- byte_end: email_end,
1495
- text: content[email_start..email_end].to_string(),
1496
- is_email: true,
1497
- });
1498
- }
1499
-
1500
- bare_urls
1501
- }
1502
1199
  }
1503
1200
 
1504
1201
  /// Merge adjacent list blocks that should be treated as one
@@ -1545,48 +1242,15 @@ fn merge_adjacent_list_blocks(list_blocks: &mut Vec<ListBlock>) {
1545
1242
  }
1546
1243
 
1547
1244
  /// Check if content contains patterns that cause the markdown crate to panic
1548
- fn content_has_problematic_lists(content: &str) -> bool {
1549
- let lines: Vec<&str> = content.lines().collect();
1550
-
1551
- // Look for mixed list markers in consecutive lines (which causes the panic)
1552
- for window in lines.windows(3) {
1553
- if window.len() >= 2 {
1554
- let line1 = window[0].trim_start();
1555
- let line2 = window[1].trim_start();
1556
-
1557
- // Check if both lines are list items with different markers
1558
- let is_list1 = line1.starts_with("* ") || line1.starts_with("+ ") || line1.starts_with("- ");
1559
- let is_list2 = line2.starts_with("* ") || line2.starts_with("+ ") || line2.starts_with("- ");
1560
-
1561
- if is_list1 && is_list2 {
1562
- let marker1 = line1.chars().next().unwrap_or(' ');
1563
- let marker2 = line2.chars().next().unwrap_or(' ');
1564
-
1565
- // If different markers, this could cause a panic
1566
- if marker1 != marker2 {
1567
- return true;
1568
- }
1569
- }
1570
- }
1571
- }
1572
-
1573
- false
1574
- }
1575
1245
 
1576
1246
  #[cfg(test)]
1577
1247
  mod tests {
1578
1248
  use super::*;
1579
- use markdown::mdast::{Heading, Node};
1580
1249
 
1581
1250
  #[test]
1582
1251
  fn test_empty_content() {
1583
1252
  let ctx = LintContext::new("");
1584
1253
  assert_eq!(ctx.content, "");
1585
- // Should be a Root node with no children
1586
- match &ctx.ast {
1587
- Node::Root(root) => assert!(root.children.is_empty()),
1588
- _ => panic!("AST root is not Root node"),
1589
- }
1590
1254
  assert_eq!(ctx.line_offsets, vec![0]);
1591
1255
  assert_eq!(ctx.offset_to_line_col(0), (1, 1));
1592
1256
  assert_eq!(ctx.lines.len(), 0);
@@ -1596,17 +1260,6 @@ mod tests {
1596
1260
  fn test_single_line() {
1597
1261
  let ctx = LintContext::new("# Hello");
1598
1262
  assert_eq!(ctx.content, "# Hello");
1599
- // Should parse a heading
1600
- match &ctx.ast {
1601
- Node::Root(root) => {
1602
- assert_eq!(root.children.len(), 1);
1603
- match &root.children[0] {
1604
- Node::Heading(Heading { depth, .. }) => assert_eq!(*depth, 1),
1605
- _ => panic!("First child is not a Heading"),
1606
- }
1607
- }
1608
- _ => panic!("AST root is not Root node"),
1609
- }
1610
1263
  assert_eq!(ctx.line_offsets, vec![0]);
1611
1264
  assert_eq!(ctx.offset_to_line_col(0), (1, 1));
1612
1265
  assert_eq!(ctx.offset_to_line_col(3), (1, 4));
@@ -1971,7 +1971,18 @@ fn run_check(args: &CheckArgs, global_config_path: Option<&str>, no_config: bool
1971
1971
  let start_time = Instant::now();
1972
1972
 
1973
1973
  // Choose processing strategy based on file count and fix mode
1974
- let use_parallel = file_paths.len() > 1 && !args._fix; // Don't parallelize fixes due to file I/O conflicts
1974
+ // Also check if it's a single small file to avoid parallel overhead
1975
+ let single_small_file = if file_paths.len() == 1 {
1976
+ if let Ok(metadata) = fs::metadata(&file_paths[0]) {
1977
+ metadata.len() < 10_000 // 10KB threshold
1978
+ } else {
1979
+ false
1980
+ }
1981
+ } else {
1982
+ false
1983
+ };
1984
+
1985
+ let use_parallel = file_paths.len() > 1 && !args._fix && !single_small_file; // Don't parallelize fixes or small files
1975
1986
 
1976
1987
  // Collect all warnings for statistics if requested
1977
1988
  let mut all_warnings_for_stats = Vec::new();
@@ -131,6 +131,7 @@ pub trait Rule: DynClone + Send + Sync {
131
131
  false
132
132
  }
133
133
 
134
+
134
135
  fn as_any(&self) -> &dyn std::any::Any;
135
136
 
136
137
  fn as_maybe_document_structure(&self) -> Option<&dyn MaybeDocumentStructure> {
@@ -250,6 +250,7 @@ impl Rule for MD009TrailingSpaces {
250
250
  RuleCategory::Whitespace
251
251
  }
252
252
 
253
+
253
254
  fn default_config_section(&self) -> Option<(String, toml::Value)> {
254
255
  let default_config = MD009Config::default();
255
256
  let json_value = serde_json::to_value(&default_config).ok()?;