diff --git a/.link-checker.js b/.link-checker.js index 04d6ef7260..af09b214c3 100644 --- a/.link-checker.js +++ b/.link-checker.js @@ -1,5 +1,24 @@ const HTMLParser = require('node-html-parser'); +const getAttributeValue = (obj, attribute) => { + if (typeof obj !== 'object' || obj === null) return undefined; + if (obj.hasOwnProperty(attribute)) return obj[attribute]; + + if (Array.isArray(obj)) { + for (const element of obj) { + const attributeValue = getAttributeValue(element, attribute); + if (attributeValue !== undefined) return attributeValue; + } + } else { + for (const key in obj) { + const attributeValue = getAttributeValue(obj[key], attribute); + if (attributeValue !== undefined) return attributeValue; + } + } + + return undefined; +}; + module.exports = { filesToIgnore: [ // For example: @@ -20,19 +39,16 @@ module.exports = { { name: 'github', pattern: /^https:\/\/github\.com\/.*/, - matchHash: (ids, hash, { ssr }) => { - if (ssr) { + matchHash: (ids, hash, { reactPartial }) => { + if (reactPartial) { // This is where the react-partial keeps data about READMEs and other *.md files - const overviewFiles = - ssr['props']['initialPayload']['overview']['overviewFiles']; - for (let file of overviewFiles) { - if (file['richText']) { - const html = HTMLParser.parse(file['richText']); - const githubIds = html - .querySelectorAll('[id]') - .map((idElement) => idElement.getAttribute('id')); - return githubIds.includes(`user-content-${hash}`); - } + const richText = getAttributeValue(reactPartial, 'richText'); + if (richText !== undefined) { + const html = HTMLParser.parse(richText); + const githubIds = html + .querySelectorAll('[id]') + .map((idElement) => idElement.getAttribute('id')); + return githubIds.includes(`user-content-${hash}`); } } return ids.includes(hash) || ids.includes(`user-content-${hash}`); diff --git a/scripts/link-checker.js b/scripts/link-checker.js index bcc865cecb..d7174b79e4 100644 --- a/scripts/link-checker.js +++ b/scripts/link-checker.js @@ -33,7 +33,24 @@ async function checkLinks() { return getLineNumber; }; - const checkPathForHash = (hrefOrSrc, ids = [], hash, { ssr } = {}) => { + const getHashCheckHandler = (hrefOrSrc) => { + return options.hashCheckHandlers.find(({ pattern }) => + pattern.test(hrefOrSrc) + ); + }; + + const getReactPartial = (hrefOrSrc, html) => { + const handler = getHashCheckHandler(hrefOrSrc); + if (handler) return handler.getPartial(html); + return undefined; + }; + + const checkPathForHash = ( + hrefOrSrc, + ids = [], + hash, + { reactPartial } = {} + ) => { // On some websites, the ids may not exactly match the hash included // in the link. // For e.g. GitHub will prepend client facing ids with their own @@ -43,10 +60,8 @@ async function checkLinks() { // as being 'user-content-foo-bar' for its own page processing purposes. // // See https://github.com/w3c/aria-practices/issues/2809 - const handler = options.hashCheckHandlers.find(({ pattern }) => - pattern.test(hrefOrSrc) - ); - if (handler) return handler.matchHash(ids, hash, { ssr }); + const handler = getHashCheckHandler(hrefOrSrc); + if (handler) return handler.matchHash(ids, hash, { reactPartial }); else return ids.includes(hash); }; @@ -151,14 +166,13 @@ async function checkLinks() { // Handle GitHub README links. // These links are stored within a react-partial element - const handler = options.hashCheckHandlers.find(({ pattern }) => - pattern.test(hrefOrSrc) - ); - let ssr = undefined; - if (handler) { - ssr = handler.getPartial(html); - } - return { ok: response.ok, status: response.status, ids, ssr }; + const reactPartial = getReactPartial(hrefOrSrc, html); + return { + ok: response.ok, + status: response.status, + ids, + reactPartial, + }; } catch (error) { return { errorMessage: @@ -315,7 +329,7 @@ async function checkLinks() { !isHashCheckingDisabled && hash && !checkPathForHash(hrefOrSrc, pageData.ids, hash, { - ssr: pageData.ssr, + reactPartial: pageData.reactPartial, }) ) { consoleError(