Skip to content

Comments

fix: recognize Definition node in no-missing-link-fragments#603

Merged
DMartens merged 8 commits intomainfrom
fix/recognize-definition-node-in-no-missing-link-fragments
Jan 22, 2026
Merged

fix: recognize Definition node in no-missing-link-fragments#603
DMartens merged 8 commits intomainfrom
fix/recognize-definition-node-in-no-missing-link-fragments

Conversation

@lumirlumir
Copy link
Member

@lumirlumir lumirlumir commented Jan 4, 2026

Prerequisites checklist

What is the purpose of this pull request?

Which language are you using?

CommonMark and GFM.

What did you do?

I expected the [reference]: #non-existent definition to be reported by the no-missing-link-fragments rule, but it isn't.

The Invalid link reference is also considered valid link when using reference-style links.

image

What did you expect to happen?

I expected the [reference]: #non-existent definition to be reported by the no-missing-link-fragments rule.

Link to minimal reproducible Example

The following example would help identify the problem:

<!-- eslint markdown/no-missing-link-fragments: "error" -->

<!-- Valid -->

[Valid](#non-existent)

<!-- Invalid (False Negative) -->

[Invalid][reference]

[reference]: #non-existent

What changes did you make? (Give an overview)

In this PR, I've fixed a false negative caused by an unrecognized Definition node in no-missing-link-fragments.

This issue was discovered while working on #583, and to avoid making that PR too large, I split this into a separate PR.


Previously, the rule did not handle a Definition node like the following:

link(node) {
const url = node.url;
if (!url || !url.startsWith("#")) {
return;
}
const fragment = url.slice(1);
if (!fragment) {
return;
}
linkNodes.push({ node, fragment });
},

I've updated the logic to recognize Definition nodes accordingly.


I've also refactored the codebase. There was some unnecessary or duplicate logic in the rule, so I refactored it to make the rule logic clearer, and faster. I've left comments on the notable parts of this change.

Related Issues

Ref: #583

Is there anything you'd like reviewers to focus on?

N/A

@eslint-github-bot eslint-github-bot bot added the bug label Jan 4, 2026
@eslintbot eslintbot added this to Triage Jan 4, 2026
@github-project-automation github-project-automation bot moved this to Needs Triage in Triage Jan 4, 2026
@lumirlumir lumirlumir moved this from Needs Triage to Implementing in Triage Jan 4, 2026
Comment on lines +550 to +579
{
code: dedent`
[Invalid Format](#l20)
`,
errors: [
{
messageId: "invalidFragment",
data: { fragment: "l20" },
line: 1,
column: 1,
endLine: 1,
endColumn: 23,
},
],
},
{
code: dedent`
[Invalid Format](#l20-l30)
`,
errors: [
{
messageId: "invalidFragment",
data: { fragment: "l20-l30" },
line: 1,
column: 1,
endLine: 1,
endColumn: 27,
},
],
},
Copy link
Member Author

Choose a reason for hiding this comment

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

These test cases were added primarily to ensure that githubLineReferencePattern is case-insensitive.

Before adding this test, the suite passed even when I added the i flag to the following regex pattern:

const githubLineReferencePattern = /^L\d+(?:C\d+)?(?:-L\d+(?:C\d+)?)?$/u;


FYI: You can verify that the githubLineReferencePattern is case-insensitive using the following examples:

  • OK

https://github.com/eslint/markdown/blob/main/package.json#L4
https://github.com/eslint/markdown/blob/main/package.json#L4-L6

  • Not OK

https://github.com/eslint/markdown/blob/main/package.json#l4 // Unworking.
https://github.com/eslint/markdown/blob/main/package.json#l4-l6 // Unworking.

Comment on lines +124 to 133
"definition, link"(/** @type {Definition | Link} */ node) {
const { url } = node;

const fragment = url.slice(1);
if (!fragment) {
// If `url` is empty, `"#"`, or does not start with `"#"`, skip it.
if (url === "" || url === "#" || !url.startsWith("#")) {
return;
}

linkNodes.push({ node, fragment });
relevantNodes.push(node);
},
Copy link
Member Author

@lumirlumir lumirlumir Jan 4, 2026

Choose a reason for hiding this comment

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

This is a small improvement: I've simplified the logic to reduce a bit of memory usage and computation.

Previously, we created a new data structure type as follows:

/** @type {Array<{node: Link, fragment: string}>} */
const linkNodes = [];

linkNodes.push({ node, fragment });

However, now we no longer create a new object and instead use an existing object reference; it's small, but it would reduce memory usage and computation.

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 PR fixes a false negative in the no-missing-link-fragments rule where reference-style link definitions (e.g., [reference]: #fragment) were not being validated against existing headings. The rule now correctly reports when Definition nodes reference non-existent fragments.

Key changes:

  • Added support for checking Definition nodes in addition to Link nodes
  • Refactored redundant code, including removing unnecessary toLowerCase() calls (github-slugger already lowercases)
  • Replaced htmlCommentPattern regex with stripHtmlComments() utility function for better maintainability

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/rules/no-missing-link-fragments.js Updated to recognize Definition nodes using a combined "definition, link" handler; refactored to remove redundant toLowerCase operations since github-slugger already returns lowercase slugs; switched to using stripHtmlComments() utility function
tests/rules/no-missing-link-fragments.test.js Added test cases for valid and invalid Definition nodes; added additional test cases for invalid line reference formats (#l20 and #l20-l30) to verify case-sensitive validation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@lumirlumir lumirlumir moved this from Implementing to Needs Triage in Triage Jan 4, 2026
@lumirlumir lumirlumir requested a review from a team January 19, 2026 14:37
…cognize-definition-node-in-no-missing-link-fragments
@lumirlumir lumirlumir requested a review from DMartens January 20, 2026 14:16
Copy link
Contributor

@snitin315 snitin315 left a comment

Choose a reason for hiding this comment

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

LGTM, thanks! Leaving it open for @DMartens

@DMartens
Copy link
Contributor

Changes LGTM, thanks.

@DMartens DMartens merged commit 9b58e36 into main Jan 22, 2026
25 checks passed
@DMartens DMartens deleted the fix/recognize-definition-node-in-no-missing-link-fragments branch January 22, 2026 22:35
@github-project-automation github-project-automation bot moved this from Needs Triage to Complete in Triage Jan 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Complete

Development

Successfully merging this pull request may close these issues.

3 participants