diff --git a/src/rules/no-missing-link-fragments.js b/src/rules/no-missing-link-fragments.js
index ebc29c8f..0455d642 100644
--- a/src/rules/no-missing-link-fragments.js
+++ b/src/rules/no-missing-link-fragments.js
@@ -28,7 +28,8 @@ import GithubSlugger from "github-slugger";
const githubLineReferencePattern = /^L\d+(?:C\d+)?(?:-L\d+(?:C\d+)?)?$/u;
const customHeadingIdPattern = /\{#([^}\s]+)\}\s*$/u;
const htmlCommentPattern = //gu;
-const htmlIdNamePattern = /(?]+)\s(?:id|name)=["']([^"']+)["']/giu;
+const htmlIdNamePattern =
+ /(?]+)\s(?:id|name)\s*=\s*["']?([^"'\s>]+)["']?/giu;
/**
* Checks if the fragment is a valid GitHub line reference
diff --git a/tests/rules/no-missing-link-fragments.test.js b/tests/rules/no-missing-link-fragments.test.js
index 4c44ac77..233582b3 100644
--- a/tests/rules/no-missing-link-fragments.test.js
+++ b/tests/rules/no-missing-link-fragments.test.js
@@ -101,6 +101,59 @@ ruleTester.run("no-missing-link-fragments", rule, {
[Link](#old-style-6)
`,
+ // HTML id/name attributes using unquoted values and spaces around equals sign
+ dedent`
+
Bookmark
+ Old Style
+ Bookmark 2
+ Old Style 2
+ Bookmark 3
+ Old Style 3
+ Bookmark 4
+ Old Style 4
+ Bookmark 5
+ Old Style 5
+ Bookmark 6
+ Old Style 6
+ Bookmark 7
+ Old Style 7
+ Bookmark 8
+ Old Style 8
+ Bookmark 9
+ Old Style 9
+ Bookmark 10
+ Old Style 10
+ Bookmark 11
+ Old Style 11
+ Bookmark 12
+ Old Style 12
+
+ [Link](#bookmark)
+ [Link](#old-style)
+ [Link](#bookmark-2)
+ [Link](#old-style-2)
+ [Link](#bookmark-3)
+ [Link](#old-style-3)
+ [Link](#bookmark-4)
+ [Link](#old-style-4)
+ [Link](#bookmark-5)
+ [Link](#old-style-5)
+ [Link](#bookmark-6)
+ [Link](#old-style-6)
+ [Link](#bookmark-7)
+ [Link](#old-style-7)
+ [Link](#bookmark-8)
+ [Link](#old-style-8)
+ [Link](#bookmark-9)
+ [Link](#old-style-9)
+ [Link](#bookmark-10)
+ [Link](#old-style-10)
+ [Link](#bookmark-11)
+ [Link](#old-style-11)
+ [Link](#bookmark-12)
+ [Link](#old-style-12)
+ `,
+
// Special #top link
"[Link](#top)",
@@ -497,6 +550,101 @@ ruleTester.run("no-missing-link-fragments", rule, {
},
],
},
+
+ // Invalid: Link to non-existent ID with unquoted attributes
+ {
+ code: dedent`
+ Bookmark
+
+ [Link](#notfound)
+ `,
+ errors: [
+ {
+ messageId: "invalidFragment",
+ data: { fragment: "notfound" },
+ line: 3,
+ column: 1,
+ endLine: 3,
+ endColumn: 18,
+ },
+ ],
+ },
+
+ // Invalid: Link to non-existent ID with spaced attributes
+ {
+ code: dedent`
+ Bookmark 2
+
+ [Link](#notfound)
+ `,
+ errors: [
+ {
+ messageId: "invalidFragment",
+ data: { fragment: "notfound" },
+ line: 3,
+ column: 1,
+ endLine: 3,
+ endColumn: 18,
+ },
+ ],
+ },
+
+ // Invalid: Link to non-existent name attribute
+ {
+ code: dedent`
+ Old Style 3
+
+ [Link](#notfound)
+ `,
+ errors: [
+ {
+ messageId: "invalidFragment",
+ data: { fragment: "notfound" },
+ line: 3,
+ column: 1,
+ endLine: 3,
+ endColumn: 18,
+ },
+ ],
+ },
+
+ // Invalid: Link to non-existent ID with quoted attributes
+ {
+ code: dedent`
+ Bookmark 4
+
+ [Link](#notfound)
+ `,
+ errors: [
+ {
+ messageId: "invalidFragment",
+ data: { fragment: "notfound" },
+ line: 3,
+ column: 1,
+ endLine: 3,
+ endColumn: 18,
+ },
+ ],
+ },
+
+ // Invalid: Link to non-existent ID with spaced quoted attributes
+ {
+ code: dedent`
+ Bookmark 5
+
+ [Link](#notfound)
+ `,
+ errors: [
+ {
+ messageId: "invalidFragment",
+ data: { fragment: "notfound" },
+ line: 3,
+ column: 1,
+ endLine: 3,
+ endColumn: 18,
+ },
+ ],
+ },
{
code: dedent`