From 201d450b9002ea2a1f96ba2487475dc880894b7c Mon Sep 17 00:00:00 2001 From: Claas Augner Date: Fri, 10 Apr 2026 23:21:42 +0200 Subject: [PATCH 1/3] fix(lint): add MDN urls for features with `@@` prefix --- utils/mdn-content-inventory.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/mdn-content-inventory.js b/utils/mdn-content-inventory.js index f15d3bce78bcb3..dfc30fb2253a23 100644 --- a/utils/mdn-content-inventory.js +++ b/utils/mdn-content-inventory.js @@ -29,7 +29,7 @@ const slugByPath = (() => { for (const path of paths) { const slugTail = slug.split('/').at(-1); - const pathTail = path.split('.').at(-1); + const pathTail = path.split('.').at(-1)?.replace(/^@@/g, ''); if (!slugTail.includes(pathTail) && !pathTail?.includes(slugTail)) { // Ignore unrelated pages/features. From 37ebca26e99ed0cae0e6bf84a8318145b6252e61 Mon Sep 17 00:00:00 2001 From: Claas Augner Date: Fri, 10 Apr 2026 23:21:57 +0200 Subject: [PATCH 2/3] chore: run `npm run lint:fix` once --- api/CSSFontFeatureValuesMap.json | 1 + javascript/builtins/AsyncDisposableStack.json | 1 + javascript/builtins/AsyncIterator.json | 1 + javascript/builtins/DisposableStack.json | 1 + javascript/builtins/Iterator.json | 1 + 5 files changed, 5 insertions(+) diff --git a/api/CSSFontFeatureValuesMap.json b/api/CSSFontFeatureValuesMap.json index e1259355d8c412..895ec742d8be74 100644 --- a/api/CSSFontFeatureValuesMap.json +++ b/api/CSSFontFeatureValuesMap.json @@ -386,6 +386,7 @@ }, "@@iterator": { "__compat": { + "mdn_url": "https://developer.mozilla.org/docs/Web/API/CSSFontFeatureValuesMap/Symbol.iterator", "spec_url": "https://drafts.csswg.org/css-fonts/#cssfontfeaturevaluesmap", "tags": [ "web-features:font-variant-alternates" diff --git a/javascript/builtins/AsyncDisposableStack.json b/javascript/builtins/AsyncDisposableStack.json index c2aa5dcc50f9ec..76b18d2522b43f 100644 --- a/javascript/builtins/AsyncDisposableStack.json +++ b/javascript/builtins/AsyncDisposableStack.json @@ -354,6 +354,7 @@ }, "@@asyncDispose": { "__compat": { + "mdn_url": "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/AsyncDisposableStack/Symbol.asyncDispose", "spec_url": "https://tc39.es/proposal-async-explicit-resource-management/#sec-asyncdisposablestack.prototype-@@asyncDispose", "tags": [ "web-features:explicit-resource-management" diff --git a/javascript/builtins/AsyncIterator.json b/javascript/builtins/AsyncIterator.json index e94a4c495bf287..08ea6c74caeb3b 100644 --- a/javascript/builtins/AsyncIterator.json +++ b/javascript/builtins/AsyncIterator.json @@ -47,6 +47,7 @@ }, "@@asyncDispose": { "__compat": { + "mdn_url": "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/AsyncIterator/Symbol.asyncDispose", "spec_url": "https://tc39.es/proposal-async-explicit-resource-management/#sec-asyncdisposablestack.prototype-@@asyncDispose", "tags": [ "web-features:explicit-resource-management" diff --git a/javascript/builtins/DisposableStack.json b/javascript/builtins/DisposableStack.json index 1286115148975f..0a48a032fdef3f 100644 --- a/javascript/builtins/DisposableStack.json +++ b/javascript/builtins/DisposableStack.json @@ -354,6 +354,7 @@ }, "@@dispose": { "__compat": { + "mdn_url": "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/DisposableStack/Symbol.dispose", "spec_url": "https://tc39.es/proposal-async-explicit-resource-management/#sec-disposablestack.prototype-@@dispose", "tags": [ "web-features:explicit-resource-management" diff --git a/javascript/builtins/Iterator.json b/javascript/builtins/Iterator.json index bf15ef9f0737ce..9b77e4f1416cad 100644 --- a/javascript/builtins/Iterator.json +++ b/javascript/builtins/Iterator.json @@ -830,6 +830,7 @@ }, "@@dispose": { "__compat": { + "mdn_url": "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Iterator/Symbol.dispose", "spec_url": "https://tc39.es/proposal-async-explicit-resource-management/#sec-%iteratorprototype%-@@dispose", "tags": [ "web-features:explicit-resource-management" From 2c8fcaf0ba55dc9646a25008395534a150280036 Mon Sep 17 00:00:00 2001 From: Claas Augner Date: Fri, 10 Apr 2026 23:42:49 +0200 Subject: [PATCH 3/3] test(utils): extract + test `tailsMatch()` helper --- utils/mdn-content-inventory.js | 20 ++++++++++++++-- utils/mdn-content-inventory.test.js | 36 +++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 utils/mdn-content-inventory.test.js diff --git a/utils/mdn-content-inventory.js b/utils/mdn-content-inventory.js index dfc30fb2253a23..c157303504a6f6 100644 --- a/utils/mdn-content-inventory.js +++ b/utils/mdn-content-inventory.js @@ -13,6 +13,22 @@ const slugs = (() => { return result; })(); +/** + * Returns true if the slug tail and path tail are related enough to link. + * Strips leading `@@` from path tail to handle well-known symbol names + * (e.g. `@@dispose` matches `Symbol.dispose`). + * @param {string} slugTail Last segment of an MDN slug + * @param {string | undefined} pathTail Last segment of a BCD path + * @returns {boolean} Whether the tails are related + */ +export const tailsMatch = (slugTail, pathTail) => { + if (!pathTail) { + return false; + } + const normalized = pathTail.replace(/^@@/, ''); + return slugTail.includes(normalized) || normalized.includes(slugTail); +}; + /** @type {Map} BCD path → MDN slug (only unambiguous mappings) */ const slugByPath = (() => { /** @type {Map} */ @@ -29,9 +45,9 @@ const slugByPath = (() => { for (const path of paths) { const slugTail = slug.split('/').at(-1); - const pathTail = path.split('.').at(-1)?.replace(/^@@/g, ''); + const pathTail = path.split('.').at(-1); - if (!slugTail.includes(pathTail) && !pathTail?.includes(slugTail)) { + if (!tailsMatch(slugTail, pathTail)) { // Ignore unrelated pages/features. continue; } diff --git a/utils/mdn-content-inventory.test.js b/utils/mdn-content-inventory.test.js new file mode 100644 index 00000000000000..05deadbf22ac2c --- /dev/null +++ b/utils/mdn-content-inventory.test.js @@ -0,0 +1,36 @@ +/* This file is a part of @mdn/browser-compat-data + * See LICENSE file for more information. */ + +import assert from 'node:assert/strict'; + +import { tailsMatch } from './mdn-content-inventory.js'; + +describe('tailsMatch()', () => { + it('matches identical tails', () => { + assert.ok(tailsMatch('abort', 'abort')); + }); + + it('matches when slug tail contains path tail', () => { + assert.ok(tailsMatch('Symbol.dispose', 'dispose')); + }); + + it('matches when path tail contains slug tail', () => { + assert.ok(tailsMatch('bar', 'foobar')); + }); + + it('matches @@symbol path tail against Symbol.* slug tail', () => { + assert.ok(tailsMatch('Symbol.dispose', '@@dispose')); + assert.ok(tailsMatch('Symbol.iterator', '@@iterator')); + assert.ok(tailsMatch('Symbol.asyncIterator', '@@asyncIterator')); + assert.ok(tailsMatch('Symbol.toPrimitive', '@@toPrimitive')); + }); + + it('does not match unrelated tails', () => { + assert.ok(!tailsMatch('Symbol.dispose', 'foo')); + assert.ok(!tailsMatch('abort', 'fetch')); + }); + + it('does not match when path tail is undefined', () => { + assert.ok(!tailsMatch('abort', undefined)); + }); +});