Skip to content

Commit 2afa6a8

Browse files
authored
Address remaining unresolved biblio references (#4174)
Resolves #2535. This resolves the remaining unresolved references by implementing the following: - Local aliases map for querying specref (fixes broken ref for css3-values, which is an alias of css-values-3) - References section, appearing after Key Terms for any pages that cite references that only ever existed in WCAG 2.0's XML sources Also improved output source formatting for Key Terms while adding the new `dl` for References, and repurposed the Key Terms template to be reusable for both. Understanding pages with References sections: - Contrast (Minimum) - Contrast (Enhanced) - Low or No Background Audio Understanding pages that reference css3-values: - Reflow - Three Flashes or Below Threshold - Focus Appearance - Target Size (Enhanced) - Target Size (Minimum)
1 parent 05fd019 commit 2afa6a8

File tree

4 files changed

+68
-20
lines changed

4 files changed

+68
-20
lines changed

11ty/CustomLiquid.ts

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { basename } from "path";
77

88
import type { GlobalData } from "eleventy.config";
99

10-
import { biblioPattern, getBiblio } from "./biblio";
10+
import { biblioPattern, getBiblio, getXmlBiblio } from "./biblio";
1111
import { flattenDom, load, type CheerioAnyNode } from "./cheerio";
1212
import { generateId } from "./common";
1313
import { getAcknowledgementsForVersion, type TermsMap } from "./guidelines";
@@ -22,12 +22,22 @@ const techniquesPattern = /\btechniques\//;
2222
const understandingPattern = /\bunderstanding\//;
2323

2424
const biblio = await getBiblio();
25+
const xmlBiblio = await getXmlBiblio();
2526
const termLinkSelector = "a:not([href])";
2627

2728
/** Generates {% include "foo.html" %} directives from 1 or more basenames */
2829
const generateIncludes = (...basenames: string[]) =>
2930
`\n${basenames.map((basename) => `{% include "${basename}.html" %}`).join("\n")}\n`;
3031

32+
/** Version of generateIncludes for a single include with parameters */
33+
const generateIncludeWithParams = (basename: string, params: Record<string, string>) => {
34+
const strParams = Object.entries(params).reduce(
35+
(str, [key, value]) => `${str}, ${key}: ${JSON.stringify(value)}`,
36+
""
37+
);
38+
return `\n{% include "${basename}.html"${strParams} %}\n`;
39+
};
40+
3141
/**
3242
* Determines whether a given string is actually HTML,
3343
* not e.g. a data value Eleventy sent to the templating engine.
@@ -305,8 +315,9 @@ export class CustomLiquid extends Liquid {
305315
// Expand techniques links to always include title
306316
$(understandingToTechniqueLinkSelector).each((_, el) => expandTechniqueLink($(el)));
307317

308-
// Add key terms by default, to be removed in #parse if there are no terms
309-
$("body").append(generateIncludes("understanding/key-terms"));
318+
// Add key terms and references by default, to be removed in #parse if not needed
319+
$("body").append(generateIncludeWithParams("dl-section", { title: "Key Terms" }));
320+
$("body").append(generateIncludeWithParams("dl-section", { title: "References" }));
310321
}
311322

312323
// Remove h2-level sections with no content other than heading
@@ -504,7 +515,7 @@ export class CustomLiquid extends Liquid {
504515
<p><a href="https://www.w3.org/WAI/WCAG${scope.version}/errata/">View all errata</a></p>
505516
`;
506517
}
507-
$termsList.append(`<dt id="${term.id}">${term.name}</dt><dd>${termBody}</dd>`);
518+
$termsList.append(`\n <dt id="${term.id}">${term.name}</dt><dd>${termBody}</dd>`);
508519
}
509520

510521
// Iterate over non-href links once more in now-expanded document to add hrefs
@@ -600,17 +611,33 @@ export class CustomLiquid extends Liquid {
600611

601612
// Link biblio references
602613
if (scope.isUnderstanding) {
614+
const xmlBiblioReferences: string[] = [];
603615
$("p").each((_, el) => {
604616
const $el = $(el);
605617
const html = $el.html();
606618
if (html && biblioPattern.test(html)) {
607619
$el.html(
608-
html.replace(biblioPattern, (substring, code) =>
609-
biblio[code]?.href ? `[<a href="${biblio[code].href}">${code}</a>]` : substring
610-
)
620+
html.replace(biblioPattern, (substring, code) => {
621+
if (biblio[code]?.href) return `[<a href="${biblio[code].href}">${code}</a>]`;
622+
if (code in xmlBiblio) {
623+
xmlBiblioReferences.push(code);
624+
return `[<a href="#${code}">${code}</a>]`;
625+
}
626+
console.warn(`${scope.page.inputPath}: Unresolved biblio ref: ${code}`);
627+
return substring;
628+
})
611629
);
612630
}
613631
});
632+
633+
// Populate references section, or remove if unused
634+
if (xmlBiblioReferences.length) {
635+
for (const ref of uniq(xmlBiblioReferences).sort()) {
636+
$("section#references dl").append(
637+
`\n <dt id="${ref}">${ref}</dt><dd>${xmlBiblio[ref]}</dd>`
638+
);
639+
}
640+
} else $("section#references").remove();
614641
}
615642

616643
// Allow autogenerating missing top-level section IDs in understanding docs,

11ty/biblio.ts

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
import axios from "axios";
22
import { readFile } from "fs/promises";
33
import { glob } from "glob";
4+
import invert from "lodash-es/invert";
45
import uniq from "lodash-es/uniq";
6+
import { join } from "path";
57

8+
import { loadFromFile } from "./cheerio";
69
import { wrapAxiosRequest } from "./common";
710

811
export const biblioPattern = /\[\[\??([\w-]+)\]\]/g;
912

13+
// Resolve necessary aliases locally rather than requiring an extra round trip to specref
14+
const aliases = {
15+
"css3-values": "css-values-3",
16+
};
17+
1018
/** Compiles URLs from local biblio + specref for linking in Understanding documents. */
1119
export async function getBiblio() {
1220
const localBiblio = eval(
@@ -21,19 +29,32 @@ export async function getBiblio() {
2129
let match;
2230
while ((match = biblioPattern.exec(content))) if (!localBiblio[match[1]]) refs.push(match[1]);
2331
}
24-
const uniqueRefs = uniq(refs);
32+
const uniqueRefs = uniq(refs).map((ref) =>
33+
ref in aliases ? aliases[ref as keyof typeof aliases] : ref
34+
);
2535

2636
const response = await wrapAxiosRequest(
2737
axios.get(`https://api.specref.org/bibrefs?refs=${uniqueRefs.join(",")}`)
2838
);
29-
const fullBiblio = {
39+
for (const [from, to] of Object.entries(invert(aliases)))
40+
response.data[to] = response.data[from];
41+
42+
return {
3043
...response.data,
3144
...localBiblio,
3245
};
46+
}
3347

34-
const resolvedRefs = Object.keys(fullBiblio);
35-
const unresolvedRefs = uniqueRefs.filter((ref) => !resolvedRefs.includes(ref));
36-
if (unresolvedRefs.length) console.warn(`Unresolved biblio refs: ${unresolvedRefs.join(", ")}`);
37-
38-
return fullBiblio;
48+
/** Returns mapping of references included in WCAG 2.0, which largely lack URLs */
49+
export async function getXmlBiblio() {
50+
const xmlRefs: Record<string, string> = {};
51+
const $ = await loadFromFile(join("wcag20", "sources", "guide-to-wcag2-src.xml"));
52+
$("bibl[id]").each((_, el) => {
53+
const $ref = $(`#${el.attribs.id}`);
54+
if (!$ref.length) return;
55+
// Note: Using text() drops links (<loc> tags in the XML),
56+
// but the only link within refs that are actually used seems to be broken
57+
xmlRefs[el.attribs.id] = $ref.text();
58+
});
59+
return xmlRefs;
3960
}

_includes/dl-section.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<section id="{{ title | slugify }}">
2+
<details>
3+
<summary><h2>{{ title }}</h2></summary>
4+
<dl></dl>
5+
</details>
6+
</section>

_includes/understanding/key-terms.html

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)