Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/core/link-to-dfn.js
Original file line number Diff line number Diff line change
Expand Up @@ -323,9 +323,9 @@ function showLinkingError(elems) {
// Check if the link is inside a data-link-for section — a common footgun
// where [=global-term=] gets scoped to the interface and fails.
const scopedSection = /** @type {HTMLElement | null} */ (
elem.closest("[data-link-for]")
elem.parentElement?.closest("[data-link-for]") ?? null
);
const scopingNote = scopedSection
const scopingNote = scopedSection?.dataset.linkFor
? ` This link is inside a \`data-link-for="${scopedSection.dataset.linkFor}"\` section — \`[=term=]\` links are scoped to that context. To link to a global concept instead, either add \`data-link-for=""\` on this \`<a>\` or move it outside the scoped section.`
: "";
Comment thread
marcoscaceres marked this conversation as resolved.
const hint = `Add a matching \`<dfn>\` element, ${docLink`use ${"[data-cite]"} to link to an external definition, or enable ${"[xref]"} for automatic cross-spec linking.`}${scopingNote}`;
Expand Down
46 changes: 45 additions & 1 deletion tests/spec/core/link-to-dfn-spec.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
"use strict";

import { flushIframes, makeRSDoc, makeStandardOps } from "../SpecHelper.js";
import {
flushIframes,
makeRSDoc,
makeStandardOps,
warningFilters,
} from "../SpecHelper.js";

describe("Core — Link to definitions", () => {
afterAll(flushIframes);
const warnings = warningFilters.filter("core/link-to-dfn");

it("removes non-alphanum chars from fragment components", async () => {
const bodyText = `
Expand Down Expand Up @@ -404,4 +410,42 @@ describe("Core — Link to definitions", () => {
const corrupt = doc.querySelector("[data-cite*='__SPEC__']");
expect(corrupt).toBeNull();
});

it("scoping hint only fires for ancestor data-link-for, not self", async () => {
const body = `
<section>
<h2>Scoping</h2>
<section data-link-for="Iface">
<h3>Inside scope</h3>
<p><a data-cite="">globalTerm</a></p>
</section>
<section data-link-for="">
<h3>Empty scope</h3>
<p><a data-cite="">anotherTerm</a></p>
</section>
<section>
<h3>No scope</h3>
<p><a data-cite="">noScopeTerm</a></p>
</section>
</section>
`;
const ops = makeStandardOps(null, body);
const doc = await makeRSDoc(ops);
const scopedWarnings = warnings(doc);
const insideScopeWarning = scopedWarnings.find(w =>
w.message?.includes("globalTerm")
);
const emptyScopeWarning = scopedWarnings.find(w =>
w.message?.includes("anotherTerm")
);
const noScopeWarning = scopedWarnings.find(w =>
w.message?.includes("noScopeTerm")
);
expect(insideScopeWarning).toBeTruthy();
expect(insideScopeWarning.hint).toContain('data-link-for="Iface"');
expect(emptyScopeWarning).toBeTruthy();
expect(emptyScopeWarning.hint).not.toContain("data-link-for=");
expect(noScopeWarning).toBeTruthy();
expect(noScopeWarning.hint).not.toContain("data-link-for=");
});
});