aria-api 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/atree.js CHANGED
@@ -1,10 +1,10 @@
1
- var attrs = require('./attrs');
1
+ const attrs = require('./attrs');
2
2
 
3
- var _getOwner = function(node, owners) {
3
+ const _getOwner = function(node, owners) {
4
4
  if (node.nodeType === node.ELEMENT_NODE && node.id) {
5
- var selector = '[aria-owns~="' + CSS.escape(node.id) + '"]';
5
+ const selector = '[aria-owns~="' + CSS.escape(node.id) + '"]';
6
6
  if (owners) {
7
- for (var owner of owners) {
7
+ for (const owner of owners) {
8
8
  if (owner.matches(selector)) {
9
9
  return owner;
10
10
  }
@@ -15,12 +15,12 @@ var _getOwner = function(node, owners) {
15
15
  }
16
16
  };
17
17
 
18
- var _getParentNode = function(node, owners) {
18
+ const _getParentNode = function(node, owners) {
19
19
  return _getOwner(node, owners) || node.parentNode;
20
20
  };
21
21
 
22
- var detectLoop = function(node, owners) {
23
- var seen = [node];
22
+ const detectLoop = function(node, owners) {
23
+ const seen = [node];
24
24
  while ((node = _getParentNode(node, owners))) {
25
25
  if (seen.includes(node)) {
26
26
  return true;
@@ -29,35 +29,35 @@ var detectLoop = function(node, owners) {
29
29
  }
30
30
  };
31
31
 
32
- var getOwner = function(node, owners) {
33
- var owner = _getOwner(node, owners);
32
+ const getOwner = function(node, owners) {
33
+ const owner = _getOwner(node, owners);
34
34
  if (owner && !detectLoop(node, owners)) {
35
35
  return owner;
36
36
  }
37
37
  };
38
38
 
39
- var getParentNode = function(node, owners) {
39
+ const getParentNode = function(node, owners) {
40
40
  return getOwner(node, owners) || node.parentNode;
41
41
  };
42
42
 
43
- var isHidden = function(node) {
43
+ const isHidden = function(node) {
44
44
  return node.nodeType === node.ELEMENT_NODE && attrs.getAttribute(node, 'hidden');
45
45
  };
46
46
 
47
- var getChildNodes = function(node, owners) {
48
- var childNodes = [];
47
+ const getChildNodes = function(node, owners) {
48
+ const childNodes = [];
49
49
 
50
- for (var i = 0; i < node.childNodes.length; i++) {
51
- var child = node.childNodes[i];
50
+ for (let i = 0; i < node.childNodes.length; i++) {
51
+ const child = node.childNodes[i];
52
52
  if (!getOwner(child, owners) && !isHidden(child)) {
53
53
  childNodes.push(child);
54
54
  }
55
55
  }
56
56
 
57
57
  if (node.nodeType === node.ELEMENT_NODE) {
58
- var owns = attrs.getAttribute(node, 'owns') || [];
59
- for (var i = 0; i < owns.length; i++) {
60
- var child = document.getElementById(owns[i]);
58
+ const owns = attrs.getAttribute(node, 'owns') || [];
59
+ for (let i = 0; i < owns.length; i++) {
60
+ const child = document.getElementById(owns[i]);
61
61
  // double check with getOwner for consistency
62
62
  if (child && getOwner(child, owners) === node && !isHidden(child)) {
63
63
  childNodes.push(child);
@@ -68,18 +68,18 @@ var getChildNodes = function(node, owners) {
68
68
  return childNodes;
69
69
  };
70
70
 
71
- var walk = function(root, fn) {
72
- var owners = document.querySelectorAll('[aria-owns]');
73
- var queue = [root];
71
+ const walk = function(root, fn) {
72
+ const owners = document.querySelectorAll('[aria-owns]');
73
+ let queue = [root];
74
74
  while (queue.length) {
75
- var item = queue.shift();
75
+ const item = queue.shift();
76
76
  fn(item);
77
77
  queue = getChildNodes(item, owners).concat(queue);
78
78
  }
79
79
  };
80
80
 
81
- var searchUp = function(node, test) {
82
- var candidate = getParentNode(node);
81
+ const searchUp = function(node, test) {
82
+ const candidate = getParentNode(node);
83
83
  if (candidate) {
84
84
  if (test(candidate)) {
85
85
  return candidate;
package/lib/attrs.js CHANGED
@@ -1,41 +1,56 @@
1
- var constants = require('./constants.js');
1
+ const constants = require('./constants.js');
2
+
3
+ var unique = function(arr) {
4
+ return arr.filter((a, i) => arr.indexOf(a) === i);
5
+ };
6
+
7
+ var flatten = function(arr) {
8
+ return [].concat.apply([], arr);
9
+ };
10
+
11
+ var normalizeRoles = function(roles, includeAbstract) {
12
+ return unique(roles
13
+ .map(r => constants.aliases[r] || r)
14
+ .filter(r => constants.roles[r])
15
+ .filter(r => includeAbstract || !constants.roles[r].abstract)
16
+ );
17
+ };
2
18
 
3
19
  // candidates can be passed for performance optimization
4
- var getRole = function(el, candidates) {
5
- if (el.hasAttribute('role')) {
6
- var roles = el.getAttribute('role').toLowerCase().split(/\s+/);
7
- if (roles.length > 1 && candidates) {
8
- return [roles, candidates];
9
- }
10
- for (var role of roles) {
20
+ const getRole = function(el, candidates) {
21
+ // TODO: filter out any invalid roles (e.g. name or context required)
22
+ const roles = normalizeRoles(
23
+ (el.getAttribute('role') || '').toLowerCase().split(/\s+/)
24
+ );
25
+
26
+ if (roles.length > 1 && candidates) {
27
+ return [roles, candidates];
28
+ } else if (roles.length) {
29
+ for (const role of roles) {
11
30
  if (!candidates || candidates.includes(role)) {
12
31
  return role;
13
32
  }
14
33
  }
15
34
  } else {
16
- var roles = candidates ? candidates : Object.keys(constants.roles);
17
- for (var role of roles) {
18
- var r = constants.roles[role];
19
- if (r) {
20
- var selector = (r.selectors || []).join(',');
21
- if (selector && el.matches(selector)) {
22
- return role;
23
- }
35
+ for (const role of (candidates || Object.keys(constants.roles))) {
36
+ const r = constants.roles[role];
37
+ if (!r.abstract && r.selectors && el.matches(r.selectors.join(','))) {
38
+ return role;
24
39
  }
25
40
  }
26
41
  }
27
42
  };
28
43
 
29
- var hasRole = function(el, roles) {
30
- var candidates = [].concat.apply([], roles.map(role => {
31
- return (constants.roles[role] || {}).subRoles || [role];
32
- }));
33
- return !!getRole(el, candidates);
44
+ const hasRole = function(el, roles) {
45
+ const subRoles = normalizeRoles(roles, true).map(role => {
46
+ return constants.roles[role].subRoles || [role];
47
+ });
48
+ return !!getRole(el, unique(flatten(subRoles)));
34
49
  };
35
50
 
36
- var getAttribute = function(el, key) {
51
+ const getAttribute = function(el, key) {
37
52
  if (constants.attributeStrongMapping.hasOwnProperty(key)) {
38
- var value = el[constants.attributeStrongMapping[key]];
53
+ const value = el[constants.attributeStrongMapping[key]];
39
54
  if (value) {
40
55
  return value;
41
56
  }
@@ -52,14 +67,14 @@ var getAttribute = function(el, key) {
52
67
  if (el.matches('details:not([open]) > :not(summary)')) {
53
68
  return true;
54
69
  }
55
- var style = window.getComputedStyle(el);
56
- if (style.display === 'none' || style.visibility === 'hidden') {
70
+ const style = window.getComputedStyle(el);
71
+ if (style.display === 'none' || style.visibility === 'hidden' || style.visibility === 'collapse') {
57
72
  return true;
58
73
  }
59
74
  }
60
75
 
61
- var type = constants.attributes[key];
62
- var raw = el.getAttribute('aria-' + key);
76
+ const type = constants.attributes[key];
77
+ const raw = el.getAttribute('aria-' + key);
63
78
 
64
79
  if (raw) {
65
80
  if (type === 'bool') {
@@ -88,7 +103,7 @@ var getAttribute = function(el, key) {
88
103
  // list -> aria-controls
89
104
 
90
105
  if (key === 'level') {
91
- for (var i = 1; i <= 6; i++) {
106
+ for (let i = 1; i <= 6; i++) {
92
107
  if (el.tagName.toLowerCase() === 'h' + i) {
93
108
  return i;
94
109
  }
@@ -98,8 +113,8 @@ var getAttribute = function(el, key) {
98
113
  }
99
114
 
100
115
  if (key in constants.attrsWithDefaults) {
101
- var role = getRole(el);
102
- var defaults = (constants.roles[role] || {}).defaults;
116
+ const role = getRole(el);
117
+ const defaults = constants.roles[role].defaults;
103
118
  if (defaults && defaults.hasOwnProperty(key)) {
104
119
  return defaults[key];
105
120
  }
package/lib/constants.js CHANGED
@@ -3,14 +3,18 @@ exports.attributes = {
3
3
  'activedescendant': 'id',
4
4
  'atomic': 'bool',
5
5
  'autocomplete': 'token',
6
+ 'braillelabel': 'string',
7
+ 'brailleroledescription': 'string',
6
8
  'busy': 'bool',
7
9
  'checked': 'tristate',
8
10
  'colcount': 'int',
9
11
  'colindex': 'int',
12
+ 'colindextext': 'string',
10
13
  'colspan': 'int',
11
14
  'controls': 'id-list',
12
15
  'current': 'token',
13
16
  'describedby': 'id-list',
17
+ 'description': 'string',
14
18
  'details': 'id',
15
19
  'disabled': 'bool',
16
20
  'dropeffect': 'token-list',
@@ -40,6 +44,7 @@ exports.attributes = {
40
44
  'roledescription': 'string',
41
45
  'rowcount': 'int',
42
46
  'rowindex': 'int',
47
+ 'rowindextext': 'string',
43
48
  'rowspan': 'int',
44
49
  'selected': 'bool-undefined',
45
50
  'setsize': 'int',
@@ -67,7 +72,20 @@ exports.attributeWeakMapping = {
67
72
  };
68
73
 
69
74
  // https://www.w3.org/TR/html/dom.html#sectioning-content-2
70
- var scoped = ['article *', 'aside *', 'nav *', 'section *'].join(',');
75
+ const scoped = ['article *', 'aside *', 'nav *', 'section *'].join(',');
76
+
77
+ const svgSelectors = function(selector) {
78
+ return [
79
+ // `${selector}:has(> title:not(:empty))`,
80
+ // `${selector}:has(> desc:not(:empty))`,
81
+ `${selector}[aria-label]`,
82
+ `${selector}[aria-roledescription]`,
83
+ `${selector}[aria-labelledby]`,
84
+ `${selector}[aria-describedby]`,
85
+ `${selector}[tabindex]`,
86
+ `${selector}[role]`,
87
+ ];
88
+ };
71
89
 
72
90
  // https://www.w3.org/TR/html-aam-1.0/#html-element-role-mappings
73
91
  // https://www.w3.org/TR/wai-aria/roles
@@ -79,8 +97,11 @@ exports.roles = {
79
97
  'atomic': true,
80
98
  },
81
99
  },
100
+ alertdialog: {},
101
+ application: {},
82
102
  article: {
83
103
  selectors: ['article'],
104
+ childRoles: ['comment'],
84
105
  },
85
106
  banner: {
86
107
  selectors: [`header:not(main *, ${scoped})`],
@@ -103,7 +124,7 @@ exports.roles = {
103
124
  selectors: ['caption', 'figcaption'],
104
125
  },
105
126
  cell: {
106
- selectors: ['td', 'th:not([scope])'],
127
+ selectors: ['td', 'td ~ th:not([scope])'],
107
128
  childRoles: ['columnheader', 'gridcell', 'rowheader'],
108
129
  nameFromContents: true,
109
130
  },
@@ -140,8 +161,12 @@ exports.roles = {
140
161
  },
141
162
  },
142
163
  command: {
164
+ abstract: true,
143
165
  childRoles: ['button', 'link', 'menuitem'],
144
166
  },
167
+ comment: {
168
+ nameFromContents: true,
169
+ },
145
170
  complementary: {
146
171
  selectors: [
147
172
  `aside:not(${scoped})`,
@@ -151,6 +176,7 @@ exports.roles = {
151
176
  ],
152
177
  },
153
178
  composite: {
179
+ abstract: true,
154
180
  childRoles: ['grid', 'select', 'spinbutton', 'tablist'],
155
181
  },
156
182
  contentinfo: {
@@ -166,24 +192,59 @@ exports.roles = {
166
192
  selectors: ['dialog'],
167
193
  childRoles: ['alertdialog'],
168
194
  },
195
+ 'doc-abstract': {},
196
+ 'doc-acknowledgments': {},
197
+ 'doc-afterword': {},
198
+ 'doc-appendix': {},
169
199
  'doc-backlink': {
170
200
  nameFromContents: true,
171
201
  },
202
+ 'doc-biblioentry': {},
203
+ 'doc-bibliography': {},
172
204
  'doc-biblioref': {
173
205
  nameFromContents: true,
174
206
  },
207
+ 'doc-chapter': {},
208
+ 'doc-colophon': {},
209
+ 'doc-conclusion': {},
210
+ 'doc-cover': {},
211
+ 'doc-credit': {},
212
+ 'doc-credits': {},
213
+ 'doc-dedication': {},
214
+ 'doc-endnote': {},
215
+ 'doc-endnotes': {},
216
+ 'doc-epilogue': {},
217
+ 'doc-epigraph': {},
218
+ 'doc-errata': {},
219
+ 'doc-example': {},
220
+ 'doc-footnote': {},
221
+ 'doc-foreword': {},
222
+ 'doc-glossary': {},
175
223
  'doc-glossref': {
176
224
  nameFromContents: true,
177
225
  },
226
+ 'doc-index': {},
227
+ 'doc-introduction': {},
178
228
  'doc-noteref': {
179
229
  nameFromContents: true,
180
230
  },
231
+ 'doc-notice': {},
181
232
  'doc-pagebreak': {
182
233
  nameFromContents: true,
183
234
  },
235
+ 'doc-pagefooter': {},
236
+ 'doc-pageheader': {},
237
+ 'doc-pagelist': {},
238
+ 'doc-part': {},
239
+ 'doc-preface': {},
240
+ 'doc-prologue': {},
241
+ 'doc-pullquote': {},
242
+ 'doc-qna': {},
184
243
  'doc-subtitle': {
185
244
  nameFromContents: true,
186
245
  },
246
+ 'doc-tip': {},
247
+ 'doc-toc': {},
187
248
  document: {
188
249
  selectors: ['html'],
189
250
  childRoles: ['article', 'graphics-document'],
@@ -191,6 +252,7 @@ exports.roles = {
191
252
  emphasis: {
192
253
  selectors: ['em'],
193
254
  },
255
+ feed: {},
194
256
  figure: {
195
257
  selectors: ['figure'],
196
258
  childRoles: ['doc-example'],
@@ -199,11 +261,49 @@ exports.roles = {
199
261
  selectors: ['form[aria-label]', 'form[aria-labelledby]', 'form[title]'],
200
262
  },
201
263
  generic: {
202
- // too many selectors to list
264
+ selectors: [
265
+ 'a:not([*|href])',
266
+ 'area:not([*|href])',
267
+ `aside:not(${scoped}):not([aria-label]):not([aria-labelledby]):not([title])`,
268
+ 'b',
269
+ 'bdi',
270
+ 'bdo',
271
+ 'body',
272
+ 'data',
273
+ 'div',
274
+ // footer scoped
275
+ // header scoped
276
+ 'i',
277
+ 'li:not(ul > li):not(ol > li)',
278
+ 'pre',
279
+ 'q',
280
+ 'samp',
281
+ 'section:not([aria-label]):not([aria-labelledby]):not([title])',
282
+ 'small',
283
+ 'span',
284
+ 'u',
285
+ ],
203
286
  },
204
287
  'graphics-document': {
205
288
  selectors: ['svg'],
206
289
  },
290
+ 'graphics-object': {
291
+ selectors: [
292
+ ...svgSelectors('symbol'),
293
+ ...svgSelectors('use'),
294
+ ],
295
+ },
296
+ 'graphics-symbol': {
297
+ selectors: [
298
+ ...svgSelectors('circle'),
299
+ ...svgSelectors('ellipse'),
300
+ ...svgSelectors('line'),
301
+ ...svgSelectors('path'),
302
+ ...svgSelectors('polygon'),
303
+ ...svgSelectors('polyline'),
304
+ ...svgSelectors('rect'),
305
+ ],
306
+ },
207
307
  grid: {
208
308
  childRoles: ['treegrid'],
209
309
  },
@@ -218,7 +318,11 @@ exports.roles = {
218
318
  'fieldset',
219
319
  'hgroup',
220
320
  'optgroup',
321
+ ...svgSelectors('foreignObject'),
322
+ ...svgSelectors('g'),
221
323
  'text',
324
+ ...svgSelectors('textPath'),
325
+ ...svgSelectors('tspan'),
222
326
  ],
223
327
  childRoles: ['row', 'select', 'toolbar', 'graphics-object'],
224
328
  },
@@ -229,11 +333,17 @@ exports.roles = {
229
333
  'level': 2,
230
334
  },
231
335
  },
232
- img: {
233
- selectors: ['img:not([alt=""])', 'graphics-symbol'],
336
+ image: {
337
+ selectors: [
338
+ 'img:not([alt=""])',
339
+ 'graphics-symbol',
340
+ ...svgSelectors('image'),
341
+ ...svgSelectors('mesh'),
342
+ ],
234
343
  childRoles: ['doc-cover'],
235
344
  },
236
345
  input: {
346
+ abstract: true,
237
347
  childRoles: [
238
348
  'checkbox',
239
349
  'combobox',
@@ -248,6 +358,7 @@ exports.roles = {
248
358
  selectors: ['ins'],
249
359
  },
250
360
  landmark: {
361
+ abstract: true,
251
362
  childRoles: [
252
363
  'banner',
253
364
  'complementary',
@@ -276,13 +387,13 @@ exports.roles = {
276
387
  ],
277
388
  },
278
389
  link: {
279
- selectors: ['a[href]', 'area[href]'],
390
+ selectors: ['a[*|href]', 'area[href]'],
280
391
  childRoles: ['doc-backlink', 'doc-biblioref', 'doc-glossref', 'doc-noteref'],
281
392
  nameFromContents: true,
282
393
  },
283
394
  list: {
284
395
  selectors: ['dl', 'ol', 'ul', 'menu'],
285
- childRoles: ['directory', 'feed'],
396
+ childRoles: ['feed'],
286
397
  },
287
398
  listbox: {
288
399
  selectors: [
@@ -295,7 +406,7 @@ exports.roles = {
295
406
  },
296
407
  },
297
408
  listitem: {
298
- selectors: ['li'],
409
+ selectors: ['ol > li', 'ul > li'],
299
410
  childRoles: ['doc-biblioentry', 'doc-endnote', 'treeitem'],
300
411
  },
301
412
  log: {
@@ -306,6 +417,10 @@ exports.roles = {
306
417
  main: {
307
418
  selectors: ['main'],
308
419
  },
420
+ mark: {
421
+ selectors: ['mark'],
422
+ },
423
+ marquee: {},
309
424
  math: {
310
425
  selectors: ['math'],
311
426
  },
@@ -328,11 +443,10 @@ exports.roles = {
328
443
  },
329
444
  },
330
445
  menuitem: {
331
- childRoles: ['menuitemcheckbox'],
446
+ childRoles: ['menuitemcheckbox', 'menuitemradio'],
332
447
  nameFromContents: true,
333
448
  },
334
449
  menuitemcheckbox: {
335
- childRoles: ['menuitemradio'],
336
450
  nameFromContents: true,
337
451
  defaults: {
338
452
  'checked': 'false',
@@ -348,6 +462,9 @@ exports.roles = {
348
462
  selectors: ['nav'],
349
463
  childRoles: ['doc-index', 'doc-pagelist', 'doc-toc'],
350
464
  },
465
+ none: {
466
+ selectors: ['img[alt=""]'],
467
+ },
351
468
  note: {
352
469
  childRoles: ['doc-notice', 'doc-tip'],
353
470
  },
@@ -362,9 +479,6 @@ exports.roles = {
362
479
  paragraph: {
363
480
  selectors: ['p'],
364
481
  },
365
- presentation: {
366
- selectors: ['img[alt=""]'],
367
- },
368
482
  progressbar: {
369
483
  selectors: ['progress'],
370
484
  defaults: {
@@ -380,13 +494,16 @@ exports.roles = {
380
494
  'checked': 'false',
381
495
  },
382
496
  },
497
+ radiogroup: {},
383
498
  range: {
499
+ abstract: true,
384
500
  childRoles: ['meter', 'progressbar', 'scrollbar', 'slider', 'spinbutton'],
385
501
  },
386
502
  region: {
387
503
  selectors: ['section[aria-label]', 'section[aria-labelledby]', 'section[title]'],
388
504
  },
389
505
  roletype: {
506
+ abstract: true,
390
507
  childRoles: ['structure', 'widget', 'window'],
391
508
  },
392
509
  row: {
@@ -397,7 +514,7 @@ exports.roles = {
397
514
  selectors: ['tbody', 'thead', 'tfoot'],
398
515
  },
399
516
  rowheader: {
400
- selectors: ['th[scope="row"]'],
517
+ selectors: ['th[scope="row"]', 'th:not([scope]):not(td ~ th)'],
401
518
  nameFromContents: true,
402
519
  },
403
520
  scrollbar: {
@@ -414,6 +531,7 @@ exports.roles = {
414
531
  selectors: ['input[type="search"]:not([list])'],
415
532
  },
416
533
  section: {
534
+ abstract: true,
417
535
  childRoles: [
418
536
  'alert',
419
537
  'blockquote',
@@ -435,12 +553,13 @@ exports.roles = {
435
553
  'emphasis',
436
554
  'figure',
437
555
  'group',
438
- 'img',
556
+ 'image',
439
557
  'insertion',
440
558
  'landmark',
441
559
  'list',
442
560
  'listitem',
443
561
  'log',
562
+ 'mark',
444
563
  'marquee',
445
564
  'math',
446
565
  'note',
@@ -448,6 +567,7 @@ exports.roles = {
448
567
  'status',
449
568
  'strong',
450
569
  'subscript',
570
+ 'suggestion',
451
571
  'superscript',
452
572
  'table',
453
573
  'tabpanel',
@@ -457,6 +577,7 @@ exports.roles = {
457
577
  ],
458
578
  },
459
579
  sectionhead: {
580
+ abstract: true,
460
581
  childRoles: [
461
582
  'columnheader',
462
583
  'doc-subtitle',
@@ -467,6 +588,7 @@ exports.roles = {
467
588
  nameFromContents: true,
468
589
  },
469
590
  select: {
591
+ abstract: true,
470
592
  childRoles: ['listbox', 'menu', 'radiogroup', 'tree'],
471
593
  },
472
594
  separator: {
@@ -507,12 +629,12 @@ exports.roles = {
507
629
  selectors: ['strong'],
508
630
  },
509
631
  structure: {
632
+ abstract: true,
510
633
  childRoles: [
511
634
  'application',
512
635
  'document',
513
636
  'none',
514
637
  'generic',
515
- 'presentation',
516
638
  'range',
517
639
  'rowgroup',
518
640
  'section',
@@ -520,6 +642,7 @@ exports.roles = {
520
642
  'separator',
521
643
  ],
522
644
  },
645
+ suggestion: {},
523
646
  subscript: {
524
647
  selectors: ['sub'],
525
648
  },
@@ -547,6 +670,7 @@ exports.roles = {
547
670
  'orientation': 'horizontal',
548
671
  },
549
672
  },
673
+ tabpanel: {},
550
674
  term: {
551
675
  selectors: ['dfn', 'dt'],
552
676
  },
@@ -583,10 +707,12 @@ exports.roles = {
583
707
  'orientation': 'vertical',
584
708
  },
585
709
  },
710
+ treegrid: {},
586
711
  treeitem: {
587
712
  nameFromContents: true,
588
713
  },
589
714
  widget: {
715
+ abstract: true,
590
716
  childRoles: [
591
717
  'command',
592
718
  'composite',
@@ -600,15 +726,16 @@ exports.roles = {
600
726
  ],
601
727
  },
602
728
  window: {
729
+ abstract: true,
603
730
  childRoles: ['dialog'],
604
731
  },
605
732
  };
606
733
 
607
- var getSubRoles = function(role) {
608
- var children = (exports.roles[role] || {}).childRoles || [];
609
- var descendents = children.map(getSubRoles);
734
+ const getSubRoles = function(role) {
735
+ const children = (exports.roles[role]).childRoles || [];
736
+ const descendents = children.map(getSubRoles);
610
737
 
611
- var result = [role];
738
+ const result = [role];
612
739
 
613
740
  descendents.forEach(list => {
614
741
  list.forEach(r => {
@@ -623,18 +750,20 @@ var getSubRoles = function(role) {
623
750
 
624
751
  exports.attrsWithDefaults = [];
625
752
 
626
- for (var role in exports.roles) {
753
+ for (const role in exports.roles) {
627
754
  exports.roles[role].subRoles = getSubRoles(role);
628
- for (var key in exports.roles[role].defaults) {
755
+ for (const key in exports.roles[role].defaults) {
629
756
  if (!exports.attrsWithDefaults.includes(key)) {
630
757
  exports.attrsWithDefaults.push(key);
631
758
  }
632
759
  }
633
760
  }
634
- exports.roles['none'] = exports.roles['none'] || {};
635
- exports.roles['none'].subRoles = ['none', 'presentation'];
636
- exports.roles['presentation'] = exports.roles['presentation'] || {};
637
- exports.roles['presentation'].subRoles = ['presentation', 'none'];
761
+
762
+ exports.aliases = {
763
+ 'presentation': 'none',
764
+ 'directory': 'list',
765
+ 'img': 'image',
766
+ };
638
767
 
639
768
  exports.nameFromDescendant = {
640
769
  'figure': 'figcaption',