rumdl 0.0.73__tar.gz → 0.0.75__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 (266) hide show
  1. {rumdl-0.0.73 → rumdl-0.0.75}/Cargo.lock +1 -1
  2. {rumdl-0.0.73 → rumdl-0.0.75}/Cargo.toml +1 -1
  3. {rumdl-0.0.73 → rumdl-0.0.75}/PKG-INFO +1 -1
  4. rumdl-0.0.75/src/rules/md011_no_reversed_links.rs +447 -0
  5. rumdl-0.0.75/src/rules/md018_no_missing_space_atx.rs +479 -0
  6. rumdl-0.0.75/src/rules/md027_multiple_spaces_blockquote.rs +269 -0
  7. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md032_blanks_around_lists.rs +34 -0
  8. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md042_no_empty_links.rs +7 -49
  9. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md051_link_fragments.rs +74 -51
  10. {rumdl-0.0.73 → rumdl-0.0.75}/src/utils/document_structure.rs +70 -68
  11. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md033_test.rs +321 -0
  12. rumdl-0.0.75/tests/rules/md042_test.rs +291 -0
  13. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md051_test.rs +128 -0
  14. rumdl-0.0.73/src/rules/md011_no_reversed_links.rs +0 -233
  15. rumdl-0.0.73/src/rules/md018_no_missing_space_atx.rs +0 -257
  16. rumdl-0.0.73/src/rules/md027_multiple_spaces_blockquote.rs +0 -111
  17. rumdl-0.0.73/tests/rules/md042_test.rs +0 -84
  18. {rumdl-0.0.73 → rumdl-0.0.75}/.rumdl.toml +0 -0
  19. {rumdl-0.0.73 → rumdl-0.0.75}/MANIFEST.in +0 -0
  20. {rumdl-0.0.73 → rumdl-0.0.75}/Makefile +0 -0
  21. {rumdl-0.0.73 → rumdl-0.0.75}/README.md +0 -0
  22. {rumdl-0.0.73 → rumdl-0.0.75}/assets/logo.png +0 -0
  23. {rumdl-0.0.73 → rumdl-0.0.75}/benches/fix_performance.rs +0 -0
  24. {rumdl-0.0.73 → rumdl-0.0.75}/benches/range_performance.rs +0 -0
  25. {rumdl-0.0.73 → rumdl-0.0.75}/benches/range_utils_benchmark.rs +0 -0
  26. {rumdl-0.0.73 → rumdl-0.0.75}/benches/rule_performance.rs +0 -0
  27. {rumdl-0.0.73 → rumdl-0.0.75}/benches/simple_fix_bench.rs +0 -0
  28. {rumdl-0.0.73 → rumdl-0.0.75}/docs/RULES.md +0 -0
  29. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md001.md +0 -0
  30. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md002.md +0 -0
  31. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md003.md +0 -0
  32. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md004.md +0 -0
  33. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md005.md +0 -0
  34. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md006.md +0 -0
  35. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md007.md +0 -0
  36. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md009.md +0 -0
  37. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md010.md +0 -0
  38. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md011.md +0 -0
  39. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md012.md +0 -0
  40. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md013.md +0 -0
  41. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md014.md +0 -0
  42. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md018.md +0 -0
  43. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md019.md +0 -0
  44. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md020.md +0 -0
  45. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md021.md +0 -0
  46. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md022.md +0 -0
  47. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md023.md +0 -0
  48. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md024.md +0 -0
  49. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md025.md +0 -0
  50. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md026.md +0 -0
  51. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md027.md +0 -0
  52. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md028.md +0 -0
  53. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md029.md +0 -0
  54. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md030.md +0 -0
  55. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md031.md +0 -0
  56. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md032.md +0 -0
  57. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md033.md +0 -0
  58. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md034.md +0 -0
  59. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md035.md +0 -0
  60. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md036.md +0 -0
  61. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md037.md +0 -0
  62. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md038.md +0 -0
  63. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md039.md +0 -0
  64. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md040.md +0 -0
  65. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md041.md +0 -0
  66. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md042.md +0 -0
  67. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md043.md +0 -0
  68. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md044.md +0 -0
  69. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md045.md +0 -0
  70. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md046.md +0 -0
  71. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md047.md +0 -0
  72. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md048.md +0 -0
  73. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md049.md +0 -0
  74. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md050.md +0 -0
  75. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md051.md +0 -0
  76. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md052.md +0 -0
  77. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md053.md +0 -0
  78. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md054.md +0 -0
  79. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md055.md +0 -0
  80. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md056.md +0 -0
  81. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md057.md +0 -0
  82. {rumdl-0.0.73 → rumdl-0.0.75}/docs/md058.md +0 -0
  83. {rumdl-0.0.73 → rumdl-0.0.75}/issues/plan-rule-parity-with-markdownlint.md +0 -0
  84. {rumdl-0.0.73 → rumdl-0.0.75}/parity_check.py +0 -0
  85. {rumdl-0.0.73 → rumdl-0.0.75}/pyproject.toml +0 -0
  86. {rumdl-0.0.73 → rumdl-0.0.75}/python/MANIFEST.in +0 -0
  87. {rumdl-0.0.73 → rumdl-0.0.75}/python/PYTHON-README.md +0 -0
  88. {rumdl-0.0.73 → rumdl-0.0.75}/python/rumdl/__init__.py +0 -0
  89. {rumdl-0.0.73 → rumdl-0.0.75}/python/rumdl/__main__.py +0 -0
  90. {rumdl-0.0.73 → rumdl-0.0.75}/python/rumdl/py.typed +0 -0
  91. {rumdl-0.0.73 → rumdl-0.0.75}/rumdl.toml.example +0 -0
  92. {rumdl-0.0.73 → rumdl-0.0.75}/src/config.rs +0 -0
  93. {rumdl-0.0.73 → rumdl-0.0.75}/src/init.rs +0 -0
  94. {rumdl-0.0.73 → rumdl-0.0.75}/src/lib.rs +0 -0
  95. {rumdl-0.0.73 → rumdl-0.0.75}/src/lint_context.rs +0 -0
  96. {rumdl-0.0.73 → rumdl-0.0.75}/src/lsp/mod.rs +0 -0
  97. {rumdl-0.0.73 → rumdl-0.0.75}/src/lsp/server.rs +0 -0
  98. {rumdl-0.0.73 → rumdl-0.0.75}/src/lsp/types.rs +0 -0
  99. {rumdl-0.0.73 → rumdl-0.0.75}/src/main.rs +0 -0
  100. {rumdl-0.0.73 → rumdl-0.0.75}/src/markdownlint_config.rs +0 -0
  101. {rumdl-0.0.73 → rumdl-0.0.75}/src/parallel.rs +0 -0
  102. {rumdl-0.0.73 → rumdl-0.0.75}/src/performance.rs +0 -0
  103. {rumdl-0.0.73 → rumdl-0.0.75}/src/profiling.rs +0 -0
  104. {rumdl-0.0.73 → rumdl-0.0.75}/src/python.rs +0 -0
  105. {rumdl-0.0.73 → rumdl-0.0.75}/src/rule.rs +0 -0
  106. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/blockquote_utils.rs +0 -0
  107. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/code_block_utils.rs +0 -0
  108. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/code_fence_utils.rs +0 -0
  109. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/emphasis_style.rs +0 -0
  110. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/front_matter_utils.rs +0 -0
  111. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/heading_utils.rs +0 -0
  112. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/list_utils.rs +0 -0
  113. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md001_heading_increment.rs +0 -0
  114. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md002_first_heading_h1.rs +0 -0
  115. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md003_heading_style.rs +0 -0
  116. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md004_unordered_list_style.rs +0 -0
  117. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md005_list_indent.rs +0 -0
  118. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md006_start_bullets.rs +0 -0
  119. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md007_ul_indent.rs +0 -0
  120. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md009_trailing_spaces.rs +0 -0
  121. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md010_no_hard_tabs.rs +0 -0
  122. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md012_no_multiple_blanks.rs +0 -0
  123. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md013_line_length.rs +0 -0
  124. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md014_commands_show_output.rs +0 -0
  125. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md019_no_multiple_space_atx.rs +0 -0
  126. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md020_no_missing_space_closed_atx.rs +0 -0
  127. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md021_no_multiple_space_closed_atx.rs +0 -0
  128. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md022_blanks_around_headings.rs +0 -0
  129. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md023_heading_start_left.rs +0 -0
  130. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md024_no_duplicate_heading.rs +0 -0
  131. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md025_single_title.rs +0 -0
  132. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md026_no_trailing_punctuation.rs +0 -0
  133. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md028_no_blanks_blockquote.rs +0 -0
  134. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md029_ordered_list_prefix.rs +0 -0
  135. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md030_list_marker_space.rs +0 -0
  136. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md031_blanks_around_fences.rs +0 -0
  137. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md033_no_inline_html.rs +0 -0
  138. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md034_no_bare_urls.rs +0 -0
  139. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md035_hr_style.rs +0 -0
  140. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md036_no_emphasis_only_first.rs +0 -0
  141. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md037_spaces_around_emphasis.rs +0 -0
  142. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md038_no_space_in_code.rs +0 -0
  143. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md039_no_space_in_links.rs +0 -0
  144. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md040_fenced_code_language.rs +0 -0
  145. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md041_first_line_heading.rs +0 -0
  146. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md043_required_headings.rs +0 -0
  147. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md044_proper_names.rs +0 -0
  148. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md045_no_alt_text.rs +0 -0
  149. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md046_code_block_style.rs +0 -0
  150. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md047_single_trailing_newline.rs +0 -0
  151. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md048_code_fence_style.rs +0 -0
  152. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md049_emphasis_style.rs +0 -0
  153. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md050_strong_style.rs +0 -0
  154. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md052_reference_links_images.rs +0 -0
  155. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md053_link_image_reference_definitions.rs +0 -0
  156. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md054_link_image_style.rs +0 -0
  157. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md055_table_pipe_style.rs +0 -0
  158. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md056_table_column_count.rs +0 -0
  159. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md057_existing_relative_links.rs +0 -0
  160. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/md058_blanks_around_tables.rs +0 -0
  161. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/mod.rs +0 -0
  162. {rumdl-0.0.73 → rumdl-0.0.75}/src/rules/strong_style.rs +0 -0
  163. {rumdl-0.0.73 → rumdl-0.0.75}/src/utils/ast_utils.rs +0 -0
  164. {rumdl-0.0.73 → rumdl-0.0.75}/src/utils/code_block_utils.rs +0 -0
  165. {rumdl-0.0.73 → rumdl-0.0.75}/src/utils/early_returns.rs +0 -0
  166. {rumdl-0.0.73 → rumdl-0.0.75}/src/utils/element_cache.rs +0 -0
  167. {rumdl-0.0.73 → rumdl-0.0.75}/src/utils/markdown_elements.rs +0 -0
  168. {rumdl-0.0.73 → rumdl-0.0.75}/src/utils/mod.rs +0 -0
  169. {rumdl-0.0.73 → rumdl-0.0.75}/src/utils/range_utils.rs +0 -0
  170. {rumdl-0.0.73 → rumdl-0.0.75}/src/utils/regex_cache.rs +0 -0
  171. {rumdl-0.0.73 → rumdl-0.0.75}/src/utils/string_interner.rs +0 -0
  172. {rumdl-0.0.73 → rumdl-0.0.75}/src/utils/table_utils.rs +0 -0
  173. {rumdl-0.0.73 → rumdl-0.0.75}/tests/advanced_integration_tests.rs +0 -0
  174. {rumdl-0.0.73 → rumdl-0.0.75}/tests/character_ranges/additional_tests.rs +0 -0
  175. {rumdl-0.0.73 → rumdl-0.0.75}/tests/character_ranges/basic_tests.rs +0 -0
  176. {rumdl-0.0.73 → rumdl-0.0.75}/tests/character_ranges/comprehensive_tests.rs +0 -0
  177. {rumdl-0.0.73 → rumdl-0.0.75}/tests/character_ranges/extended_tests.rs +0 -0
  178. {rumdl-0.0.73 → rumdl-0.0.75}/tests/character_ranges/mod.rs +0 -0
  179. {rumdl-0.0.73 → rumdl-0.0.75}/tests/character_ranges/unicode_utils.rs +0 -0
  180. {rumdl-0.0.73 → rumdl-0.0.75}/tests/cli_duplication_test.rs +0 -0
  181. {rumdl-0.0.73 → rumdl-0.0.75}/tests/cli_integration_tests.rs +0 -0
  182. {rumdl-0.0.73 → rumdl-0.0.75}/tests/commonmark_compliance_tests.rs +0 -0
  183. {rumdl-0.0.73 → rumdl-0.0.75}/tests/comprehensive_integration_tests.rs +0 -0
  184. {rumdl-0.0.73 → rumdl-0.0.75}/tests/config_application_tests.rs +0 -0
  185. {rumdl-0.0.73 → rumdl-0.0.75}/tests/config_tests.rs +0 -0
  186. {rumdl-0.0.73 → rumdl-0.0.75}/tests/init_command_test.rs +0 -0
  187. {rumdl-0.0.73 → rumdl-0.0.75}/tests/init_tests.rs +0 -0
  188. {rumdl-0.0.73 → rumdl-0.0.75}/tests/integration_tests.rs +0 -0
  189. {rumdl-0.0.73 → rumdl-0.0.75}/tests/json_output_test.rs +0 -0
  190. {rumdl-0.0.73 → rumdl-0.0.75}/tests/lib.rs +0 -0
  191. {rumdl-0.0.73 → rumdl-0.0.75}/tests/lsp_integration_tests.rs +0 -0
  192. {rumdl-0.0.73 → rumdl-0.0.75}/tests/lsp_tests.rs +0 -0
  193. {rumdl-0.0.73 → rumdl-0.0.75}/tests/markdownlint_cli_integration.rs +0 -0
  194. {rumdl-0.0.73 → rumdl-0.0.75}/tests/markdownlint_config_test.rs +0 -0
  195. {rumdl-0.0.73 → rumdl-0.0.75}/tests/md030_edge_cases.md +0 -0
  196. {rumdl-0.0.73 → rumdl-0.0.75}/tests/output_format_tests.rs +0 -0
  197. {rumdl-0.0.73 → rumdl-0.0.75}/tests/perf_check.rs +0 -0
  198. {rumdl-0.0.73 → rumdl-0.0.75}/tests/pyproject_config_tests.rs +0 -0
  199. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md001_test.rs +0 -0
  200. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md001_unicode_test.rs +0 -0
  201. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md002_test.rs +0 -0
  202. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md003_test.rs +0 -0
  203. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md004_test.rs +0 -0
  204. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md005_test.rs +0 -0
  205. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md006_test.rs +0 -0
  206. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md006_unicode_test.rs +0 -0
  207. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md007_test.rs +0 -0
  208. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md009_test.rs +0 -0
  209. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md010_test.rs +0 -0
  210. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md011_test.rs +0 -0
  211. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md012_test.rs +0 -0
  212. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md013_test.rs +0 -0
  213. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md014_test.rs +0 -0
  214. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md018_test.rs +0 -0
  215. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md019_test.rs +0 -0
  216. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md020_test.rs +0 -0
  217. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md021_test.rs +0 -0
  218. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md022_test.rs +0 -0
  219. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md023_extended_test.rs +0 -0
  220. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md023_test.rs +0 -0
  221. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md024_test.rs +0 -0
  222. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md025_test.rs +0 -0
  223. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md026_test.rs +0 -0
  224. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md027_test.rs +0 -0
  225. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md028_test.rs +0 -0
  226. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md029_test.rs +0 -0
  227. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md030_test.rs +0 -0
  228. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md031_test.rs +0 -0
  229. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md032_test.rs +0 -0
  230. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md033_extended_test.rs +0 -0
  231. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md034_test.rs +0 -0
  232. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md035_test.rs +0 -0
  233. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md036_test.rs +0 -0
  234. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md037_test.rs +0 -0
  235. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md038_test.rs +0 -0
  236. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md039_test.rs +0 -0
  237. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md040_test.rs +0 -0
  238. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md041_test.rs +0 -0
  239. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md043_test.rs +0 -0
  240. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md044_test.rs +0 -0
  241. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md045_test.rs +0 -0
  242. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md046_test.rs +0 -0
  243. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md047_test.rs +0 -0
  244. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md048_test.rs +0 -0
  245. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md049_test.rs +0 -0
  246. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md050_test.rs +0 -0
  247. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md052_test.rs +0 -0
  248. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md053_additional_test.rs +0 -0
  249. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md053_proptest.rs +0 -0
  250. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md053_test.rs +0 -0
  251. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md054_test.rs +0 -0
  252. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md054_unicode_test.rs +0 -0
  253. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md055_test.rs +0 -0
  254. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md056_test.rs +0 -0
  255. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md057_test.rs +0 -0
  256. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/md058_test.rs +0 -0
  257. {rumdl-0.0.73 → rumdl-0.0.75}/tests/rules/mod.rs +0 -0
  258. {rumdl-0.0.73 → rumdl-0.0.75}/tests/utils/blockquote_utils_test.rs +0 -0
  259. {rumdl-0.0.73 → rumdl-0.0.75}/tests/utils/code_block_utils_extended_test.rs +0 -0
  260. {rumdl-0.0.73 → rumdl-0.0.75}/tests/utils/code_block_utils_test.rs +0 -0
  261. {rumdl-0.0.73 → rumdl-0.0.75}/tests/utils/core_utils_test.rs +0 -0
  262. {rumdl-0.0.73 → rumdl-0.0.75}/tests/utils/front_matter_utils_test.rs +0 -0
  263. {rumdl-0.0.73 → rumdl-0.0.75}/tests/utils/line_index_test.rs +0 -0
  264. {rumdl-0.0.73 → rumdl-0.0.75}/tests/utils/mod.rs +0 -0
  265. {rumdl-0.0.73 → rumdl-0.0.75}/tests/utils_markdown_edge_cases.rs +0 -0
  266. {rumdl-0.0.73 → rumdl-0.0.75}/tests/utils_tests.rs +0 -0
