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/utils/mdn-content-inventory.js b/utils/mdn-content-inventory.js index f15d3bce78bcb3..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} */ @@ -31,7 +47,7 @@ const slugByPath = (() => { const slugTail = slug.split('/').at(-1); 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)); + }); +});