rumdl

repository·main·Indexed 23 days ago

https://github.com/rvben/rumdl

A high-performance Markdown linter and formatter written in Rust. It supports multiple Markdown flavors (GFM, MkDocs, MDX, etc.) and provides linting, automatic fixing, and formatting capabilities. Available as a CLI tool via npm, Cargo, pip, Homebrew, and other package managers, as well as through Docker images and editor plugins for VS Code and JetBrains.

Tokens
119.9K
Snippets
344
Records
574
Agent score
77%

What's inside rumdl

  1. rumdl VS Code Extension Overview

    main

    The rumdl VS Code extension provides real-time Markdown linting powered by the Rust-based rumdl engine. It is compatible with VS Code, Cursor, and Windsurf.

    Key Features:

    • Real-time Linting: Instant feedback on Markdown issues as you type.
    • Quick Fixes: One-click fixes for auto-fixable violations.
    • Full Rule Coverage: Complete coverage of all rumdl rules with proper categorization.
    • High Performance: Optimized for speed (up to 5x faster than markdownlint).
    • Configuration Support: Respects .rumdl.toml files.

    Requirements:

    • VS Code 1.74.0 or higher.
    • rumdl CLI (optional, but recommended for full functionality).
  2. Compare rumdl with markdownlint

    main

    rumdl is a high-performance Markdown linter and formatter written in Rust. It is designed to be a faster, more modern alternative to markdownlint while maintaining high compatibility.

    Key Advantages:

    • Performance: 30-100x faster than markdownlint due to Rust and intelligent caching (incremental linting).
    • Rule Coverage: Implements all 53 markdownlint rules plus 28 unique rules (e.g., MD057 for relative links, MD061 for forbidden terms).
    • Markdown Flavors: Built-in support for standard, gfm, mkdocs, mdx, obsidian, and quarto.
    • LSP Support: Includes a built-in Language Server Protocol for real-time editor integration.
    • Configuration: Automatically discovers and converts existing markdownlint configurations.
  3. What is allowed under the MD033 rule

    main

    The MD033 rule flags HTML tags, but it explicitly ignores the following patterns which are considered valid Markdown syntax rather than HTML:

    • HTML comments: <!-- This is a comment -->
    • Email autolinks: <user@example.com>
    • URL autolinks: <https://example.com>
    • FTP autolinks: <ftp://files.example.com>
  4. Understand how MD085 handles paragraph indentation

    main

    The MD085 rule targets leading whitespace in top-level paragraphs to ensure that paragraphs look identical in the source regardless of how they were wrapped or edited.

    What it changes

    It removes leading spaces and tabs from continuation lines.

    Incorrect:

    This is some paragraph
     with line breaks
      and indentation.

    Correct:

    This is some paragraph
    with line breaks
    and indentation.

    What it leaves alone (Structural Indentation)

    To avoid breaking Markdown structure, the rule does not touch indentation in the following contexts:

    • List item content (including lazy continuation lines)
    • Blockquotes and their lazy continuation lines
    • Tables, footnote bodies, and definition lists
    • Code blocks (fenced or indented), HTML, math, and front matter blocks
    • Flavor-specific containers (e.g., MkDocs admonitions, Pandoc/Quarto divs, MyST directives)
    • Multi-line code spans
    • HTML blocks (everything under a line beginning with < until the next blank line)
    • Lines that would become a new block if the indentation were removed (e.g., lines starting with #, >, -, +, *, _, =, `, ~, <, |, [, {, :, $, !, % or a digit)

    Important Nuances

    • Prose vs. Blocks: A continuation line indented by four or more spaces is treated as prose and will be rewritten, because an indented code block cannot interrupt a paragraph.
    • Hard Line Breaks: The rule only removes leading whitespace; it does not affect hard line breaks (like a backslash or two spaces at the end of a line).
  5. Configure path patterns and the home directory

    main

    Settings that accept paths or file patterns (extends, exclude, include, per-file-ignores, per-file-flavor, and cache-dir) support three forms:

    1. Relative: docs/** (Relative to the project root).
    2. Absolute: /absolute/path (That specific location on disk).
    3. Home Directory: ~/path (Expands to the user's home directory).

    Note on ~: Only a leading ~/ or a bare ~ expands to the home directory. A ~ elsewhere in a string (e.g., docs/~drafts) is treated as a literal character.

    [global]
    exclude = ["~/.cursor/plans"]
    cache-dir = "~/.cache/rumdl"
  6. MD077 - List continuation content indentation

    main

    The MD077 rule (alias: list-continuation-indent) ensures that content continuing inside a list item aligns correctly with the item's content column (the W+N rule from CommonMark).

    It flags two types of errors:

    1. Under-indentation after a blank line: This causes content to 'escape' the list and render as a separate paragraph.
    2. Over-indentation: This occurs in both tight continuation (no blank line) and loose continuation (after a blank line), pushing the body past the content column.

    Note: Content indented to the content column + 4 or more after a blank line is treated as an indented code block and is left untouched.

  7. How MyST flavor handles directives and roles

    main

    The MyST flavor adjusts how rumdl interprets several structural patterns to prevent linting errors on valid MyST syntax:

    Colon Directives

    MyST uses ::: (or more colons) for structural containers. Nesting is supported by increasing the colon count.

    • Opener: :::{name}
    • Closer: ::: (matching the number of colons used in the opener)
    • Linting: The body of colon directives is treated as normal Markdown prose and is linted accordingly.

    Backtick Directives

    MyST uses backtick code fences with a {name} info string (e.g., ```{note}).

    • Content-bearing directives: For directives like note, warning, tip, figure, etc., the body is linted as Markdown.
    • Code-bearing directives: For directives like code-cell, code-block, raw, eval-rst, and literalinclude, the body is treated as code and is not linted.

    Roles (Inline Directives)

    MyST roles use the pattern {rolename} followed by backtick-delimited content (e.g., {ref}label or `{math}`expression). These are recognized as valid syntax and are not flagged as malformed inline code.

    Directive Options

    Options can be specified as :key: value lines immediately after the opener. These lines are part of the directive and are not linted as prose.

    :::{note}
    This is a note admonition with **Markdown** content.
    :::
    
    ::::{warning}
    Outer directive.
    
    :::{tip}
    Inner directive.
    :::
    ::::
    
    ```{figure} image.png
    :alt: An image description
    :width: 80%
    
    Caption text with **Markdown** formatting.

    See {ref}my-label for details.

  8. Fix reversed link syntax (MD011)

    main

    The MD011 rule (also known by the alias no-reversed-links) detects and fixes Markdown links where the link text and the URL are swapped.

    Incorrect syntax: (text)[url] Correct syntax: [text](url)

    This rule is useful for preventing broken links, improving SEO, and ensuring professional formatting. It automatically handles complex cases, such as nested parentheses within the link text, by swapping the components into the correct order.

    ### ✅ Correct
    
    ```markdown
    Check out [our documentation](https://docs.example.com)
    Visit the [GitHub repository](https://github.com/example/repo)
    Contact us at [support@example.com](mailto:support@example.com)

    ❌ Incorrect

    Check out (our documentation)[https://docs.example.com]
    Visit the (GitHub repository)[https://github.com/example/repo]
    Contact us at (support@example.com)[mailto:support@example.com]
  9. Understand MD026: Keep headings clean and professional

    main

    The MD026 rule (alias: no-trailing-punctuation) removes trailing punctuation from the end of headings to maintain a clean, professional appearance and improve readability in tables of contents.

    Automatic Fixes

    When applied, rumdl will automatically:

    • Remove periods, commas, semicolons, colons, and exclamation marks from heading endings.
    • Preserve question marks (e.g., ## What is Markdown? remains unchanged).

    Examples

    Correct usage:

    # Introduction
    
    ## What is Markdown?
    
    ### FAQ: Frequently Asked Questions

    Incorrect usage (will be fixed):

    # This is a sentence.
    
    ## Random heading;
    
    ### This seems wrong,
    
    #### Important!
    
    ##### Ending with colon:

    Fixed output:

    # This is a sentence
    
    ## Random heading
    
    ### This seems wrong
    
    #### Important
    
    ##### Ending with colon
    # Introduction
    
    ## What is Markdown?
    
    ### FAQ: Frequently Asked Questions
    
    #### Step 1: Getting Started
    
    ##### Chapter 2: Configuration
  10. Behavioral differences between rumdl and markdownlint

    main

    Because rumdl prioritizes CommonMark compliance and performance, some rules behave differently than markdownlint.

    Key Rule Divergences

    • MD004 (unordered-list-style): In consistent mode, rumdl uses prevalence-based detection (the most common marker wins; ties prefer dashes). markdownlint uses the first marker as the standard.
    • MD005/MD007 (list-indent / ul-indent): rumdl uses parent-based dynamic indentation to handle ordered lists with variable marker widths (e.g., 1. vs 10.).
    • MD012 (no-multiple-blanks): rumdl uses a filtered_lines() architecture to skip frontmatter and code blocks, which may result in different counts near block boundaries.
    • MD013 (line-length): rumdl exempts unbreakable lines (URLs, long code spans) and supports a line_length = 0 setting for unlimited length. It also includes a math-blocks option (default true) to exempt display-math ($$ ... $$) from length checks.
    • MD027 (no-multiple-space-blockquote): rumdl's list-items option defaults to false to reduce noise in blockquotes. Set list-items = true for strict markdownlint parity.
    • MD029 (ordered-list-prefix): rumdl uses CommonMark AST start values. It only auto-fixes when start_value == 1 to preserve explicit numbering intent.
    • MD051 (link-fragments): rumdl's ignore-case option defaults to true. Set ignore-case = false for strict markdownlint parity.
  11. Understand MD080 heading anchor collisions

    main

    MD080 detects when different heading texts result in the same slug, creating ambiguous fragment targets. This is distinct from:

    • MD024: Flags duplicate heading text (e.g., two headings both named ## Setup).
    • MD051: Flags broken fragment references (links that point to nothing).

    MD080 flags cases where the link works, but points to the wrong heading because the slug is not unique. For example, in GitHub's algorithm, Setup & Run and Setup Run both slugify to #setup--run.

  12. Understand how MD087 (unused-disable-comment) works

    main

    The MD087 rule identifies 'dead' disable comments—comments that are present but no longer serve a purpose because the violation they were meant to suppress no longer exists.

    Why use it?

    Disable comments often persist after code is refactored. If a long URL is shortened, a rumdl-disable-line MD013 comment might remain. This silently keeps coverage turned off for a rule that is no longer needed. MD087 flags these to ensure your linting coverage remains accurate.

    Examples

    Incorrect (triggers MD087):

    A short line. <!-- rumdl-disable-line MD013 -->

    In this case, MD013 has nothing to report on this line, so the comment is useless.

    Correct:

    <!-- rumdl-disable-next-line MD013 -->
    A line so long that it genuinely exceeds the configured limit, which is what the comment is for.

    Partial Suppression: If a comment names multiple rules, MD087 will report only the specific rules that suppressed nothing:

    Text with <b>html</b>. <!-- rumdl-disable-line MD033 MD013 -->

    If MD033 fires but MD013 does not, the error message will name MD013 alone.

    What MD087 ignores

    • Rules that are not part of the current run (e.g., disabled in config, excluded via --disable, or in per-file-ignores).
    • Comments with no rule name (e.g., <!-- rumdl-disable -->).
    • Comments inside fenced or indented code blocks.
    • <!-- prettier-ignore --> comments.
    • Unknown rule names (e.g., MD999).