rumdl 0.0.118__tar.gz → 0.0.119__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.118 → rumdl-0.0.119}/CHANGELOG.md +18 -3
- {rumdl-0.0.118 → rumdl-0.0.119}/Cargo.lock +1 -1
- {rumdl-0.0.118 → rumdl-0.0.119}/Cargo.toml +2 -1
- {rumdl-0.0.118 → rumdl-0.0.119}/PKG-INFO +1 -1
- {rumdl-0.0.118 → rumdl-0.0.119}/src/lint_context.rs +26 -2
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md007_ul_indent.rs +1 -25
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md051_link_fragments.rs +194 -150
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md057_existing_relative_links.rs +0 -13
- {rumdl-0.0.118 → rumdl-0.0.119}/src/utils/document_structure.rs +0 -8
- rumdl-0.0.119/src/utils/header_id_utils.rs +349 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/utils/kramdown_utils.rs +73 -156
- {rumdl-0.0.118 → rumdl-0.0.119}/src/utils/mod.rs +1 -0
- rumdl-0.0.119/tests/rules/md051_issue_39_regression_test.rs +232 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md051_test.rs +382 -25
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md051_unicode_test.rs +13 -14
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/mod.rs +1 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/.config/nextest.toml +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/.mise.toml +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/.pre-commit-config.yaml +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/.rumdl.toml +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/.rustfmt.toml +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/LICENSE +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/MANIFEST.in +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/Makefile +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/README.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/assets/logo.png +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/benches/fix_performance.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/benches/range_performance.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/benches/range_utils_benchmark.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/benches/rule_performance.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/benches/simple_fix_bench.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/benchmark/bin/bench_lint_context.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/benchmark/bin/benchmark.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/benchmark/bin/benchmark_rule.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/benchmark/bin/file_parallel_benchmark.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/benchmark/bin/measure_code_span_performance.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/RULES.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/global-settings.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md001.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md002.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md003.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md004.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md005.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md006.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md007.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md009.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md010.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md011.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md012.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md013.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md014.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md018.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md019.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md020.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md021.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md022.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md023.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md024.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md025.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md026.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md027.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md028.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md029.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md030.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md031.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md032.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md033.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md034.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md035.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md036.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md037.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md038.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md039.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md040.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md041.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md042.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md043.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md044.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md045.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md046.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md047.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md048.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md049.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md050.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md051.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md052.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md053.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md054.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md055.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md056.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md057.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/md058.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/docs/vscode-extension.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/parity_check.py +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/pyproject.toml +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/python/MANIFEST.in +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/python/PYTHON-README.md +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/python/rumdl/__init__.py +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/python/rumdl/__main__.py +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/python/rumdl/py.typed +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/rumdl.toml.example +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/rust-toolchain.toml +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/scripts/extract-changelog.sh +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/scripts/generate-downloads-table.sh +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/scripts/pre-release.sh +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/scripts/prepare-release.sh +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/scripts/setup-pre-commit.sh +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/scripts/update-pre-commit-docs.sh +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/exit_codes.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/inline_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/lib.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/lsp/mod.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/lsp/server.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/lsp/types.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/main.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/markdownlint_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/output/formatters/azure.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/output/formatters/concise.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/output/formatters/github.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/output/formatters/gitlab.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/output/formatters/grouped.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/output/formatters/json.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/output/formatters/json_lines.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/output/formatters/junit.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/output/formatters/mod.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/output/formatters/pylint.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/output/formatters/sarif.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/output/formatters/text.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/output/mod.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/parallel.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/performance.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/profiling.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/python.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rule.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rule_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rule_config_serde.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/blockquote_utils.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/code_block_utils.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/code_fence_utils.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/emphasis_style.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/front_matter_utils.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/heading_utils.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/list_utils.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md001_heading_increment.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md002_first_heading_h1/md002_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md002_first_heading_h1.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md003_heading_style/md003_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md003_heading_style.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md004_unordered_list_style/md004_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md004_unordered_list_style.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md005_list_indent.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md006_start_bullets.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md007_ul_indent/md007_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md009_trailing_spaces/md009_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md009_trailing_spaces.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md010_no_hard_tabs/md010_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md010_no_hard_tabs.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md011_no_reversed_links.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md012_no_multiple_blanks/md012_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md012_no_multiple_blanks.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md013_line_length/md013_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md013_line_length.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md014_commands_show_output/md014_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md014_commands_show_output.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md018_no_missing_space_atx.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md019_no_multiple_space_atx.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md020_no_missing_space_closed_atx.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md021_no_multiple_space_closed_atx.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md022_blanks_around_headings/md022_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md022_blanks_around_headings.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md023_heading_start_left.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md024_no_duplicate_heading/md024_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md024_no_duplicate_heading.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md025_single_title/md025_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md025_single_title.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md026_no_trailing_punctuation/md026_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md026_no_trailing_punctuation.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md027_multiple_spaces_blockquote.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md028_no_blanks_blockquote.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md029_ordered_list_prefix/md029_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md029_ordered_list_prefix.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md030_list_marker_space/md030_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md030_list_marker_space.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md031_blanks_around_fences.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md032_blanks_around_lists.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md033_no_inline_html/md033_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md033_no_inline_html.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md034_no_bare_urls.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md035_hr_style/md035_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md035_hr_style.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md036_no_emphasis_only_first/md036_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md036_no_emphasis_only_first.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md037_spaces_around_emphasis.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md038_no_space_in_code.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md039_no_space_in_links.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md040_fenced_code_language.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md041_first_line_heading.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md042_no_empty_links.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md043_required_headings.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md044_proper_names/md044_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md044_proper_names.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md045_no_alt_text/md045_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md045_no_alt_text.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md046_code_block_style/md046_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md046_code_block_style.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md047_single_trailing_newline.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md048_code_fence_style/md048_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md048_code_fence_style.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md049_emphasis_style/md049_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md049_emphasis_style.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md050_strong_style/md050_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md050_strong_style.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md052_reference_links_images.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md053_link_image_reference_definitions.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md054_link_image_style/md054_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md054_link_image_style.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md055_table_pipe_style/md055_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md055_table_pipe_style.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md056_table_column_count.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md057_existing_relative_links/md057_config.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/md058_blanks_around_tables.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/mod.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/rules/strong_style.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/utils/ast_utils.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/utils/code_block_utils.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/utils/early_returns.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/utils/element_cache.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/utils/emphasis_utils.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/utils/fix_utils.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/utils/markdown_elements.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/utils/range_utils.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/utils/regex_cache.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/utils/skip_context.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/utils/string_interner.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/utils/table_utils.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/utils/text_reflow.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/src/vscode.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/advanced_integration_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/character_ranges/additional_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/character_ranges/basic_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/character_ranges/comprehensive_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/character_ranges/extended_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/character_ranges/mod.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/character_ranges/unicode_utils.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/cli_duplication_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/cli_explain_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/cli_flag_precedence_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/cli_integration_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/cli_lsp_fix_consistency.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/cli_statistics_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/common/cli_test_utils.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/common/fixtures.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/common/mod.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/common/test_utils.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/commonmark_compliance_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/comprehensive_integration_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/comprehensive_output_format_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/config_application_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/config_file_command_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/config_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/configuration_inheritance_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/consistency_regression_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/cross_platform_compatibility_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/deeply_nested_lists_performance_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/escaped_brackets_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/final_confidence_assessment.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/fixable_unfixable_config_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/init_command_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/init_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/inline_config_blocks_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/inline_config_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/integration_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/json_output_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/kramdown_integration_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/lib.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/lsp_editor_integration_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/lsp_integration_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/lsp_memory_leak_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/lsp_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/malformed_markdown_stress_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/markdownlint_cli_integration.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/markdownlint_config_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/markdownlintignore_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/md013_reflow_integration_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/nested_code_block_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/output_format_integration_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/output_format_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/perf_check.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/performance_validation_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/pyproject_config_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/python_bindings_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/real_world_repository_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/regression_prevention_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/emphasis_edge_cases_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/heading_edge_cases_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/inline_content_edge_cases_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/link_edge_cases_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/list_rules_integration_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md001_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md001_unicode_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md002_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md003_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md004_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md005_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md005_unicode_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md006_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md006_unicode_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md007_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md009_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md010_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md011_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md012_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md013_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md014_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md018_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md019_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md020_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md021_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md022_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md023_extended_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md023_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md024_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md025_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md026_kramdown_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md026_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md027_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md028_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md029_issue42_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md029_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md029_unicode_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md030_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md031_kramdown_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md031_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md032_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md033_extended_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md033_kramdown_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md033_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md034_ipv6_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md034_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md035_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md036_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md037_kramdown_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md037_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md038_nested_backticks_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md038_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md039_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md040_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md041_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md042_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md043_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md044_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md045_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md046_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md047_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md048_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md049_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md050_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md052_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md053_additional_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md053_proptest.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md053_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md054_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md054_unicode_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md055_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md056_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md057_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md058_kramdown_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules/md058_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/rules_mod_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/skip_context_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/thread_safety_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/unicode_edge_case_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/utils/blockquote_utils_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/utils/code_block_utils_extended_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/utils/code_block_utils_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/utils/core_utils_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/utils/front_matter_utils_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/utils/line_index_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/utils/mod.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/utils_markdown_edge_cases.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/utils_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/vscode_extension_fixes.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/vscode_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/vscode_tests.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/tests/vscode_windows_comprehensive_test.rs +0 -0
- {rumdl-0.0.118 → rumdl-0.0.119}/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.119] - 2025-08-15
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **MD051**: Fixed GitHub anchor generation algorithm to correctly handle consecutive spaces
|
|
14
|
+
- "Test & Heading!" now correctly generates "test--heading" instead of "test-heading"
|
|
15
|
+
- Improved compliance with GitHub's official anchor generation behavior
|
|
16
|
+
- Fixed whitespace normalization bug that was collapsing multiple spaces to single spaces
|
|
17
|
+
|
|
18
|
+
### Improved
|
|
19
|
+
- **Code Quality**: Removed all `#[allow(dead_code)]` violations in codebase
|
|
20
|
+
- Removed unused `InternalCodeBlockState` enum from document_structure.rs
|
|
21
|
+
- Removed unused `extract_url_from_link` function from md057_existing_relative_links.rs
|
|
22
|
+
- Removed unused `is_in_code_block` function from md007_ul_indent.rs
|
|
23
|
+
|
|
10
24
|
## [0.0.118] - 2025-08-14
|
|
11
25
|
|
|
12
26
|
## [0.0.117] - 2025-08-14
|
|
@@ -124,7 +138,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
124
138
|
## [0.0.99] - 2025-07-22
|
|
125
139
|
|
|
126
140
|
### Fixed
|
|
127
|
-
- MD034: Added support for `ftps://` URLs
|
|
141
|
+
- MD034: Added support for `ftps://` URLs
|
|
128
142
|
- MD034: Fixed detection of URLs in HTML comments (now properly ignored)
|
|
129
143
|
- MD039: Fixed escaped character handling in link text
|
|
130
144
|
- MD044: Fixed clippy warnings and improved pattern matching for proper names
|
|
@@ -202,7 +216,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
202
216
|
### Performance Improvements
|
|
203
217
|
- Implemented lazy code span loading - 3.8x speedup for 94% of rules that don't use code spans
|
|
204
218
|
- MD013: 34.5% faster check operations through aggressive early returns
|
|
205
|
-
- MD038: 14% faster by leveraging lazy code span loading
|
|
219
|
+
- MD038: 14% faster by leveraging lazy code span loading
|
|
206
220
|
- MD044: 93.5% faster with global regex caching
|
|
207
221
|
- MD047: 8.3% faster using pre-computed line data
|
|
208
222
|
- MD053: 39.7% faster by leveraging pre-parsed reference definitions
|
|
@@ -337,7 +351,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
337
351
|
|
|
338
352
|
- Initial implementation of remaining rules for markdownlint parity
|
|
339
353
|
|
|
340
|
-
[Unreleased]: https://github.com/rvben/rumdl/compare/v0.0.
|
|
354
|
+
[Unreleased]: https://github.com/rvben/rumdl/compare/v0.0.119...HEAD
|
|
355
|
+
[0.0.119]: https://github.com/rvben/rumdl/compare/v0.0.118...v0.0.119
|
|
341
356
|
[0.0.118]: https://github.com/rvben/rumdl/compare/v0.0.117...v0.0.118
|
|
342
357
|
[0.0.117]: https://github.com/rvben/rumdl/compare/v0.0.116...v0.0.117
|
|
343
358
|
[0.0.116]: https://github.com/rvben/rumdl/compare/v0.0.115...v0.0.116
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "rumdl"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.119"
|
|
4
4
|
edition = "2024"
|
|
5
5
|
rust-version = "1.89.0"
|
|
6
6
|
description = "A fast Markdown linter written in Rust (Ru(st) MarkDown Linter)"
|
|
@@ -24,6 +24,7 @@ crate-type = ["cdylib", "rlib"]
|
|
|
24
24
|
name = "rumdl"
|
|
25
25
|
path = "src/main.rs"
|
|
26
26
|
|
|
27
|
+
|
|
27
28
|
# Benchmark binaries - only built when explicitly requested
|
|
28
29
|
[[bin]]
|
|
29
30
|
name = "benchmark"
|
|
@@ -1154,7 +1154,19 @@ impl<'a> LintContext<'a> {
|
|
|
1154
1154
|
|
|
1155
1155
|
// Extract custom header ID if present
|
|
1156
1156
|
let raw_text = text.trim().to_string();
|
|
1157
|
-
let (clean_text, custom_id) = crate::utils::
|
|
1157
|
+
let (clean_text, mut custom_id) = crate::utils::header_id_utils::extract_header_id(&raw_text);
|
|
1158
|
+
|
|
1159
|
+
// If no custom ID was found on the header line, check the next line for standalone attr-list
|
|
1160
|
+
if custom_id.is_none() && i + 1 < content_lines.len() && i + 1 < lines.len() {
|
|
1161
|
+
let next_line = content_lines[i + 1];
|
|
1162
|
+
if !lines[i + 1].in_code_block
|
|
1163
|
+
&& crate::utils::header_id_utils::is_standalone_attr_list(next_line)
|
|
1164
|
+
&& let Some(next_line_id) =
|
|
1165
|
+
crate::utils::header_id_utils::extract_standalone_attr_list_id(next_line)
|
|
1166
|
+
{
|
|
1167
|
+
custom_id = Some(next_line_id);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1158
1170
|
|
|
1159
1171
|
lines[i].heading = Some(HeadingInfo {
|
|
1160
1172
|
level,
|
|
@@ -1188,7 +1200,19 @@ impl<'a> LintContext<'a> {
|
|
|
1188
1200
|
|
|
1189
1201
|
// Extract custom header ID if present
|
|
1190
1202
|
let raw_text = line.trim().to_string();
|
|
1191
|
-
let (clean_text, custom_id) = crate::utils::
|
|
1203
|
+
let (clean_text, mut custom_id) = crate::utils::header_id_utils::extract_header_id(&raw_text);
|
|
1204
|
+
|
|
1205
|
+
// If no custom ID was found on the header line, check the line after underline for standalone attr-list
|
|
1206
|
+
if custom_id.is_none() && i + 2 < content_lines.len() && i + 2 < lines.len() {
|
|
1207
|
+
let attr_line = content_lines[i + 2];
|
|
1208
|
+
if !lines[i + 2].in_code_block
|
|
1209
|
+
&& crate::utils::header_id_utils::is_standalone_attr_list(attr_line)
|
|
1210
|
+
&& let Some(attr_line_id) =
|
|
1211
|
+
crate::utils::header_id_utils::extract_standalone_attr_list_id(attr_line)
|
|
1212
|
+
{
|
|
1213
|
+
custom_id = Some(attr_line_id);
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1192
1216
|
|
|
1193
1217
|
lines[i].heading = Some(HeadingInfo {
|
|
1194
1218
|
level,
|
|
@@ -5,7 +5,7 @@ use crate::rule::{LintError, LintResult, LintWarning, Rule, RuleCategory, Severi
|
|
|
5
5
|
use crate::rule_config_serde::RuleConfig;
|
|
6
6
|
use crate::utils::document_structure::{DocumentStructure, DocumentStructureExtensions};
|
|
7
7
|
use crate::utils::element_cache::{ElementCache, ListMarkerType};
|
|
8
|
-
use crate::utils::regex_cache::
|
|
8
|
+
use crate::utils::regex_cache::UNORDERED_LIST_MARKER_REGEX;
|
|
9
9
|
use toml;
|
|
10
10
|
|
|
11
11
|
mod md007_config;
|
|
@@ -69,30 +69,6 @@ impl MD007ULIndent {
|
|
|
69
69
|
}
|
|
70
70
|
(false, None)
|
|
71
71
|
}
|
|
72
|
-
|
|
73
|
-
#[allow(dead_code)]
|
|
74
|
-
fn is_in_code_block(content: &str, line_idx: usize) -> bool {
|
|
75
|
-
// Use centralized code fence pattern
|
|
76
|
-
|
|
77
|
-
let lines: Vec<&str> = content.lines().collect();
|
|
78
|
-
let mut in_code_block = false;
|
|
79
|
-
|
|
80
|
-
for (i, line) in lines.iter().enumerate() {
|
|
81
|
-
if i > line_idx {
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if CODE_FENCE_REGEX.is_match(line.trim_start()) {
|
|
86
|
-
in_code_block = !in_code_block;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if i == line_idx {
|
|
90
|
-
return in_code_block;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
false
|
|
95
|
-
}
|
|
96
72
|
}
|
|
97
73
|
|
|
98
74
|
impl Rule for MD007ULIndent {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
use crate::rule::{LintError, LintResult, LintWarning, Rule, Severity};
|
|
2
|
+
use crate::utils::kramdown_utils;
|
|
2
3
|
use crate::utils::regex_cache::get_cached_regex;
|
|
3
4
|
use lazy_static::lazy_static;
|
|
4
5
|
use regex::Regex;
|
|
@@ -7,10 +8,10 @@ use std::collections::HashSet;
|
|
|
7
8
|
lazy_static! {
|
|
8
9
|
// Pre-compiled optimized patterns for quick checks
|
|
9
10
|
static ref QUICK_MARKDOWN_CHECK: Regex = Regex::new(r"[*_`\[\]]").unwrap();
|
|
10
|
-
//
|
|
11
|
-
static ref EMPHASIS_PATTERN: Regex = Regex::new(r"\*+([^*]+)
|
|
11
|
+
// GitHub only strips asterisks (*), not underscores (_) - underscores are preserved
|
|
12
|
+
static ref EMPHASIS_PATTERN: Regex = Regex::new(r"\*+([^*]+)\*+").unwrap();
|
|
12
13
|
static ref CODE_PATTERN: Regex = Regex::new(r"`([^`]+)`").unwrap();
|
|
13
|
-
static ref LINK_PATTERN: Regex = Regex::new(r"\[([^\]]+)\]\([^)]
|
|
14
|
+
static ref LINK_PATTERN: Regex = Regex::new(r"\[([^\]]+)\]\(([^)]+)\)|\[([^\]]+)\]\[[^\]]*\]").unwrap();
|
|
14
15
|
static ref TOC_SECTION_START: Regex = Regex::new(r"(?i)^#+\s*(table\s+of\s+contents?|contents?|toc)\s*$").unwrap();
|
|
15
16
|
}
|
|
16
17
|
|
|
@@ -123,7 +124,7 @@ impl MD051LinkFragments {
|
|
|
123
124
|
/// Fragment generation following GitHub's official algorithm
|
|
124
125
|
/// GitHub preserves most Unicode characters, underscores, and consecutive hyphens
|
|
125
126
|
#[inline]
|
|
126
|
-
fn heading_to_fragment_github(&self, heading: &str) -> String {
|
|
127
|
+
pub fn heading_to_fragment_github(&self, heading: &str) -> String {
|
|
127
128
|
if heading.is_empty() {
|
|
128
129
|
return String::new();
|
|
129
130
|
}
|
|
@@ -135,72 +136,36 @@ impl MD051LinkFragments {
|
|
|
135
136
|
heading.to_string()
|
|
136
137
|
};
|
|
137
138
|
|
|
138
|
-
//
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
// Follow GitHub's actual algorithm (verified with github-slugger)
|
|
142
|
-
// GitHub PRESERVES most Unicode characters including:
|
|
143
|
-
// - Accented Latin (café, résumé, über)
|
|
144
|
-
// - Chinese, Japanese, Korean
|
|
145
|
-
// - Arabic, Hebrew
|
|
146
|
-
// - Greek, Cyrillic
|
|
147
|
-
// - Hindi and other scripts
|
|
148
|
-
// It only removes emoji and certain punctuation
|
|
149
|
-
let mut fragment = String::with_capacity(text.len());
|
|
150
|
-
let mut last_was_space = false;
|
|
151
|
-
|
|
152
|
-
for c in text.to_lowercase().chars() {
|
|
153
|
-
// Check if character should be kept
|
|
154
|
-
if Self::is_valid_github_char(c) {
|
|
155
|
-
fragment.push(c);
|
|
156
|
-
last_was_space = false;
|
|
157
|
-
} else if c == '-' {
|
|
158
|
-
// Always preserve hyphens
|
|
159
|
-
fragment.push('-');
|
|
160
|
-
last_was_space = false;
|
|
161
|
-
} else if c.is_whitespace() {
|
|
162
|
-
// Convert whitespace to hyphens, but avoid consecutive spaces becoming multiple hyphens
|
|
163
|
-
if !last_was_space {
|
|
164
|
-
fragment.push('-');
|
|
165
|
-
last_was_space = true;
|
|
166
|
-
}
|
|
167
|
-
} else {
|
|
168
|
-
// Skip emoji, symbols, etc.
|
|
169
|
-
// If the last character we added was not a hyphen, and this character
|
|
170
|
-
// is skipped (like emoji), we might need to add a hyphen if the next
|
|
171
|
-
// character is not whitespace. For now, just skip it.
|
|
172
|
-
// This handles cases like "A🎉B" → "a-b" but we don't implement that complexity yet.
|
|
173
|
-
}
|
|
174
|
-
}
|
|
139
|
+
// NOTE: GitHub does NOT trim whitespace - it preserves leading/trailing spaces
|
|
140
|
+
// and converts them to hyphens. This matches the official github-slugger behavior.
|
|
175
141
|
|
|
176
|
-
//
|
|
177
|
-
|
|
178
|
-
|
|
142
|
+
// GitHub's EXACT algorithm from github-slugger npm package:
|
|
143
|
+
// function slug(value, maintainCase) {
|
|
144
|
+
// if (typeof value !== 'string') return ''
|
|
145
|
+
// if (!maintainCase) value = value.toLowerCase()
|
|
146
|
+
// return value.replace(regex, '').replace(/ /g, '-')
|
|
147
|
+
// }
|
|
179
148
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
'\u{2000}'..='\u{206F}' | // General punctuation
|
|
189
|
-
|
|
190
|
-
'\u{3000}'..='\u{303F}' | // CJK symbols and punctuation (but keep CJK letters)
|
|
191
|
-
'\u{FE00}'..='\u{FE0F}' // Variation selectors
|
|
192
|
-
) {
|
|
193
|
-
return false;
|
|
194
|
-
}
|
|
149
|
+
// 1. Convert to lowercase (maintainCase = false)
|
|
150
|
+
let text = text.to_lowercase();
|
|
151
|
+
|
|
152
|
+
// 2. Apply GitHub's exact regex pattern to remove punctuation/symbols
|
|
153
|
+
// This is the EXACT regex from github-slugger/regex.js
|
|
154
|
+
// Note: In Rust, we need to use \u{} syntax for Unicode above \uFFFF
|
|
155
|
+
// The original JavaScript regex includes surrogate pairs that we convert to direct Unicode ranges
|
|
156
|
+
let github_regex = get_cached_regex(
|
|
157
|
+
r"[\x00-\x1F!-,\./:-@\[-\^`\{-\xA9\xAB-\xB4\xB6-\xB9\xBB-\xBF\xD7\xF7\u{02C2}-\u{02C5}\u{02D2}-\u{02DF}\u{02E5}-\u{02EB}\u{02ED}\u{02EF}-\u{02FF}\u{0375}\u{0378}\u{0379}\u{037E}\u{0380}-\u{0385}\u{0387}\u{038B}\u{038D}\u{03A2}\u{03F6}\u{0482}\u{0530}\u{0557}\u{0558}\u{055A}-\u{055F}\u{0589}-\u{0590}\u{05BE}\u{05C0}\u{05C3}\u{05C6}\u{05C8}-\u{05CF}\u{05EB}-\u{05EE}\u{05F3}-\u{060F}\u{061B}-\u{061F}\u{066A}-\u{066D}\u{06D4}\u{06DD}\u{06DE}\u{06E9}\u{06FD}\u{06FE}\u{0700}-\u{070F}\u{074B}\u{074C}\u{07B2}-\u{07BF}\u{07F6}-\u{07F9}\u{07FB}\u{07FC}\u{07FE}\u{07FF}\u{082E}-\u{083F}\u{085C}-\u{085F}\u{086B}-\u{089F}\u{08B5}\u{08C8}-\u{08D2}\u{08E2}\u{0964}\u{0965}\u{0970}\u{0984}\u{098D}\u{098E}\u{0991}\u{0992}\u{09A9}\u{09B1}\u{09B3}-\u{09B5}\u{09BA}\u{09BB}\u{09C5}\u{09C6}\u{09C9}\u{09CA}\u{09CF}-\u{09D6}\u{09D8}-\u{09DB}\u{09DE}\u{09E4}\u{09E5}\u{09F2}-\u{09FB}\u{09FD}\u{09FF}\u{0A00}\u{0A04}\u{0A0B}-\u{0A0E}\u{0A11}\u{0A12}\u{0A29}\u{0A31}\u{0A34}\u{0A37}\u{0A3A}\u{0A3B}\u{0A3D}\u{0A43}-\u{0A46}\u{0A49}\u{0A4A}\u{0A4E}-\u{0A50}\u{0A52}-\u{0A58}\u{0A5D}\u{0A5F}-\u{0A65}\u{0A76}-\u{0A80}\u{0A84}\u{0A8E}\u{0A92}\u{0AA9}\u{0AB1}\u{0AB4}\u{0ABA}\u{0ABB}\u{0AC6}\u{0ACA}\u{0ACE}\u{0ACF}\u{0AD1}-\u{0ADF}\u{0AE4}\u{0AE5}\u{0AF0}-\u{0AF8}\u{0B00}\u{0B04}\u{0B0D}\u{0B0E}\u{0B11}\u{0B12}\u{0B29}\u{0B31}\u{0B34}\u{0B3A}\u{0B3B}\u{0B45}\u{0B46}\u{0B49}\u{0B4A}\u{0B4E}-\u{0B54}\u{0B58}-\u{0B5B}\u{0B5E}\u{0B64}\u{0B65}\u{0B70}\u{0B72}-\u{0B81}\u{0B84}\u{0B8B}-\u{0B8D}\u{0B91}\u{0B96}-\u{0B98}\u{0B9B}\u{0B9D}\u{0BA0}-\u{0BA2}\u{0BA5}-\u{0BA7}\u{0BAB}-\u{0BAD}\u{0BBA}-\u{0BBD}\u{0BC3}-\u{0BC5}\u{0BC9}\u{0BCE}\u{0BCF}\u{0BD1}-\u{0BD6}\u{0BD8}-\u{0BE5}\u{0BF0}-\u{0BFF}\u{0C0D}\u{0C11}\u{0C29}\u{0C3A}-\u{0C3C}\u{0C45}\u{0C49}\u{0C4E}-\u{0C54}\u{0C57}\u{0C5B}-\u{0C5F}\u{0C64}\u{0C65}\u{0C70}-\u{0C7F}\u{0C84}\u{0C8D}\u{0C91}\u{0CA9}\u{0CB4}\u{0CBA}\u{0CBB}\u{0CC5}\u{0CC9}\u{0CCE}-\u{0CD4}\u{0CD7}-\u{0CDD}\u{0CDF}\u{0CE4}\u{0CE5}\u{0CF0}\u{0CF3}-\u{0CFF}\u{0D0D}\u{0D11}\u{0D45}\u{0D49}\u{0D4F}-\u{0D53}\u{0D58}-\u{0D5E}\u{0D64}\u{0D65}\u{0D70}-\u{0D79}\u{0D80}\u{0D84}\u{0D97}-\u{0D99}\u{0DB2}\u{0DBC}\u{0DBE}\u{0DBF}\u{0DC7}-\u{0DC9}\u{0DCB}-\u{0DCE}\u{0DD5}\u{0DD7}\u{0DE0}-\u{0DE5}\u{0DF0}\u{0DF1}\u{0DF4}-\u{0E00}\u{0E3B}-\u{0E3F}\u{0E4F}\u{0E5A}-\u{0E80}\u{0E83}\u{0E85}\u{0E8B}\u{0EA4}\u{0EA6}\u{0EBE}\u{0EBF}\u{0EC5}\u{0EC7}\u{0ECE}\u{0ECF}\u{0EDA}\u{0EDB}\u{0EE0}-\u{0EFF}\u{0F01}-\u{0F17}\u{0F1A}-\u{0F1F}\u{0F2A}-\u{0F34}\u{0F36}\u{0F38}\u{0F3A}-\u{0F3D}\u{0F48}\u{0F6D}-\u{0F70}\u{0F85}\u{0F98}\u{0FBD}-\u{0FC5}\u{0FC7}-\u{0FFF}\u{104A}-\u{104F}\u{109E}\u{109F}\u{10C6}\u{10C8}-\u{10CC}\u{10CE}\u{10CF}\u{10FB}\u{1249}\u{124E}\u{124F}\u{1257}\u{1259}\u{125E}\u{125F}\u{1289}\u{128E}\u{128F}\u{12B1}\u{12B6}\u{12B7}\u{12BF}\u{12C1}\u{12C6}\u{12C7}\u{12D7}\u{1311}\u{1316}\u{1317}\u{135B}\u{135C}\u{1360}-\u{137F}\u{1390}-\u{139F}\u{13F6}\u{13F7}\u{13FE}-\u{1400}\u{166D}\u{166E}\u{1680}\u{169B}-\u{169F}\u{16EB}-\u{16ED}\u{16F9}-\u{16FF}\u{170D}\u{1715}-\u{171F}\u{1735}-\u{173F}\u{1754}-\u{175F}\u{176D}\u{1771}\u{1774}-\u{177F}\u{17D4}-\u{17D6}\u{17D8}-\u{17DB}\u{17DE}\u{17DF}\u{17EA}-\u{180A}\u{180E}\u{180F}\u{181A}-\u{181F}\u{1879}-\u{187F}\u{18AB}-\u{18AF}\u{18F6}-\u{18FF}\u{191F}\u{192C}-\u{192F}\u{193C}-\u{1945}\u{196E}\u{196F}\u{1975}-\u{197F}\u{19AC}-\u{19AF}\u{19CA}-\u{19CF}\u{19DA}-\u{19FF}\u{1A1C}-\u{1A1F}\u{1A5F}\u{1A7D}\u{1A7E}\u{1A8A}-\u{1A8F}\u{1A9A}-\u{1AA6}\u{1AA8}-\u{1AAF}\u{1AC1}-\u{1AFF}\u{1B4C}-\u{1B4F}\u{1B5A}-\u{1B6A}\u{1B74}-\u{1B7F}\u{1BF4}-\u{1BFF}\u{1C38}-\u{1C3F}\u{1C4A}-\u{1C4C}\u{1C7E}\u{1C7F}\u{1C89}-\u{1C8F}\u{1CBB}\u{1CBC}\u{1CC0}-\u{1CCF}\u{1CD3}\u{1CFB}-\u{1CFF}\u{1DFA}\u{1F16}\u{1F17}\u{1F1E}\u{1F1F}\u{1F46}\u{1F47}\u{1F4E}\u{1F4F}\u{1F58}\u{1F5A}\u{1F5C}\u{1F5E}\u{1F7E}\u{1F7F}\u{1FB5}\u{1FBD}\u{1FBF}-\u{1FC1}\u{1FC5}\u{1FCD}-\u{1FCF}\u{1FD4}\u{1FD5}\u{1FDC}-\u{1FDF}\u{1FED}-\u{1FF1}\u{1FF5}\u{1FFD}-\u{203E}\u{2041}-\u{2053}\u{2055}-\u{2070}\u{2072}-\u{207E}\u{2080}-\u{208F}\u{209D}-\u{20CF}\u{20F1}-\u{2101}\u{2103}-\u{2106}\u{2108}\u{2109}\u{2114}\u{2116}-\u{2118}\u{211E}-\u{2123}\u{2125}\u{2127}\u{2129}\u{212E}\u{213A}\u{213B}\u{2140}-\u{2144}\u{214A}-\u{214D}\u{214F}-\u{215F}\u{2189}-\u{24B5}\u{24EA}-\u{2BFF}\u{2C2F}\u{2C5F}\u{2CE5}-\u{2CEA}\u{2CF4}-\u{2CFF}\u{2D26}\u{2D28}-\u{2D2C}\u{2D2E}\u{2D2F}\u{2D68}-\u{2D6E}\u{2D70}-\u{2D7E}\u{2D97}-\u{2D9F}\u{2DA7}\u{2DAF}\u{2DB7}\u{2DBF}\u{2DC7}\u{2DCF}\u{2DD7}\u{2DDF}\u{2E00}-\u{2E2E}\u{2E30}-\u{3004}\u{3008}-\u{3020}\u{3030}\u{3036}\u{3037}\u{303D}-\u{3040}\u{3097}\u{3098}\u{309B}\u{309C}\u{30A0}\u{30FB}\u{3100}-\u{3104}\u{3130}\u{318F}-\u{319F}\u{31C0}-\u{31EF}\u{3200}-\u{33FF}\u{4DC0}-\u{4DFF}\u{9FFD}-\u{9FFF}\u{A48D}-\u{A4CF}\u{A4FE}\u{A4FF}\u{A60D}-\u{A60F}\u{A62C}-\u{A63F}\u{A673}\u{A67E}\u{A6F2}-\u{A716}\u{A720}\u{A721}\u{A789}\u{A78A}\u{A7C0}\u{A7C1}\u{A7CB}-\u{A7F4}\u{A828}-\u{A82B}\u{A82D}-\u{A83F}\u{A874}-\u{A87F}\u{A8C6}-\u{A8CF}\u{A8DA}-\u{A8DF}\u{A8F8}-\u{A8FA}\u{A8FC}\u{A92E}\u{A92F}\u{A954}-\u{A95F}\u{A97D}-\u{A97F}\u{A9C1}-\u{A9CE}\u{A9DA}-\u{A9DF}\u{A9FF}\u{AA37}-\u{AA3F}\u{AA4E}\u{AA4F}\u{AA5A}-\u{AA5F}\u{AA77}-\u{AA79}\u{AAC3}-\u{AADA}\u{AADE}\u{AADF}\u{AAF0}\u{AAF1}\u{AAF7}-\u{AB00}\u{AB07}\u{AB08}\u{AB0F}\u{AB10}\u{AB17}-\u{AB1F}\u{AB27}\u{AB2F}\u{AB5B}\u{AB6A}-\u{AB6F}\u{ABEB}\u{ABEE}\u{ABEF}\u{ABFA}-\u{ABFF}\u{D7A4}-\u{D7AF}\u{D7C7}-\u{D7CA}\u{D7FC}-\u{D7FF}\u{E000}-\u{F8FF}\u{FA6E}\u{FA6F}\u{FADA}-\u{FAFF}\u{FB07}-\u{FB12}\u{FB18}-\u{FB1C}\u{FB29}\u{FB37}\u{FB3D}\u{FB3F}\u{FB42}\u{FB45}\u{FBB2}-\u{FBD2}\u{FD3E}-\u{FD4F}\u{FD90}\u{FD91}\u{FDC8}-\u{FDEF}\u{FDFC}-\u{FDFF}\u{FE10}-\u{FE1F}\u{FE30}-\u{FE32}\u{FE35}-\u{FE4C}\u{FE50}-\u{FE6F}\u{FE75}\u{FEFD}-\u{FF0F}\u{FF1A}-\u{FF20}\u{FF3B}-\u{FF3E}\u{FF40}\u{FF5B}-\u{FF65}\u{FFBF}-\u{FFC1}\u{FFC8}\u{FFC9}\u{FFD0}\u{FFD1}\u{FFD8}\u{FFD9}\u{FFDD}-\u{FFFF}\u{1000C}\u{10027}\u{1003B}\u{1003E}\u{1004E}\u{1004F}\u{1005E}-\u{1007F}\u{100FB}-\u{1013F}\u{10175}-\u{101FC}\u{101FE}-\u{1027F}\u{1029D}-\u{1029F}\u{102D1}-\u{102DF}\u{102E1}-\u{102FF}\u{10320}-\u{1032C}\u{1034B}-\u{1034F}\u{1037B}-\u{1037F}\u{1039E}\u{1039F}\u{103C4}-\u{103C7}\u{103D0}\u{103D6}-\u{103FF}\u{1049E}\u{1049F}\u{104AA}-\u{104AF}\u{104D4}-\u{104D7}\u{104FC}-\u{104FF}\u{10528}-\u{1052F}\u{10564}-\u{105FF}\u{10737}-\u{1073F}\u{10756}-\u{1075F}\u{10768}-\u{107FF}\u{10806}\u{10807}\u{10809}\u{10836}\u{10839}-\u{1083B}\u{1083D}\u{1083E}\u{10856}-\u{1085F}\u{10877}-\u{1087F}\u{1089F}-\u{108DF}\u{108F3}\u{108F6}-\u{108FF}\u{10916}-\u{1091F}\u{1093A}-\u{1097F}\u{109B8}-\u{109BD}\u{109C0}-\u{109FF}\u{10A04}\u{10A07}-\u{10A0B}\u{10A14}\u{10A18}\u{10A36}\u{10A37}\u{10A3B}-\u{10A3E}\u{10A40}-\u{10A5F}\u{10A7D}-\u{10A7F}\u{10A9D}-\u{10ABF}\u{10AC8}\u{10AE7}-\u{10AFF}\u{10B36}-\u{10B3F}\u{10B56}-\u{10B5F}\u{10B73}-\u{10B7F}\u{10B92}-\u{10BFF}\u{10C49}-\u{10C7F}\u{10CB3}-\u{10CBF}\u{10CF3}-\u{10CFF}\u{10D28}-\u{10D2F}\u{10D3A}-\u{10E7F}\u{10EAA}\u{10EAD}-\u{10EAF}\u{10EB2}-\u{10EFF}\u{10F1D}-\u{10F26}\u{10F28}-\u{10F2F}\u{10F51}-\u{10FAF}\u{10FC5}-\u{10FDF}\u{10FF7}-\u{10FFF}\u{11047}-\u{11065}\u{11070}-\u{1107E}\u{110BB}-\u{110CF}\u{110E9}-\u{110EF}\u{110FA}-\u{110FF}\u{11135}\u{11140}-\u{11143}\u{11148}-\u{1114F}\u{11174}\u{11175}\u{11177}-\u{1117F}\u{111C5}-\u{111C8}\u{111CD}\u{111DB}\u{111DD}-\u{111FF}\u{11212}\u{11238}-\u{1123D}\u{1123F}-\u{1127F}\u{11287}\u{11289}\u{1128E}\u{1129E}\u{112A9}-\u{112AF}\u{112EB}-\u{112EF}\u{112FA}-\u{112FF}\u{11304}\u{1130D}\u{1130E}\u{11311}\u{11312}\u{11329}\u{11331}\u{11334}\u{1133A}\u{11345}\u{11346}\u{11349}\u{1134A}\u{1134E}\u{1134F}\u{11351}-\u{11356}\u{11358}-\u{1135C}\u{11364}\u{11365}\u{1136D}-\u{1136F}\u{11375}-\u{113FF}\u{1144B}-\u{1144F}\u{1145A}-\u{1145D}\u{1145F}-\u{1147F}\u{114C6}\u{114C8}-\u{114CF}\u{114DA}-\u{1157F}\u{115B6}\u{115B7}\u{115C1}-\u{115D7}\u{115DE}-\u{115FF}\u{11641}-\u{11643}\u{11645}-\u{1164F}\u{1165A}-\u{1167F}\u{116B9}-\u{116BF}\u{116CA}-\u{116FF}\u{1171B}-\u{1171C}\u{1172C}-\u{1172F}\u{1173A}-\u{117FF}\u{1183B}-\u{1189F}\u{118EA}-\u{118FE}\u{11900}-\u{1199F}\u{119A8}\u{119A9}\u{119D8}\u{119D9}\u{119E2}\u{119E5}-\u{119FF}\u{11A3F}-\u{11A46}\u{11A48}-\u{11A4F}\u{11A9A}-\u{11A9C}\u{11A9E}-\u{11ABF}\u{11AF9}-\u{11BFF}\u{11C09}\u{11C37}\u{11C41}-\u{11C4F}\u{11C5A}-\u{11C71}\u{11C90}\u{11C91}\u{11CA8}\u{11CB7}-\u{11CFF}\u{11D07}\u{11D0A}\u{11D37}-\u{11D39}\u{11D3B}\u{11D3E}\u{11D48}-\u{11D4F}\u{11D5A}-\u{11D5F}\u{11D66}\u{11D69}\u{11D8F}\u{11D92}\u{11D99}-\u{11D9F}\u{11DAA}-\u{11EDF}\u{11EF7}-\u{11FAF}\u{11FB1}-\u{11FFF}\u{1239A}-\u{123FF}\u{1246F}-\u{1247F}\u{12544}-\u{12FFF}\u{1342F}-\u{143FF}\u{14647}-\u{167FF}\u{16A39}-\u{16A3F}\u{16A5F}\u{16A6A}-\u{16ACF}\u{16AEE}\u{16AEF}\u{16AF5}-\u{16AFF}\u{16B37}-\u{16B3F}\u{16B44}-\u{16B4F}\u{16B5A}-\u{16B62}\u{16B78}-\u{16B7C}\u{16B90}-\u{16EFF}\u{16F4B}-\u{16F4E}\u{16F88}-\u{16F8E}\u{16FA0}-\u{16FDF}\u{16FE2}\u{16FE5}-\u{16FEF}\u{16FF2}-\u{16FFF}\u{187F8}-\u{187FF}\u{18CD6}-\u{18CFF}\u{18D09}-\u{1AFFF}\u{1B11F}-\u{1B14F}\u{1B153}-\u{1B163}\u{1B168}-\u{1B16F}\u{1B2FC}-\u{1BBFF}\u{1BC6B}-\u{1BC6F}\u{1BC7D}-\u{1BC7F}\u{1BC89}-\u{1BC8F}\u{1BC9A}-\u{1BC9C}\u{1BC9F}-\u{1CFFF}\u{1D0F6}-\u{1D0FF}\u{1D127}-\u{1D128}\u{1D173}-\u{1D17A}\u{1D1E9}-\u{1D1FF}\u{1D246}-\u{1D2DF}\u{1D2F4}-\u{1D2FF}\u{1D357}-\u{1D35F}\u{1D379}-\u{1D3FF}\u{1D455}\u{1D49D}\u{1D4A0}\u{1D4A1}\u{1D4A3}\u{1D4A4}\u{1D4A7}\u{1D4A8}\u{1D4AD}\u{1D4BA}\u{1D4BC}\u{1D4C4}\u{1D506}\u{1D50B}\u{1D50C}\u{1D515}\u{1D51D}\u{1D53A}\u{1D53F}\u{1D545}\u{1D547}-\u{1D549}\u{1D551}\u{1D6A6}\u{1D6A7}\u{1D6C1}\u{1D6DB}\u{1D6FB}\u{1D715}\u{1D735}\u{1D74F}\u{1D76F}\u{1D789}\u{1D7A9}\u{1D7C3}\u{1D7CC}\u{1D7CD}\u{1D800}-\u{1D9FF}\u{1DA37}-\u{1DA3A}\u{1DA6D}-\u{1DA74}\u{1DA76}-\u{1DA83}\u{1DA85}-\u{1DA9A}\u{1DAA0}\u{1DAB0}-\u{1DFFF}\u{1E007}\u{1E019}\u{1E01A}\u{1E022}\u{1E025}\u{1E02B}-\u{1E0FF}\u{1E12D}-\u{1E12F}\u{1E13E}\u{1E13F}\u{1E14A}-\u{1E14D}\u{1E14F}-\u{1E2BF}\u{1E2FA}-\u{1E2FF}\u{1E4FA}-\u{1E7FF}\u{1E8C5}-\u{1E8CF}\u{1E8D7}-\u{1E8FF}\u{1E94C}-\u{1E94F}\u{1E95A}-\u{1E9FF}\u{1EA00}-\u{1EDFF}\u{1EE04}\u{1EE20}\u{1EE23}\u{1EE25}\u{1EE26}\u{1EE28}\u{1EE33}\u{1EE38}\u{1EE3A}\u{1EE3C}-\u{1EE41}\u{1EE43}-\u{1EE46}\u{1EE48}\u{1EE4A}\u{1EE4C}\u{1EE50}\u{1EE53}\u{1EE55}\u{1EE56}\u{1EE58}\u{1EE5A}\u{1EE5C}\u{1EE5E}\u{1EE60}\u{1EE63}\u{1EE65}\u{1EE66}\u{1EE6B}\u{1EE73}\u{1EE78}\u{1EE7D}\u{1EE7F}\u{1EE8A}\u{1EE9C}-\u{1EEA0}\u{1EEA4}\u{1EEAA}\u{1EEBC}-\u{1EFFF}\u{1F000}-\u{1F02B}\u{1F030}-\u{1F093}\u{1F0A0}-\u{1F0AE}\u{1F0B1}-\u{1F0BF}\u{1F0C1}-\u{1F0CF}\u{1F0D1}-\u{1F0F5}\u{1F100}-\u{1F1AD}\u{1F1E6}-\u{1F202}\u{1F210}-\u{1F23B}\u{1F240}-\u{1F248}\u{1F250}\u{1F251}\u{1F260}-\u{1F265}\u{1F300}-\u{1F6D7}\u{1F6DD}-\u{1F6EC}\u{1F6F0}-\u{1F6FC}\u{1F700}-\u{1F773}\u{1F780}-\u{1F7D8}\u{1F7E0}-\u{1F7EB}\u{1F7F0}\u{1F800}-\u{1F80B}\u{1F810}-\u{1F847}\u{1F850}-\u{1F859}\u{1F860}-\u{1F887}\u{1F890}-\u{1F8AD}\u{1F8B0}\u{1F8B1}\u{1F900}-\u{1F978}\u{1F97A}-\u{1F9CB}\u{1F9CD}-\u{1FA53}\u{1FA60}-\u{1FA6D}\u{1FA70}-\u{1FA74}\u{1FA78}-\u{1FA7C}\u{1FA80}-\u{1FA86}\u{1FA90}-\u{1FAAC}\u{1FAB0}-\u{1FABA}\u{1FAC0}-\u{1FAC5}\u{1FAD0}-\u{1FAD9}\u{1FAE0}-\u{1FAE7}\u{1FAF0}-\u{1FAF6}\u{1FB00}-\u{1FB92}\u{1FB94}-\u{1FBCA}\u{1FBF0}-\u{1FBF9}\u{1FC00}-\u{1FFFF}\u{2A6DE}-\u{2A6FF}\u{2B735}-\u{2B73F}\u{2B81E}\u{2B81F}\u{2CEA2}-\u{2CEAF}\u{2EBE1}-\u{2F7FF}\u{2FA1E}-\u{2FFFF}\u{3134B}-\u{E00FF}\u{E01F0}-\u{10FFFF}]"
|
|
158
|
+
).expect("Valid GitHub regex pattern");
|
|
195
159
|
|
|
196
|
-
//
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
160
|
+
// Remove all punctuation and symbols matched by the regex
|
|
161
|
+
let result = github_regex.replace_all(&text, "");
|
|
162
|
+
|
|
163
|
+
// 3. Replace spaces with hyphens (/ /g, '-')
|
|
164
|
+
result.replace(' ', "-")
|
|
200
165
|
}
|
|
201
166
|
|
|
202
167
|
/// Fragment generation following kramdown's algorithm
|
|
203
|
-
///
|
|
168
|
+
/// Uses the official kramdown implementation from kramdown_utils
|
|
204
169
|
#[inline]
|
|
205
170
|
fn heading_to_fragment_kramdown(&self, heading: &str) -> String {
|
|
206
171
|
if heading.is_empty() {
|
|
@@ -214,75 +179,8 @@ impl MD051LinkFragments {
|
|
|
214
179
|
heading.to_string()
|
|
215
180
|
};
|
|
216
181
|
|
|
217
|
-
//
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
// Check if this would result in empty/non-Latin content
|
|
221
|
-
let has_latin = text
|
|
222
|
-
.chars()
|
|
223
|
-
.any(|c| c.is_ascii_alphabetic() || (c as u32 >= 0x00C0 && c as u32 <= 0x024F)); // Latin extended
|
|
224
|
-
|
|
225
|
-
if !has_latin {
|
|
226
|
-
// kramdown generates generic "section" for non-Latin scripts
|
|
227
|
-
return "section".to_string();
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// Follow kramdown's algorithm
|
|
231
|
-
let mut result = String::with_capacity(text.len());
|
|
232
|
-
let mut found_letter = false;
|
|
233
|
-
|
|
234
|
-
for c in text.chars() {
|
|
235
|
-
// Skip leading non-letters
|
|
236
|
-
if !found_letter && !Self::is_kramdown_letter(c) {
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
239
|
-
if Self::is_kramdown_letter(c) {
|
|
240
|
-
found_letter = true;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// Process character
|
|
244
|
-
if c.is_ascii_alphabetic() {
|
|
245
|
-
result.push(c.to_ascii_lowercase());
|
|
246
|
-
} else if c.is_ascii_digit() && found_letter {
|
|
247
|
-
result.push(c);
|
|
248
|
-
} else if c == ' ' || c == '-' {
|
|
249
|
-
result.push('-');
|
|
250
|
-
} else if let Some(replacement) = Self::kramdown_normalize_char(c) {
|
|
251
|
-
// kramdown normalizes accented characters
|
|
252
|
-
result.push_str(replacement);
|
|
253
|
-
}
|
|
254
|
-
// Skip underscores and other characters
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// Remove leading and trailing hyphens
|
|
258
|
-
result.trim_matches('-').to_string()
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/// Check if character is considered a letter by kramdown
|
|
262
|
-
#[inline]
|
|
263
|
-
fn is_kramdown_letter(c: char) -> bool {
|
|
264
|
-
c.is_ascii_alphabetic() ||
|
|
265
|
-
// Latin-1 Supplement and Extended Latin
|
|
266
|
-
(c as u32 >= 0x00C0 && c as u32 <= 0x024F)
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/// Normalize accented characters for kramdown (simplified)
|
|
270
|
-
#[inline]
|
|
271
|
-
fn kramdown_normalize_char(c: char) -> Option<&'static str> {
|
|
272
|
-
match c {
|
|
273
|
-
'À' | 'Á' | 'Â' | 'Ã' | 'Ä' | 'Å' | 'à' | 'á' | 'â' | 'ã' | 'ä' | 'å' => Some("a"),
|
|
274
|
-
'È' | 'É' | 'Ê' | 'Ë' | 'è' | 'é' | 'ê' | 'ë' => Some("e"),
|
|
275
|
-
'Ì' | 'Í' | 'Î' | 'Ï' | 'ì' | 'í' | 'î' | 'ï' => Some("i"),
|
|
276
|
-
'Ò' | 'Ó' | 'Ô' | 'Õ' | 'Ö' | 'Ø' | 'ò' | 'ó' | 'ô' | 'õ' | 'ö' | 'ø' => Some("o"),
|
|
277
|
-
'Ù' | 'Ú' | 'Û' | 'Ü' | 'ù' | 'ú' | 'û' | 'ü' => Some("u"),
|
|
278
|
-
'Ý' | 'ý' | 'ÿ' => Some("y"),
|
|
279
|
-
'Ñ' | 'ñ' => Some("n"),
|
|
280
|
-
'Ç' | 'ç' => Some("c"),
|
|
281
|
-
'ß' => Some("ss"),
|
|
282
|
-
'Æ' | 'æ' => Some("ae"),
|
|
283
|
-
'Œ' | 'œ' => Some("oe"),
|
|
284
|
-
_ => None,
|
|
285
|
-
}
|
|
182
|
+
// Use the official kramdown algorithm from utils
|
|
183
|
+
kramdown_utils::heading_to_fragment(&text)
|
|
286
184
|
}
|
|
287
185
|
|
|
288
186
|
/// Fragment generation for Bitbucket style
|
|
@@ -310,14 +208,27 @@ impl MD051LinkFragments {
|
|
|
310
208
|
heading.to_string()
|
|
311
209
|
};
|
|
312
210
|
|
|
313
|
-
// Step 2: Apply deburr (accent removal) -
|
|
211
|
+
// Step 2: Apply deburr (accent removal) - basic accent normalization
|
|
314
212
|
let mut result = String::with_capacity(text.len());
|
|
315
213
|
for c in text.chars() {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
214
|
+
let replacement = match c {
|
|
215
|
+
'À' | 'Á' | 'Â' | 'Ã' | 'Ä' | 'Å' | 'à' | 'á' | 'â' | 'ã' | 'ä' | 'å' => "a",
|
|
216
|
+
'È' | 'É' | 'Ê' | 'Ë' | 'è' | 'é' | 'ê' | 'ë' => "e",
|
|
217
|
+
'Ì' | 'Í' | 'Î' | 'Ï' | 'ì' | 'í' | 'î' | 'ï' => "i",
|
|
218
|
+
'Ò' | 'Ó' | 'Ô' | 'Õ' | 'Ö' | 'Ø' | 'ò' | 'ó' | 'ô' | 'õ' | 'ö' | 'ø' => "o",
|
|
219
|
+
'Ù' | 'Ú' | 'Û' | 'Ü' | 'ù' | 'ú' | 'û' | 'ü' => "u",
|
|
220
|
+
'Ý' | 'ý' | 'ÿ' => "y",
|
|
221
|
+
'Ñ' | 'ñ' => "n",
|
|
222
|
+
'Ç' | 'ç' => "c",
|
|
223
|
+
'ß' => "ss",
|
|
224
|
+
'Æ' | 'æ' => "ae",
|
|
225
|
+
'Œ' | 'œ' => "oe",
|
|
226
|
+
_ => {
|
|
227
|
+
result.push(c);
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
result.push_str(replacement);
|
|
321
232
|
}
|
|
322
233
|
text = result;
|
|
323
234
|
|
|
@@ -364,9 +275,9 @@ impl MD051LinkFragments {
|
|
|
364
275
|
fn strip_markdown_formatting_fast(&self, text: &str) -> String {
|
|
365
276
|
let mut result = text.to_string();
|
|
366
277
|
|
|
367
|
-
// Strip emphasis (
|
|
368
|
-
if result.contains('*')
|
|
369
|
-
result = EMPHASIS_PATTERN.replace_all(&result, "$1
|
|
278
|
+
// Strip emphasis (only asterisks, underscores are preserved per GitHub spec)
|
|
279
|
+
if result.contains('*') {
|
|
280
|
+
result = EMPHASIS_PATTERN.replace_all(&result, "$1").to_string();
|
|
370
281
|
}
|
|
371
282
|
|
|
372
283
|
// Strip inline code
|
|
@@ -374,9 +285,9 @@ impl MD051LinkFragments {
|
|
|
374
285
|
result = CODE_PATTERN.replace_all(&result, "$1").to_string();
|
|
375
286
|
}
|
|
376
287
|
|
|
377
|
-
// Strip links
|
|
288
|
+
// Strip links (GitHub keeps both link text and URL)
|
|
378
289
|
if result.contains('[') {
|
|
379
|
-
result = LINK_PATTERN.replace_all(&result, "$1$2").to_string();
|
|
290
|
+
result = LINK_PATTERN.replace_all(&result, "$1$2$3").to_string();
|
|
380
291
|
}
|
|
381
292
|
|
|
382
293
|
result
|
|
@@ -637,8 +548,8 @@ mod tests {
|
|
|
637
548
|
assert_eq!(rule.heading_to_fragment_github("Café"), "café");
|
|
638
549
|
assert_eq!(rule.heading_to_fragment_github("Über uns"), "über-uns");
|
|
639
550
|
|
|
640
|
-
// Emojis should be stripped
|
|
641
|
-
assert_eq!(rule.heading_to_fragment_github("Emoji 🎉 Party"), "emoji
|
|
551
|
+
// Emojis should be stripped (results in double hyphen)
|
|
552
|
+
assert_eq!(rule.heading_to_fragment_github("Emoji 🎉 Party"), "emoji--party");
|
|
642
553
|
}
|
|
643
554
|
|
|
644
555
|
#[test]
|
|
@@ -661,11 +572,11 @@ mod tests {
|
|
|
661
572
|
);
|
|
662
573
|
|
|
663
574
|
// Accented characters normalized
|
|
664
|
-
assert_eq!(rule.heading_to_fragment_kramdown("Café"), "
|
|
665
|
-
assert_eq!(rule.heading_to_fragment_kramdown("Über uns"), "
|
|
575
|
+
assert_eq!(rule.heading_to_fragment_kramdown("Café"), "caf");
|
|
576
|
+
assert_eq!(rule.heading_to_fragment_kramdown("Über uns"), "ber-uns");
|
|
666
577
|
|
|
667
|
-
// Leading
|
|
668
|
-
assert_eq!(rule.heading_to_fragment_kramdown("---test---"), "test");
|
|
578
|
+
// Leading hyphens removed, trailing preserved
|
|
579
|
+
assert_eq!(rule.heading_to_fragment_kramdown("---test---"), "test---");
|
|
669
580
|
}
|
|
670
581
|
|
|
671
582
|
#[test]
|
|
@@ -941,4 +852,137 @@ More content.
|
|
|
941
852
|
assert!(!MD051LinkFragments::is_cross_file_link("%}some{%#fragment"));
|
|
942
853
|
assert!(!MD051LinkFragments::is_cross_file_link("}}text{{#fragment"));
|
|
943
854
|
}
|
|
855
|
+
|
|
856
|
+
#[test]
|
|
857
|
+
fn test_simplified_github_algorithm_edge_cases() {
|
|
858
|
+
let rule = MD051LinkFragments::new();
|
|
859
|
+
|
|
860
|
+
// Test consecutive punctuation - GitHub removes punctuation, no spaces to convert
|
|
861
|
+
assert_eq!(rule.heading_to_fragment_github("Test:::Multiple"), "testmultiple");
|
|
862
|
+
assert_eq!(rule.heading_to_fragment_github("Step >>> Next"), "step--next"); // Spaces around >>> become hyphens
|
|
863
|
+
|
|
864
|
+
// Test mixed hyphens and punctuation
|
|
865
|
+
assert_eq!(
|
|
866
|
+
rule.heading_to_fragment_github("Double--Hyphen: Test"),
|
|
867
|
+
"double--hyphen-test"
|
|
868
|
+
);
|
|
869
|
+
assert_eq!(
|
|
870
|
+
rule.heading_to_fragment_github("Pre-existing: More--Hyphens"),
|
|
871
|
+
"pre-existing-more--hyphens"
|
|
872
|
+
);
|
|
873
|
+
|
|
874
|
+
// Test multiple whitespace
|
|
875
|
+
assert_eq!(
|
|
876
|
+
rule.heading_to_fragment_github("Multiple Spaces"),
|
|
877
|
+
"multiple---spaces"
|
|
878
|
+
); // Each space becomes a hyphen
|
|
879
|
+
|
|
880
|
+
// Test leading/trailing punctuation - hyphens are preserved!
|
|
881
|
+
assert_eq!(
|
|
882
|
+
rule.heading_to_fragment_github("---Leading and Trailing---"),
|
|
883
|
+
"---leading-and-trailing---"
|
|
884
|
+
);
|
|
885
|
+
assert_eq!(
|
|
886
|
+
rule.heading_to_fragment_github(":::Mixed:::Punctuation:::"),
|
|
887
|
+
"mixedpunctuation"
|
|
888
|
+
); // No spaces between colons
|
|
889
|
+
|
|
890
|
+
// Test complex combinations
|
|
891
|
+
assert_eq!(
|
|
892
|
+
rule.heading_to_fragment_github("API::Response > Error--Handling"),
|
|
893
|
+
"apiresponse--error--handling"
|
|
894
|
+
);
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
#[test]
|
|
898
|
+
fn test_github_slugger_comprehensive_compliance() {
|
|
899
|
+
let rule = MD051LinkFragments::new();
|
|
900
|
+
|
|
901
|
+
// Comprehensive test cases generated from the official github-slugger npm package
|
|
902
|
+
// to ensure our implementation exactly matches GitHub's behavior
|
|
903
|
+
let test_cases = vec![
|
|
904
|
+
("Simple Title", "simple-title"),
|
|
905
|
+
("Title With Numbers 123", "title-with-numbers-123"),
|
|
906
|
+
("UPPERCASE TITLE", "uppercase-title"),
|
|
907
|
+
("lowercase title", "lowercase-title"),
|
|
908
|
+
("MiXeD CaSe TiTlE", "mixed-case-title"),
|
|
909
|
+
// Issue #39 specific cases
|
|
910
|
+
("cbrown --> sbrown: --unsafe-paths", "cbrown----sbrown---unsafe-paths"),
|
|
911
|
+
("cbrown -> sbrown", "cbrown---sbrown"),
|
|
912
|
+
("Arrow Test <-> bidirectional", "arrow-test---bidirectional"),
|
|
913
|
+
("Double Arrow ==> Test", "double-arrow--test"),
|
|
914
|
+
// Ampersands and special chars
|
|
915
|
+
("Testing & Coverage", "testing--coverage"),
|
|
916
|
+
(
|
|
917
|
+
"API Reference: Methods & Properties",
|
|
918
|
+
"api-reference-methods--properties",
|
|
919
|
+
),
|
|
920
|
+
("Config: Database & Cache Settings", "config-database--cache-settings"),
|
|
921
|
+
("PHP $_REQUEST", "php-_request"),
|
|
922
|
+
("sched_debug", "sched_debug"),
|
|
923
|
+
("Add ldap_monitor to delegator$", "add-ldap_monitor-to-delegator"),
|
|
924
|
+
// Complex punctuation patterns
|
|
925
|
+
("Step 1: Setup (Prerequisites)", "step-1-setup-prerequisites"),
|
|
926
|
+
("Error #404 - Not Found!", "error-404---not-found"),
|
|
927
|
+
("FAQ: What's Next?", "faq-whats-next"),
|
|
928
|
+
("Version 2.0.1 - Release Notes", "version-201---release-notes"),
|
|
929
|
+
// Multiple hyphens and spaces
|
|
930
|
+
("Test --- Multiple Hyphens", "test-----multiple-hyphens"),
|
|
931
|
+
("Test -- Spaced Hyphens", "test------spaced-hyphens"),
|
|
932
|
+
("Test - Single - Hyphen", "test---single---hyphen"),
|
|
933
|
+
("Multiple Spaces", "multiple---spaces"),
|
|
934
|
+
// Leading/trailing punctuation
|
|
935
|
+
("---Leading Hyphens", "---leading-hyphens"),
|
|
936
|
+
("Trailing Hyphens---", "trailing-hyphens---"),
|
|
937
|
+
("---Both Sides---", "---both-sides---"),
|
|
938
|
+
(":::Colons:::", "colons"),
|
|
939
|
+
("***Asterisks***", "asterisks"),
|
|
940
|
+
("___Underscores___", "___underscores___"),
|
|
941
|
+
("...Dots...", "dots"),
|
|
942
|
+
// Unicode preservation
|
|
943
|
+
("Café René", "café-rené"),
|
|
944
|
+
("Über uns", "über-uns"),
|
|
945
|
+
("日本語タイトル", "日本語タイトル"),
|
|
946
|
+
("Русский заголовок", "русский-заголовок"),
|
|
947
|
+
("مرحبا بالعالم", "مرحبا-بالعالم"),
|
|
948
|
+
// Emojis are removed
|
|
949
|
+
("🎉 Emoji Start", "-emoji-start"),
|
|
950
|
+
("Emoji 🎉 Middle", "emoji--middle"),
|
|
951
|
+
("End Emoji 🎉", "end-emoji-"),
|
|
952
|
+
("Multiple 🚀 🎨 Emojis", "multiple---emojis"),
|
|
953
|
+
// Special symbols
|
|
954
|
+
("Price: $99.99", "price-9999"),
|
|
955
|
+
("Copyright © 2024", "copyright--2024"),
|
|
956
|
+
("Temperature: 25°C", "temperature-25c"),
|
|
957
|
+
("Percentage: 100%", "percentage-100"),
|
|
958
|
+
("Email: user@example.com", "email-userexamplecom"),
|
|
959
|
+
// Edge cases
|
|
960
|
+
("", ""),
|
|
961
|
+
(" ", "-"),
|
|
962
|
+
(" ", "---"),
|
|
963
|
+
("-", "-"),
|
|
964
|
+
("---", "---"),
|
|
965
|
+
("_", "_"),
|
|
966
|
+
("___", "___"),
|
|
967
|
+
("123", "123"),
|
|
968
|
+
("!@#$%^&*()", ""),
|
|
969
|
+
// URL and paths
|
|
970
|
+
("GET /api/v1/users", "get-apiv1users"),
|
|
971
|
+
("C:\\Windows\\Path", "cwindowspath"),
|
|
972
|
+
("URL: https://example.com", "url-httpsexamplecom"),
|
|
973
|
+
// Nested brackets
|
|
974
|
+
("[Bracketed] Content", "bracketed-content"),
|
|
975
|
+
("(Parenthetical) Remark", "parenthetical-remark"),
|
|
976
|
+
("{Braced} Text", "braced-text"),
|
|
977
|
+
("<Angled> Brackets", "angled-brackets"),
|
|
978
|
+
];
|
|
979
|
+
|
|
980
|
+
for (input, expected) in test_cases {
|
|
981
|
+
let actual = rule.heading_to_fragment_github(input);
|
|
982
|
+
assert_eq!(
|
|
983
|
+
actual, expected,
|
|
984
|
+
"Failed for input: {input:?}\nExpected: {expected:?}\nActual: {actual:?}"
|
|
985
|
+
);
|
|
986
|
+
}
|
|
987
|
+
}
|
|
944
988
|
}
|
|
@@ -195,19 +195,6 @@ impl MD057ExistingRelativeLinks {
|
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
|
-
|
|
199
|
-
/// Extract a URL from a Markdown link segment
|
|
200
|
-
#[allow(dead_code)]
|
|
201
|
-
fn extract_url_from_link<'a>(&self, link_text: &'a str) -> Option<(&'a str, usize)> {
|
|
202
|
-
// Find the URL part using regex
|
|
203
|
-
URL_EXTRACT_REGEX.captures(link_text).and_then(move |caps| {
|
|
204
|
-
caps.get(1).map(|url_match| {
|
|
205
|
-
let url = url_match.as_str().trim();
|
|
206
|
-
let position = url_match.start();
|
|
207
|
-
(url, position)
|
|
208
|
-
})
|
|
209
|
-
})
|
|
210
|
-
}
|
|
211
198
|
}
|
|
212
199
|
|
|
213
200
|
impl Rule for MD057ExistingRelativeLinks {
|
|
@@ -120,14 +120,6 @@ pub struct BlockquoteRange {
|
|
|
120
120
|
pub end_line: usize,
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
/// Code block processing state
|
|
124
|
-
#[allow(dead_code)]
|
|
125
|
-
enum InternalCodeBlockState {
|
|
126
|
-
None,
|
|
127
|
-
InFenced,
|
|
128
|
-
InIndented,
|
|
129
|
-
}
|
|
130
|
-
|
|
131
123
|
/// OPTIMIZATION 1: Inline code span representation
|
|
132
124
|
#[derive(Debug, Clone)]
|
|
133
125
|
pub struct CodeSpan {
|