From 7aad7a702bd17bc23785f7bc8fba1278d6d6dc67 Mon Sep 17 00:00:00 2001 From: "Kenneth G. Franqueiro" Date: Thu, 28 Nov 2024 06:12:13 -0500 Subject: [PATCH] Pin definitions when building an older version (#4155) This is a follow-up to #4007, in which I had neglected to pin definitions for key terms to the published recommendation when building for 2.1. - Moves `termsMap` definition to the Eleventy config (where all other target-version-dependent assignments are made), to be passed into the `CustomLiquid` constructor - Updates `termsMap` references within `CustomLiquid` to use an instance variable set in the constructor - Updates `loadRemoteGuidelines` to account for pre-processed terms content - Also updates to account for #4124 - Skips entirety of custom `render` processing for pages not being output for 2.1 (to avoid irrelevant error messages as well as save time) --- 11ty/CustomLiquid.ts | 26 +++++++++++++++++--------- 11ty/guidelines.ts | 30 +++++++++++++++++------------- 11ty/types.ts | 2 +- eleventy.config.ts | 4 ++++ 4 files changed, 39 insertions(+), 23 deletions(-) diff --git a/11ty/CustomLiquid.ts b/11ty/CustomLiquid.ts index 1a302627c6..948a4847f3 100644 --- a/11ty/CustomLiquid.ts +++ b/11ty/CustomLiquid.ts @@ -1,5 +1,5 @@ import { Liquid, type Template } from "liquidjs"; -import type { RenderOptions } from "liquidjs/dist/liquid-options"; +import type { LiquidOptions, RenderOptions } from "liquidjs/dist/liquid-options"; import compact from "lodash-es/compact"; import uniq from "lodash-es/uniq"; @@ -10,7 +10,7 @@ import type { GlobalData } from "eleventy.config"; import { biblioPattern, getBiblio } from "./biblio"; import { flattenDom, load, type CheerioAnyNode } from "./cheerio"; import { generateId } from "./common"; -import { getAcknowledgementsForVersion, getTermsMap } from "./guidelines"; +import { getAcknowledgementsForVersion, type TermsMap } from "./guidelines"; import { resolveTechniqueIdFromHref, understandingToTechniqueLinkSelector } from "./techniques"; import { techniqueToUnderstandingLinkSelector } from "./understanding"; @@ -22,7 +22,6 @@ const techniquesPattern = /\btechniques\//; const understandingPattern = /\bunderstanding\//; const biblio = await getBiblio(); -const termsMap = await getTermsMap(); const termLinkSelector = "a:not([href])"; /** Generates {% include "foo.html" %} directives from 1 or more basenames */ @@ -72,6 +71,10 @@ function expandTechniqueLink($el: CheerioAnyNode) { const stripHtmlComments = (html: string) => html.replace(//g, ""); +interface CustomLiquidOptions extends LiquidOptions { + termsMap: TermsMap; +} + // Dev note: Eleventy doesn't expose typings for its template engines for us to neatly extend. // Fortunately, it passes both the content string and the file path through to Liquid#parse: // https://github.com/11ty/eleventy/blob/9c3a7619/src/Engines/Liquid.js#L253 @@ -84,6 +87,11 @@ const stripHtmlComments = (html: string) => html.replace(//g, "") * - generating/expanding sections with auto-generated content */ export class CustomLiquid extends Liquid { + termsMap: TermsMap; + constructor(options: CustomLiquidOptions) { + super(options); + this.termsMap = options.termsMap; + } public parse(html: string, filepath?: string) { // Filter out Liquid calls for computed data and includes themselves if (filepath && !filepath.includes("_includes/") && isHtmlFileContent(html)) { @@ -300,7 +308,7 @@ export class CustomLiquid extends Liquid { public async render(templates: Template[], scope: GlobalData, options?: RenderOptions) { // html contains markup after Liquid tags/includes have been processed const html = (await super.render(templates, scope, options)).toString(); - if (!isHtmlFileContent(html) || !scope) return html; + if (!isHtmlFileContent(html) || !scope || scope.page.url === false) return html; const $ = load(html); @@ -414,7 +422,7 @@ export class CustomLiquid extends Liquid { .toLowerCase() .trim() .replace(/\s*\n+\s*/, " "); - const term = termsMap[name]; + const term = this.termsMap[name]; if (!term) { console.warn(`${scope.page.inputPath}: Term not found: ${name}`); return; @@ -428,7 +436,7 @@ export class CustomLiquid extends Liquid { const $el = $(el); const termName = extractTermName($el); $el - .attr("href", `${scope.guidelinesUrl}#${termName ? termsMap[termName].trId : ""}`) + .attr("href", `${scope.guidelinesUrl}#${termName ? this.termsMap[termName].trId : ""}`) .attr("target", "terms"); }); } else if (scope.isUnderstanding) { @@ -442,7 +450,7 @@ export class CustomLiquid extends Liquid { // since terms may reference other terms in their own definitions. // Each iteration may append to termNames. for (let i = 0; i < termNames.length; i++) { - const term = termsMap[termNames[i]]; + const term = this.termsMap[termNames[i]]; if (!term) continue; // This will already warn via extractTermNames const $definition = load(term.definition); @@ -459,7 +467,7 @@ export class CustomLiquid extends Liquid { return 0; }); for (const name of termNames) { - const term = termsMap[name]; // Already verified existence in the earlier loop + const term = this.termsMap[name]; // Already verified existence in the earlier loop $termsList.append( `
${term.name}
` + `
${term.definition}
` @@ -469,7 +477,7 @@ export class CustomLiquid extends Liquid { // Iterate over non-href links once more in now-expanded document to add hrefs $(termLinkSelector).each((_, el) => { const name = extractTermName($(el)); - el.attribs.href = `#${name ? termsMap[name].id : ""}`; + el.attribs.href = `#${name ? this.termsMap[name].id : ""}`; }); } else { // No terms: remove skeleton that was placed in #parse diff --git a/11ty/guidelines.ts b/11ty/guidelines.ts index cbdc084bcb..0dc8ace485 100644 --- a/11ty/guidelines.ts +++ b/11ty/guidelines.ts @@ -197,14 +197,17 @@ interface Term { /** id of dfn in TR, which matches original id in terms file */ trId: string; } +export type TermsMap = Record; /** * Resolves term definitions from guidelines/index.html organized for lookup by name; * comparable to the term elements in wcag.xml from the guidelines-xml Ant task. */ -export async function getTermsMap() { - const $ = await flattenDomFromFile("guidelines/index.html"); - const terms: Record = {}; +export async function getTermsMap(version?: WcagVersion) { + const $ = version + ? await loadRemoteGuidelines(version) + : await flattenDomFromFile("guidelines/index.html"); + const terms: TermsMap = {}; $("dfn").each((_, el) => { const $el = $(el); @@ -240,24 +243,25 @@ const loadRemoteGuidelines = async (version: WcagVersion) => { ); // Re-collapse definition links and notes, to be processed by this build system - $(".guideline a.internalDFN").removeAttr("class data-link-type id href title"); - $(".guideline [role='note'] .marker").remove(); - $(".guideline [role='note']").find("> div, > p").addClass("note").unwrap(); + $("a.internalDFN").removeAttr("class data-link-type id href title"); + $("[role='note'] .marker").remove(); + $("[role='note']").find("> div, > p").addClass("note").unwrap(); - // Bibliography references are not processed in Understanding SC boxes - $(".guideline cite:has(a.bibref:only-child)").each((_, el) => { + // Un-process bibliography references, to be processed by CustomLiquid + $("cite:has(a.bibref:only-child)").each((_, el) => { const $el = $(el); - const $parent = $el.parent(); - $el.remove(); - // Remove surrounding square brackets (which aren't in a dedicated element) - $parent.html($parent.html()!.replace(/ \[\]/g, "")); + $el.replaceWith(`[${$el.find("a.bibref").html()}]`); }); + // Remove generated IDs and markers from examples + $(".example[id]").removeAttr("id"); + $(".example .marker:has(.self-link)").remove(); + // Remove extra markup from headings so they can be parsed for names $("bdi").remove(); // Remove abbr elements which exist only in TR, not in informative docs - $("#acknowledgements li abbr").each((_, abbrEl) => { + $("#acknowledgements li abbr, #glossary abbr").each((_, abbrEl) => { $(abbrEl).replaceWith($(abbrEl).text()); }); diff --git a/11ty/types.ts b/11ty/types.ts index 9bdd86c9f1..ed89e25178 100644 --- a/11ty/types.ts +++ b/11ty/types.ts @@ -9,7 +9,7 @@ interface EleventyPage { outputPath: string; rawInput: string; templateSyntax: string; - url: string; + url: string | false; // (false when permalink is set to false for the page) } interface EleventyDirectories { diff --git a/eleventy.config.ts b/eleventy.config.ts index 4313c5f2fa..d579a657ff 100644 --- a/eleventy.config.ts +++ b/eleventy.config.ts @@ -14,6 +14,7 @@ import { getFlatGuidelines, getPrinciples, getPrinciplesForVersion, + getTermsMap, scSlugOverrides, type FlatGuidelinesMap, type Guideline, @@ -103,6 +104,8 @@ for (const [technology, list] of Object.entries(techniques)) { const understandingDocs = await getUnderstandingDocs(version); const understandingNav = await generateUnderstandingNavMap(principles, understandingDocs); +const termsMap = process.env.WCAG_VERSION ? await getTermsMap(version) : await getTermsMap(); + // Declare static global data up-front so we can build typings from it const globalData = { version, @@ -274,6 +277,7 @@ export default function (eleventyConfig: any) { root: ["_includes", "."], jsTruthy: true, strictFilters: true, + termsMap, }) );