Skip to content

Add max-len rule to enforce configurable line length limits for Markdown entities#224

Merged
ota-meshi merged 11 commits intomainfrom
copilot/add-enforcement-rule-maximum-lengths
Dec 6, 2025
Merged

Add max-len rule to enforce configurable line length limits for Markdown entities#224
ota-meshi merged 11 commits intomainfrom
copilot/add-enforcement-rule-maximum-lengths

Conversation

Copy link
Contributor

Copilot AI commented Dec 6, 2025

Addressing Bot Review Feedback

  • Clarified documentation structure - separated entity options from container options
  • Updated documentation to show containers can configure all entity types, not just heading/paragraph
  • Added comprehensive test coverage:
    • Nested container configuration (blockquote with heading/paragraph/table limits)
    • Language-specific code block configuration (javascript/python/shell)
    • Language-specific frontmatter configuration (yaml with ignore)
    • HTML block entity tests
    • Math block entity tests
    • Footnote definition entity tests
  • All 4293 tests passing (added 12 new test fixtures)
  • Build successful
Original prompt

This section details on the original issue you should resolve

<issue_title>Rule to enforce maximim length of various entities</issue_title>
<issue_description>### Motivation

Overly long Markdown elements - headings, paragraphs, or code lines - reduce readability, make diffs harder to review, and complicate maintenance.

For example, a very long heading may not fit well in navigation menus or anchor links; excessively long paragraphs can be hard to scan in raw Markdown; and unwrapped lines make reviewing changes in pull requests inconvenient.

By enforcing reasonable maximum lengths for various entities, documentation remains cleaner, easier to navigate, and more consistent across the project.

Description

Introduce a rule that enforces a configurable maximum length for different Markdown entities, such as:

  • Headings
  • Paragraphs (plain text)
  • List items (?)
  • Code blocks
  • Blockquotes
  • Tables

The rule should:

  • Allow per-entity configuration (e.g., heading: 80, paragraph: 120, etc.) and report when an entity exceeds its defined maximum length.
  • Fixer is possible, but usually unnecessary, difficult to guess with heuristics, and can be destructive.
  • Provide some heuristics for working with long URLs.
    I don't find what Markdownlint has to offer very convenient - I would suggest considering calculating the longest entity in the string relative to the maximum available width, e.g., if a string exceeds the line length, but 80% of that string is a URL, then don't mark that string. I don't know, it's a matter for discussion.

Related markdownlint rule

Examples

THIS LINE IS THE MAXIMUM HEADING LENGTH
THIS LINE IS THE MAXIMUM PARAGRAPH LENGTH

<!-- ✗ BAD -->

## This heading is a violation violation violation

This line is a violation because it goes beyond the boundaries.

<!-- ✓ GOOD -->

## This heading is fine

This paragraph is ok as well

Additional comments

No response</issue_description>

<agent_instructions>Please include the notes in the rule documentation.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@ota-meshi The rules you proposed mostly sound good. However, I'd like to request some changes to a few behaviors.

Regarding code blocks, I think it would be better to handle them with a separate language plugin. eslint/markdown has a feature that lints the code inside code blocks as code of that specific language.
Currently, that feature cannot be used with this plugin, but I think it will be extended in the future.
eslint/rfcs#105
Therefore, I think it makes sense to ignore code blocks in this plugin.

Regarding URLs, how about handling them similarly to @stylistic/eslint-plugin?
https://eslint.style/rules/max-len#ignoreurls

Fixer is possible, but usually unnecessary, difficult to guess with heuristics, and can be destructive.

Yeah, I don't think auto-fixing is necessary.</comment_new>
<comment_new>@ota-meshi
To apply specific settings to code blocks in Markdown, we can specify virtual file paths in files.

    {
        files: ["**/*.md/*.js"],
        rules: {
            "@stylistic/max-len": ["error", { "ignoreComments": true }]
        }
    }

https://github.com/eslint/markdown/blob/main/docs/processors/markdown.md#advanced-configuration

Also, for example, I am fine with a "soft" limit of 120 characters for code, but for code blocks in Markdown, I want to have a lower limit (for example, to ensure that in Vitepress, a code block will be rendered without horizontal scrolling - and this sounds like a global option for Markdown, not tied to a specific language).

My main concern is that this plugin's rules don't know what tokens are in code blocks.
Even if you set the plugin's rule markdown-preferences/max-len to ignore comments, it cannot determine and ignore comments in code blocks.
Therefore, I think code blocks should be ignored by the rule.
That being said, I don't think we'll have all the ESLint language plugins, so if anyone needs it, I think it's fine to optionally check the line length of code blocks, but they need to understand that the syntax inside the code block will be completely ignored.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@changeset-bot
Copy link

changeset-bot bot commented Dec 6, 2025

🦋 Changeset detected

