rumdl 0.0.59__tar.gz → 0.0.60__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.59 → rumdl-0.0.60}/Cargo.lock +43 -1
- {rumdl-0.0.59 → rumdl-0.0.60}/Cargo.toml +6 -5
- {rumdl-0.0.59 → rumdl-0.0.60}/PKG-INFO +1 -1
- {rumdl-0.0.59 → rumdl-0.0.60}/src/config.rs +65 -15
- rumdl-0.0.60/src/lib.rs +273 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/main.rs +112 -31
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rule.rs +81 -1
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md005_list_indent.rs +1 -1
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md009_trailing_spaces.rs +21 -8
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md010_no_hard_tabs.rs +10 -1
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md013_line_length.rs +17 -8
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md034_no_bare_urls.rs +28 -1
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md044_proper_names.rs +21 -17
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md057_existing_relative_links.rs +18 -20
- rumdl-0.0.60/src/utils/ast_utils.rs +235 -0
- rumdl-0.0.60/src/utils/early_returns.rs +288 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/utils/element_cache.rs +18 -31
- {rumdl-0.0.59 → rumdl-0.0.60}/src/utils/mod.rs +3 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/utils/regex_cache.rs +97 -0
- rumdl-0.0.60/src/utils/string_interner.rs +114 -0
- rumdl-0.0.59/src/lib.rs +0 -85
- rumdl-0.0.59/src/utils/early_returns.rs +0 -125
- {rumdl-0.0.59 → rumdl-0.0.60}/.rumdl.toml +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/MANIFEST.in +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/Makefile +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/README.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/assets/logo.png +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/benches/range_performance.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/benches/range_utils_benchmark.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/benches/rule_performance.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/RULES.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md001.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md002.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md003.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md004.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md005.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md006.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md007.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md009.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md010.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md011.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md012.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md013.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md014.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md018.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md019.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md020.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md021.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md022.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md023.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md024.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md025.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md026.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md027.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md028.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md029.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md030.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md031.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md032.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md033.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md034.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md035.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md036.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md037.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md038.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md039.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md040.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md041.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md042.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md043.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md044.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md045.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md046.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md047.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md048.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md049.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md050.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md051.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md052.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md053.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md054.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md055.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md056.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md057.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/docs/md058.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/issues/plan-rule-parity-with-markdownlint.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/parity_check.py +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/pyproject.toml +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/python/MANIFEST.in +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/python/PYTHON-README.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/python/rumdl/__init__.py +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/python/rumdl/__main__.py +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/python/rumdl/py.typed +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/rumdl.toml.example +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/init.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/lint_context.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/markdownlint_config.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/profiling.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/python.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/blockquote_utils.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/code_block_utils.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/code_fence_utils.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/emphasis_style.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/front_matter_utils.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/heading_utils.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/list_utils.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md001_heading_increment.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md002_first_heading_h1.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md003_heading_style.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md004_unordered_list_style.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md006_start_bullets.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md007_ul_indent.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md011_no_reversed_links.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md012_no_multiple_blanks.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md014_commands_show_output.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md018_no_missing_space_atx.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md019_no_multiple_space_atx.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md020_no_missing_space_closed_atx.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md021_no_multiple_space_closed_atx.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md022_blanks_around_headings.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md023_heading_start_left.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md024_no_duplicate_heading.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md025_single_title.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md026_no_trailing_punctuation.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md027_multiple_spaces_blockquote.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md028_no_blanks_blockquote.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md029_ordered_list_prefix.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md030_list_marker_space.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md031_blanks_around_fences.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md032_blanks_around_lists.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md033_no_inline_html.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md035_hr_style.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md036_no_emphasis_only_first.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md037_spaces_around_emphasis.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md038_no_space_in_code.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md039_no_space_in_links.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md040_fenced_code_language.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md041_first_line_heading.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md042_no_empty_links.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md043_required_headings.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md045_no_alt_text.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md046_code_block_style.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md047_single_trailing_newline.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md048_code_fence_style.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md049_emphasis_style.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md050_strong_style.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md051_link_fragments.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md052_reference_links_images.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md053_link_image_reference_definitions.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md054_link_image_style.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md055_table_pipe_style.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md056_table_column_count.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/md058_blanks_around_tables.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/mod.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/rules/strong_style.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/utils/code_block_utils.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/utils/document_structure.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/utils/markdown_elements.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/src/utils/range_utils.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/advanced_integration_tests.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/cli_duplication_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/cli_integration_tests.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/commonmark_compliance_tests.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/comprehensive_integration_tests.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/config_application_tests.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/config_tests.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/init_command_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/init_tests.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/integration_tests.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/json_output_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/lib.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/markdownlint_cli_integration.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/markdownlint_config_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/md030_edge_cases.md +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/output_format_tests.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/perf_check.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/pyproject_config_tests.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md001_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md001_unicode_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md002_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md003_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md004_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md005_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md006_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md006_unicode_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md007_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md009_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md010_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md011_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md012_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md013_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md014_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md018_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md019_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md020_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md021_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md022_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md023_extended_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md023_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md024_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md025_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md026_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md027_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md028_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md029_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md030_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md031_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md032_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md033_extended_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md033_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md034_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md035_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md036_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md037_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md038_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md039_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md040_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md041_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md042_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md043_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md044_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md045_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md046_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md047_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md048_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md049_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md050_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md051_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md052_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md053_additional_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md053_proptest.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md053_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md054_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md054_unicode_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md055_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md056_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md057_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/md058_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/rules/mod.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/utils/blockquote_utils_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/utils/code_block_utils_extended_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/utils/code_block_utils_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/utils/core_utils_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/utils/front_matter_utils_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/utils/line_index_test.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/utils/mod.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/utils_markdown_edge_cases.rs +0 -0
- {rumdl-0.0.59 → rumdl-0.0.60}/tests/utils_tests.rs +0 -0
|
@@ -917,6 +917,15 @@ version = "2.7.4"
|
|
|
917
917
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
918
918
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
|
919
919
|
|
|
920
|
+
[[package]]
|
|
921
|
+
name = "memmap2"
|
|
922
|
+
version = "0.9.5"
|
|
923
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
924
|
+
checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f"
|
|
925
|
+
dependencies = [
|
|
926
|
+
"libc",
|
|
927
|
+
]
|
|
928
|
+
|
|
920
929
|
[[package]]
|
|
921
930
|
name = "memoffset"
|
|
922
931
|
version = "0.9.1"
|
|
@@ -1368,7 +1377,7 @@ dependencies = [
|
|
|
1368
1377
|
|
|
1369
1378
|
[[package]]
|
|
1370
1379
|
name = "rumdl"
|
|
1371
|
-
version = "0.0.
|
|
1380
|
+
version = "0.0.60"
|
|
1372
1381
|
dependencies = [
|
|
1373
1382
|
"anyhow",
|
|
1374
1383
|
"assert_cmd",
|
|
@@ -1388,6 +1397,7 @@ dependencies = [
|
|
|
1388
1397
|
"lazy_static",
|
|
1389
1398
|
"log",
|
|
1390
1399
|
"markdown",
|
|
1400
|
+
"memmap2",
|
|
1391
1401
|
"once_cell",
|
|
1392
1402
|
"predicates",
|
|
1393
1403
|
"pretty_assertions",
|
|
@@ -1396,6 +1406,7 @@ dependencies = [
|
|
|
1396
1406
|
"rand 0.9.1",
|
|
1397
1407
|
"rayon",
|
|
1398
1408
|
"regex",
|
|
1409
|
+
"seahash",
|
|
1399
1410
|
"serde",
|
|
1400
1411
|
"serde_json",
|
|
1401
1412
|
"serde_yaml",
|
|
@@ -1404,6 +1415,7 @@ dependencies = [
|
|
|
1404
1415
|
"thiserror 2.0.12",
|
|
1405
1416
|
"toml",
|
|
1406
1417
|
"toml_edit",
|
|
1418
|
+
"unicode-normalization",
|
|
1407
1419
|
"url",
|
|
1408
1420
|
"walkdir",
|
|
1409
1421
|
]
|
|
@@ -1465,6 +1477,12 @@ dependencies = [
|
|
|
1465
1477
|
"winapi-util",
|
|
1466
1478
|
]
|
|
1467
1479
|
|
|
1480
|
+
[[package]]
|
|
1481
|
+
name = "seahash"
|
|
1482
|
+
version = "4.1.0"
|
|
1483
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1484
|
+
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
|
1485
|
+
|
|
1468
1486
|
[[package]]
|
|
1469
1487
|
name = "serde"
|
|
1470
1488
|
version = "1.0.219"
|
|
@@ -1670,6 +1688,21 @@ dependencies = [
|
|
|
1670
1688
|
"serde_json",
|
|
1671
1689
|
]
|
|
1672
1690
|
|
|
1691
|
+
[[package]]
|
|
1692
|
+
name = "tinyvec"
|
|
1693
|
+
version = "1.9.0"
|
|
1694
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1695
|
+
checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71"
|
|
1696
|
+
dependencies = [
|
|
1697
|
+
"tinyvec_macros",
|
|
1698
|
+
]
|
|
1699
|
+
|
|
1700
|
+
[[package]]
|
|
1701
|
+
name = "tinyvec_macros"
|
|
1702
|
+
version = "0.1.1"
|
|
1703
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1704
|
+
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|
1705
|
+
|
|
1673
1706
|
[[package]]
|
|
1674
1707
|
name = "toml"
|
|
1675
1708
|
version = "0.8.22"
|
|
@@ -1747,6 +1780,15 @@ version = "1.0.18"
|
|
|
1747
1780
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1748
1781
|
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
|
1749
1782
|
|
|
1783
|
+
[[package]]
|
|
1784
|
+
name = "unicode-normalization"
|
|
1785
|
+
version = "0.1.24"
|
|
1786
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1787
|
+
checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
|
|
1788
|
+
dependencies = [
|
|
1789
|
+
"tinyvec",
|
|
1790
|
+
]
|
|
1791
|
+
|
|
1750
1792
|
[[package]]
|
|
1751
1793
|
name = "unicode-segmentation"
|
|
1752
1794
|
version = "1.12.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "rumdl"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.60"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
description = "A fast Markdown linter written in Rust (Ru(st) MarkDown Linter)"
|
|
6
6
|
authors = ["Ruben J. Jongejan <ruben.jongejan@gmail.com>"]
|
|
@@ -44,15 +44,17 @@ anyhow = "1.0"
|
|
|
44
44
|
console = "0.15.11"
|
|
45
45
|
dialoguer = "0.11.0"
|
|
46
46
|
indicatif = "0.17.11"
|
|
47
|
-
|
|
48
47
|
log = "0.4.27"
|
|
49
48
|
pretty_assertions = "1.4"
|
|
50
|
-
markdown = "1.0
|
|
49
|
+
markdown = "1.0"
|
|
51
50
|
config = "0.15"
|
|
52
|
-
regex = "1.11
|
|
51
|
+
regex = "1.11"
|
|
53
52
|
toml_edit = "0.22"
|
|
54
53
|
dyn-clone = "1"
|
|
55
54
|
url = { version = "2", features = ["serde"] }
|
|
55
|
+
unicode-normalization = "0.1"
|
|
56
|
+
memmap2 = "0.9"
|
|
57
|
+
seahash = "4.1"
|
|
56
58
|
|
|
57
59
|
[features]
|
|
58
60
|
default = ["parallel", "profiling"]
|
|
@@ -70,7 +72,6 @@ glob = "0.3.2"
|
|
|
70
72
|
proptest = "1.6.0"
|
|
71
73
|
criterion = { version = "0.5", features = ["html_reports"] }
|
|
72
74
|
rand = "0.9.1"
|
|
73
|
-
|
|
74
75
|
pretty_assertions = "1.4"
|
|
75
76
|
|
|
76
77
|
[[bench]]
|
|
@@ -209,21 +209,35 @@ pub enum ConfigError {
|
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
/// Get a rule-specific configuration value
|
|
212
|
+
/// Automatically tries both the original key and normalized variants (kebab-case ↔ snake_case)
|
|
213
|
+
/// for better markdownlint compatibility
|
|
212
214
|
pub fn get_rule_config_value<T: serde::de::DeserializeOwned>(
|
|
213
215
|
config: &Config,
|
|
214
216
|
rule_name: &str,
|
|
215
217
|
key: &str,
|
|
216
218
|
) -> Option<T> {
|
|
217
|
-
let norm_key = normalize_key(key);
|
|
218
219
|
let norm_rule_name = rule_name.to_ascii_uppercase(); // Use uppercase for lookup
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
220
|
+
|
|
221
|
+
let rule_config = config.rules.get(&norm_rule_name)?;
|
|
222
|
+
|
|
223
|
+
// Try multiple key variants to support both underscore and kebab-case formats
|
|
224
|
+
let key_variants = [
|
|
225
|
+
key.to_string(), // Original key as provided
|
|
226
|
+
normalize_key(key), // Normalized key (lowercase, kebab-case)
|
|
227
|
+
key.replace('-', "_"), // Convert kebab-case to snake_case
|
|
228
|
+
key.replace('_', "-"), // Convert snake_case to kebab-case
|
|
229
|
+
];
|
|
230
|
+
|
|
231
|
+
// Try each variant until we find a match
|
|
232
|
+
for variant in &key_variants {
|
|
233
|
+
if let Some(value) = rule_config.values.get(variant) {
|
|
234
|
+
if let Ok(result) = T::deserialize(value.clone()) {
|
|
235
|
+
return Some(result);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
None
|
|
227
241
|
}
|
|
228
242
|
|
|
229
243
|
/// Generate default rumdl configuration for pyproject.toml
|
|
@@ -904,16 +918,52 @@ impl RuleRegistry {
|
|
|
904
918
|
self.rule_schemas.keys().cloned().collect()
|
|
905
919
|
}
|
|
906
920
|
|
|
907
|
-
/// Get valid
|
|
921
|
+
/// Get the valid configuration keys for a rule, including both original and normalized variants
|
|
908
922
|
pub fn config_keys_for(&self, rule: &str) -> Option<std::collections::BTreeSet<String>> {
|
|
909
|
-
self.rule_schemas
|
|
910
|
-
|
|
911
|
-
|
|
923
|
+
self.rule_schemas.get(rule).map(|schema| {
|
|
924
|
+
let mut all_keys = std::collections::BTreeSet::new();
|
|
925
|
+
|
|
926
|
+
// Add original keys from schema
|
|
927
|
+
for key in schema.keys() {
|
|
928
|
+
all_keys.insert(key.clone());
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
// Add normalized variants for markdownlint compatibility
|
|
932
|
+
for key in schema.keys() {
|
|
933
|
+
// Add kebab-case variant
|
|
934
|
+
all_keys.insert(key.replace('_', "-"));
|
|
935
|
+
// Add snake_case variant
|
|
936
|
+
all_keys.insert(key.replace('-', "_"));
|
|
937
|
+
// Add normalized variant
|
|
938
|
+
all_keys.insert(normalize_key(key));
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
all_keys
|
|
942
|
+
})
|
|
912
943
|
}
|
|
913
944
|
|
|
914
|
-
/// Get the expected
|
|
945
|
+
/// Get the expected value type for a rule's configuration key, trying variants
|
|
915
946
|
pub fn expected_value_for(&self, rule: &str, key: &str) -> Option<&toml::Value> {
|
|
916
|
-
self.rule_schemas.get(rule)
|
|
947
|
+
if let Some(schema) = self.rule_schemas.get(rule) {
|
|
948
|
+
// Try the original key first
|
|
949
|
+
if let Some(value) = schema.get(key) {
|
|
950
|
+
return Some(value);
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
// Try key variants
|
|
954
|
+
let key_variants = [
|
|
955
|
+
key.replace('-', "_"), // Convert kebab-case to snake_case
|
|
956
|
+
key.replace('_', "-"), // Convert snake_case to kebab-case
|
|
957
|
+
normalize_key(key), // Normalized key (lowercase, kebab-case)
|
|
958
|
+
];
|
|
959
|
+
|
|
960
|
+
for variant in &key_variants {
|
|
961
|
+
if let Some(value) = schema.get(variant) {
|
|
962
|
+
return Some(value);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
None
|
|
917
967
|
}
|
|
918
968
|
}
|
|
919
969
|
|
rumdl-0.0.60/src/lib.rs
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
pub mod config;
|
|
2
|
+
pub mod init;
|
|
3
|
+
pub mod lint_context;
|
|
4
|
+
pub mod markdownlint_config;
|
|
5
|
+
pub mod profiling;
|
|
6
|
+
pub mod rule;
|
|
7
|
+
pub mod rules;
|
|
8
|
+
pub mod utils;
|
|
9
|
+
|
|
10
|
+
#[cfg(feature = "python")]
|
|
11
|
+
pub mod python;
|
|
12
|
+
|
|
13
|
+
pub use rules::heading_utils::{Heading, HeadingStyle};
|
|
14
|
+
pub use rules::*;
|
|
15
|
+
|
|
16
|
+
pub use crate::lint_context::LintContext;
|
|
17
|
+
use crate::rule::{LintResult, Rule, RuleCategory};
|
|
18
|
+
use crate::utils::document_structure::DocumentStructure;
|
|
19
|
+
use std::time::Instant;
|
|
20
|
+
|
|
21
|
+
/// Content characteristics for efficient rule filtering
|
|
22
|
+
#[derive(Debug, Default)]
|
|
23
|
+
struct ContentCharacteristics {
|
|
24
|
+
has_headings: bool, // # or setext headings
|
|
25
|
+
has_lists: bool, // *, -, +, 1. etc
|
|
26
|
+
has_links: bool, // [text](url) or [text][ref]
|
|
27
|
+
has_code: bool, // ``` or ~~~ or indented code
|
|
28
|
+
has_emphasis: bool, // * or _ for emphasis
|
|
29
|
+
has_html: bool, // < > tags
|
|
30
|
+
has_tables: bool, // | pipes
|
|
31
|
+
has_blockquotes: bool, // > markers
|
|
32
|
+
has_images: bool, // 
|
|
33
|
+
line_count: usize,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
impl ContentCharacteristics {
|
|
37
|
+
fn analyze(content: &str) -> Self {
|
|
38
|
+
let mut chars = Self::default();
|
|
39
|
+
chars.line_count = content.lines().count();
|
|
40
|
+
|
|
41
|
+
// Quick single-pass analysis
|
|
42
|
+
let mut has_atx_heading = false;
|
|
43
|
+
let mut has_setext_heading = false;
|
|
44
|
+
|
|
45
|
+
for line in content.lines() {
|
|
46
|
+
let trimmed = line.trim();
|
|
47
|
+
|
|
48
|
+
// Headings: ATX (#) or Setext (underlines)
|
|
49
|
+
if !has_atx_heading && trimmed.starts_with('#') {
|
|
50
|
+
has_atx_heading = true;
|
|
51
|
+
}
|
|
52
|
+
if !has_setext_heading && (trimmed.chars().all(|c| c == '=' || c == '-') && trimmed.len() > 1) {
|
|
53
|
+
has_setext_heading = true;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Quick character-based detection (more efficient than regex)
|
|
57
|
+
if !chars.has_lists && (line.contains("* ") || line.contains("- ") || line.contains("+ ")) {
|
|
58
|
+
chars.has_lists = true;
|
|
59
|
+
}
|
|
60
|
+
if !chars.has_lists && line.chars().next().map_or(false, |c| c.is_ascii_digit()) && line.contains(". ") {
|
|
61
|
+
chars.has_lists = true;
|
|
62
|
+
}
|
|
63
|
+
if !chars.has_links && line.contains('[') {
|
|
64
|
+
chars.has_links = true;
|
|
65
|
+
}
|
|
66
|
+
if !chars.has_images && line.contains("![") {
|
|
67
|
+
chars.has_images = true;
|
|
68
|
+
}
|
|
69
|
+
if !chars.has_code && (line.contains('`') || line.contains("~~~")) {
|
|
70
|
+
chars.has_code = true;
|
|
71
|
+
}
|
|
72
|
+
if !chars.has_emphasis && (line.contains('*') || line.contains('_')) {
|
|
73
|
+
chars.has_emphasis = true;
|
|
74
|
+
}
|
|
75
|
+
if !chars.has_html && line.contains('<') {
|
|
76
|
+
chars.has_html = true;
|
|
77
|
+
}
|
|
78
|
+
if !chars.has_tables && line.contains('|') {
|
|
79
|
+
chars.has_tables = true;
|
|
80
|
+
}
|
|
81
|
+
if !chars.has_blockquotes && line.starts_with('>') {
|
|
82
|
+
chars.has_blockquotes = true;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
chars.has_headings = has_atx_heading || has_setext_heading;
|
|
87
|
+
chars
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/// Check if a rule should be skipped based on content characteristics
|
|
91
|
+
fn should_skip_rule(&self, rule: &dyn Rule) -> bool {
|
|
92
|
+
match rule.category() {
|
|
93
|
+
RuleCategory::Heading => !self.has_headings,
|
|
94
|
+
RuleCategory::List => !self.has_lists,
|
|
95
|
+
RuleCategory::Link => !self.has_links && !self.has_images,
|
|
96
|
+
RuleCategory::Image => !self.has_images,
|
|
97
|
+
RuleCategory::CodeBlock => !self.has_code,
|
|
98
|
+
RuleCategory::Html => !self.has_html,
|
|
99
|
+
RuleCategory::Emphasis => !self.has_emphasis,
|
|
100
|
+
RuleCategory::Blockquote => !self.has_blockquotes,
|
|
101
|
+
RuleCategory::Table => !self.has_tables,
|
|
102
|
+
// Always check these categories as they apply to all content
|
|
103
|
+
RuleCategory::Whitespace | RuleCategory::FrontMatter | RuleCategory::Other => false,
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/// Lint a file against the given rules with intelligent rule filtering
|
|
109
|
+
/// Assumes the provided `rules` vector contains the final,
|
|
110
|
+
/// configured, and filtered set of rules to be executed.
|
|
111
|
+
pub fn lint(content: &str, rules: &[Box<dyn Rule>], _verbose: bool) -> LintResult {
|
|
112
|
+
let mut warnings = Vec::new();
|
|
113
|
+
let _overall_start = Instant::now();
|
|
114
|
+
|
|
115
|
+
// Early return for empty content
|
|
116
|
+
if content.is_empty() {
|
|
117
|
+
return Ok(warnings);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Analyze content characteristics for rule filtering
|
|
121
|
+
let characteristics = ContentCharacteristics::analyze(content);
|
|
122
|
+
|
|
123
|
+
// Filter rules based on content characteristics
|
|
124
|
+
let applicable_rules: Vec<_> = rules
|
|
125
|
+
.iter()
|
|
126
|
+
.filter(|rule| !characteristics.should_skip_rule(rule.as_ref()))
|
|
127
|
+
.collect();
|
|
128
|
+
|
|
129
|
+
// Calculate skipped rules count before consuming applicable_rules
|
|
130
|
+
let _total_rules = rules.len();
|
|
131
|
+
let _applicable_count = applicable_rules.len();
|
|
132
|
+
|
|
133
|
+
// Parse DocumentStructure once
|
|
134
|
+
let structure = DocumentStructure::new(content);
|
|
135
|
+
|
|
136
|
+
// Parse AST once for rules that can benefit from it
|
|
137
|
+
let ast_rules_count = applicable_rules.iter().filter(|rule| rule.uses_ast()).count();
|
|
138
|
+
let ast = if ast_rules_count > 0 {
|
|
139
|
+
Some(crate::utils::ast_utils::get_cached_ast(content))
|
|
140
|
+
} else {
|
|
141
|
+
None
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// Parse LintContext once (migration step)
|
|
145
|
+
let lint_ctx = crate::lint_context::LintContext::new(content);
|
|
146
|
+
|
|
147
|
+
for rule in applicable_rules {
|
|
148
|
+
let _rule_start = Instant::now();
|
|
149
|
+
|
|
150
|
+
// Try optimized paths in order of preference
|
|
151
|
+
let result = if rule.uses_ast() && ast.is_some() {
|
|
152
|
+
// 1. AST-based path
|
|
153
|
+
rule.as_maybe_ast()
|
|
154
|
+
.and_then(|ext| ext.check_with_ast_opt(&lint_ctx, ast.as_ref().unwrap()))
|
|
155
|
+
.unwrap_or_else(|| rule.check_with_ast(&lint_ctx, ast.as_ref().unwrap()))
|
|
156
|
+
} else {
|
|
157
|
+
// 2. Document structure path
|
|
158
|
+
rule.as_maybe_document_structure()
|
|
159
|
+
.and_then(|ext| ext.check_with_structure_opt(&lint_ctx, &structure))
|
|
160
|
+
.unwrap_or_else(|| rule.check(&lint_ctx))
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
match result {
|
|
164
|
+
Ok(rule_warnings) => {
|
|
165
|
+
warnings.extend(rule_warnings);
|
|
166
|
+
}
|
|
167
|
+
Err(e) => {
|
|
168
|
+
log::error!("Error checking rule {}: {}", rule.name(), e);
|
|
169
|
+
return Err(e);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
#[cfg(not(test))]
|
|
174
|
+
if _verbose {
|
|
175
|
+
let rule_duration = _rule_start.elapsed();
|
|
176
|
+
if rule_duration.as_millis() > 500 {
|
|
177
|
+
log::debug!("Rule {} took {:?}", rule.name(), rule_duration);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
#[cfg(not(test))]
|
|
183
|
+
if _verbose {
|
|
184
|
+
let skipped_rules = _total_rules - _applicable_count;
|
|
185
|
+
if skipped_rules > 0 {
|
|
186
|
+
log::debug!("Skipped {} of {} rules based on content analysis", skipped_rules, _total_rules);
|
|
187
|
+
}
|
|
188
|
+
if ast.is_some() {
|
|
189
|
+
log::debug!("Used shared AST for {} rules", ast_rules_count);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
Ok(warnings)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/// Get the profiling report
|
|
197
|
+
pub fn get_profiling_report() -> String {
|
|
198
|
+
profiling::get_report()
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/// Reset the profiling data
|
|
202
|
+
pub fn reset_profiling() {
|
|
203
|
+
profiling::reset()
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/// Get regex cache statistics for performance monitoring
|
|
207
|
+
pub fn get_regex_cache_stats() -> std::collections::HashMap<String, u64> {
|
|
208
|
+
crate::utils::regex_cache::get_cache_stats()
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/// Get AST cache statistics for performance monitoring
|
|
212
|
+
pub fn get_ast_cache_stats() -> std::collections::HashMap<u64, u64> {
|
|
213
|
+
crate::utils::ast_utils::get_ast_cache_stats()
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/// Clear all caches (useful for testing and memory management)
|
|
217
|
+
pub fn clear_all_caches() {
|
|
218
|
+
crate::utils::ast_utils::clear_ast_cache();
|
|
219
|
+
// Note: Regex cache is intentionally not cleared as it's global and shared
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/// Get comprehensive cache performance report
|
|
223
|
+
pub fn get_cache_performance_report() -> String {
|
|
224
|
+
let regex_stats = get_regex_cache_stats();
|
|
225
|
+
let ast_stats = get_ast_cache_stats();
|
|
226
|
+
|
|
227
|
+
let mut report = String::new();
|
|
228
|
+
|
|
229
|
+
report.push_str("=== Cache Performance Report ===\n\n");
|
|
230
|
+
|
|
231
|
+
// Regex cache statistics
|
|
232
|
+
report.push_str("Regex Cache:\n");
|
|
233
|
+
if regex_stats.is_empty() {
|
|
234
|
+
report.push_str(" No regex patterns cached\n");
|
|
235
|
+
} else {
|
|
236
|
+
let total_usage: u64 = regex_stats.values().sum();
|
|
237
|
+
report.push_str(&format!(" Total patterns: {}\n", regex_stats.len()));
|
|
238
|
+
report.push_str(&format!(" Total usage: {}\n", total_usage));
|
|
239
|
+
|
|
240
|
+
// Show top 5 most used patterns
|
|
241
|
+
let mut sorted_patterns: Vec<_> = regex_stats.iter().collect();
|
|
242
|
+
sorted_patterns.sort_by(|a, b| b.1.cmp(a.1));
|
|
243
|
+
|
|
244
|
+
report.push_str(" Top patterns by usage:\n");
|
|
245
|
+
for (pattern, count) in sorted_patterns.iter().take(5) {
|
|
246
|
+
let truncated_pattern = if pattern.len() > 50 {
|
|
247
|
+
format!("{}...", &pattern[..47])
|
|
248
|
+
} else {
|
|
249
|
+
pattern.to_string()
|
|
250
|
+
};
|
|
251
|
+
report.push_str(&format!(" {} ({}x): {}\n", count, pattern.len().min(50), truncated_pattern));
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
report.push_str("\n");
|
|
256
|
+
|
|
257
|
+
// AST cache statistics
|
|
258
|
+
report.push_str("AST Cache:\n");
|
|
259
|
+
if ast_stats.is_empty() {
|
|
260
|
+
report.push_str(" No AST nodes cached\n");
|
|
261
|
+
} else {
|
|
262
|
+
let total_usage: u64 = ast_stats.values().sum();
|
|
263
|
+
report.push_str(&format!(" Total ASTs: {}\n", ast_stats.len()));
|
|
264
|
+
report.push_str(&format!(" Total usage: {}\n", total_usage));
|
|
265
|
+
|
|
266
|
+
if total_usage > ast_stats.len() as u64 {
|
|
267
|
+
let cache_hit_rate = ((total_usage - ast_stats.len() as u64) as f64 / total_usage as f64) * 100.0;
|
|
268
|
+
report.push_str(&format!(" Cache hit rate: {:.1}%\n", cache_hit_rate));
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
report
|
|
273
|
+
}
|