From 3c81e2763eaa0c81639c12e21acc329ad53dab5d Mon Sep 17 00:00:00 2001 From: Wilco Fiers Date: Wed, 2 Jun 2021 11:46:39 +0200 Subject: [PATCH] chore: refactor --- lib/checks/navigation/heading-order-after.js | 117 +++++++------------ 1 file changed, 41 insertions(+), 76 deletions(-) diff --git a/lib/checks/navigation/heading-order-after.js b/lib/checks/navigation/heading-order-after.js index 9959cb6e3b..72902633e3 100644 --- a/lib/checks/navigation/heading-order-after.js +++ b/lib/checks/navigation/heading-order-after.js @@ -11,23 +11,22 @@ export default function headingOrderAfter(results) { * Determine check outcome, based on the position of the result in the headingOrder */ function getHeadingOrderOutcome(result, headingOrder) { - const index = headingOrder.findIndex(heading => heading.result === result); + const index = headingOrder.findIndex(heading => { + return matchAncestry(heading.ancestry, result.node.ancestry) + }); const currLevel = headingOrder[index]?.level ?? -1; const prevLevel = headingOrder[index - 1]?.level ?? -1; + // First heading always passes if (index === 0) { return true }; - // Heading not in the map if (currLevel === -1) { - return undefined; - // Heading level is skipped - } else if (currLevel - prevLevel > 1) { - return false; - } else { - return true; + return undefined; } + // Check if a heading is skipped + return (currLevel - prevLevel <= 1) } /** @@ -40,101 +39,67 @@ function getHeadingOrder(results) { results.sort(({ node: nodeA }, { node: nodeB }) => { return nodeA.ancestry.length - nodeB.ancestry.length; }); - - // Recursively push or splice result.data into headingOrder - const headingOrder = results.reduce(addResultToHeadingOrder, []); + // push or splice result.data into headingOrder + const headingOrder = results.reduce(mergeHeadingOrder, []); + // Remove all frame placeholders that was fully replaced return headingOrder.filter(heading => heading && !heading.replaced); } /** * Add the data of a heading-order result to the headingOrder map */ -function addResultToHeadingOrder(headingOrder, result) { - let frameHeadingOrder = result?.data?.headingOrder; - // Only the first selected element in the window has headingOrder info +function mergeHeadingOrder(mergedHeadingOrder, result) { + const frameHeadingOrder = result.data?.headingOrder; + const frameAncestry = shortenArray(result.node.ancestry, 1); + + // Only the first result in each frame has a headingOrder. Ignore the rest if (!frameHeadingOrder) { - setResultInHeadingOrder(headingOrder, result); - return headingOrder; + return mergedHeadingOrder; } - // Update the ancestry to include frame information - frameHeadingOrder = frameHeadingOrder.map(heading => { - return normalizeHeading(heading, result); + // Prepend node ancestry to each heading.ancestry + const normalizedHeadingOrder = frameHeadingOrder.map(heading => { + return addFrameToHeadingAncestry(heading, frameAncestry); }); - const index = getFrameIndex(headingOrder, result); + // Find if the result is from a frame previously processed + const index = getFrameIndex(mergedHeadingOrder, frameAncestry); // heading is not in a frame, stick 'm in at the end. if (index === -1) { - headingOrder.push(...frameHeadingOrder); + mergedHeadingOrder.push(...normalizedHeadingOrder); } else { - // Mark the frame for later removal - // Keep it, for nested iframes where a parent has no headings - headingOrder[index].replaced = true; - headingOrder.splice(index, 0, ...frameHeadingOrder); + // Flag the frame placeholder so it can be deleted later + mergedHeadingOrder[index].replaced = true; + mergedHeadingOrder.splice(index, 0, ...normalizedHeadingOrder); } - return headingOrder; + return mergedHeadingOrder; } /** * Determine where the iframe results fit into the top-level * heading order */ -function getFrameIndex(headingOrder, result) { +function getFrameIndex(headingOrder, frameAncestry) { let index = -1; - const ancestry = shortenArray(result.node.ancestry, 1); // If a frame has no headings, but it does have iframes we might // not have a result. We can account for this by finding the closest // ancestor we do know about. - while (ancestry.length && index === -1) { + while (frameAncestry.length) { index = headingOrder.findIndex(heading => { - return matchAncestry(heading.ancestry, ancestry); + return matchAncestry(heading.ancestry, frameAncestry); }); - ancestry.pop(); + if (index !== -1) break; + frameAncestry = shortenArray(frameAncestry, 1) } return index; } /** - * Find the heading based on ancestry, and set the result property + * Prepend the frame ancestry of a node to heading.ancestry */ -function setResultInHeadingOrder(headingOrder, result) { - const ancestry = result.node.ancestry; - const index = headingOrder.findIndex(heading => { - return matchAncestry(heading.ancestry, ancestry); - }); - - if (index === -1) { - // Something went wrong, set it to incomplete - result.result = undefined; - return; - } - - headingOrder[index] = { - ...headingOrder[index], - result - }; -} - -/** - * Add all required props to the heading - */ -function normalizeHeading(heading, result) { - const ancestry = combineAncestry(result, heading); - const resultMatches = matchAncestry(result.node.ancestry, ancestry); - return { - ...heading, - result: resultMatches ? result : undefined, - ancestry - }; -} - -/** - * Take the frame ancestry from a result, and add it to the ancestry - * of a heading. - */ -function combineAncestry(result, heading) { - const frameAncestry = shortenArray(result.node.ancestry, 1); - return frameAncestry.concat(heading.ancestry); +function addFrameToHeadingAncestry(heading, frameAncestry) { + const ancestry = frameAncestry.concat(heading.ancestry); + return { ...heading, ancestry }; } /** @@ -146,13 +111,13 @@ function matchAncestry(ancestryA, ancestryB) { } return ancestryA.every((selectorA, index) => { const selectorB = ancestryB[index]; - if (Array.isArray(selectorA)) { - if (selectorA.length !== selectorB.length) { - return false; - } - return selectorA.every((str, index) => selectorB[index] === str); + if (!Array.isArray(selectorA)) { + return selectorA === selectorB; + } + if (selectorA.length !== selectorB.length) { + return false; } - return selectorA === selectorB; + return selectorA.every((str, index) => selectorB[index] === str); }); }