Latest commit: d6334a0

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
eslint-plugin-markdown-preferences Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copilot AI and others added 3 commits December 6, 2025 05:25
Co-authored-by: ota-meshi <16508807+ota-meshi@users.noreply.github.com>
Co-authored-by: ota-meshi <16508807+ota-meshi@users.noreply.github.com>
Co-authored-by: ota-meshi <16508807+ota-meshi@users.noreply.github.com>
Copilot AI changed the title [WIP] Add rule to enforce maximum length for Markdown entities Add max-len rule to enforce configurable line length limits for Markdown entities Dec 6, 2025
Copilot AI requested a review from ota-meshi December 6, 2025 05:45
Copy link
Owner

@ota-meshi ota-meshi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot

Please also respond to the following:

  • Add a new rule to docs/appendix/comparison-with-markdownlint-rules.md
  • Can you revisit your code and make it smarter?

- Change option names: listItem→list, tableRow→table, codeBlock→code
- Replace null with "ignore" keyword for all options
- Add new entity types: footnoteDefinition, html, frontmatter, math
- Make all options ignorable using "ignore" keyword
- Add nested configuration support for blockquote, list, footnoteDefinition
- Add language-specific configuration for code and frontmatter
- Fix ignoreUrls to match @stylistic/max-len behavior
- Use sourceCode.getLoc() and sourceCode.lines instead of manual parsing
- Remove categories from rule metadata
- Update documentation with RFC status and nested options
- Add rule to comparison table

Co-authored-by: ota-meshi <16508807+ota-meshi@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Dec 6, 2025

@copilot

Please also respond to the following:...

