1
1
import axios from "axios" ;
2
2
import type { CheerioAPI } from "cheerio" ;
3
3
import { glob } from "glob" ;
4
+ import pick from "lodash-es/pick" ;
4
5
5
6
import { readFile } from "fs/promises" ;
6
7
import { basename , join } from "path" ;
@@ -34,22 +35,28 @@ export const actRules = (
34
35
JSON . parse ( await readFile ( "guidelines/act-mapping.json" , "utf8" ) ) as ActMapping
35
36
) [ "act-rules" ] ;
36
37
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
+ } ;
42
+
37
43
/**
38
44
* Flattened object hash, mapping each WCAG 2 SC slug to the earliest WCAG version it applies to.
39
45
* (Functionally equivalent to "guidelines-versions" target in build.xml; structurally inverted)
40
46
*/
41
- const scVersions = await ( async function ( ) {
47
+ async function resolveScVersions ( version : WcagVersion ) {
42
48
const paths = await glob ( "*/*.html" , { cwd : "understanding" } ) ;
43
49
const map : Record < string , WcagVersion > = { } ;
44
50
45
51
for ( const path of paths ) {
46
52
const [ fileVersion , filename ] = path . split ( "/" ) ;
47
53
assertIsWcagVersion ( fileVersion ) ;
48
- map [ basename ( filename , ".html" ) ] = fileVersion ;
54
+ const slug = basename ( filename , ".html" ) ;
55
+ map [ slug in scSlugOverrides ? scSlugOverrides [ slug ] ( version ) : slug ] = fileVersion ;
49
56
}
50
57
51
58
return map ;
52
- } ) ( ) ;
59
+ }
53
60
54
61
export interface DocNode {
55
62
id : string ;
@@ -83,15 +90,12 @@ export interface SuccessCriterion extends DocNode {
83
90
type : "SC" ;
84
91
}
85
92
93
+ export type WcagItem = Principle | Guideline | SuccessCriterion ;
94
+
86
95
export function isSuccessCriterion ( criterion : any ) : criterion is SuccessCriterion {
87
96
return ! ! ( criterion ?. type === "SC" && "level" in criterion ) ;
88
97
}
89
98
90
- /** Version-dependent overrides of SC shortcodes for older versions */
91
- export const scSlugOverrides : Record < string , ( version : WcagVersion ) => string > = {
92
- "target-size-enhanced" : ( version ) => ( version < "22" ? "target-size" : "target-size-enhanced" ) ,
93
- } ;
94
-
95
99
/** Selectors ignored when capturing content of each Principle / Guideline / SC */
96
100
const contentIgnores = [
97
101
"h1, h2, h3, h4, h5, h6" ,
@@ -115,7 +119,12 @@ const getContentHtml = ($el: CheerioAnyNode) => {
115
119
} ;
116
120
117
121
/** Performs processing common across WCAG versions */
118
- function processPrinciples ( $ : CheerioAPI ) {
122
+ async function processPrinciples ( $ : CheerioAPI ) {
123
+ // Auto-detect version from end of title
124
+ const version = $ ( "title" ) . text ( ) . trim ( ) . split ( " " ) . pop ( ) ! . replace ( "." , "" ) ;
125
+ assertIsWcagVersion ( version ) ;
126
+ const scVersions = await resolveScVersions ( version ) ;
127
+
119
128
const principles : Principle [ ] = [ ] ;
120
129
$ ( ".principle" ) . each ( ( i , el ) => {
121
130
const guidelines : Guideline [ ] = [ ] ;
@@ -175,7 +184,7 @@ export const getPrinciples = async (path = "guidelines/index.html") =>
175
184
* Returns a flattened object hash, mapping shortcodes to each principle/guideline/SC.
176
185
*/
177
186
export function getFlatGuidelines ( principles : Principle [ ] ) {
178
- const map : Record < string , Principle | Guideline | SuccessCriterion > = { } ;
187
+ const map : Record < string , WcagItem > = { } ;
179
188
for ( const principle of principles ) {
180
189
map [ principle . id ] = principle ;
181
190
for ( const guideline of principle . guidelines ) {
@@ -199,7 +208,7 @@ interface Term {
199
208
}
200
209
export type TermsMap = Record < string , Term > ;
201
210
202
- function processTermsMap ( $ : CheerioAPI ) {
211
+ function processTermsMap ( $ : CheerioAPI , includeSynonyms = true ) {
203
212
const terms : TermsMap = { } ;
204
213
205
214
$ ( "dfn" ) . each ( ( _ , el ) => {
@@ -213,12 +222,16 @@ function processTermsMap($: CheerioAPI) {
213
222
trId : el . attribs . id ,
214
223
} ;
215
224
216
- // Include both original and all-lowercase version to simplify lookups
217
- // (since most synonyms are lowercase) while preserving case in name
218
- const names = [ term . name , term . name . toLowerCase ( ) ] . concat (
219
- ( el . attribs [ "data-lt" ] || "" ) . toLowerCase ( ) . split ( "|" )
220
- ) ;
221
- for ( const name of names ) terms [ name ] = term ;
225
+ if ( includeSynonyms ) {
226
+ // Include both original and all-lowercase version to simplify lookups
227
+ // (since most synonyms are lowercase) while preserving case in name
228
+ const names = [ term . name , term . name . toLowerCase ( ) ] . concat (
229
+ ( el . attribs [ "data-lt" ] || "" ) . toLowerCase ( ) . split ( "|" )
230
+ ) ;
231
+ for ( const name of names ) terms [ name ] = term ;
232
+ } else {
233
+ terms [ term . name ] = term ;
234
+ }
222
235
} ) ;
223
236
224
237
return terms ;
@@ -230,7 +243,7 @@ function processTermsMap($: CheerioAPI) {
230
243
* comparable to the term elements in wcag.xml from the guidelines-xml Ant task.
231
244
*/
232
245
export const getTermsMap = async ( path = "guidelines/index.html" ) =>
233
- processTermsMap ( await flattenDomFromFile ( path ) ) ;
246
+ processTermsMap ( await flattenDomFromFile ( path ) , true ) ;
234
247
235
248
// Version-specific APIs
236
249
@@ -245,6 +258,11 @@ const loadRemoteGuidelines = async (version: WcagVersion, stripRespec = true) =>
245
258
) . data ) ;
246
259
247
260
const $ = load ( html ) ;
261
+
262
+ // Remove extra markup from headings, regardless of stripRespec setting,
263
+ // so that names parse consistently
264
+ $ ( "bdi" ) . remove ( ) ;
265
+
248
266
if ( ! stripRespec ) return $ ;
249
267
250
268
// Re-collapse definition links and notes, to be processed by this build system
@@ -271,9 +289,6 @@ const loadRemoteGuidelines = async (version: WcagVersion, stripRespec = true) =>
271
289
$ ( ".example[id]" ) . removeAttr ( "id" ) ;
272
290
$ ( ".example > .marker" ) . remove ( ) ;
273
291
274
- // Remove extra markup from headings so they can be parsed for names
275
- $ ( "bdi" ) . remove ( ) ;
276
-
277
292
// Remove abbr elements which exist only in TR, not in informative docs
278
293
$ ( "#acknowledgements li abbr, #glossary abbr" ) . each ( ( _ , abbrEl ) => {
279
294
$ ( abbrEl ) . replaceWith ( $ ( abbrEl ) . text ( ) ) ;
@@ -300,15 +315,30 @@ export const getAcknowledgementsForVersion = async (version: WcagVersion) => {
300
315
/**
301
316
* Retrieves and processes a pinned WCAG version using published guidelines.
302
317
*/
303
- export const getPrinciplesForVersion = async ( version : WcagVersion ) =>
304
- processPrinciples ( await loadRemoteGuidelines ( version ) ) ;
318
+ export const getPrinciplesForVersion = async ( version : WcagVersion , stripRespec ?: boolean ) =>
319
+ processPrinciples ( await loadRemoteGuidelines ( version , stripRespec ) ) ;
320
+
321
+ interface GetTermsMapForVersionOptions {
322
+ /**
323
+ * Whether to populate additional map keys based on synonyms defined in data-lt;
324
+ * this should typically be true for informative docs, but may be false for other purposes
325
+ */
326
+ includeSynonyms ?: boolean ;
327
+ /**
328
+ * Whether to strip respec-generated content and attributes;
329
+ * this should typically be true for informative docs, but may be false for other purposes
330
+ */
331
+ stripRespec ?: boolean ;
332
+ }
305
333
306
334
/**
307
335
* Resolves term definitions from a WCAG 2.x publication,
308
336
* organized for lookup by name.
309
337
*/
310
- export const getTermsMapForVersion = async ( version : WcagVersion ) =>
311
- processTermsMap ( await loadRemoteGuidelines ( version ) ) ;
338
+ export const getTermsMapForVersion = async (
339
+ version : WcagVersion ,
340
+ { includeSynonyms, stripRespec } : GetTermsMapForVersionOptions = { }
341
+ ) => processTermsMap ( await loadRemoteGuidelines ( version , stripRespec ) , includeSynonyms ) ;
312
342
313
343
/** Parses errata items from the errata document for the specified WCAG version. */
314
344
export const getErrataForVersion = async ( version : WcagVersion ) => {
0 commit comments