@@ -1789,7 +1789,7 @@ dependencies = [
1789
1789
 
1790
1790
  [[package]]
1791
1791
  name = "rumdl"
1792
- version = "0.0.73"
1792
+ version = "0.0.75"
1793
1793
  dependencies = [
1794
1794
  "anyhow",
1795
1795
  "assert_cmd",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "rumdl"
3
- version = "0.0.73"
3
+ version = "0.0.75"
4
4
  edition = "2021"
5
5
  description = "A fast Markdown linter written in Rust (Ru(st) MarkDown Linter)"
6
6
  authors = ["Ruben J. Jongejan <ruben.jongejan@gmail.com>"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rumdl
3
- Version: 0.0.73
3
+ Version: 0.0.75
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -0,0 +1,447 @@
1
+ /// Rule MD011: No reversed link syntax
2
+ ///
3
+ /// See [docs/md011.md](../../docs/md011.md) for full documentation, configuration, and examples.
4
+ use crate::rule::{Fix, LintError, LintResult, LintWarning, Rule, Severity};
5
+ use crate::utils::range_utils::calculate_match_range;
6
+ use lazy_static::lazy_static;
7
+ use regex::Regex;
8
+
9
+ lazy_static! {
10
+ static ref REVERSED_LINK_REGEX: Regex =
11
+ Regex::new(r"\[([^\]]+)\]\(([^)]+)\)|(\([^)]+\))\[([^\]]+)\]").unwrap();
12
+ static ref REVERSED_LINK_CHECK_REGEX: Regex = Regex::new(r"\(([^)]+)\)\[([^\]]+)\]").unwrap();
13
+ static ref CODE_FENCE_REGEX: Regex = Regex::new(r"^(\s*)(```|~~~)").unwrap();
14
+
15
+ // New patterns for detecting malformed link attempts where user intent is clear
16
+ static ref MALFORMED_LINK_PATTERNS: Vec<(Regex, &'static str)> = vec![
17
+ // Missing closing bracket: (URL)[text or [text](URL
18
+ (Regex::new(r"\(([^)]+)\)\[([^\]]*$)").unwrap(), "missing closing bracket"),
19
+ (Regex::new(r"\[([^\]]+)\]\(([^)]*$)").unwrap(), "missing closing parenthesis"),
20
+
21
+ // Wrong bracket types: {URL}[text] or [text]{URL}
22
+ (Regex::new(r"\{([^}]+)\}\[([^\]]+)\]").unwrap(), "wrong bracket type (curly instead of parentheses)"),
23
+ (Regex::new(r"\[([^\]]+)\]\{([^}]+)\}").unwrap(), "wrong bracket type (curly instead of parentheses)"),
24
+
25
+ // URL and text swapped in correct syntax: [URL](text) where URL is clearly a URL
26
+ (Regex::new(r"\[(https?://[^\]]+)\]\(([^)]+)\)").unwrap(), "URL and text appear to be swapped"),
27
+ (Regex::new(r"\[(www\.[^\]]+)\]\(([^)]+)\)").unwrap(), "URL and text appear to be swapped"),
28
+ (Regex::new(r"\[([^\]]*\.[a-z]{2,4}[^\]]*)\]\(([^)]+)\)").unwrap(), "URL and text appear to be swapped"),
29
+ ];
30
+ }
31
+
32
+ #[derive(Clone)]
33
+ pub struct MD011NoReversedLinks;
34
+
35
+ impl MD011NoReversedLinks {
36
+ fn find_reversed_links(content: &str) -> Vec<(usize, usize, String, String)> {
37
+ let mut results = Vec::new();
38
+ let mut line_start = 0;
39
+ let mut current_line = 1;
40
+
41
+ for line in content.lines() {
42
+ for cap in REVERSED_LINK_REGEX.captures_iter(line) {
43
+ if cap.get(3).is_some() {
44
+ // Found reversed link syntax (text)[url]
45
+ let text = cap[3].trim_matches('(').trim_matches(')');
46
+ let url = &cap[4];
47
+ let start = line_start + cap.get(0).unwrap().start();
48
+ results.push((
49
+ current_line,
50
+ start - line_start + 1,
51
+ text.to_string(),
52
+ url.to_string(),
53
+ ));
54
+ }
55
+ }
56
+ line_start += line.len() + 1; // +1 for newline
57
+ current_line += 1;
58
+ }
59
+
60
+ results
61
+ }
62
+
63
+ /// Detect malformed link attempts where user intent is clear
64
+ fn detect_malformed_link_attempts(&self, line: &str) -> Vec<(usize, usize, String, String)> {
65
+ let mut results = Vec::new();
66
+ let mut processed_ranges = Vec::new(); // Track processed character ranges to avoid duplicates
67
+
68
+ for (pattern, issue_type) in MALFORMED_LINK_PATTERNS.iter() {
69
+ for cap in pattern.captures_iter(line) {
70
+ let match_obj = cap.get(0).unwrap();
71
+ let start = match_obj.start();
72
+ let len = match_obj.len();
73
+ let end = start + len;
74
+
75
+ // Skip if this range overlaps with already processed ranges
76
+ if processed_ranges.iter().any(|(proc_start, proc_end)|
77
+ (start < *proc_end && end > *proc_start)
78
+ ) {
79
+ continue;
80
+ }
81
+
82
+ // Extract potential URL and text based on the pattern
83
+ if let Some((url, text)) = self.extract_url_and_text_from_match(&cap, issue_type) {
84
+ // Only proceed if this looks like a genuine link attempt
85
+ if self.looks_like_link_attempt(&url, &text) {
86
+ results.push((start, len, url, text));
87
+ processed_ranges.push((start, end));
88
+ }
89
+ }
90
+ }
91
+ }
92
+
93
+ results
94
+ }
95
+
96
+ /// Extract URL and text from regex match based on the issue type
97
+ fn extract_url_and_text_from_match(&self, cap: &regex::Captures, issue_type: &str) -> Option<(String, String)> {
98
+ match issue_type {
99
+ "missing closing bracket" => {
100
+ // (URL)[text -> cap[1] = URL, cap[2] = incomplete text
101
+ Some((cap[1].to_string(), format!("{}]", &cap[2])))
102
+ },
103
+ "missing closing parenthesis" => {
104
+ // [text](URL -> cap[1] = text, cap[2] = incomplete URL
105
+ Some((format!("{})", &cap[2]), cap[1].to_string()))
106
+ },
107
+ "wrong bracket type (curly instead of parentheses)" => {
108
+ // {URL}[text] or [text]{URL} -> cap[1] and cap[2]
109
+ if cap.get(0).unwrap().as_str().starts_with('{') {
110
+ // {URL}[text] -> swap and fix brackets
111
+ Some((cap[1].to_string(), cap[2].to_string()))
112
+ } else {
113
+ // [text]{URL} -> already in correct order, fix brackets
114
+ Some((cap[2].to_string(), cap[1].to_string()))
115
+ }
116
+ },
117
+ "URL and text appear to be swapped" => {
118
+ // [URL](text) -> cap[1] = URL, cap[2] = text, need to swap
119
+ Some((cap[1].to_string(), cap[2].to_string()))
120
+ },
121
+ _ => None,
122
+ }
123
+ }
124
+
125
+ /// Check if the extracted URL and text look like a genuine link attempt
126
+ fn looks_like_link_attempt(&self, url: &str, text: &str) -> bool {
127
+ // URL should look like a URL
128
+ let url_indicators = [
129
+ "http://", "https://", "www.", "ftp://",
130
+ ".com", ".org", ".net", ".edu", ".gov", ".io", ".co"
131
+ ];
132
+
133
+ let has_url_indicator = url_indicators.iter().any(|indicator|
134
+ url.to_lowercase().contains(indicator)
135
+ );
136
+
137
+ // Text should be reasonable length and not look like a URL
138
+ let text_looks_reasonable = text.len() >= 3 && text.len() <= 50
139
+ && !url_indicators.iter().any(|indicator|
140
+ text.to_lowercase().contains(indicator)
141
+ )
142
+ && !text.to_lowercase().starts_with("http")
143
+ && text.chars().any(|c| c.is_alphabetic()); // Must contain at least one letter
144
+
145
+ // URL should not be too short or contain only non-URL characters
146
+ let url_looks_reasonable = url.len() >= 4
147
+ && (has_url_indicator || url.contains('.'))
148
+ && !url.chars().all(|c| c.is_alphabetic()); // Shouldn't be just letters
149
+
150
+ // Both URL and text should look reasonable for this to be a link attempt
151
+ has_url_indicator && text_looks_reasonable && url_looks_reasonable
152
+ }
153
+
154
+ fn is_in_code_block(&self, content: &str, position: usize) -> bool {
155
+ let mut in_code_block = false;
156
+ let mut current_pos = 0;
157
+
158
+ for line in content.lines() {
159
+ if CODE_FENCE_REGEX.is_match(line) {
160
+ in_code_block = !in_code_block;
161
+ }
162
+ current_pos += line.len() + 1;
163
+ if current_pos > position {
164
+ break;
165
+ }
166
+ }
167
+
168
+ in_code_block
169
+ }
170
+ }
171
+
172
+ impl Rule for MD011NoReversedLinks {
173
+ fn name(&self) -> &'static str {
174
+ "MD011"
175
+ }
176
+
177
+ fn description(&self) -> &'static str {
178
+ "Link syntax should not be reversed"
179
+ }
180
+
181
+ fn check(&self, ctx: &crate::lint_context::LintContext) -> LintResult {
182
+ let content = ctx.content;
183
+ let mut warnings = Vec::new();
184
+
185
+ for (line_num, line) in content.lines().enumerate() {
186
+ // Part 1: Check for existing perfectly formed reversed links
187
+ for cap in REVERSED_LINK_CHECK_REGEX.captures_iter(line) {
188
+ let match_obj = cap.get(0).unwrap();
189
+
190
+ // Calculate precise character range for the reversed syntax
191
+ let (start_line, start_col, end_line, end_col) =
192
+ calculate_match_range(line_num + 1, line, match_obj.start(), match_obj.len());
193
+
194
+ warnings.push(LintWarning {
195
+ rule_name: Some(self.name()),
196
+ message: "Reversed link syntax".to_string(),
197
+ line: start_line,
198
+ column: start_col,
199
+ end_line,
200
+ end_column: end_col,
201
+ severity: Severity::Warning,
202
+ fix: Some(Fix {
203
+ range: (0..0), // TODO: Replace with correct byte range if available
204
+ replacement: format!("[{}]({})", &cap[2], &cap[1]),
205
+ }),
206
+ });
207
+ }
208
+
209
+ // Part 2: Check for malformed link attempts where user intent is clear
210
+ let malformed_attempts = self.detect_malformed_link_attempts(line);
211
+ for (start, len, url, text) in malformed_attempts {
212
+ // Calculate precise character range for the malformed syntax
213
+ let (start_line, start_col, end_line, end_col) =
214
+ calculate_match_range(line_num + 1, line, start, len);
215
+
216
+ warnings.push(LintWarning {
217
+ rule_name: Some(self.name()),
218
+ message: "Malformed link syntax".to_string(),
219
+ line: start_line,
220
+ column: start_col,
221
+ end_line,
222
+ end_column: end_col,
223
+ severity: Severity::Warning,
224
+ fix: Some(Fix {
225
+ range: (0..0), // TODO: Replace with correct byte range if available
226
+ replacement: format!("[{}]({})", text, url),
227
+ }),
228
+ });
229
+ }
230
+ }
231
+
232
+ Ok(warnings)
233
+ }
234
+
235
+ fn fix(&self, ctx: &crate::lint_context::LintContext) -> Result<String, LintError> {
236
+ let content = ctx.content;
237
+ let mut result = content.to_string();
238
+ let mut offset: usize = 0;
239
+
240
+ for (line_num, column, text, url) in Self::find_reversed_links(content) {
241
+ // Calculate absolute position in original content
242
+ let mut pos = 0;
243
+ for (i, line) in content.lines().enumerate() {
244
+ if i + 1 == line_num {
245
+ pos += column - 1;
246
+ break;
247
+ }
248
+ pos += line.len() + 1;
249
+ }
250
+
251
+ if !self.is_in_code_block(content, pos) {
252
+ let adjusted_pos = pos + offset;
253
+ let original_len = format!("({})[{}]", url, text).len();
254
+ let replacement = format!("[{}]({})", text, url);
255
+ result.replace_range(adjusted_pos..adjusted_pos + original_len, &replacement);
256
+ // Update offset based on the difference in lengths
257
+ if replacement.len() > original_len {
258
+ offset += replacement.len() - original_len;
259
+ } else {
260
+ offset = offset.saturating_sub(original_len - replacement.len());
261
+ }
262
+ }
263
+ }
264
+
265
+ Ok(result)
266
+ }
267
+
268
+ fn as_any(&self) -> &dyn std::any::Any {
269
+ self
270
+ }
271
+
272
+ fn from_config(_config: &crate::config::Config) -> Box<dyn Rule>
273
+ where
274
+ Self: Sized,
275
+ {
276
+ Box::new(MD011NoReversedLinks)
277
+ }
278
+ }
279
+
280
+ #[cfg(test)]
281
+ mod tests {
282
+ use super::*;
283
+ use crate::lint_context::LintContext;
284
+
285
+ #[test]
286
+ fn test_capture_group_order_fix() {
287
+ // This test confirms that the capture group order bug is fixed
288
+ // The regex pattern \(([^)]+)\)\[([^\]]+)\] captures:
289
+ // cap[1] = URL (inside parentheses)
290
+ // cap[2] = text (inside brackets)
291
+ // So (URL)[text] should become [text](URL)
292
+
293
+ let rule = MD011NoReversedLinks;
294
+
295
+ // Test with reversed link syntax
296
+ let content = "Check out (https://example.com)[this link] for more info.";
297
+ let ctx = LintContext::new(content);
298
+
299
+ // This should detect the reversed syntax
300
+ let result = rule.check(&ctx).unwrap();
301
+ assert_eq!(result.len(), 1);
302
+ assert!(result[0].message.contains("Reversed link syntax"));
303
+
304
+ // Verify the fix produces correct output
305
+ let fix = result[0].fix.as_ref().unwrap();
306
+ assert_eq!(fix.replacement, "[this link](https://example.com)");
307
+ }
308
+
309
+ #[test]
310
+ fn test_multiple_reversed_links() {
311
+ // Test multiple reversed links in the same content
312
+ let rule = MD011NoReversedLinks;
313
+
314
+ let content = "Visit (https://example.com)[Example] and (https://test.com)[Test Site].";
315
+ let ctx = LintContext::new(content);
316
+
317
+ let result = rule.check(&ctx).unwrap();
318
+ assert_eq!(result.len(), 2);
319
+
320
+ // Verify both fixes are correct
321
+ assert_eq!(result[0].fix.as_ref().unwrap().replacement, "[Example](https://example.com)");
322
+ assert_eq!(result[1].fix.as_ref().unwrap().replacement, "[Test Site](https://test.com)");
323
+ }
324
+
325
+ #[test]
326
+ fn test_normal_links_not_flagged() {
327
+ // Test that normal link syntax is not flagged
328
+ let rule = MD011NoReversedLinks;
329
+
330
+ let content = "This is a normal [link](https://example.com) and another [link](https://test.com).";
331
+ let ctx = LintContext::new(content);
332
+
333
+ let result = rule.check(&ctx).unwrap();
334
+ assert_eq!(result.len(), 0);
335
+ }
336
+
337
+ #[test]
338
+ fn debug_capture_groups() {
339
+ // Debug test to understand capture group behavior
340
+ let pattern = r"\(([^)]+)\)\[([^\]]+)\]";
341
+ let regex = Regex::new(pattern).unwrap();
342
+
343
+ let test_text = "(https://example.com)[Click here]";
344
+
345
+ if let Some(cap) = regex.captures(test_text) {
346
+ println!("Full match: {}", &cap[0]);
347
+ println!("cap[1] (first group): {}", &cap[1]);
348
+ println!("cap[2] (second group): {}", &cap[2]);
349
+
350
+ // Current fix format
351
+ let current_fix = format!("[{}]({})", &cap[2], &cap[1]);
352
+ println!("Current fix produces: {}", current_fix);
353
+
354
+ // Test what the actual rule produces
355
+ let rule = MD011NoReversedLinks;
356
+ let ctx = LintContext::new(test_text);
357
+ let result = rule.check(&ctx).unwrap();
358
+ if !result.is_empty() {
359
+ println!("Rule fix produces: {}", result[0].fix.as_ref().unwrap().replacement);
360
+ }
361
+ }
362
+ }
363
+
364
+ #[test]
365
+ fn test_malformed_link_detection() {
366
+ let rule = MD011NoReversedLinks;
367
+
368
+ // Test wrong bracket types
369
+ let content = "Check out {https://example.com}[this website].";
370
+ let ctx = LintContext::new(content);
371
+ let result = rule.check(&ctx).unwrap();
372
+ assert_eq!(result.len(), 1);
373
+ assert!(result[0].message.contains("Malformed link syntax"));
374
+
375
+ // Test URL and text swapped
376
+ let content = "Visit [https://example.com](Click Here).";
377
+ let ctx = LintContext::new(content);
378
+ let result = rule.check(&ctx).unwrap();
379
+ assert_eq!(result.len(), 1);
380
+ assert!(result[0].message.contains("Malformed link syntax"));
381
+
382
+ // Test that valid links are not flagged
383
+ let content = "This is a [normal link](https://example.com).";
384
+ let ctx = LintContext::new(content);
385
+ let result = rule.check(&ctx).unwrap();
386
+ assert_eq!(result.len(), 0);
387
+
388
+ // Test that non-links are not flagged
389
+ let content = "Regular text with [brackets] and (parentheses).";
390
+ let ctx = LintContext::new(content);
391
+ let result = rule.check(&ctx).unwrap();
392
+ assert_eq!(result.len(), 0);
393
+
394
+ // Test that risky patterns are NOT flagged (conservative approach)
395
+ let content = "(example.com)is a test domain.";
396
+ let ctx = LintContext::new(content);
397
+ let result = rule.check(&ctx).unwrap();
398
+ assert_eq!(result.len(), 0);
399
+
400
+ let content = "(optional)parameter should not be flagged.";
401
+ let ctx = LintContext::new(content);
402
+ let result = rule.check(&ctx).unwrap();
403
+ assert_eq!(result.len(), 0);
404
+ }
405
+
406
+ #[test]
407
+ fn test_malformed_link_fixes() {
408
+ let rule = MD011NoReversedLinks;
409
+
410
+ // Test wrong bracket types fix
411
+ let content = "Check out {https://example.com}[this website].";
412
+ let ctx = LintContext::new(content);
413
+ let result = rule.check(&ctx).unwrap();
414
+ assert_eq!(result.len(), 1);
415
+ let fix = result[0].fix.as_ref().unwrap();
416
+ assert_eq!(fix.replacement, "[this website](https://example.com)");
417
+
418
+ // Test URL and text swapped fix
419
+ let content = "Visit [https://example.com](Click Here).";
420
+ let ctx = LintContext::new(content);
421
+ let result = rule.check(&ctx).unwrap();
422
+ assert_eq!(result.len(), 1);
423
+ let fix = result[0].fix.as_ref().unwrap();
424
+ assert_eq!(fix.replacement, "[Click Here](https://example.com)");
425
+ }
426
+
427
+ #[test]
428
+ fn test_conservative_detection() {
429
+ let rule = MD011NoReversedLinks;
430
+
431
+ // Test that edge cases are not flagged
432
+ let content = "This (not-a-url)text should be ignored.";
433
+ let ctx = LintContext::new(content);
434
+ let result = rule.check(&ctx).unwrap();
435
+ assert_eq!(result.len(), 0);
436
+
437
+ let content = "Also [regular text](not a url) should be ignored.";
438
+ let ctx = LintContext::new(content);
439
+ let result = rule.check(&ctx).unwrap();
440
+ assert_eq!(result.len(), 0);
441
+
442
+ let content = "And {not-url}[not-text] should be ignored.";
443
+ let ctx = LintContext::new(content);
444
+ let result = rule.check(&ctx).unwrap();
445
+ assert_eq!(result.len(), 0);
446
+ }
447
+ }