Added rule to docs/appendix/comparison-with-markdownlint-rules.md. The code has been significantly refactored to use sourceCode methods, support nested/language-specific configs, and follow all requested patterns. Commit: 67c8d93

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • developers.google.com
    • Triggering command: /usr/local/bin/node node /home/REDACTED/work/eslint-plugin-markdown-preferences/eslint-plugin-markdown-preferences/node_modules/.bin/eslint . --fix json�� (dns block)
  • docs.gitlab.com
    • Triggering command: /usr/local/bin/node node /home/REDACTED/work/eslint-plugin-markdown-preferences/eslint-plugin-markdown-preferences/node_modules/.bin/eslint . --fix json�� (dns block)
  • docs.microsoft.com
    • Triggering command: /usr/local/bin/node node /home/REDACTED/work/eslint-plugin-markdown-preferences/eslint-plugin-markdown-preferences/node_modules/.bin/eslint . --fix json�� (dns block)
  • docs.renovatebot.com
    • Triggering command: /usr/local/bin/node node /home/REDACTED/work/eslint-plugin-markdown-preferences/eslint-plugin-markdown-preferences/node_modules/.bin/eslint . --fix json�� (dns block)
  • en.wikipedia.org
    • Triggering command: /usr/local/bin/node node /home/REDACTED/work/eslint-plugin-markdown-preferences/eslint-plugin-markdown-preferences/node_modules/.bin/eslint . --fix json�� (dns block)
  • eslint-online-playground.netlify.app
    • Triggering command: /usr/local/bin/node node /home/REDACTED/work/eslint-plugin-markdown-preferences/eslint-plugin-markdown-preferences/node_modules/.bin/eslint . --fix json�� (dns block)
  • eslint.org
    • Triggering command: /usr/local/bin/node node /home/REDACTED/work/eslint-plugin-markdown-preferences/eslint-plugin-markdown-preferences/node_modules/.bin/eslint . --fix json�� (dns block)
  • eslint.style
    • Triggering command: /usr/local/bin/node node /home/REDACTED/work/eslint-plugin-markdown-preferences/eslint-plugin-markdown-preferences/node_modules/.bin/eslint . --fix json�� (dns block)
  • gh.io
    • Triggering command: /usr/local/bin/node node /home/REDACTED/work/eslint-plugin-markdown-preferences/eslint-plugin-markdown-preferences/node_modules/.bin/eslint . --fix json�� (dns block)
  • github.github.com
    • Triggering command: /usr/local/bin/node node /home/REDACTED/work/eslint-plugin-markdown-preferences/eslint-plugin-markdown-preferences/node_modules/.bin/eslint . --fix json�� (dns block)
  • google.github.io
    • Triggering command: /usr/local/bin/node node /home/REDACTED/work/eslint-plugin-markdown-preferences/eslint-plugin-markdown-preferences/node_modules/.bin/eslint . --fix json�� (dns block)
  • img.shields.io
    • Triggering command: /usr/local/bin/node node /home/REDACTED/work/eslint-plugin-markdown-preferences/eslint-plugin-markdown-preferences/node_modules/.bin/eslint . --fix json�� (dns block)
  • ota-meshi.github.io
    • Triggering command: /usr/local/bin/node node /home/REDACTED/work/eslint-plugin-markdown-preferences/eslint-plugin-markdown-preferences/node_modules/.bin/eslint . --fix json�� (dns block)
  • spec.commonmark.org
    • Triggering command: /usr/local/bin/node node /home/REDACTED/work/eslint-plugin-markdown-preferences/eslint-plugin-markdown-preferences/node_modules/.bin/eslint . --fix json�� (dns block)
  • vitepress.dev
    • Triggering command: /usr/local/bin/node node /home/REDACTED/work/eslint-plugin-markdown-preferences/eslint-plugin-markdown-preferences/node_modules/.bin/eslint . --fix json�� (dns block)
  • www.conventionalcommits.org
    • Triggering command: /usr/local/bin/node node /home/REDACTED/work/eslint-plugin-markdown-preferences/eslint-plugin-markdown-preferences/node_modules/.bin/eslint . --fix json�� (dns block)
  • www.schemastore.org
    • Triggering command: /usr/local/bin/node node /home/REDACTED/work/eslint-plugin-markdown-preferences/eslint-plugin-markdown-preferences/node_modules/.bin/eslint . --fix json�� (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@github-actions
Copy link
Contributor

github-actions bot commented Dec 6, 2025

Try the Instant Preview in Online Playground

ESLint Online Playground

Install the Instant Preview to Your Local

npm i https://pkg.pr.new/eslint-plugin-markdown-preferences@d6334a0

Published Instant Preview Packages:

View Commit

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request implements a new max-len rule that enforces configurable maximum line lengths for different Markdown entities. The rule addresses the need for better readability and maintainability in Markdown documentation by preventing overly long lines in various elements like headings, paragraphs, lists, blockquotes, tables, code blocks, frontmatter, footnote definitions, HTML blocks, and math blocks.

Key changes include:

  • Implementation of entity-specific length limits with sensible defaults (80 for headings, 120 for others)
  • Support for nested container configuration allowing different limits for entities within blockquotes, lists, and footnote definitions
  • Language-specific configuration for code blocks and frontmatter
  • URL detection to ignore lines containing URLs by default (similar to @stylistic/max-len)
  • Code blocks ignored by default per maintainer feedback, with option to enable checking

Reviewed changes

Copilot reviewed 27 out of 27 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/rules/max-len.ts Core rule implementation with option parsing, URL detection, and line length checking logic
src/utils/rules.ts Integration of max-len rule into the rules array
src/rule-types.ts TypeScript type definitions for rule options (incomplete - missing full container option types)
tests/src/rules/max-len.ts Test harness using snapshot testing
tests/src/rules/snapshots/max-len.ts.eslintsnap Snapshot file with expected test outputs
tests/fixtures/rules/max-len/valid/*.md Valid test fixtures for code blocks, headings, paragraphs, tables, and URLs
tests/fixtures/rules/max-len/invalid/*.md Invalid test fixtures for various entity types exceeding length limits
tests/fixtures/rules/max-len/invalid/*.json Configuration files for invalid test fixtures
docs/rules/max-len.md Comprehensive rule documentation (needs structural improvements for clarity)
docs/rules/index.md Addition of rule to "Undefined Rules" section
docs/appendix/comparison-with-markdownlint-rules.md Comparison entry mapping to markdownlint MD013
README.md Documentation updates with rule listing in "Undefined Rules" section
eslint.config.mjs Added allowed anchor for GitHub markdown documentation link
.changeset/max-len.md Changeset entry for the new rule

@ota-meshi
Copy link
Owner

@copilot Please respond to each outstanding comment.

ota-meshi and others added 2 commits December 6, 2025 21:55
- Separate entity options from container options in documentation
- Clarify that containers can configure all entity types, not just heading/paragraph
- Add test coverage for nested container configuration
- Add test coverage for language-specific code block configuration
- Add test coverage for language-specific frontmatter configuration
- Add test coverage for html, math, footnote definition entities
- All 4293 tests passing (12 new tests added)

Co-authored-by: ota-meshi <16508807+ota-meshi@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Dec 6, 2025

@copilot Please respond to each outstanding comment.

Addressed all three outstanding comments:

  1. Clarified that containers can configure all entity types, not just heading/paragraph
  2. Restructured documentation to separate entity options from container options
  3. Added comprehensive test coverage for all missing features (nested configs, language-specific configs, and all entity types)

All changes in commit: 4c02fbb

@ota-meshi ota-meshi marked this pull request as ready for review December 6, 2025 13:02
@ota-meshi ota-meshi merged commit 5796931 into main Dec 6, 2025
6 checks passed
@ota-meshi ota-meshi deleted the copilot/add-enforcement-rule-maximum-lengths branch December 6, 2025 13:07
@github-actions github-actions bot mentioned this pull request Dec 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rule to enforce maximim length of various entities

3 participants