rumdl 0.0.72__tar.gz → 0.0.73__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.
- {rumdl-0.0.72 → rumdl-0.0.73}/Cargo.lock +1 -1
- {rumdl-0.0.72 → rumdl-0.0.73}/Cargo.toml +1 -1
- {rumdl-0.0.72 → rumdl-0.0.73}/PKG-INFO +1 -1
- {rumdl-0.0.72 → rumdl-0.0.73}/src/main.rs +7 -10
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md006_start_bullets.rs +19 -8
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md034_no_bare_urls.rs +81 -92
- rumdl-0.0.73/tests/rules/md006_test.rs +243 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md034_test.rs +69 -2
- rumdl-0.0.72/tests/rules/md006_test.rs +0 -143
- {rumdl-0.0.72 → rumdl-0.0.73}/.rumdl.toml +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/MANIFEST.in +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/Makefile +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/README.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/assets/logo.png +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/benches/fix_performance.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/benches/range_performance.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/benches/range_utils_benchmark.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/benches/rule_performance.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/benches/simple_fix_bench.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/RULES.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md001.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md002.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md003.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md004.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md005.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md006.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md007.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md009.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md010.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md011.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md012.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md013.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md014.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md018.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md019.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md020.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md021.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md022.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md023.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md024.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md025.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md026.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md027.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md028.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md029.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md030.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md031.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md032.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md033.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md034.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md035.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md036.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md037.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md038.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md039.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md040.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md041.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md042.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md043.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md044.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md045.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md046.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md047.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md048.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md049.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md050.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md051.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md052.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md053.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md054.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md055.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md056.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md057.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/docs/md058.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/issues/plan-rule-parity-with-markdownlint.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/parity_check.py +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/pyproject.toml +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/python/MANIFEST.in +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/python/PYTHON-README.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/python/rumdl/__init__.py +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/python/rumdl/__main__.py +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/python/rumdl/py.typed +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/rumdl.toml.example +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/config.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/init.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/lib.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/lint_context.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/lsp/mod.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/lsp/server.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/lsp/types.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/markdownlint_config.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/parallel.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/performance.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/profiling.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/python.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rule.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/blockquote_utils.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/code_block_utils.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/code_fence_utils.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/emphasis_style.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/front_matter_utils.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/heading_utils.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/list_utils.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md001_heading_increment.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md002_first_heading_h1.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md003_heading_style.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md004_unordered_list_style.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md005_list_indent.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md007_ul_indent.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md009_trailing_spaces.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md010_no_hard_tabs.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md011_no_reversed_links.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md012_no_multiple_blanks.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md013_line_length.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md014_commands_show_output.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md018_no_missing_space_atx.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md019_no_multiple_space_atx.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md020_no_missing_space_closed_atx.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md021_no_multiple_space_closed_atx.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md022_blanks_around_headings.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md023_heading_start_left.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md024_no_duplicate_heading.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md025_single_title.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md026_no_trailing_punctuation.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md027_multiple_spaces_blockquote.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md028_no_blanks_blockquote.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md029_ordered_list_prefix.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md030_list_marker_space.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md031_blanks_around_fences.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md032_blanks_around_lists.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md033_no_inline_html.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md035_hr_style.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md036_no_emphasis_only_first.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md037_spaces_around_emphasis.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md038_no_space_in_code.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md039_no_space_in_links.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md040_fenced_code_language.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md041_first_line_heading.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md042_no_empty_links.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md043_required_headings.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md044_proper_names.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md045_no_alt_text.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md046_code_block_style.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md047_single_trailing_newline.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md048_code_fence_style.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md049_emphasis_style.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md050_strong_style.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md051_link_fragments.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md052_reference_links_images.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md053_link_image_reference_definitions.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md054_link_image_style.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md055_table_pipe_style.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md056_table_column_count.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md057_existing_relative_links.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/md058_blanks_around_tables.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/mod.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/rules/strong_style.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/utils/ast_utils.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/utils/code_block_utils.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/utils/document_structure.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/utils/early_returns.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/utils/element_cache.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/utils/markdown_elements.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/utils/mod.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/utils/range_utils.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/utils/regex_cache.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/utils/string_interner.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/src/utils/table_utils.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/advanced_integration_tests.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/character_ranges/additional_tests.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/character_ranges/basic_tests.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/character_ranges/comprehensive_tests.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/character_ranges/extended_tests.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/character_ranges/mod.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/character_ranges/unicode_utils.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/cli_duplication_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/cli_integration_tests.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/commonmark_compliance_tests.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/comprehensive_integration_tests.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/config_application_tests.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/config_tests.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/init_command_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/init_tests.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/integration_tests.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/json_output_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/lib.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/lsp_integration_tests.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/lsp_tests.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/markdownlint_cli_integration.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/markdownlint_config_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/md030_edge_cases.md +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/output_format_tests.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/perf_check.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/pyproject_config_tests.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md001_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md001_unicode_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md002_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md003_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md004_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md005_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md006_unicode_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md007_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md009_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md010_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md011_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md012_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md013_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md014_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md018_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md019_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md020_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md021_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md022_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md023_extended_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md023_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md024_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md025_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md026_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md027_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md028_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md029_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md030_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md031_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md032_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md033_extended_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md033_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md035_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md036_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md037_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md038_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md039_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md040_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md041_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md042_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md043_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md044_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md045_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md046_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md047_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md048_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md049_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md050_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md051_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md052_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md053_additional_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md053_proptest.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md053_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md054_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md054_unicode_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md055_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md056_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md057_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/md058_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/rules/mod.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/utils/blockquote_utils_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/utils/code_block_utils_extended_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/utils/code_block_utils_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/utils/core_utils_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/utils/front_matter_utils_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/utils/line_index_test.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/utils/mod.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/utils_markdown_edge_cases.rs +0 -0
- {rumdl-0.0.72 → rumdl-0.0.73}/tests/utils_tests.rs +0 -0
|
@@ -1297,16 +1297,13 @@ fn process_stdin(rules: &[Box<dyn Rule>], args: &CheckArgs) {
|
|
|
1297
1297
|
let has_issues = !all_warnings.is_empty();
|
|
1298
1298
|
if has_issues {
|
|
1299
1299
|
for warning in &all_warnings {
|
|
1300
|
+
let rule_name = warning.rule_name.unwrap_or("unknown");
|
|
1300
1301
|
println!(
|
|
1301
|
-
"<stdin>:{}:{}: {}
|
|
1302
|
-
warning.line,
|
|
1303
|
-
warning.column,
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
rumdl::rule::Severity::Warning => "warning".yellow(),
|
|
1307
|
-
},
|
|
1308
|
-
warning.message,
|
|
1309
|
-
warning.rule_name.unwrap_or("unknown")
|
|
1302
|
+
"<stdin>:{}:{}: {} {}",
|
|
1303
|
+
warning.line.to_string().cyan(),
|
|
1304
|
+
warning.column.to_string().cyan(),
|
|
1305
|
+
format!("[{:5}]", rule_name).yellow(), // Align rule names consistently
|
|
1306
|
+
warning.message
|
|
1310
1307
|
);
|
|
1311
1308
|
}
|
|
1312
1309
|
}
|
|
@@ -1611,7 +1608,7 @@ fn process_file(
|
|
|
1611
1608
|
file_path.blue().underline(),
|
|
1612
1609
|
warning.line.to_string().cyan(),
|
|
1613
1610
|
warning.column.to_string().cyan(),
|
|
1614
|
-
format!("[{}]", rule_name).yellow(),
|
|
1611
|
+
format!("[{:5}]", rule_name).yellow(), // Pad rule name to 5 characters for alignment
|
|
1615
1612
|
warning.message,
|
|
1616
1613
|
fix_indicator.green()
|
|
1617
1614
|
);
|
|
@@ -66,9 +66,15 @@ impl MD006StartBullets {
|
|
|
66
66
|
if Self::is_bullet_list_item(lines[check_idx]).is_none() {
|
|
67
67
|
// Found non-list content - check if it breaks the list structure
|
|
68
68
|
let content_indent = lines[check_idx].len() - lines[check_idx].trim_start().len();
|
|
69
|
-
|
|
70
|
-
//
|
|
71
|
-
|
|
69
|
+
|
|
70
|
+
// Content is acceptable if:
|
|
71
|
+
// 1. It's indented at least as much as the current item (continuation of parent)
|
|
72
|
+
// 2. OR it's indented more than the previous bullet (continuation of previous item)
|
|
73
|
+
// 3. AND we have a true parent relationship (prev_indent < current_indent)
|
|
74
|
+
let is_continuation = content_indent >= prev_indent.max(2); // At least 2 spaces for continuation
|
|
75
|
+
let is_valid_nesting = prev_indent < current_indent;
|
|
76
|
+
|
|
77
|
+
if !is_continuation || !is_valid_nesting {
|
|
72
78
|
has_breaking_content = true;
|
|
73
79
|
break;
|
|
74
80
|
}
|
|
@@ -78,13 +84,19 @@ impl MD006StartBullets {
|
|
|
78
84
|
if !has_breaking_content {
|
|
79
85
|
return Some((i, prev_indent));
|
|
80
86
|
} else {
|
|
81
|
-
// Content breaks the list structure
|
|
82
|
-
|
|
87
|
+
// Content breaks the list structure, but continue searching for an earlier valid parent
|
|
88
|
+
continue;
|
|
83
89
|
}
|
|
84
90
|
}
|
|
85
91
|
// If prev_indent > current_indent, it's a child of a sibling, ignore it and keep searching.
|
|
86
92
|
} else {
|
|
87
|
-
// Found non-list content -
|
|
93
|
+
// Found non-list content - check if it's a continuation line
|
|
94
|
+
let content_indent = lines[i].len() - lines[i].trim_start().len();
|
|
95
|
+
// If it's indented enough to be a continuation, don't break the search
|
|
96
|
+
if content_indent >= 2 {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
// Otherwise, this breaks the search
|
|
88
100
|
return None;
|
|
89
101
|
}
|
|
90
102
|
}
|
|
@@ -247,8 +259,7 @@ impl Rule for MD006StartBullets {
|
|
|
247
259
|
column: start_col,
|
|
248
260
|
end_line: line_num,
|
|
249
261
|
end_column: end_col,
|
|
250
|
-
message: "List item
|
|
251
|
-
.to_string(),
|
|
262
|
+
message: "List item indentation".to_string(),
|
|
252
263
|
fix: Some(Fix {
|
|
253
264
|
range: line_index.line_col_to_byte_range(line_num, 1),
|
|
254
265
|
replacement,
|
|
@@ -96,61 +96,53 @@ impl MD034NoBareUrls {
|
|
|
96
96
|
&url[..end]
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
//
|
|
100
|
-
fn
|
|
99
|
+
// Uses DocumentStructure for code block and code span detection in check_with_structure.
|
|
100
|
+
pub fn check_with_structure(
|
|
101
101
|
&self,
|
|
102
|
-
|
|
103
|
-
line_idx: usize,
|
|
102
|
+
ctx: &crate::lint_context::LintContext,
|
|
104
103
|
structure: &crate::utils::document_structure::DocumentStructure,
|
|
105
|
-
) ->
|
|
106
|
-
let
|
|
107
|
-
|
|
108
|
-
// Early return: empty lines
|
|
109
|
-
if line.trim().is_empty() {
|
|
110
|
-
return warnings;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Fast path - check if line potentially contains a URL
|
|
114
|
-
if !URL_QUICK_CHECK.is_match(line) {
|
|
115
|
-
return warnings;
|
|
116
|
-
}
|
|
104
|
+
) -> LintResult {
|
|
105
|
+
let content = ctx.content;
|
|
117
106
|
|
|
118
|
-
//
|
|
119
|
-
if
|
|
120
|
-
return
|
|
107
|
+
// Early return: skip if no URLs or emails
|
|
108
|
+
if self.should_skip(content) {
|
|
109
|
+
return Ok(vec![]);
|
|
121
110
|
}
|
|
122
111
|
|
|
123
|
-
//
|
|
124
|
-
|
|
125
|
-
return warnings;
|
|
126
|
-
}
|
|
112
|
+
// Process the entire content to handle multi-line markdown links
|
|
113
|
+
let mut warnings = Vec::new();
|
|
127
114
|
|
|
128
|
-
//
|
|
115
|
+
// First, find all markdown link ranges across the entire content
|
|
129
116
|
let mut excluded_ranges: Vec<(usize, usize)> = Vec::new();
|
|
130
|
-
|
|
131
|
-
|
|
117
|
+
|
|
118
|
+
// Markdown links: [text](url) - handle multi-line
|
|
119
|
+
for cap in MARKDOWN_LINK_PATTERN.captures_iter(content) {
|
|
132
120
|
if let Some(dest) = cap.get(1) {
|
|
133
121
|
excluded_ranges.push((dest.start(), dest.end()));
|
|
134
122
|
}
|
|
135
123
|
}
|
|
136
|
-
|
|
137
|
-
|
|
124
|
+
|
|
125
|
+
// Markdown images:  - handle multi-line
|
|
126
|
+
for cap in MARKDOWN_IMAGE_PATTERN.captures_iter(content) {
|
|
138
127
|
if let Some(dest) = cap.get(2) {
|
|
139
128
|
excluded_ranges.push((dest.start(), dest.end()));
|
|
140
129
|
}
|
|
141
130
|
}
|
|
131
|
+
|
|
142
132
|
// Angle-bracket links: <url>
|
|
143
|
-
for cap in ANGLE_LINK_PATTERN.captures_iter(
|
|
133
|
+
for cap in ANGLE_LINK_PATTERN.captures_iter(content) {
|
|
144
134
|
if let Some(m) = cap.get(1) {
|
|
145
135
|
excluded_ranges.push((m.start(), m.end()));
|
|
146
136
|
}
|
|
147
137
|
}
|
|
138
|
+
|
|
148
139
|
// HTML attribute URLs: src="url", href="url", etc.
|
|
149
|
-
for cap in HTML_ATTRIBUTE_URL.captures_iter(
|
|
140
|
+
for cap in HTML_ATTRIBUTE_URL.captures_iter(content) {
|
|
150
141
|
if let Some(url_attr) = cap.get(1) {
|
|
151
142
|
excluded_ranges.push((url_attr.start(), url_attr.end()));
|
|
152
143
|
}
|
|
153
144
|
}
|
|
145
|
+
|
|
154
146
|
// Sort and merge overlapping ranges
|
|
155
147
|
excluded_ranges.sort_by_key(|r| r.0);
|
|
156
148
|
let mut merged: Vec<(usize, usize)> = Vec::new();
|
|
@@ -164,12 +156,13 @@ impl MD034NoBareUrls {
|
|
|
164
156
|
merged.push((start, end));
|
|
165
157
|
}
|
|
166
158
|
|
|
167
|
-
|
|
159
|
+
// Now find all URLs in the content and check if they're excluded
|
|
160
|
+
for url_match in SIMPLE_URL_REGEX.find_iter(content) {
|
|
168
161
|
let url_start = url_match.start();
|
|
169
162
|
let mut url_end = url_match.end();
|
|
170
163
|
|
|
171
164
|
// Trim trailing punctuation that's likely sentence punctuation
|
|
172
|
-
let raw_url = &
|
|
165
|
+
let raw_url = &content[url_start..url_end];
|
|
173
166
|
let trimmed_url = self.trim_trailing_punctuation(raw_url);
|
|
174
167
|
url_end = url_start + trimmed_url.len();
|
|
175
168
|
|
|
@@ -182,9 +175,9 @@ impl MD034NoBareUrls {
|
|
|
182
175
|
let before = if url_start == 0 {
|
|
183
176
|
None
|
|
184
177
|
} else {
|
|
185
|
-
|
|
178
|
+
content.get(url_start - 1..url_start)
|
|
186
179
|
};
|
|
187
|
-
let after =
|
|
180
|
+
let after = content.get(url_end..url_end + 1);
|
|
188
181
|
let is_valid_boundary = before.map_or(true, |c| {
|
|
189
182
|
!c.chars().next().unwrap().is_alphanumeric() && c != "_"
|
|
190
183
|
}) && after.map_or(true, |c| {
|
|
@@ -193,45 +186,67 @@ impl MD034NoBareUrls {
|
|
|
193
186
|
if !is_valid_boundary {
|
|
194
187
|
continue;
|
|
195
188
|
}
|
|
196
|
-
|
|
197
|
-
|
|
189
|
+
|
|
190
|
+
// Convert byte offset to line/column
|
|
191
|
+
let (line_num, col_num) = ctx.offset_to_line_col(url_start);
|
|
192
|
+
|
|
193
|
+
// Skip if this URL is within a code span
|
|
194
|
+
if structure.is_in_code_span(line_num, col_num) {
|
|
198
195
|
continue;
|
|
199
196
|
}
|
|
200
|
-
|
|
197
|
+
|
|
198
|
+
// Skip if this URL is within a code block
|
|
199
|
+
if structure.is_in_code_block(line_num) {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Skip if URL is within any excluded range (link/image dest)
|
|
201
204
|
let in_any_range = merged
|
|
202
205
|
.iter()
|
|
203
206
|
.any(|(start, end)| url_start >= *start && url_end <= *end);
|
|
204
207
|
if in_any_range {
|
|
205
208
|
continue;
|
|
206
209
|
}
|
|
210
|
+
|
|
211
|
+
// Skip reference definitions
|
|
212
|
+
let line_start = content[..url_start].rfind('\n').map(|i| i + 1).unwrap_or(0);
|
|
213
|
+
let line_end = content[url_start..].find('\n').map(|i| url_start + i).unwrap_or(content.len());
|
|
214
|
+
let line = &content[line_start..line_end];
|
|
215
|
+
if REFERENCE_DEF_RE.is_match(line) {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
let url_text = &content[url_start..url_end];
|
|
207
220
|
let (start_line, start_col, end_line, end_col) =
|
|
208
|
-
calculate_url_range(
|
|
221
|
+
calculate_url_range(line_num, line, col_num - 1, url_text.len());
|
|
222
|
+
|
|
209
223
|
warnings.push(LintWarning {
|
|
210
224
|
rule_name: Some(self.name()),
|
|
211
225
|
line: start_line,
|
|
212
226
|
column: start_col,
|
|
213
227
|
end_line,
|
|
214
228
|
end_column: end_col,
|
|
215
|
-
message: format!("Bare URL found
|
|
229
|
+
message: format!("Bare URL found"),
|
|
216
230
|
severity: Severity::Warning,
|
|
217
231
|
fix: Some(Fix {
|
|
218
232
|
range: url_start..url_end,
|
|
219
|
-
replacement: format!("<{}>",
|
|
233
|
+
replacement: format!("<{}>", url_text),
|
|
220
234
|
}),
|
|
221
235
|
});
|
|
222
236
|
}
|
|
223
237
|
|
|
224
238
|
// Check for email addresses - similar logic to URLs
|
|
225
|
-
for email_match in EMAIL_REGEX.find_iter(
|
|
239
|
+
for email_match in EMAIL_REGEX.find_iter(content) {
|
|
226
240
|
let email_start = email_match.start();
|
|
227
241
|
let email_end = email_match.end();
|
|
242
|
+
|
|
228
243
|
// Manual boundary check: not part of a larger word
|
|
229
244
|
let before = if email_start == 0 {
|
|
230
245
|
None
|
|
231
246
|
} else {
|
|
232
|
-
|
|
247
|
+
content.get(email_start - 1..email_start)
|
|
233
248
|
};
|
|
234
|
-
let after =
|
|
249
|
+
let after = content.get(email_end..email_end + 1);
|
|
235
250
|
let is_valid_boundary = before.map_or(true, |c| {
|
|
236
251
|
!c.chars().next().unwrap().is_alphanumeric() && c != "_" && c != "."
|
|
237
252
|
}) && after.map_or(true, |c| {
|
|
@@ -240,10 +255,20 @@ impl MD034NoBareUrls {
|
|
|
240
255
|
if !is_valid_boundary {
|
|
241
256
|
continue;
|
|
242
257
|
}
|
|
243
|
-
|
|
244
|
-
|
|
258
|
+
|
|
259
|
+
// Convert byte offset to line/column
|
|
260
|
+
let (line_num, col_num) = ctx.offset_to_line_col(email_start);
|
|
261
|
+
|
|
262
|
+
// Skip if this email is within a code span
|
|
263
|
+
if structure.is_in_code_span(line_num, col_num) {
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Skip if this email is within a code block
|
|
268
|
+
if structure.is_in_code_block(line_num) {
|
|
245
269
|
continue;
|
|
246
270
|
}
|
|
271
|
+
|
|
247
272
|
// Skip if email is within any excluded range (link/image dest)
|
|
248
273
|
let in_any_range = merged
|
|
249
274
|
.iter()
|
|
@@ -251,65 +276,29 @@ impl MD034NoBareUrls {
|
|
|
251
276
|
if in_any_range {
|
|
252
277
|
continue;
|
|
253
278
|
}
|
|
279
|
+
|
|
280
|
+
let email_text = &content[email_start..email_end];
|
|
281
|
+
let line_start = content[..email_start].rfind('\n').map(|i| i + 1).unwrap_or(0);
|
|
282
|
+
let line_end = content[email_start..].find('\n').map(|i| email_start + i).unwrap_or(content.len());
|
|
283
|
+
let line = &content[line_start..line_end];
|
|
254
284
|
let (start_line, start_col, end_line, end_col) =
|
|
255
|
-
calculate_url_range(
|
|
285
|
+
calculate_url_range(line_num, line, col_num - 1, email_text.len());
|
|
286
|
+
|
|
256
287
|
warnings.push(LintWarning {
|
|
257
288
|
rule_name: Some(self.name()),
|
|
258
289
|
line: start_line,
|
|
259
290
|
column: start_col,
|
|
260
291
|
end_line,
|
|
261
292
|
end_column: end_col,
|
|
262
|
-
message: format!(
|
|
263
|
-
"Bare email address found: {}",
|
|
264
|
-
&line[email_start..email_end]
|
|
265
|
-
),
|
|
293
|
+
message: format!("Bare email address found"),
|
|
266
294
|
severity: Severity::Warning,
|
|
267
295
|
fix: Some(Fix {
|
|
268
296
|
range: email_start..email_end,
|
|
269
|
-
replacement: format!("<{}>",
|
|
297
|
+
replacement: format!("<{}>", email_text),
|
|
270
298
|
}),
|
|
271
299
|
});
|
|
272
300
|
}
|
|
273
|
-
warnings
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// Uses DocumentStructure for code block and code span detection in check_with_structure.
|
|
277
|
-
pub fn check_with_structure(
|
|
278
|
-
&self,
|
|
279
|
-
ctx: &crate::lint_context::LintContext,
|
|
280
|
-
structure: &crate::utils::document_structure::DocumentStructure,
|
|
281
|
-
) -> LintResult {
|
|
282
|
-
let content = ctx.content;
|
|
283
301
|
|
|
284
|
-
// Early return: skip if no URLs or emails
|
|
285
|
-
if self.should_skip(content) {
|
|
286
|
-
return Ok(vec![]);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
let mut warnings = Vec::new();
|
|
290
|
-
for (i, line) in content.lines().enumerate() {
|
|
291
|
-
// Fast path: Skip empty lines
|
|
292
|
-
if line.trim().is_empty() {
|
|
293
|
-
continue;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// Fast path: Skip lines without potential URLs or emails
|
|
297
|
-
if !line.contains("http") && !line.contains("ftp") && !line.contains('@') {
|
|
298
|
-
continue;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// Skip lines in code blocks
|
|
302
|
-
if structure.is_in_code_block(i + 1) {
|
|
303
|
-
continue;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Fast path: Skip reference link definitions
|
|
307
|
-
if REFERENCE_DEF_RE.is_match(line) {
|
|
308
|
-
continue;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
warnings.extend(self.find_bare_urls_with_structure(line, i, structure));
|
|
312
|
-
}
|
|
313
302
|
Ok(warnings)
|
|
314
303
|
}
|
|
315
304
|
|
|
@@ -368,7 +357,7 @@ impl MD034NoBareUrls {
|
|
|
368
357
|
column: start_col,
|
|
369
358
|
end_line,
|
|
370
359
|
end_column: end_col,
|
|
371
|
-
message: format!("Bare URL found
|
|
360
|
+
message: format!("Bare URL found"),
|
|
372
361
|
severity: Severity::Warning,
|
|
373
362
|
fix: Some(Fix {
|
|
374
363
|
range: offset..(offset + url_text.len()),
|
|
@@ -466,7 +455,7 @@ impl MD034NoBareUrls {
|
|
|
466
455
|
column: start_col,
|
|
467
456
|
end_line,
|
|
468
457
|
end_column: end_col,
|
|
469
|
-
message: format!("Bare URL found
|
|
458
|
+
message: format!("Bare URL found"),
|
|
470
459
|
severity: Severity::Warning,
|
|
471
460
|
fix: Some(Fix {
|
|
472
461
|
range: offset..(offset + url_text.len()),
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
use rumdl::lint_context::LintContext;
|
|
2
|
+
use rumdl::rule::Rule;
|
|
3
|
+
use rumdl::rules::MD006StartBullets;
|
|
4
|
+
|
|
5
|
+
#[test]
|
|
6
|
+
fn test_valid_unordered_list() {
|
|
7
|
+
let rule = MD006StartBullets;
|
|
8
|
+
let content = "\
|
|
9
|
+
* Item 1
|
|
10
|
+
* Item 2
|
|
11
|
+
* Nested item
|
|
12
|
+
* Another nested item
|
|
13
|
+
* Item 3";
|
|
14
|
+
let ctx = LintContext::new(content);
|
|
15
|
+
let result = rule.check(&ctx).unwrap();
|
|
16
|
+
assert!(result.is_empty());
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
#[test]
|
|
20
|
+
fn test_valid_nested_list() {
|
|
21
|
+
let rule = MD006StartBullets;
|
|
22
|
+
let content = "\
|
|
23
|
+
* Item 1
|
|
24
|
+
* Item 2
|
|
25
|
+
* Deeply nested item
|
|
26
|
+
* Item 3";
|
|
27
|
+
let ctx = LintContext::new(content);
|
|
28
|
+
let result = rule.check(&ctx).unwrap();
|
|
29
|
+
assert!(
|
|
30
|
+
result.is_empty(),
|
|
31
|
+
"Valid nested lists should not generate warnings, found: {:?}",
|
|
32
|
+
result
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#[test]
|
|
37
|
+
fn test_invalid_indented_list() {
|
|
38
|
+
let rule = MD006StartBullets;
|
|
39
|
+
let content = "\
|
|
40
|
+
Some text here.
|
|
41
|
+
|
|
42
|
+
* First item should not be indented
|
|
43
|
+
* Second item should not be indented
|
|
44
|
+
* Third item should not be indented";
|
|
45
|
+
let ctx = LintContext::new(content);
|
|
46
|
+
let result = rule.check(&ctx).unwrap();
|
|
47
|
+
assert_eq!(result.len(), 3);
|
|
48
|
+
let fixed = rule.fix(&ctx).unwrap();
|
|
49
|
+
assert_eq!(
|
|
50
|
+
fixed,
|
|
51
|
+
"\
|
|
52
|
+
Some text here.
|
|
53
|
+
|
|
54
|
+
* First item should not be indented
|
|
55
|
+
* Second item should not be indented
|
|
56
|
+
* Third item should not be indented"
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
#[test]
|
|
61
|
+
fn test_mixed_list_styles() {
|
|
62
|
+
let rule = MD006StartBullets;
|
|
63
|
+
let content = "\
|
|
64
|
+
* Item 1
|
|
65
|
+
* Nested item
|
|
66
|
+
* Item 2
|
|
67
|
+
|
|
68
|
+
- Another item
|
|
69
|
+
- Nested item
|
|
70
|
+
- Final item";
|
|
71
|
+
let ctx = LintContext::new(content);
|
|
72
|
+
let result = rule.check(&ctx).unwrap();
|
|
73
|
+
assert!(result.is_empty());
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
#[test]
|
|
77
|
+
fn test_multiple_lists() {
|
|
78
|
+
let rule = MD006StartBullets;
|
|
79
|
+
let content = "\
|
|
80
|
+
* First list item
|
|
81
|
+
* Second list item
|
|
82
|
+
|
|
83
|
+
Some text here
|
|
84
|
+
|
|
85
|
+
* Indented list 1
|
|
86
|
+
* Indented list 2";
|
|
87
|
+
let ctx = LintContext::new(content);
|
|
88
|
+
let result = rule.check(&ctx).unwrap();
|
|
89
|
+
assert_eq!(result.len(), 2);
|
|
90
|
+
let fixed = rule.fix(&ctx).unwrap();
|
|
91
|
+
assert_eq!(
|
|
92
|
+
fixed,
|
|
93
|
+
"\
|
|
94
|
+
* First list item
|
|
95
|
+
* Second list item
|
|
96
|
+
|
|
97
|
+
Some text here
|
|
98
|
+
|
|
99
|
+
* Indented list 1
|
|
100
|
+
* Indented list 2"
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
#[test]
|
|
105
|
+
fn test_empty_lines() {
|
|
106
|
+
let rule = MD006StartBullets;
|
|
107
|
+
let content = "\
|
|
108
|
+
* Item 1
|
|
109
|
+
|
|
110
|
+
* Nested item
|
|
111
|
+
|
|
112
|
+
* Item 2";
|
|
113
|
+
let ctx = LintContext::new(content);
|
|
114
|
+
let result = rule.check(&ctx).unwrap();
|
|
115
|
+
assert!(result.is_empty());
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
#[test]
|
|
119
|
+
fn test_no_lists() {
|
|
120
|
+
let rule = MD006StartBullets;
|
|
121
|
+
let content = "\
|
|
122
|
+
Just some text
|
|
123
|
+
More text
|
|
124
|
+
Even more text";
|
|
125
|
+
let ctx = LintContext::new(content);
|
|
126
|
+
let result = rule.check(&ctx).unwrap();
|
|
127
|
+
assert!(result.is_empty());
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
#[test]
|
|
131
|
+
fn test_code_blocks_ignored() {
|
|
132
|
+
let rule = MD006StartBullets;
|
|
133
|
+
let content = "\
|
|
134
|
+
```markdown
|
|
135
|
+
* This indented item is inside a code block
|
|
136
|
+
* These should be ignored
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
* Regular item outside code block";
|
|
140
|
+
let ctx = LintContext::new(content);
|
|
141
|
+
let result = rule.check(&ctx).unwrap();
|
|
142
|
+
assert!(result.is_empty());
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// REGRESSION TESTS: Prevent false positives that were previously fixed
|
|
146
|
+
|
|
147
|
+
#[test]
|
|
148
|
+
fn test_nested_list_with_multiline_content_not_flagged() {
|
|
149
|
+
let rule = MD006StartBullets;
|
|
150
|
+
// This is the exact pattern that was causing false positives before the fix
|
|
151
|
+
let content = "\
|
|
152
|
+
- Introduces changes or additions to the [MLflow REST
|
|
153
|
+
API](https://mlflow.org/docs/latest/rest-api.html)
|
|
154
|
+
- The MLflow REST API is implemented by a variety of open source
|
|
155
|
+
and proprietary platforms. Changes to the REST API impact all of
|
|
156
|
+
these platforms. Accordingly, we encourage developers to
|
|
157
|
+
thoroughly explore alternatives before attempting to introduce
|
|
158
|
+
REST API changes.
|
|
159
|
+
- Introduces new user-facing MLflow APIs
|
|
160
|
+
- MLflow's API surface is carefully designed to generalize across
|
|
161
|
+
a variety of common ML operations. It is important to ensure
|
|
162
|
+
that new APIs are broadly useful to ML developers, easy to work
|
|
163
|
+
with, and simple yet powerful.";
|
|
164
|
+
|
|
165
|
+
let ctx = LintContext::new(content);
|
|
166
|
+
let result = rule.check(&ctx).unwrap();
|
|
167
|
+
|
|
168
|
+
// Should not flag any list items since they are properly nested
|
|
169
|
+
assert!(
|
|
170
|
+
result.is_empty(),
|
|
171
|
+
"Properly nested list items with multi-line content should not be flagged. Found {} warnings: {:#?}",
|
|
172
|
+
result.len(),
|
|
173
|
+
result
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
// Fix should not change anything since the list structure is correct
|
|
177
|
+
let fixed = rule.fix(&ctx).unwrap();
|
|
178
|
+
assert_eq!(
|
|
179
|
+
fixed, content,
|
|
180
|
+
"Fix should not change content with properly nested list items"
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
#[test]
|
|
185
|
+
fn test_nested_list_with_markdown_link_continuation() {
|
|
186
|
+
let rule = MD006StartBullets;
|
|
187
|
+
// Test that markdown link continuations don't break list nesting validation
|
|
188
|
+
let content = "\
|
|
189
|
+
* First item with [a link that spans
|
|
190
|
+
multiple lines](https://example.com/very/long/url)
|
|
191
|
+
* This nested item should be valid
|
|
192
|
+
* Another nested item
|
|
193
|
+
* Second top-level item";
|
|
194
|
+
|
|
195
|
+
let ctx = LintContext::new(content);
|
|
196
|
+
let result = rule.check(&ctx).unwrap();
|
|
197
|
+
|
|
198
|
+
// Should not flag any list items since the nesting is correct
|
|
199
|
+
assert!(
|
|
200
|
+
result.is_empty(),
|
|
201
|
+
"List items with markdown link continuations should not break nesting validation. Found {} warnings: {:#?}",
|
|
202
|
+
result.len(),
|
|
203
|
+
result
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
#[test]
|
|
208
|
+
fn test_mixed_valid_and_invalid_nesting() {
|
|
209
|
+
let rule = MD006StartBullets;
|
|
210
|
+
// Test that we correctly identify invalid nesting while preserving valid nesting
|
|
211
|
+
let content = "\
|
|
212
|
+
* Valid top-level item
|
|
213
|
+
* Valid nested item
|
|
214
|
+
* Valid deeply nested item
|
|
215
|
+
|
|
216
|
+
Some breaking content
|
|
217
|
+
|
|
218
|
+
* This should be flagged as invalid (indented without parent)
|
|
219
|
+
* This should also be flagged
|
|
220
|
+
|
|
221
|
+
* Valid top-level item after break
|
|
222
|
+
* Valid nested item after break";
|
|
223
|
+
|
|
224
|
+
let ctx = LintContext::new(content);
|
|
225
|
+
let result = rule.check(&ctx).unwrap();
|
|
226
|
+
|
|
227
|
+
// Should only flag the 2 items that are improperly indented after the break
|
|
228
|
+
assert_eq!(
|
|
229
|
+
result.len(),
|
|
230
|
+
2,
|
|
231
|
+
"Should only flag improperly indented items, not valid nested items. Found {} warnings: {:#?}",
|
|
232
|
+
result.len(),
|
|
233
|
+
result
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
// Verify the correct lines are flagged
|
|
237
|
+
let flagged_lines: Vec<usize> = result.iter().map(|w| w.line).collect();
|
|
238
|
+
assert!(
|
|
239
|
+
flagged_lines.contains(&7) && flagged_lines.contains(&8),
|
|
240
|
+
"Should flag lines 7 and 8 (the improperly indented items), but flagged: {:?}",
|
|
241
|
+
flagged_lines
|
|
242
|
+
);
|
|
243
|
+
}
|