Skip to content

Commit c9db7fe

Browse files
authored
Reimplement associated techniques as data (#4509)
This replaces the HTML for each Understanding page's Techniques section with a data representation of the same information, to improve consistency, reduce likelihood of mistakes, and eventually enable restoring the structured `techniques` field to success criteria in the JSON export (see the first list item in #4393). All associated techniques are now defined in `understanding/understanding.11tydata.js` under the `associatedTechniques` field, in a way that should make the simplest cases easier to define than they were before. Documentation is added in this PR. In addition, various common mistakes are checked for at runtime with specific error messages, and typings are also defined, enabling some amount of autocomplete and feedback in editors that support TypeScript, such as Visual Studio Code. Most of the changes in this PR involve the build system and centralized templates; the only changes to the Understanding pages themselves are to use the new template rather than spell out the related techniques within HTML. However, this _does_ visibly impact some pages within the informative docs. See the associated PR #4509 for notable content changes.
1 parent c7286fc commit c9db7fe

File tree

105 files changed

+2115
-6907
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

105 files changed

+2115
-6907
lines changed

.eleventyignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ understanding/*/identify-changes.html
1919
understanding/*/interruptions-minimum.html
2020
understanding/*/seizures.html
2121

22+
# Ignore typings
23+
**/*.d.ts
24+
2225
# Ignore templates used for creating new documents
2326
**/*-template.html
2427

11ty/CustomLiquid.ts

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -256,22 +256,10 @@ export class CustomLiquid extends Liquid {
256256
throw new Error("Incorrectly-nested Benefits section found: please resolve.");
257257
}
258258

259-
// XSLT orders resources then techniques last, opposite of source files
260-
$("body")
261-
.append("\n", $(`body > section#resources`))
262-
.append("\n", $(`body > section#techniques`));
263-
264259
// Expand top-level heading and add box for guideline/SC pages
265260
if ($("section#intent").length) $("h1").replaceWith(generateIncludes("understanding/h1"));
266261
$("section#intent").before(generateIncludes("understanding/about"));
267262

268-
$("section#techniques h2").after(generateIncludes("understanding/intro/techniques"));
269-
if ($("section#sufficient .situation").length) {
270-
$("section#sufficient h3").after(
271-
generateIncludes("understanding/intro/sufficient-situation")
272-
);
273-
}
274-
275263
// Disallow handwritten success-criteria section (should be auto-generated)
276264
if ($("section#success-criteria").length) {
277265
console.error(
@@ -283,21 +271,7 @@ export class CustomLiquid extends Liquid {
283271
// success-criteria template only renders content for guideline (not SC) pages
284272
$("body").append(generateIncludes("understanding/success-criteria"));
285273

286-
// Remove unpopulated techniques subsections
287-
for (const id of ["sufficient", "advisory", "failure"]) {
288-
$(`section#${id}:not(:has(:not(h3)))`).remove();
289-
}
290-
291-
// Normalize subsection names for Guidelines (h2) and/or SC (h3)
292-
$("section#sufficient h3").text("Sufficient Techniques");
293-
$("section#advisory").find("h2, h3").text("Advisory Techniques");
294-
$("section#failure h3").text("Failures");
295-
296274
// Add intro prose to populated sections
297-
$("section#advisory")
298-
.find("h2, h3")
299-
.after(generateIncludes("understanding/intro/advisory"));
300-
$("section#failure h3").after(generateIncludes("understanding/intro/failure"));
301275
$("section#resources h2").after(generateIncludes("understanding/intro/resources"));
302276

303277
// Expand techniques links to always include title
@@ -440,8 +414,8 @@ export class CustomLiquid extends Liquid {
440414
if (scope.guideline?.level === "") $("section#techniques").remove();
441415
}
442416

443-
// Process defined terms within #render,
444-
// where we have access to global data and the about box's HTML
417+
// Process defined terms within #render, where we have access to
418+
// global data and the rendered HTML for the About box and related Techniques
445419
const $termLinks = $(termLinkSelector);
446420
const extractTermName = ($el: CheerioAnyNode) => {
447421
const name = $el

11ty/README.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,77 @@ Each of these scripts performs the following steps:
4242
2. Runs the build for the appropriate WCAG version, generating pages and `wcag.json` under `_site`
4343
3. Copies the built files from `_site` to the CVS checkout (see [`WCAG_CVSDIR`](#wcag_cvsdir))
4444

45+
## Associated Techniques Data
46+
47+
Each success criterion's page contains a Techniques section which links to associated techniques.
48+
These used to be defined directly in HTML in each respective page, but have since been relocated to
49+
a single data file, `understanding/understanding.11tydata.js`, under the key `associatedTechniques`.
50+
51+
This field is typed, in order to provide some degree of autocomplete in IDEs that support TypeScript
52+
(e.g. Visual Studio Code), as well as some amount of immediate feedback while editing.
53+
Further validation is performed when running the build or dev server, to provide more focused error messages for common mistakes.
54+
55+
### Listing Techniques
56+
57+
Techniques may be indicated via an object as outlined below, or using a shorthand string.
58+
Shorthand strings may function as either `id` or `title` seen below, and are
59+
recommended for brevity when no `using` or `and` relationship is present.
60+
61+
The following list outlines properties available on each technique object:
62+
63+
- `id` - Technique ID
64+
- `title` - Technique description (HTML flow content allowed), to define free-form entries that don't reference a specific technique
65+
- `using` - Optional array of further techniques to be populated into a child list
66+
- Child techniques may also include `using`
67+
- `usingConjunction` - When `using` is specified, this overrides the word that appears before `usingQuantity`
68+
- Default: `"using"`; HTML flow content allowed
69+
- `usingQuantity` - When `using` is specified, this overrides the word that appears after `usingConjunction` and before "of the following techniques"
70+
- Default: `"one"`
71+
- May be empty string (`""`), in which case the subsequent "of" is dropped
72+
- `usingPrefix` - Adds text to appear before `usingConjunction`
73+
- `skipUsingPhrase` - Omits the entire "... using ... of the following techniques" phrase
74+
- This is mainly an escape hatch for rare instances where a child list is used but no "using" phrase appears at all (e.g. in 1.4.4: Resize Text)
75+
76+
Typically, either `id` or `title` is required.
77+
If `id` is specified, then `prefix` and/or `suffix` may also be specified (with HTML flow content allowed in each),
78+
resulting in "{prefix} {linked technique title} {suffix}".
79+
80+
In extremely rare cases, `using` may be specified alone without either `id` or `title`,
81+
e.g. for top-level "Using two or more of the following" in 2.4.5: Multiple Ways.
82+
83+
#### Conjunctions
84+
85+
To represent multiple parallel techniques, an `and` key may be specified instead of `id` or `title`. In this case, the following properties are supported:
86+
87+
- `and` - an array of technique objects or shorthand strings (as described above)
88+
- `using` and its related fields (seen above) may optionally be specified alongside `and`
89+
- `andConjunction` may optionally be specified alongside `and`,
90+
to override the default `"<strong>AND</strong>"` phrasing (e.g. in 4.1.3: Status Messages)
91+
- Techniques listed _within_ `and` should be flat, never containing `and` or `using`
92+
93+
### Situations or Other Subsections (Sufficient only)
94+
95+
The top level of the `sufficient` array may consist entirely of either technique entries (see above)
96+
or subsection entries. It should not contain a mix of both.
97+
98+
Subsections are typically used to define multiple "situations", where each title begins with "Situation A:", "Situation B:", etc.;
99+
in rare cases it is used for other purposes, e.g. in 1.4.8: Visual Presentation.
100+
101+
Subsection entries contain the following:
102+
103+
- `title` (required, HTML allowed)
104+
- `techniques` (required) - array of technique entries (see above)
105+
- `note` (optional, HTML allowed) - content to appear in a Note at the end of the subsection (e.g. in 4.1.3: Status Messages)
106+
- `groups` (optional) - array of objects with `id`, `title`, `techniques`; see more below
107+
- `techniques` within `groups` are not expected to involve `and` or `using`
108+
109+
#### Groups within Situations
110+
111+
Most of the situations in 1.1.1: Non-text Content include groupings which start with a boldface paragraph (not a heading),
112+
and are referenced one or more times within preceding "using" clauses.
113+
Groups can be defined at the top level of each situation/section entry as mentioned above.
114+
Defining `groups` automatically implies a "using" relationship, without explicitly defining `using` for each technique.
115+
45116
## Environment Variables
46117

47118
### `WCAG_CVSDIR`

11ty/data-dependencies.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,11 @@ export async function loadDataDependencies(version?: string) {
5252
const techniques = await getTechniquesByTechnology(flatGuidelines);
5353
const flatTechniques = getFlatTechniques(techniques);
5454

55-
const techniqueAssociations = await getTechniqueAssociations(flatGuidelines);
56-
const futureTechniqueAssociations = await getTechniqueAssociations(futureGuidelines);
55+
const techniqueAssociations = await getTechniqueAssociations(flatGuidelines, definedVersion);
56+
const futureTechniqueAssociations = await getTechniqueAssociations(
57+
futureGuidelines,
58+
definedVersion
59+
);
5760
const futureExclusiveTechniqueAssociations: typeof techniqueAssociations = {};
5861
for (const [id, associations] of Object.entries(futureTechniqueAssociations)) {
5962
if (!techniqueAssociations[id]) futureExclusiveTechniqueAssociations[id] = associations;

11ty/guidelines.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,24 +35,27 @@ export const actRules = (
3535
JSON.parse(await readFile("guidelines/act-mapping.json", "utf8")) as ActMapping
3636
)["act-rules"];
3737

38-
/** Version-dependent overrides of SC shortcodes for older versions */
39-
export const scSlugOverrides: Record<string, (version: WcagVersion) => string> = {
40-
"target-size-enhanced": (version) => (version < "22" ? "target-size" : "target-size-enhanced"),
41-
};
38+
/** Generates version-dependent overrides of SC shortcodes for older versions */
39+
export const generateScSlugOverrides = (version: WcagVersion): Record<string, string> => ({
40+
...(version < "22" && {
41+
"target-size-enhanced": "target-size",
42+
}),
43+
});
4244

4345
/**
4446
* Flattened object hash, mapping each WCAG 2 SC slug to the earliest WCAG version it applies to.
4547
* (Functionally equivalent to "guidelines-versions" target in build.xml; structurally inverted)
4648
*/
4749
async function resolveScVersions(version: WcagVersion) {
4850
const paths = await glob("*/*.html", { cwd: "understanding" });
51+
const scSlugOverrides = generateScSlugOverrides(version);
4952
const map: Record<string, WcagVersion> = {};
5053

5154
for (const path of paths) {
5255
const [fileVersion, filename] = path.split("/");
5356
assertIsWcagVersion(fileVersion);
5457
const slug = basename(filename, ".html");
55-
map[slug in scSlugOverrides ? scSlugOverrides[slug](version) : slug] = fileVersion;
58+
map[slug in scSlugOverrides ? scSlugOverrides[slug] : slug] = fileVersion;
5659
}
5760

5861
return map;

0 commit comments

Comments
 (0)