rumdl 0.0.115__tar.gz → 0.0.116__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.115 → rumdl-0.0.116}/CHANGELOG.md +16 -1
- {rumdl-0.0.115 → rumdl-0.0.116}/Cargo.lock +1 -1
- {rumdl-0.0.115 → rumdl-0.0.116}/Cargo.toml +1 -1
- {rumdl-0.0.115 → rumdl-0.0.116}/PKG-INFO +1 -1
- {rumdl-0.0.115 → rumdl-0.0.116}/scripts/pre-release.sh +29 -6
- {rumdl-0.0.115 → rumdl-0.0.116}/src/lint_context.rs +57 -11
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md020_no_missing_space_closed_atx.rs +15 -10
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md026_no_trailing_punctuation/md026_config.rs +6 -1
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md026_no_trailing_punctuation.rs +32 -148
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md034_no_bare_urls.rs +9 -10
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md051_link_fragments.rs +7 -1
- {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/kramdown_utils.rs +38 -1
- rumdl-0.0.116/tests/rules/md020_test.rs +267 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md026_kramdown_test.rs +45 -17
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md026_test.rs +39 -92
- rumdl-0.0.116/tests/rules/md029_issue42_test.rs +320 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md034_test.rs +41 -0
- rumdl-0.0.115/tests/rules/md020_test.rs +0 -130
- {rumdl-0.0.115 → rumdl-0.0.116}/.config/nextest.toml +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/.mise.toml +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/.pre-commit-config.yaml +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/.rumdl.toml +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/.rustfmt.toml +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/LICENSE +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/MANIFEST.in +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/Makefile +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/README.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/assets/logo.png +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/benches/fix_performance.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/benches/range_performance.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/benches/range_utils_benchmark.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/benches/rule_performance.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/benches/simple_fix_bench.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/benchmark/bin/bench_lint_context.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/benchmark/bin/benchmark.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/benchmark/bin/benchmark_rule.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/benchmark/bin/file_parallel_benchmark.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/benchmark/bin/measure_code_span_performance.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/RULES.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/global-settings.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md001.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md002.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md003.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md004.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md005.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md006.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md007.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md009.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md010.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md011.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md012.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md013.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md014.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md018.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md019.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md020.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md021.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md022.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md023.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md024.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md025.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md026.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md027.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md028.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md029.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md030.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md031.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md032.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md033.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md034.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md035.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md036.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md037.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md038.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md039.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md040.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md041.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md042.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md043.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md044.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md045.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md046.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md047.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md048.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md049.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md050.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md051.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md052.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md053.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md054.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md055.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md056.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md057.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/md058.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/docs/vscode-extension.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/parity_check.py +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/pyproject.toml +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/python/MANIFEST.in +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/python/PYTHON-README.md +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/python/rumdl/__init__.py +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/python/rumdl/__main__.py +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/python/rumdl/py.typed +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/rumdl.toml.example +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/rust-toolchain.toml +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/scripts/extract-changelog.sh +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/scripts/generate-downloads-table.sh +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/scripts/prepare-release.sh +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/scripts/setup-pre-commit.sh +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/scripts/update-pre-commit-docs.sh +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/exit_codes.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/inline_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/lib.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/lsp/mod.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/lsp/server.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/lsp/types.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/main.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/markdownlint_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/azure.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/concise.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/github.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/gitlab.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/grouped.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/json.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/json_lines.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/junit.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/mod.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/pylint.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/sarif.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/output/formatters/text.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/output/mod.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/parallel.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/performance.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/profiling.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/python.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rule.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rule_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rule_config_serde.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/blockquote_utils.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/code_block_utils.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/code_fence_utils.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/emphasis_style.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/front_matter_utils.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/heading_utils.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/list_utils.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md001_heading_increment.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md002_first_heading_h1/md002_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md002_first_heading_h1.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md003_heading_style/md003_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md003_heading_style.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md004_unordered_list_style/md004_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md004_unordered_list_style.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md005_list_indent.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md006_start_bullets.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md007_ul_indent/md007_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md007_ul_indent.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md009_trailing_spaces/md009_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md009_trailing_spaces.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md010_no_hard_tabs/md010_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md010_no_hard_tabs.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md011_no_reversed_links.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md012_no_multiple_blanks/md012_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md012_no_multiple_blanks.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md013_line_length/md013_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md013_line_length.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md014_commands_show_output/md014_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md014_commands_show_output.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md018_no_missing_space_atx.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md019_no_multiple_space_atx.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md021_no_multiple_space_closed_atx.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md022_blanks_around_headings/md022_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md022_blanks_around_headings.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md023_heading_start_left.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md024_no_duplicate_heading/md024_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md024_no_duplicate_heading.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md025_single_title/md025_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md025_single_title.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md027_multiple_spaces_blockquote.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md028_no_blanks_blockquote.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md029_ordered_list_prefix/md029_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md029_ordered_list_prefix.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md030_list_marker_space/md030_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md030_list_marker_space.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md031_blanks_around_fences.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md032_blanks_around_lists.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md033_no_inline_html/md033_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md033_no_inline_html.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md035_hr_style/md035_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md035_hr_style.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md036_no_emphasis_only_first/md036_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md036_no_emphasis_only_first.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md037_spaces_around_emphasis.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md038_no_space_in_code.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md039_no_space_in_links.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md040_fenced_code_language.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md041_first_line_heading.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md042_no_empty_links.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md043_required_headings.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md044_proper_names/md044_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md044_proper_names.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md045_no_alt_text/md045_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md045_no_alt_text.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md046_code_block_style/md046_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md046_code_block_style.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md047_single_trailing_newline.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md048_code_fence_style/md048_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md048_code_fence_style.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md049_emphasis_style/md049_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md049_emphasis_style.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md050_strong_style/md050_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md050_strong_style.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md052_reference_links_images.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md053_link_image_reference_definitions.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md054_link_image_style/md054_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md054_link_image_style.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md055_table_pipe_style/md055_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md055_table_pipe_style.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md056_table_column_count.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md057_existing_relative_links/md057_config.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md057_existing_relative_links.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/md058_blanks_around_tables.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/mod.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/rules/strong_style.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/ast_utils.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/code_block_utils.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/document_structure.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/early_returns.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/element_cache.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/emphasis_utils.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/fix_utils.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/markdown_elements.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/mod.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/range_utils.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/regex_cache.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/string_interner.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/table_utils.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/utils/text_reflow.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/src/vscode.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/advanced_integration_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/character_ranges/additional_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/character_ranges/basic_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/character_ranges/comprehensive_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/character_ranges/extended_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/character_ranges/mod.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/character_ranges/unicode_utils.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/cli_duplication_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/cli_explain_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/cli_flag_precedence_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/cli_integration_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/cli_lsp_fix_consistency.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/cli_statistics_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/common/cli_test_utils.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/common/fixtures.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/common/mod.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/common/test_utils.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/commonmark_compliance_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/comprehensive_integration_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/comprehensive_output_format_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/config_application_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/config_file_command_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/config_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/configuration_inheritance_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/consistency_regression_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/cross_platform_compatibility_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/deeply_nested_lists_performance_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/escaped_brackets_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/final_confidence_assessment.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/fixable_unfixable_config_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/init_command_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/init_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/inline_config_blocks_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/inline_config_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/integration_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/json_output_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/kramdown_integration_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/lib.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/lsp_editor_integration_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/lsp_integration_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/lsp_memory_leak_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/lsp_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/malformed_markdown_stress_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/markdownlint_cli_integration.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/markdownlint_config_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/markdownlintignore_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/md013_reflow_integration_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/nested_code_block_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/output_format_integration_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/output_format_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/perf_check.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/performance_validation_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/pyproject_config_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/python_bindings_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/real_world_repository_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/regression_prevention_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/emphasis_edge_cases_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/heading_edge_cases_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/inline_content_edge_cases_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/link_edge_cases_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/list_rules_integration_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md001_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md001_unicode_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md002_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md003_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md004_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md005_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md005_unicode_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md006_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md006_unicode_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md007_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md009_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md010_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md011_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md012_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md013_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md014_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md018_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md019_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md021_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md022_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md023_extended_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md023_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md024_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md025_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md027_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md028_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md029_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md029_unicode_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md030_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md031_kramdown_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md031_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md032_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md033_extended_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md033_kramdown_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md033_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md034_ipv6_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md035_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md036_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md037_kramdown_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md037_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md038_nested_backticks_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md038_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md039_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md040_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md041_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md042_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md043_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md044_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md045_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md046_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md047_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md048_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md049_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md050_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md051_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md051_unicode_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md052_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md053_additional_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md053_proptest.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md053_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md054_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md054_unicode_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md055_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md056_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md057_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md058_kramdown_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/md058_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules/mod.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/rules_mod_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/thread_safety_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/unicode_edge_case_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/utils/blockquote_utils_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/utils/code_block_utils_extended_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/utils/code_block_utils_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/utils/core_utils_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/utils/front_matter_utils_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/utils/line_index_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/utils/mod.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/utils_markdown_edge_cases.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/utils_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/vscode_extension_fixes.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/vscode_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/vscode_tests.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/vscode_windows_comprehensive_test.rs +0 -0
- {rumdl-0.0.115 → rumdl-0.0.116}/tests/vscode_windows_test.rs +0 -0
|
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.0.116] - 2025-08-13
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Kramdown-style custom header IDs support (#44)
|
|
14
|
+
- Headers can now have custom IDs using the `{#custom-id}` syntax
|
|
15
|
+
- Custom IDs are preserved when fixing MD051 (link fragments)
|
|
16
|
+
- MD026 (trailing punctuation) now ignores headers with custom IDs
|
|
17
|
+
- Safe character validation: accepts Unicode letters/numbers, hyphens, underscores, and colons
|
|
18
|
+
- Rejects problematic characters like spaces, quotes, brackets, and HTML/CSS special chars
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- Pre-release script now correctly handles dynamic versioning in pyproject.toml
|
|
22
|
+
- Added Cargo.lock validation and `cargo publish --dry-run` checks to prevent release failures
|
|
23
|
+
|
|
10
24
|
## [0.0.115] - 2025-08-12
|
|
11
25
|
|
|
12
26
|
## [0.0.114] - 2025-08-09
|
|
@@ -310,7 +324,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
310
324
|
|
|
311
325
|
- Initial implementation of remaining rules for markdownlint parity
|
|
312
326
|
|
|
313
|
-
[Unreleased]: https://github.com/rvben/rumdl/compare/v0.0.
|
|
327
|
+
[Unreleased]: https://github.com/rvben/rumdl/compare/v0.0.116...HEAD
|
|
328
|
+
[0.0.116]: https://github.com/rvben/rumdl/compare/v0.0.115...v0.0.116
|
|
314
329
|
[0.0.115]: https://github.com/rvben/rumdl/compare/v0.0.114...v0.0.115
|
|
315
330
|
[0.0.114]: https://github.com/rvben/rumdl/compare/v0.0.113...v0.0.114
|
|
316
331
|
[0.0.113]: https://github.com/rvben/rumdl/compare/v0.0.112...v0.0.113
|
|
@@ -73,15 +73,24 @@ run_check "Release build" "cargo build --release"
|
|
|
73
73
|
echo "6. Checking documentation..."
|
|
74
74
|
run_check "Documentation" "cargo doc --no-deps"
|
|
75
75
|
|
|
76
|
-
# 7. Verify Cargo.toml version
|
|
76
|
+
# 7. Verify Cargo.toml version (pyproject.toml uses dynamic versioning from Cargo.toml)
|
|
77
77
|
echo "7. Checking version consistency..."
|
|
78
78
|
CARGO_VERSION=$(grep '^version' Cargo.toml | head -1 | cut -d'"' -f2)
|
|
79
|
-
|
|
80
|
-
if
|
|
81
|
-
echo -e "${
|
|
82
|
-
FAILED=1
|
|
79
|
+
# pyproject.toml uses dynamic = ["version"] to read from Cargo.toml
|
|
80
|
+
if grep -q 'dynamic = \["version"\]' pyproject.toml; then
|
|
81
|
+
echo -e "${GREEN}✓${NC} Version $CARGO_VERSION (pyproject.toml uses dynamic versioning)"
|
|
83
82
|
else
|
|
84
|
-
|
|
83
|
+
# Fallback: check if there's a static version in pyproject.toml
|
|
84
|
+
PY_VERSION=$(grep '^version' pyproject.toml | head -1 | cut -d'"' -f2)
|
|
85
|
+
if [ -z "$PY_VERSION" ]; then
|
|
86
|
+
echo -e "${YELLOW}⚠${NC} pyproject.toml should use dynamic = [\"version\"] for version"
|
|
87
|
+
# Not a failure, just a warning
|
|
88
|
+
elif [ "$CARGO_VERSION" != "$PY_VERSION" ]; then
|
|
89
|
+
echo -e "${RED}Version mismatch: Cargo.toml ($CARGO_VERSION) vs pyproject.toml ($PY_VERSION)${NC}"
|
|
90
|
+
FAILED=1
|
|
91
|
+
else
|
|
92
|
+
echo -e "${GREEN}✓${NC} Version $CARGO_VERSION is consistent"
|
|
93
|
+
fi
|
|
85
94
|
fi
|
|
86
95
|
|
|
87
96
|
# 8. Check for uncommitted changes
|
|
@@ -111,6 +120,20 @@ else
|
|
|
111
120
|
echo -e "${GREEN}✓${NC} Tag $TAG_VERSION is available"
|
|
112
121
|
fi
|
|
113
122
|
|
|
123
|
+
# 11. Verify Cargo.lock is up to date
|
|
124
|
+
echo "11. Verifying Cargo.lock is up to date..."
|
|
125
|
+
if cargo update --workspace --dry-run 2>&1 | grep -q "Updating"; then
|
|
126
|
+
echo -e "${RED}✗ Cargo.lock needs updating${NC}"
|
|
127
|
+
echo " Run: cargo update --workspace"
|
|
128
|
+
FAILED=1
|
|
129
|
+
else
|
|
130
|
+
echo -e "${GREEN}✓${NC} Cargo.lock is up to date"
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
# 12. Test cargo publish with --dry-run
|
|
134
|
+
echo "12. Testing cargo publish (dry run)..."
|
|
135
|
+
run_check "Cargo publish dry-run" "cargo publish --dry-run --locked"
|
|
136
|
+
|
|
114
137
|
echo ""
|
|
115
138
|
echo "====================================="
|
|
116
139
|
if [ $FAILED -eq 0 ]; then
|
|
@@ -197,8 +197,12 @@ pub struct HeadingInfo {
|
|
|
197
197
|
pub marker_column: usize,
|
|
198
198
|
/// Column where heading text starts
|
|
199
199
|
pub content_column: usize,
|
|
200
|
-
/// The heading text (without markers)
|
|
200
|
+
/// The heading text (without markers and without custom ID syntax)
|
|
201
201
|
pub text: String,
|
|
202
|
+
/// Custom header ID if present (e.g., from {#custom-id} syntax)
|
|
203
|
+
pub custom_id: Option<String>,
|
|
204
|
+
/// Original heading text including custom ID syntax
|
|
205
|
+
pub raw_text: String,
|
|
202
206
|
/// Whether it has a closing sequence (for ATX)
|
|
203
207
|
pub has_closing_sequence: bool,
|
|
204
208
|
/// The closing sequence if present
|
|
@@ -1088,10 +1092,23 @@ impl<'a> LintContext<'a> {
|
|
|
1088
1092
|
let level = hashes.len() as u8;
|
|
1089
1093
|
let marker_column = leading_spaces.len();
|
|
1090
1094
|
|
|
1091
|
-
// Check for closing sequence
|
|
1095
|
+
// Check for closing sequence, but handle custom IDs that might come after
|
|
1092
1096
|
let (text, has_closing, closing_seq) = {
|
|
1093
|
-
//
|
|
1094
|
-
let
|
|
1097
|
+
// First check if there's a custom ID at the end
|
|
1098
|
+
let (rest_without_id, custom_id_part) = if let Some(id_start) = rest.rfind(" {#") {
|
|
1099
|
+
// Check if this looks like a valid custom ID (ends with })
|
|
1100
|
+
if rest[id_start..].trim_end().ends_with('}') {
|
|
1101
|
+
// Split off the custom ID
|
|
1102
|
+
(&rest[..id_start], &rest[id_start..])
|
|
1103
|
+
} else {
|
|
1104
|
+
(rest, "")
|
|
1105
|
+
}
|
|
1106
|
+
} else {
|
|
1107
|
+
(rest, "")
|
|
1108
|
+
};
|
|
1109
|
+
|
|
1110
|
+
// Now look for closing hashes in the part before the custom ID
|
|
1111
|
+
let trimmed_rest = rest_without_id.trim_end();
|
|
1095
1112
|
if let Some(last_hash_pos) = trimmed_rest.rfind('#') {
|
|
1096
1113
|
// Look for the start of the hash sequence
|
|
1097
1114
|
let mut start_of_hashes = last_hash_pos;
|
|
@@ -1099,32 +1116,55 @@ impl<'a> LintContext<'a> {
|
|
|
1099
1116
|
start_of_hashes -= 1;
|
|
1100
1117
|
}
|
|
1101
1118
|
|
|
1102
|
-
// Check if
|
|
1119
|
+
// Check if there's at least one space before the closing hashes
|
|
1120
|
+
let has_space_before = start_of_hashes == 0
|
|
1121
|
+
|| trimmed_rest
|
|
1122
|
+
.chars()
|
|
1123
|
+
.nth(start_of_hashes - 1)
|
|
1124
|
+
.is_some_and(|c| c.is_whitespace());
|
|
1125
|
+
|
|
1126
|
+
// Check if this is a valid closing sequence (all hashes to end of trimmed part)
|
|
1103
1127
|
let potential_closing = &trimmed_rest[start_of_hashes..];
|
|
1104
1128
|
let is_all_hashes = potential_closing.chars().all(|c| c == '#');
|
|
1105
1129
|
|
|
1106
|
-
if is_all_hashes {
|
|
1107
|
-
// This is a closing sequence
|
|
1130
|
+
if is_all_hashes && has_space_before {
|
|
1131
|
+
// This is a closing sequence
|
|
1108
1132
|
let closing_hashes = potential_closing.to_string();
|
|
1109
|
-
|
|
1110
|
-
|
|
1133
|
+
// The text is everything before the closing hashes
|
|
1134
|
+
// Don't include the custom ID here - it will be extracted later
|
|
1135
|
+
let text_part = if !custom_id_part.is_empty() {
|
|
1136
|
+
// If we have a custom ID, append it back to get the full rest
|
|
1137
|
+
// This allows the extract_header_id function to handle it properly
|
|
1138
|
+
format!("{}{}", rest_without_id[..start_of_hashes].trim_end(), custom_id_part)
|
|
1139
|
+
} else {
|
|
1140
|
+
rest_without_id[..start_of_hashes].trim_end().to_string()
|
|
1141
|
+
};
|
|
1142
|
+
(text_part, true, closing_hashes)
|
|
1111
1143
|
} else {
|
|
1144
|
+
// Not a valid closing sequence, return the full content
|
|
1112
1145
|
(rest.to_string(), false, String::new())
|
|
1113
1146
|
}
|
|
1114
1147
|
} else {
|
|
1148
|
+
// No hashes found, return the full content
|
|
1115
1149
|
(rest.to_string(), false, String::new())
|
|
1116
1150
|
}
|
|
1117
1151
|
};
|
|
1118
1152
|
|
|
1119
1153
|
let content_column = marker_column + hashes.len() + spaces_after.len();
|
|
1120
1154
|
|
|
1155
|
+
// Extract custom header ID if present
|
|
1156
|
+
let raw_text = text.trim().to_string();
|
|
1157
|
+
let (clean_text, custom_id) = crate::utils::kramdown_utils::extract_header_id(&raw_text);
|
|
1158
|
+
|
|
1121
1159
|
lines[i].heading = Some(HeadingInfo {
|
|
1122
1160
|
level,
|
|
1123
1161
|
style: HeadingStyle::ATX,
|
|
1124
1162
|
marker: hashes.to_string(),
|
|
1125
1163
|
marker_column,
|
|
1126
1164
|
content_column,
|
|
1127
|
-
text:
|
|
1165
|
+
text: clean_text,
|
|
1166
|
+
custom_id,
|
|
1167
|
+
raw_text,
|
|
1128
1168
|
has_closing_sequence: has_closing,
|
|
1129
1169
|
closing_sequence: closing_seq,
|
|
1130
1170
|
});
|
|
@@ -1146,13 +1186,19 @@ impl<'a> LintContext<'a> {
|
|
|
1146
1186
|
HeadingStyle::Setext2
|
|
1147
1187
|
};
|
|
1148
1188
|
|
|
1189
|
+
// Extract custom header ID if present
|
|
1190
|
+
let raw_text = line.trim().to_string();
|
|
1191
|
+
let (clean_text, custom_id) = crate::utils::kramdown_utils::extract_header_id(&raw_text);
|
|
1192
|
+
|
|
1149
1193
|
lines[i].heading = Some(HeadingInfo {
|
|
1150
1194
|
level,
|
|
1151
1195
|
style,
|
|
1152
1196
|
marker: underline.to_string(),
|
|
1153
1197
|
marker_column: next_line.len() - next_line.trim_start().len(),
|
|
1154
1198
|
content_column: lines[i].indent,
|
|
1155
|
-
text:
|
|
1199
|
+
text: clean_text,
|
|
1200
|
+
custom_id,
|
|
1201
|
+
raw_text,
|
|
1156
1202
|
has_closing_sequence: false,
|
|
1157
1203
|
closing_sequence: String::new(),
|
|
1158
1204
|
});
|
|
@@ -7,9 +7,10 @@ use lazy_static::lazy_static;
|
|
|
7
7
|
use regex::Regex;
|
|
8
8
|
|
|
9
9
|
lazy_static! {
|
|
10
|
-
|
|
11
|
-
static ref
|
|
12
|
-
static ref
|
|
10
|
+
// Updated patterns to handle optional custom IDs like {#custom-id} after closing hashes
|
|
11
|
+
static ref CLOSED_ATX_NO_SPACE_PATTERN: Regex = Regex::new(r"^(\s*)(#+)([^#\s].*?)([^#\s])(#+)(\s*(?:\{#[^}]+\})?\s*)$").unwrap();
|
|
12
|
+
static ref CLOSED_ATX_NO_SPACE_START_PATTERN: Regex = Regex::new(r"^(\s*)(#+)([^#\s].*?)\s(#+)(\s*(?:\{#[^}]+\})?\s*)$").unwrap();
|
|
13
|
+
static ref CLOSED_ATX_NO_SPACE_END_PATTERN: Regex = Regex::new(r"^(\s*)(#+)\s(.*?)([^#\s])(#+)(\s*(?:\{#[^}]+\})?\s*)$").unwrap();
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
#[derive(Clone)]
|
|
@@ -39,20 +40,23 @@ impl MD020NoMissingSpaceClosedAtx {
|
|
|
39
40
|
let content = &captures[3];
|
|
40
41
|
let last_char = &captures[4];
|
|
41
42
|
let closing_hashes = &captures[5];
|
|
42
|
-
|
|
43
|
+
let custom_id = &captures[6];
|
|
44
|
+
format!("{indentation}{opening_hashes} {content}{last_char} {closing_hashes}{custom_id}")
|
|
43
45
|
} else if let Some(captures) = CLOSED_ATX_NO_SPACE_START_PATTERN.captures(line) {
|
|
44
46
|
let indentation = &captures[1];
|
|
45
47
|
let opening_hashes = &captures[2];
|
|
46
48
|
let content = &captures[3];
|
|
47
49
|
let closing_hashes = &captures[4];
|
|
48
|
-
|
|
50
|
+
let custom_id = &captures[5];
|
|
51
|
+
format!("{indentation}{opening_hashes} {content} {closing_hashes}{custom_id}")
|
|
49
52
|
} else if let Some(captures) = CLOSED_ATX_NO_SPACE_END_PATTERN.captures(line) {
|
|
50
53
|
let indentation = &captures[1];
|
|
51
54
|
let opening_hashes = &captures[2];
|
|
52
55
|
let content = &captures[3];
|
|
53
56
|
let last_char = &captures[4];
|
|
54
57
|
let closing_hashes = &captures[5];
|
|
55
|
-
|
|
58
|
+
let custom_id = &captures[6];
|
|
59
|
+
format!("{indentation}{opening_hashes} {content}{last_char} {closing_hashes}{custom_id}")
|
|
56
60
|
} else {
|
|
57
61
|
line.to_string()
|
|
58
62
|
}
|
|
@@ -79,11 +83,13 @@ impl Rule for MD020NoMissingSpaceClosedAtx {
|
|
|
79
83
|
continue;
|
|
80
84
|
}
|
|
81
85
|
|
|
82
|
-
//
|
|
83
|
-
if matches!(heading.style, crate::lint_context::HeadingStyle::ATX)
|
|
86
|
+
// Check all ATX headings (both properly closed and malformed)
|
|
87
|
+
if matches!(heading.style, crate::lint_context::HeadingStyle::ATX) {
|
|
84
88
|
let line = &line_info.content;
|
|
85
89
|
|
|
86
90
|
// Check if line matches closed ATX pattern without space
|
|
91
|
+
// This will detect both properly closed headings with missing space
|
|
92
|
+
// and malformed attempts at closed headings like "# Heading#"
|
|
87
93
|
if self.is_closed_atx_heading_without_space(line) {
|
|
88
94
|
let line_index = LineIndex::new(ctx.content.to_string());
|
|
89
95
|
let line_range = line_index.line_content_range(line_num + 1);
|
|
@@ -162,9 +168,8 @@ impl Rule for MD020NoMissingSpaceClosedAtx {
|
|
|
162
168
|
continue;
|
|
163
169
|
}
|
|
164
170
|
|
|
165
|
-
// Fix
|
|
171
|
+
// Fix ATX headings without space (both properly closed and malformed)
|
|
166
172
|
if matches!(heading.style, crate::lint_context::HeadingStyle::ATX)
|
|
167
|
-
&& heading.has_closing_sequence
|
|
168
173
|
&& self.is_closed_atx_heading_without_space(&line_info.content)
|
|
169
174
|
{
|
|
170
175
|
lines.push(self.fix_closed_atx_heading(&line_info.content));
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
use crate::rule_config_serde::RuleConfig;
|
|
2
2
|
use serde::{Deserialize, Serialize};
|
|
3
3
|
|
|
4
|
+
/// Default punctuation to check for MD026
|
|
5
|
+
/// Matches markdownlint's default: ".,;:!。,;:!"
|
|
6
|
+
/// We only include ASCII punctuation for now
|
|
7
|
+
pub const DEFAULT_PUNCTUATION: &str = ".,;:!";
|
|
8
|
+
|
|
4
9
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
5
10
|
pub struct MD026Config {
|
|
6
11
|
#[serde(default = "default_punctuation")]
|
|
@@ -16,7 +21,7 @@ impl Default for MD026Config {
|
|
|
16
21
|
}
|
|
17
22
|
|
|
18
23
|
fn default_punctuation() -> String {
|
|
19
|
-
|
|
24
|
+
DEFAULT_PUNCTUATION.to_string()
|
|
20
25
|
}
|
|
21
26
|
|
|
22
27
|
impl RuleConfig for MD026Config {
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
///
|
|
3
3
|
/// See [docs/md026.md](../../docs/md026.md) for full documentation, configuration, and examples.
|
|
4
4
|
use crate::rule::{Fix, LintError, LintResult, LintWarning, Rule, Severity};
|
|
5
|
-
use crate::utils::kramdown_utils::has_header_id;
|
|
6
5
|
use crate::utils::range_utils::calculate_match_range;
|
|
7
6
|
use lazy_static::lazy_static;
|
|
8
7
|
use regex::Regex;
|
|
@@ -11,14 +10,14 @@ use std::ops::Range;
|
|
|
11
10
|
use std::sync::RwLock;
|
|
12
11
|
|
|
13
12
|
mod md026_config;
|
|
14
|
-
use md026_config::MD026Config;
|
|
13
|
+
use md026_config::{DEFAULT_PUNCTUATION, MD026Config};
|
|
15
14
|
|
|
16
15
|
lazy_static! {
|
|
17
16
|
// Optimized single regex for all ATX heading types (normal, closed, indented 1-3 spaces)
|
|
18
17
|
static ref ATX_HEADING_UNIFIED: Regex = Regex::new(r"^( {0,3})(#{1,6})(\s+)(.+?)(\s+#{1,6})?$").unwrap();
|
|
19
18
|
|
|
20
|
-
// Fast check patterns for early returns -
|
|
21
|
-
static ref QUICK_PUNCTUATION_CHECK: Regex = Regex::new(r"[
|
|
19
|
+
// Fast check patterns for early returns - match defaults
|
|
20
|
+
static ref QUICK_PUNCTUATION_CHECK: Regex = Regex::new(&format!(r"[{}]", regex::escape(DEFAULT_PUNCTUATION))).unwrap();
|
|
22
21
|
|
|
23
22
|
// Regex cache for punctuation patterns
|
|
24
23
|
static ref PUNCTUATION_REGEX_CACHE: RwLock<HashMap<String, Regex>> = RwLock::new(HashMap::new());
|
|
@@ -34,7 +33,7 @@ impl MD026NoTrailingPunctuation {
|
|
|
34
33
|
pub fn new(punctuation: Option<String>) -> Self {
|
|
35
34
|
Self {
|
|
36
35
|
config: MD026Config {
|
|
37
|
-
punctuation: punctuation.unwrap_or_else(||
|
|
36
|
+
punctuation: punctuation.unwrap_or_else(|| DEFAULT_PUNCTUATION.to_string()),
|
|
38
37
|
},
|
|
39
38
|
}
|
|
40
39
|
}
|
|
@@ -68,16 +67,6 @@ impl MD026NoTrailingPunctuation {
|
|
|
68
67
|
#[inline]
|
|
69
68
|
fn has_trailing_punctuation(&self, text: &str, re: &Regex) -> bool {
|
|
70
69
|
let trimmed = text.trim();
|
|
71
|
-
|
|
72
|
-
// Only apply lenient rules for the default punctuation setting
|
|
73
|
-
// When users specify custom punctuation, they want strict behavior
|
|
74
|
-
if self.config.punctuation == ".,;" {
|
|
75
|
-
// Check for common legitimate punctuation patterns before applying the rule
|
|
76
|
-
if self.is_legitimate_punctuation(trimmed) {
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
70
|
re.is_match(trimmed)
|
|
82
71
|
}
|
|
83
72
|
|
|
@@ -102,85 +91,6 @@ impl MD026NoTrailingPunctuation {
|
|
|
102
91
|
}
|
|
103
92
|
}
|
|
104
93
|
|
|
105
|
-
/// Check if punctuation in a heading is legitimate and should be allowed
|
|
106
|
-
#[inline]
|
|
107
|
-
fn is_legitimate_punctuation(&self, text: &str) -> bool {
|
|
108
|
-
let text = text.trim();
|
|
109
|
-
|
|
110
|
-
// Allow question marks in question headings
|
|
111
|
-
if text.ends_with('?') {
|
|
112
|
-
// Check if it's likely a genuine question
|
|
113
|
-
let question_words = [
|
|
114
|
-
"what", "why", "how", "when", "where", "who", "which", "can", "should", "would", "could", "is", "are",
|
|
115
|
-
"do", "does", "did",
|
|
116
|
-
];
|
|
117
|
-
let lower_text = text.to_lowercase();
|
|
118
|
-
if question_words.iter().any(|&word| lower_text.starts_with(word)) {
|
|
119
|
-
return true;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Allow colons in common categorical/labeling patterns
|
|
124
|
-
if text.ends_with(':') {
|
|
125
|
-
// Common patterns that legitimately use colons
|
|
126
|
-
let colon_patterns = [
|
|
127
|
-
"faq",
|
|
128
|
-
"api",
|
|
129
|
-
"note",
|
|
130
|
-
"warning",
|
|
131
|
-
"error",
|
|
132
|
-
"info",
|
|
133
|
-
"tip",
|
|
134
|
-
"chapter",
|
|
135
|
-
"step",
|
|
136
|
-
"version",
|
|
137
|
-
"part",
|
|
138
|
-
"section",
|
|
139
|
-
"method",
|
|
140
|
-
"function",
|
|
141
|
-
"class",
|
|
142
|
-
"module",
|
|
143
|
-
"reference",
|
|
144
|
-
"guide",
|
|
145
|
-
"tutorial",
|
|
146
|
-
"example",
|
|
147
|
-
"demo",
|
|
148
|
-
"usage",
|
|
149
|
-
"syntax",
|
|
150
|
-
];
|
|
151
|
-
|
|
152
|
-
let lower_text = text.to_lowercase();
|
|
153
|
-
|
|
154
|
-
// Check if it starts with any of these patterns
|
|
155
|
-
if colon_patterns.iter().any(|&pattern| lower_text.starts_with(pattern)) {
|
|
156
|
-
return true;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Check for numbered items like "Step 1:", "Chapter 2:", "Version 1.0:"
|
|
160
|
-
if regex::Regex::new(r"^(step|chapter|part|section|version)\s*\d")
|
|
161
|
-
.unwrap()
|
|
162
|
-
.is_match(&lower_text)
|
|
163
|
-
{
|
|
164
|
-
return true;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Allow exclamation marks in specific contexts (less common, but sometimes legitimate)
|
|
169
|
-
if text.ends_with('!') {
|
|
170
|
-
// Only allow for very specific patterns like "Important!", "New!", "Warning!"
|
|
171
|
-
let exclamation_patterns = ["important", "new", "warning", "alert", "notice", "attention"];
|
|
172
|
-
let lower_text = text.to_lowercase();
|
|
173
|
-
if exclamation_patterns
|
|
174
|
-
.iter()
|
|
175
|
-
.any(|&pattern| lower_text.starts_with(pattern))
|
|
176
|
-
{
|
|
177
|
-
return true;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
false
|
|
182
|
-
}
|
|
183
|
-
|
|
184
94
|
// Remove trailing punctuation from text
|
|
185
95
|
#[inline]
|
|
186
96
|
fn remove_trailing_punctuation(&self, text: &str, re: &Regex) -> String {
|
|
@@ -196,17 +106,18 @@ impl MD026NoTrailingPunctuation {
|
|
|
196
106
|
let space = captures.get(3).unwrap().as_str();
|
|
197
107
|
let content = captures.get(4).unwrap().as_str();
|
|
198
108
|
|
|
199
|
-
//
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
109
|
+
// Check if content ends with a custom header ID like {#my-id}
|
|
110
|
+
// If so, we need to fix punctuation before the ID
|
|
111
|
+
let fixed_content = if let Some(id_pos) = content.rfind(" {#") {
|
|
112
|
+
// Has a custom ID - fix punctuation before it
|
|
113
|
+
let before_id = &content[..id_pos];
|
|
114
|
+
let id_part = &content[id_pos..];
|
|
115
|
+
let fixed_before = self.remove_trailing_punctuation(before_id, re);
|
|
116
|
+
format!("{fixed_before}{id_part}")
|
|
117
|
+
} else {
|
|
118
|
+
// No custom ID - just remove trailing punctuation
|
|
119
|
+
self.remove_trailing_punctuation(content, re)
|
|
120
|
+
};
|
|
210
121
|
|
|
211
122
|
// Preserve any trailing hashes if present
|
|
212
123
|
if let Some(trailing) = captures.get(5) {
|
|
@@ -276,7 +187,7 @@ impl Rule for MD026NoTrailingPunctuation {
|
|
|
276
187
|
|
|
277
188
|
// Quick check for any punctuation we care about
|
|
278
189
|
// For custom punctuation, we need to check differently
|
|
279
|
-
if self.config.punctuation ==
|
|
190
|
+
if self.config.punctuation == DEFAULT_PUNCTUATION {
|
|
280
191
|
if !QUICK_PUNCTUATION_CHECK.is_match(content) {
|
|
281
192
|
return Ok(Vec::new());
|
|
282
193
|
}
|
|
@@ -308,22 +219,10 @@ impl Rule for MD026NoTrailingPunctuation {
|
|
|
308
219
|
continue;
|
|
309
220
|
}
|
|
310
221
|
|
|
311
|
-
//
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
} else if heading.text.contains("{") && heading.text.trim().ends_with("}") {
|
|
316
|
-
// Has curly braces but not a valid Kramdown ID
|
|
317
|
-
// Check for punctuation before the opening brace
|
|
318
|
-
if let Some(brace_pos) = heading.text.rfind('{') {
|
|
319
|
-
heading.text[..brace_pos].trim().to_string()
|
|
320
|
-
} else {
|
|
321
|
-
heading.text.clone()
|
|
322
|
-
}
|
|
323
|
-
} else {
|
|
324
|
-
// Regular header without Kramdown syntax
|
|
325
|
-
heading.text.clone()
|
|
326
|
-
};
|
|
222
|
+
// LintContext already strips Kramdown IDs from heading.text
|
|
223
|
+
// So we just check the heading text directly for trailing punctuation
|
|
224
|
+
// This correctly flags "# Heading." even if it has {#id}
|
|
225
|
+
let text_to_check = heading.text.clone();
|
|
327
226
|
|
|
328
227
|
if self.has_trailing_punctuation(&text_to_check, &re) {
|
|
329
228
|
// Find the trailing punctuation
|
|
@@ -379,7 +278,7 @@ impl Rule for MD026NoTrailingPunctuation {
|
|
|
379
278
|
|
|
380
279
|
// Quick check for punctuation
|
|
381
280
|
// For custom punctuation, we need to check differently
|
|
382
|
-
if self.config.punctuation ==
|
|
281
|
+
if self.config.punctuation == DEFAULT_PUNCTUATION {
|
|
383
282
|
if !QUICK_PUNCTUATION_CHECK.is_match(content) {
|
|
384
283
|
return Ok(content.to_string());
|
|
385
284
|
}
|
|
@@ -413,22 +312,9 @@ impl Rule for MD026NoTrailingPunctuation {
|
|
|
413
312
|
continue;
|
|
414
313
|
}
|
|
415
314
|
|
|
416
|
-
//
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
continue;
|
|
420
|
-
} else if heading.text.contains("{") && heading.text.trim().ends_with("}") {
|
|
421
|
-
// Has curly braces but not a valid Kramdown ID
|
|
422
|
-
// Check for punctuation before the opening brace
|
|
423
|
-
if let Some(brace_pos) = heading.text.rfind('{') {
|
|
424
|
-
heading.text[..brace_pos].trim().to_string()
|
|
425
|
-
} else {
|
|
426
|
-
heading.text.clone()
|
|
427
|
-
}
|
|
428
|
-
} else {
|
|
429
|
-
// Regular header without Kramdown syntax
|
|
430
|
-
heading.text.clone()
|
|
431
|
-
};
|
|
315
|
+
// LintContext already strips custom header IDs from heading.text
|
|
316
|
+
// So we just check the heading text directly for trailing punctuation
|
|
317
|
+
let text_to_check = heading.text.clone();
|
|
432
318
|
|
|
433
319
|
// Check and fix trailing punctuation
|
|
434
320
|
if self.has_trailing_punctuation(&text_to_check, &re) {
|
|
@@ -544,26 +430,24 @@ mod tests {
|
|
|
544
430
|
}
|
|
545
431
|
|
|
546
432
|
#[test]
|
|
547
|
-
fn
|
|
433
|
+
fn test_question_marks_not_in_default() {
|
|
548
434
|
let rule = MD026NoTrailingPunctuation::new(None);
|
|
549
435
|
let content = "# What is Rust?\n# How does it work?\n# Is it fast?";
|
|
550
436
|
let ctx = LintContext::new(content);
|
|
551
437
|
let result = rule.check(&ctx).unwrap();
|
|
552
|
-
assert!(
|
|
553
|
-
result.is_empty(),
|
|
554
|
-
"Question marks in questions should be allowed by default"
|
|
555
|
-
);
|
|
438
|
+
assert!(result.is_empty(), "Question marks are not in default punctuation list");
|
|
556
439
|
}
|
|
557
440
|
|
|
558
441
|
#[test]
|
|
559
|
-
fn
|
|
442
|
+
fn test_colons_in_default() {
|
|
560
443
|
let rule = MD026NoTrailingPunctuation::new(None);
|
|
561
444
|
let content = "# FAQ:\n# API Reference:\n# Step 1:\n# Version 2.0:";
|
|
562
445
|
let ctx = LintContext::new(content);
|
|
563
446
|
let result = rule.check(&ctx).unwrap();
|
|
564
|
-
|
|
565
|
-
result.
|
|
566
|
-
|
|
447
|
+
assert_eq!(
|
|
448
|
+
result.len(),
|
|
449
|
+
4,
|
|
450
|
+
"Colons are in default punctuation list and should be flagged"
|
|
567
451
|
);
|
|
568
452
|
}
|
|
569
453
|
|
|
@@ -57,9 +57,6 @@ lazy_static! {
|
|
|
57
57
|
// Updated to support IPv6 addresses
|
|
58
58
|
static ref REFERENCE_DEF_RE: Regex = Regex::new(r"^\s*\[[^\]]+\]:\s*(?:https?|ftps?)://\S+$").unwrap();
|
|
59
59
|
|
|
60
|
-
// Pattern to match URLs inside HTML attributes (src, href, srcset, etc.)
|
|
61
|
-
static ref HTML_ATTRIBUTE_URL: Regex = Regex::new(r#"(?:src|href|srcset|content|data-\w+)\s*=\s*["']([^"']*)["']"#).unwrap();
|
|
62
|
-
|
|
63
60
|
// Pattern to match HTML comments
|
|
64
61
|
static ref HTML_COMMENT_PATTERN: Regex = Regex::new(r#"<!--[\s\S]*?-->"#).unwrap();
|
|
65
62
|
}
|
|
@@ -114,14 +111,18 @@ impl MD034NoBareUrls {
|
|
|
114
111
|
// First, find all markdown link ranges across the entire content
|
|
115
112
|
let mut excluded_ranges: Vec<(usize, usize)> = Vec::new();
|
|
116
113
|
|
|
117
|
-
// Markdown links: [text](url) -
|
|
114
|
+
// Markdown links: [text](url) - exclude both destination and entire link text
|
|
118
115
|
for cap in MARKDOWN_LINK_PATTERN.captures_iter(content) {
|
|
119
116
|
if let Some(dest) = cap.get(1) {
|
|
120
117
|
excluded_ranges.push((dest.start(), dest.end()));
|
|
121
118
|
}
|
|
119
|
+
// Also exclude the entire link to handle URLs in link text
|
|
120
|
+
if let Some(full_match) = cap.get(0) {
|
|
121
|
+
excluded_ranges.push((full_match.start(), full_match.end()));
|
|
122
|
+
}
|
|
122
123
|
}
|
|
123
124
|
|
|
124
|
-
// Markdown images: 
|
|
125
|
+
// Markdown images: 
|
|
125
126
|
for cap in MARKDOWN_IMAGE_PATTERN.captures_iter(content) {
|
|
126
127
|
if let Some(dest) = cap.get(2) {
|
|
127
128
|
excluded_ranges.push((dest.start(), dest.end()));
|
|
@@ -135,11 +136,9 @@ impl MD034NoBareUrls {
|
|
|
135
136
|
}
|
|
136
137
|
}
|
|
137
138
|
|
|
138
|
-
// HTML
|
|
139
|
-
for
|
|
140
|
-
|
|
141
|
-
excluded_ranges.push((url_attr.start(), url_attr.end()));
|
|
142
|
-
}
|
|
139
|
+
// HTML tags: exclude everything inside them
|
|
140
|
+
for html_tag in ctx.html_tags().iter() {
|
|
141
|
+
excluded_ranges.push((html_tag.byte_offset, html_tag.byte_end));
|
|
143
142
|
}
|
|
144
143
|
|
|
145
144
|
// HTML comments: <!-- url -->
|