aria-api

access ARIA information from JavaScript
git clone https://git.ce9e.org/aria-api.git

commit
c2268727f934d830276b5cdde18e1d261864d830
parent
d1e55b782fec41c41d3f77fd6cc46c4d6acd9196
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2024-11-01 12:46
bump version to 0.8.0

Diffstat

M CHANGES.md 10 ++++++++++
M dist/aria.js 2458 ++++++++++++++++++++++++++++++-------------------------------
M package.json 2 +-

3 files changed, 1224 insertions, 1246 deletions


diff --git a/CHANGES.md b/CHANGES.md

@@ -1,3 +1,13 @@
   -1     1 0.8.0 (2024-11-01)
   -1     2 ------------------
   -1     3 
   -1     4 -	Convert the source code to ES modules. `dist/aria.js` is still an UMD bundle.
   -1     5 -	The internal re-exports `query.getRole()` and `query.getAttribute()` have
   -1     6 	been removed. Use the corresponding exports from `attrs` instead.
   -1     7 -	fix: support `xlink:href` on `<area>` elements
   -1     8 -	fix: consider `text-transform` in `getName()` and `getDescription()`
   -1     9 
   -1    10 
    1    11 0.7.0 (2024-06-22)
    2    12 ------------------
    3    13 

diff --git a/dist/aria.js b/dist/aria.js

@@ -1,1325 +1,1293 @@
    1    -1 (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.aria = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
    2    -1 var query = require('./lib/query.js');
    3    -1 var name = require('./lib/name.js');
    4    -1 var atree = require('./lib/atree.js');
    5    -1 
    6    -1 module.exports = {
    7    -1 	getRole: query.getRole,
    8    -1 	getAttribute: query.getAttribute,
    9    -1 	getName: name.getName,
   10    -1 	getDescription: name.getDescription,
   11    -1 
   12    -1 	matches: query.matches,
   13    -1 	querySelector: query.querySelector,
   14    -1 	querySelectorAll: query.querySelectorAll,
   15    -1 	closest: query.closest,
   16    -1 
   17    -1 	getParentNode: atree.getParentNode,
   18    -1 	getChildNodes: atree.getChildNodes,
   19    -1 };
   20    -1 
   21    -1 },{"./lib/atree.js":2,"./lib/name.js":5,"./lib/query.js":6}],2:[function(require,module,exports){
   22    -1 const attrs = require('./attrs');
   23    -1 
   24    -1 const _getOwner = function(node, owners) {
   25    -1 	if (node.nodeType === node.ELEMENT_NODE && node.id) {
   26    -1 		const selector = '[aria-owns~="' + CSS.escape(node.id) + '"]';
   27    -1 		if (owners) {
   28    -1 			for (const owner of owners) {
   29    -1 				if (owner.matches(selector)) {
   30    -1 					return owner;
   31    -1 				}
   32    -1 			}
   33    -1 		} else {
   34    -1 			return document.querySelector(selector);
   35    -1 		}
   36    -1 	}
   37    -1 };
   -1     1 (function (global, factory) {
   -1     2 	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
   -1     3 	typeof define === 'function' && define.amd ? define(['exports'], factory) :
   -1     4 	(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.aria = {}));
   -1     5 })(this, (function (exports) { 'use strict';
   -1     6 
   -1     7 	// https://www.w3.org/TR/wai-aria/#state_prop_def
   -1     8 	const attributes = {
   -1     9 		'activedescendant': 'id',
   -1    10 		'atomic': 'bool',
   -1    11 		'autocomplete': 'token',
   -1    12 		'braillelabel': 'string',
   -1    13 		'brailleroledescription': 'string',
   -1    14 		'busy': 'bool',
   -1    15 		'checked': 'tristate',
   -1    16 		'colcount': 'int',
   -1    17 		'colindex': 'int',
   -1    18 		'colindextext': 'string',
   -1    19 		'colspan': 'int',
   -1    20 		'controls': 'id-list',
   -1    21 		'current': 'token',
   -1    22 		'describedby': 'id-list',
   -1    23 		'description': 'string',
   -1    24 		'details': 'id',
   -1    25 		'disabled': 'bool',
   -1    26 		'dropeffect': 'token-list',
   -1    27 		'errormessage': 'id',
   -1    28 		'expanded': 'bool-undefined',
   -1    29 		'flowto': 'id-list',
   -1    30 		'grabbed': 'bool-undefined',
   -1    31 		'haspopup': 'token',
   -1    32 		'hidden': 'bool-undefined',
   -1    33 		'invalid': 'token',
   -1    34 		'keyshortcuts': 'string',
   -1    35 		'label': 'string',
   -1    36 		'labelledby': 'id-list',
   -1    37 		'level': 'int',
   -1    38 		'live': 'token',
   -1    39 		'modal': 'bool',
   -1    40 		'multiline': 'bool',
   -1    41 		'multiselectable': 'bool',
   -1    42 		'orientation': 'token',
   -1    43 		'owns': 'id-list',
   -1    44 		'placeholder': 'string',
   -1    45 		'posinset': 'int',
   -1    46 		'pressed': 'tristate',
   -1    47 		'readonly': 'bool',
   -1    48 		'relevant': 'token-list',
   -1    49 		'required': 'bool',
   -1    50 		'roledescription': 'string',
   -1    51 		'rowcount': 'int',
   -1    52 		'rowindex': 'int',
   -1    53 		'rowindextext': 'string',
   -1    54 		'rowspan': 'int',
   -1    55 		'selected': 'bool-undefined',
   -1    56 		'setsize': 'int',
   -1    57 		'sort': 'token',
   -1    58 		'valuemax': 'number',
   -1    59 		'valuemin': 'number',
   -1    60 		'valuenow': 'number',
   -1    61 		'valuetext': 'string',
   -1    62 	};
   38    63 
   39    -1 const _getParentNode = function(node, owners) {
   40    -1 	return _getOwner(node, owners) || node.parentNode;
   41    -1 };
   -1    64 	const attributeStrongMapping = {
   -1    65 		'disabled': 'disabled',
   -1    66 		'placeholder': 'placeholder',
   -1    67 		'readonly': 'readOnly',
   -1    68 		'required': 'required',
   -1    69 	};
   42    70 
   43    -1 const detectLoop = function(node, owners) {
   44    -1 	const seen = [node];
   45    -1 	while ((node = _getParentNode(node, owners))) {
   46    -1 		if (seen.includes(node)) {
   47    -1 			return true;
   48    -1 		}
   49    -1 		seen.push(node);
   50    -1 	}
   51    -1 };
   -1    71 	const attributeWeakMapping = {
   -1    72 		'checked': 'checked',
   -1    73 		'colspan': 'colSpan',
   -1    74 		'expanded': 'open',
   -1    75 		'multiselectable': 'multiple',
   -1    76 		'rowspan': 'rowSpan',
   -1    77 		'selected': 'selected',
   -1    78 	};
   52    79 
   53    -1 const getOwner = function(node, owners) {
   54    -1 	const owner = _getOwner(node, owners);
   55    -1 	if (owner && !detectLoop(node, owners)) {
   56    -1 		return owner;
   57    -1 	}
   58    -1 };
   -1    80 	// https://www.w3.org/TR/html/dom.html#sectioning-content-2
   -1    81 	const scoped = ['article *', 'aside *', 'nav *', 'section *'].join(',');
   -1    82 
   -1    83 	const svgSelectors = function(selector) {
   -1    84 		return [
   -1    85 			// `${selector}:has(> title:not(:empty))`,
   -1    86 			// `${selector}:has(> desc:not(:empty))`,
   -1    87 			`${selector}[aria-label]`,
   -1    88 			`${selector}[aria-roledescription]`,
   -1    89 			`${selector}[aria-labelledby]`,
   -1    90 			`${selector}[aria-describedby]`,
   -1    91 			`${selector}[tabindex]`,
   -1    92 			`${selector}[role]`,
   -1    93 		];
   -1    94 	};
   -1    95 
   -1    96 	// https://www.w3.org/TR/html-aam-1.0/#html-element-role-mappings
   -1    97 	// https://www.w3.org/TR/wai-aria/roles
   -1    98 	const roles = {
   -1    99 		alert: {
   -1   100 			childRoles: ['alertdialog'],
   -1   101 			defaults: {
   -1   102 				'live': 'assertive',
   -1   103 				'atomic': true,
   -1   104 			},
   -1   105 		},
   -1   106 		alertdialog: {},
   -1   107 		application: {},
   -1   108 		article: {
   -1   109 			selectors: ['article'],
   -1   110 			childRoles: ['comment'],
   -1   111 		},
   -1   112 		banner: {
   -1   113 			selectors: [`header:not(main *, ${scoped})`],
   -1   114 		},
   -1   115 		blockquote: {
   -1   116 			selectors: ['blockquote'],
   -1   117 		},
   -1   118 		button: {
   -1   119 			selectors: [
   -1   120 				'button',
   -1   121 				'input[type="button"]',
   -1   122 				'input[type="image"]',
   -1   123 				'input[type="reset"]',
   -1   124 				'input[type="submit"]',
   -1   125 				'summary',
   -1   126 			],
   -1   127 			nameFromContents: true,
   -1   128 		},
   -1   129 		caption: {
   -1   130 			selectors: ['caption', 'figcaption'],
   -1   131 		},
   -1   132 		cell: {
   -1   133 			selectors: ['td', 'td ~ th:not([scope])'],
   -1   134 			childRoles: ['columnheader', 'gridcell', 'rowheader'],
   -1   135 			nameFromContents: true,
   -1   136 		},
   -1   137 		checkbox: {
   -1   138 			selectors: ['input[type="checkbox"]'],
   -1   139 			childRoles: ['switch'],
   -1   140 			nameFromContents: true,
   -1   141 			defaults: {
   -1   142 				'checked': 'false',
   -1   143 			},
   -1   144 		},
   -1   145 		code: {
   -1   146 			selectors: ['code'],
   -1   147 		},
   -1   148 		columnheader: {
   -1   149 			selectors: ['th[scope="col"]'],
   -1   150 			nameFromContents: true,
   -1   151 		},
   -1   152 		combobox: {
   -1   153 			selectors: [
   -1   154 				'input:not([type])[list]',
   -1   155 				'input[type="email"][list]',
   -1   156 				'input[type="search"][list]',
   -1   157 				'input[type="tel"][list]',
   -1   158 				'input[type="text"][list]',
   -1   159 				'input[type="url"][list]',
   -1   160 				'select:not([size]):not([multiple])',
   -1   161 				'select[size="0"]:not([multiple])',
   -1   162 				'select[size="1"]:not([multiple])',
   -1   163 			],
   -1   164 			defaults: {
   -1   165 				'expanded': false,
   -1   166 				'haspopup': 'listbox',
   -1   167 			},
   -1   168 		},
   -1   169 		command: {
   -1   170 			abstract: true,
   -1   171 			childRoles: ['button', 'link', 'menuitem'],
   -1   172 		},
   -1   173 		comment: {
   -1   174 			nameFromContents: true,
   -1   175 		},
   -1   176 		complementary: {
   -1   177 			selectors: [
   -1   178 				`aside:not(${scoped})`,
   -1   179 				'aside[aria-label]',
   -1   180 				'aside[aria-labelledby]',
   -1   181 				'aside[title]',
   -1   182 			],
   -1   183 		},
   -1   184 		composite: {
   -1   185 			abstract: true,
   -1   186 			childRoles: ['grid', 'select', 'spinbutton', 'tablist'],
   -1   187 		},
   -1   188 		contentinfo: {
   -1   189 			selectors: [`footer:not(main *, ${scoped})`],
   -1   190 		},
   -1   191 		definition: {
   -1   192 			selectors: ['dd'],
   -1   193 		},
   -1   194 		deletion: {
   -1   195 			selectors: ['del', 's'],
   -1   196 		},
   -1   197 		dialog: {
   -1   198 			selectors: ['dialog'],
   -1   199 			childRoles: ['alertdialog'],
   -1   200 		},
   -1   201 		'doc-abstract': {},
   -1   202 		'doc-acknowledgments': {},
   -1   203 		'doc-afterword': {},
   -1   204 		'doc-appendix': {},
   -1   205 		'doc-backlink': {
   -1   206 			nameFromContents: true,
   -1   207 		},
   -1   208 		'doc-biblioentry': {},
   -1   209 		'doc-bibliography': {},
   -1   210 		'doc-biblioref': {
   -1   211 			nameFromContents: true,
   -1   212 		},
   -1   213 		'doc-chapter': {},
   -1   214 		'doc-colophon': {},
   -1   215 		'doc-conclusion': {},
   -1   216 		'doc-cover': {},
   -1   217 		'doc-credit': {},
   -1   218 		'doc-credits': {},
   -1   219 		'doc-dedication': {},
   -1   220 		'doc-endnote': {},
   -1   221 		'doc-endnotes': {},
   -1   222 		'doc-epilogue': {},
   -1   223 		'doc-epigraph': {},
   -1   224 		'doc-errata': {},
   -1   225 		'doc-example': {},
   -1   226 		'doc-footnote': {},
   -1   227 		'doc-foreword': {},
   -1   228 		'doc-glossary': {},
   -1   229 		'doc-glossref': {
   -1   230 			nameFromContents: true,
   -1   231 		},
   -1   232 		'doc-index': {},
   -1   233 		'doc-introduction': {},
   -1   234 		'doc-noteref': {
   -1   235 			nameFromContents: true,
   -1   236 		},
   -1   237 		'doc-notice': {},
   -1   238 		'doc-pagebreak': {
   -1   239 			nameFromContents: true,
   -1   240 		},
   -1   241 		'doc-pagefooter': {},
   -1   242 		'doc-pageheader': {},
   -1   243 		'doc-pagelist': {},
   -1   244 		'doc-part': {},
   -1   245 		'doc-preface': {},
   -1   246 		'doc-prologue': {},
   -1   247 		'doc-pullquote': {},
   -1   248 		'doc-qna': {},
   -1   249 		'doc-subtitle': {
   -1   250 			nameFromContents: true,
   -1   251 		},
   -1   252 		'doc-tip': {},
   -1   253 		'doc-toc': {},
   -1   254 		document: {
   -1   255 			selectors: ['html'],
   -1   256 			childRoles: ['article', 'graphics-document'],
   -1   257 		},
   -1   258 		emphasis: {
   -1   259 			selectors: ['em'],
   -1   260 		},
   -1   261 		feed: {},
   -1   262 		figure: {
   -1   263 			selectors: ['figure'],
   -1   264 			childRoles: ['doc-example'],
   -1   265 		},
   -1   266 		form: {
   -1   267 			selectors: ['form[aria-label]', 'form[aria-labelledby]', 'form[title]'],
   -1   268 		},
   -1   269 		generic: {
   -1   270 			selectors: [
   -1   271 				'a:not([*|href])',
   -1   272 				'area:not([*|href])',
   -1   273 				`aside:not(${scoped}):not([aria-label]):not([aria-labelledby]):not([title])`,
   -1   274 				'b',
   -1   275 				'bdi',
   -1   276 				'bdo',
   -1   277 				'body',
   -1   278 				'data',
   -1   279 				'div',
   -1   280 				// footer scoped
   -1   281 				// header scoped
   -1   282 				'i',
   -1   283 				'li:not(ul > li):not(ol > li)',
   -1   284 				'pre',
   -1   285 				'q',
   -1   286 				'samp',
   -1   287 				'section:not([aria-label]):not([aria-labelledby]):not([title])',
   -1   288 				'small',
   -1   289 				'span',
   -1   290 				'u',
   -1   291 			],
   -1   292 		},
   -1   293 		'graphics-document': {
   -1   294 			selectors: ['svg'],
   -1   295 		},
   -1   296 		'graphics-object': {
   -1   297 			selectors: [
   -1   298 				...svgSelectors('symbol'),
   -1   299 				...svgSelectors('use'),
   -1   300 			],
   -1   301 		},
   -1   302 		'graphics-symbol': {
   -1   303 			selectors: [
   -1   304 				...svgSelectors('circle'),
   -1   305 				...svgSelectors('ellipse'),
   -1   306 				...svgSelectors('line'),
   -1   307 				...svgSelectors('path'),
   -1   308 				...svgSelectors('polygon'),
   -1   309 				...svgSelectors('polyline'),
   -1   310 				...svgSelectors('rect'),
   -1   311 			],
   -1   312 		},
   -1   313 		grid: {
   -1   314 			childRoles: ['treegrid'],
   -1   315 		},
   -1   316 		gridcell: {
   -1   317 			childRoles: ['columnheader', 'rowheader'],
   -1   318 			nameFromContents: true,
   -1   319 		},
   -1   320 		group: {
   -1   321 			selectors: [
   -1   322 				'address',
   -1   323 				'details',
   -1   324 				'fieldset',
   -1   325 				'hgroup',
   -1   326 				'optgroup',
   -1   327 				...svgSelectors('foreignObject'),
   -1   328 				...svgSelectors('g'),
   -1   329 				'text',
   -1   330 				...svgSelectors('textPath'),
   -1   331 				...svgSelectors('tspan'),
   -1   332 			],
   -1   333 			childRoles: ['row', 'select', 'toolbar', 'graphics-object'],
   -1   334 		},
   -1   335 		heading: {
   -1   336 			selectors: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
   -1   337 			nameFromContents: true,
   -1   338 			defaults: {
   -1   339 				'level': 2,
   -1   340 			},
   -1   341 		},
   -1   342 		image: {
   -1   343 			selectors: [
   -1   344 				'img:not([alt=""])',
   -1   345 				'graphics-symbol',
   -1   346 				...svgSelectors('image'),
   -1   347 				...svgSelectors('mesh'),
   -1   348 			],
   -1   349 			childRoles: ['doc-cover'],
   -1   350 		},
   -1   351 		input: {
   -1   352 			abstract: true,
   -1   353 			childRoles: [
   -1   354 				'checkbox',
   -1   355 				'combobox',
   -1   356 				'option',
   -1   357 				'radio',
   -1   358 				'slider',
   -1   359 				'spinbutton',
   -1   360 				'textbox',
   -1   361 			],
   -1   362 		},
   -1   363 		insertion: {
   -1   364 			selectors: ['ins'],
   -1   365 		},
   -1   366 		landmark: {
   -1   367 			abstract: true,
   -1   368 			childRoles: [
   -1   369 				'banner',
   -1   370 				'complementary',
   -1   371 				'contentinfo',
   -1   372 				'doc-acknowledgments',
   -1   373 				'doc-afterword',
   -1   374 				'doc-appendix',
   -1   375 				'doc-bibliography',
   -1   376 				'doc-chapter',
   -1   377 				'doc-conclusion',
   -1   378 				'doc-credits',
   -1   379 				'doc-endnotes',
   -1   380 				'doc-epilogue',
   -1   381 				'doc-errata',
   -1   382 				'doc-foreword',
   -1   383 				'doc-glossary',
   -1   384 				'doc-introduction',
   -1   385 				'doc-part',
   -1   386 				'doc-preface',
   -1   387 				'doc-prologue',
   -1   388 				'form',
   -1   389 				'main',
   -1   390 				'navigation',
   -1   391 				'region',
   -1   392 				'search',
   -1   393 			],
   -1   394 		},
   -1   395 		link: {
   -1   396 			selectors: ['a[*|href]', 'area[*|href]'],
   -1   397 			childRoles: ['doc-backlink', 'doc-biblioref', 'doc-glossref', 'doc-noteref'],
   -1   398 			nameFromContents: true,
   -1   399 		},
   -1   400 		list: {
   -1   401 			selectors: ['dl', 'ol', 'ul', 'menu'],
   -1   402 			childRoles: ['feed'],
   -1   403 		},
   -1   404 		listbox: {
   -1   405 			selectors: [
   -1   406 				'datalist',
   -1   407 				'select[multiple]',
   -1   408 				'select[size]:not([size="0"]):not([size="1"])',
   -1   409 			],
   -1   410 			defaults: {
   -1   411 				'orientation': 'vertical',
   -1   412 			},
   -1   413 		},
   -1   414 		listitem: {
   -1   415 			selectors: ['ol > li', 'ul > li'],
   -1   416 			childRoles: ['doc-biblioentry', 'doc-endnote', 'treeitem'],
   -1   417 		},
   -1   418 		log: {
   -1   419 			defaults: {
   -1   420 				'live': 'polite',
   -1   421 			},
   -1   422 		},
   -1   423 		main: {
   -1   424 			selectors: ['main'],
   -1   425 		},
   -1   426 		mark: {
   -1   427 			selectors: ['mark'],
   -1   428 		},
   -1   429 		marquee: {},
   -1   430 		math: {
   -1   431 			selectors: ['math'],
   -1   432 		},
   -1   433 		meter: {
   -1   434 			selectors: ['meter'],
   -1   435 			defaults: {
   -1   436 				'valuemin': 0,
   -1   437 				'valuemax': 100,
   -1   438 			},
   -1   439 		},
   -1   440 		menu: {
   -1   441 			childRoles: ['menubar'],
   -1   442 			defaults: {
   -1   443 				'orientation': 'vertical',
   -1   444 			},
   -1   445 		},
   -1   446 		menubar: {
   -1   447 			defaults: {
   -1   448 				'orientation': 'horizontal',
   -1   449 			},
   -1   450 		},
   -1   451 		menuitem: {
   -1   452 			childRoles: ['menuitemcheckbox', 'menuitemradio'],
   -1   453 			nameFromContents: true,
   -1   454 		},
   -1   455 		menuitemcheckbox: {
   -1   456 			nameFromContents: true,
   -1   457 			defaults: {
   -1   458 				'checked': 'false',
   -1   459 			},
   -1   460 		},
   -1   461 		menuitemradio: {
   -1   462 			nameFromContents: true,
   -1   463 			defaults: {
   -1   464 				'checked': 'false',
   -1   465 			},
   -1   466 		},
   -1   467 		navigation: {
   -1   468 			selectors: ['nav'],
   -1   469 			childRoles: ['doc-index', 'doc-pagelist', 'doc-toc'],
   -1   470 		},
   -1   471 		none: {
   -1   472 			selectors: ['img[alt=""]'],
   -1   473 		},
   -1   474 		note: {
   -1   475 			childRoles: ['doc-notice', 'doc-tip'],
   -1   476 		},
   -1   477 		option: {
   -1   478 			selectors: ['option'],
   -1   479 			childRoles: ['treeitem'],
   -1   480 			nameFromContents: true,
   -1   481 			defaults: {
   -1   482 				'selected': 'false',
   -1   483 			},
   -1   484 		},
   -1   485 		paragraph: {
   -1   486 			selectors: ['p'],
   -1   487 		},
   -1   488 		progressbar: {
   -1   489 			selectors: ['progress'],
   -1   490 			defaults: {
   -1   491 				'valuemin': 0,
   -1   492 				'valuemax': 100,
   -1   493 			},
   -1   494 		},
   -1   495 		radio: {
   -1   496 			selectors: ['input[type="radio"]'],
   -1   497 			childRoles: ['menuitemradio'],
   -1   498 			nameFromContents: true,
   -1   499 			defaults: {
   -1   500 				'checked': 'false',
   -1   501 			},
   -1   502 		},
   -1   503 		radiogroup: {},
   -1   504 		range: {
   -1   505 			abstract: true,
   -1   506 			childRoles: ['meter', 'progressbar', 'scrollbar', 'slider', 'spinbutton'],
   -1   507 		},
   -1   508 		region: {
   -1   509 			selectors: ['section[aria-label]', 'section[aria-labelledby]', 'section[title]'],
   -1   510 		},
   -1   511 		roletype: {
   -1   512 			abstract: true,
   -1   513 			childRoles: ['structure', 'widget', 'window'],
   -1   514 		},
   -1   515 		row: {
   -1   516 			selectors: ['tr'],
   -1   517 			nameFromContents: true,
   -1   518 		},
   -1   519 		rowgroup: {
   -1   520 			selectors: ['tbody', 'thead', 'tfoot'],
   -1   521 		},
   -1   522 		rowheader: {
   -1   523 			selectors: ['th[scope="row"]', 'th:not([scope]):not(td ~ th)'],
   -1   524 			nameFromContents: true,
   -1   525 		},
   -1   526 		scrollbar: {
   -1   527 			defaults: {
   -1   528 				'orientation': 'vertical',
   -1   529 				'valuemin': 0,
   -1   530 				'valuemax': 100,
   -1   531 			},
   -1   532 		},
   -1   533 		search: {
   -1   534 			selectors: ['search'],
   -1   535 		},
   -1   536 		searchbox: {
   -1   537 			selectors: ['input[type="search"]:not([list])'],
   -1   538 		},
   -1   539 		section: {
   -1   540 			abstract: true,
   -1   541 			childRoles: [
   -1   542 				'alert',
   -1   543 				'blockquote',
   -1   544 				'caption',
   -1   545 				'cell',
   -1   546 				'code',
   -1   547 				'definition',
   -1   548 				'deletion',
   -1   549 				'doc-abstract',
   -1   550 				'doc-colophon',
   -1   551 				'doc-credit',
   -1   552 				'doc-dedication',
   -1   553 				'doc-epigraph',
   -1   554 				'doc-footnote',
   -1   555 				'doc-pagefooter',
   -1   556 				'doc-pageheader',
   -1   557 				'doc-pullquote',
   -1   558 				'doc-qna',
   -1   559 				'emphasis',
   -1   560 				'figure',
   -1   561 				'group',
   -1   562 				'image',
   -1   563 				'insertion',
   -1   564 				'landmark',
   -1   565 				'list',
   -1   566 				'listitem',
   -1   567 				'log',
   -1   568 				'mark',
   -1   569 				'marquee',
   -1   570 				'math',
   -1   571 				'note',
   -1   572 				'paragraph',
   -1   573 				'status',
   -1   574 				'strong',
   -1   575 				'subscript',
   -1   576 				'suggestion',
   -1   577 				'superscript',
   -1   578 				'table',
   -1   579 				'tabpanel',
   -1   580 				'term',
   -1   581 				'time',
   -1   582 				'tooltip',
   -1   583 			],
   -1   584 		},
   -1   585 		sectionhead: {
   -1   586 			abstract: true,
   -1   587 			childRoles: [
   -1   588 				'columnheader',
   -1   589 				'doc-subtitle',
   -1   590 				'heading',
   -1   591 				'rowheader',
   -1   592 				'tab',
   -1   593 			],
   -1   594 			nameFromContents: true,
   -1   595 		},
   -1   596 		select: {
   -1   597 			abstract: true,
   -1   598 			childRoles: ['listbox', 'menu', 'radiogroup', 'tree'],
   -1   599 		},
   -1   600 		separator: {
   -1   601 			// assume not focussable because <hr> is not
   -1   602 			selectors: ['hr'],
   -1   603 			childRoles: ['doc-pagebreak'],
   -1   604 			defaults: {
   -1   605 				'orientation': 'horizontal',
   -1   606 				'valuemin': 0,
   -1   607 				'valuemax': 100,
   -1   608 			},
   -1   609 		},
   -1   610 		slider: {
   -1   611 			selectors: ['input[type="range"]'],
   -1   612 			defaults: {
   -1   613 				'orientation': 'horizontal',
   -1   614 				'valuemin': 0,
   -1   615 				'valuemax': 100,
   -1   616 				// FIXME: halfway between actual valuemin and valuemax
   -1   617 				'valuenow': 50,
   -1   618 			},
   -1   619 		},
   -1   620 		spinbutton: {
   -1   621 			selectors: ['input[type="number"]'],
   -1   622 			defaults: {
   -1   623 				// FIXME: no valuemin/valuemax/valuenow
   -1   624 			},
   -1   625 		},
   -1   626 		status: {
   -1   627 			selectors: ['output'],
   -1   628 			childRoles: ['timer'],
   -1   629 			defaults: {
   -1   630 				'live': 'polite',
   -1   631 				'atomic': true,
   -1   632 			},
   -1   633 		},
   -1   634 		strong: {
   -1   635 			selectors: ['strong'],
   -1   636 		},
   -1   637 		structure: {
   -1   638 			abstract: true,
   -1   639 			childRoles: [
   -1   640 				'application',
   -1   641 				'document',
   -1   642 				'none',
   -1   643 				'generic',
   -1   644 				'range',
   -1   645 				'rowgroup',
   -1   646 				'section',
   -1   647 				'sectionhead',
   -1   648 				'separator',
   -1   649 			],
   -1   650 		},
   -1   651 		suggestion: {},
   -1   652 		subscript: {
   -1   653 			selectors: ['sub'],
   -1   654 		},
   -1   655 		superscript: {
   -1   656 			selectors: ['sup'],
   -1   657 		},
   -1   658 		switch: {
   -1   659 			nameFromContents: true,
   -1   660 			defaults: {
   -1   661 				'checked': false,
   -1   662 			},
   -1   663 		},
   -1   664 		tab: {
   -1   665 			nameFromContents: true,
   -1   666 			defaults: {
   -1   667 				'selected': false,
   -1   668 			},
   -1   669 		},
   -1   670 		table: {
   -1   671 			selectors: ['table'],
   -1   672 			childRoles: ['grid'],
   -1   673 		},
   -1   674 		tablist: {
   -1   675 			defaults: {
   -1   676 				'orientation': 'horizontal',
   -1   677 			},
   -1   678 		},
   -1   679 		tabpanel: {},
   -1   680 		term: {
   -1   681 			selectors: ['dfn', 'dt'],
   -1   682 		},
   -1   683 		textbox: {
   -1   684 			selectors: [
   -1   685 				'input:not([type]):not([list])',
   -1   686 				'input[type="email"]:not([list])',
   -1   687 				'input[type="tel"]:not([list])',
   -1   688 				'input[type="text"]:not([list])',
   -1   689 				'input[type="url"]:not([list])',
   -1   690 				'textarea',
   -1   691 			],
   -1   692 			childRoles: ['searchbox'],
   -1   693 		},
   -1   694 		time: {
   -1   695 			selectors: ['time'],
   -1   696 		},
   -1   697 		timer: {
   -1   698 			defaults: {
   -1   699 				'live': 'off',
   -1   700 			},
   -1   701 		},
   -1   702 		toolbar: {
   -1   703 			defaults: {
   -1   704 				'orientation': 'horizontal',
   -1   705 			},
   -1   706 		},
   -1   707 		tooltip: {
   -1   708 			nameFromContents: true,
   -1   709 		},
   -1   710 		tree: {
   -1   711 			childRoles: ['treegrid'],
   -1   712 			defaults: {
   -1   713 				'orientation': 'vertical',
   -1   714 			},
   -1   715 		},
   -1   716 		treegrid: {},
   -1   717 		treeitem: {
   -1   718 			nameFromContents: true,
   -1   719 		},
   -1   720 		widget: {
   -1   721 			abstract: true,
   -1   722 			childRoles: [
   -1   723 				'command',
   -1   724 				'composite',
   -1   725 				'gridcell',
   -1   726 				'input',
   -1   727 				'progressbar',
   -1   728 				'row',
   -1   729 				'scrollbar',
   -1   730 				'separator',
   -1   731 				'tab',
   -1   732 			],
   -1   733 		},
   -1   734 		window: {
   -1   735 			abstract: true,
   -1   736 			childRoles: ['dialog'],
   -1   737 		},
   -1   738 	};
   59   739 
   60    -1 const getParentNode = function(node, owners) {
   61    -1 	return getOwner(node, owners) || node.parentNode;
   62    -1 };
   -1   740 	const getSubRoles = function(role) {
   -1   741 		const children = (roles[role]).childRoles || [];
   -1   742 		const descendents = children.map(getSubRoles);
   63   743 
   64    -1 const isHidden = function(node) {
   65    -1 	return node.nodeType === node.ELEMENT_NODE && attrs.getAttribute(node, 'hidden');
   66    -1 };
   -1   744 		const result = [role];
   67   745 
   68    -1 const getChildNodes = function(node, owners) {
   69    -1 	const childNodes = [];
   -1   746 		descendents.forEach(list => {
   -1   747 			list.forEach(r => {
   -1   748 				if (!result.includes(r)) {
   -1   749 					result.push(r);
   -1   750 				}
   -1   751 			});
   -1   752 		});
   70   753 
   71    -1 	for (let i = 0; i < node.childNodes.length; i++) {
   72    -1 		const child = node.childNodes[i];
   73    -1 		if (!getOwner(child, owners) && !isHidden(child)) {
   74    -1 			childNodes.push(child);
   75    -1 		}
   76    -1 	}
   -1   754 		return result;
   -1   755 	};
   77   756 
   78    -1 	if (node.nodeType === node.ELEMENT_NODE) {
   79    -1 		const owns = attrs.getAttribute(node, 'owns') || [];
   80    -1 		for (let i = 0; i < owns.length; i++) {
   81    -1 			const child = document.getElementById(owns[i]);
   82    -1 			// double check with getOwner for consistency
   83    -1 			if (child && getOwner(child, owners) === node && !isHidden(child)) {
   84    -1 				childNodes.push(child);
   -1   757 	const attrsWithDefaults = [];
   -1   758 
   -1   759 	for (const role in roles) {
   -1   760 		roles[role].subRoles = getSubRoles(role);
   -1   761 		for (const key in roles[role].defaults) {
   -1   762 			if (!attrsWithDefaults.includes(key)) {
   -1   763 				attrsWithDefaults.push(key);
   85   764 			}
   86   765 		}
   87   766 	}
   88   767 
   89    -1 	return childNodes;
   90    -1 };
   -1   768 	const aliases = {
   -1   769 		'presentation': 'none',
   -1   770 		'directory': 'list',
   -1   771 		'img': 'image',
   -1   772 	};
   -1   773 
   -1   774 	const nameFromDescendant = {
   -1   775 		'figure': 'figcaption',
   -1   776 		'table': 'caption',
   -1   777 		'fieldset': 'legend',
   -1   778 	};
   91   779 
   92    -1 const walk = function(root, fn) {
   93    -1 	const owners = document.querySelectorAll('[aria-owns]');
   94    -1 	let queue = [root];
   95    -1 	while (queue.length) {
   96    -1 		const item = queue.shift();
   97    -1 		fn(item);
   98    -1 		queue = getChildNodes(item, owners).concat(queue);
   99    -1 	}
  100    -1 };
   -1   780 	const nameDefaults = {
   -1   781 		'input[type="submit"]': 'Submit',
   -1   782 		'input[type="reset"]': 'Reset',
   -1   783 		'summary': 'Details',
   -1   784 	};
  101   785 
  102    -1 const searchUp = function(node, test) {
  103    -1 	const candidate = getParentNode(node);
  104    -1 	if (candidate) {
  105    -1 		if (test(candidate)) {
  106    -1 			return candidate;
   -1   786 	var unique = function(arr) {
   -1   787 		return arr.filter((a, i) => arr.indexOf(a) === i);
   -1   788 	};
   -1   789 
   -1   790 	var flatten = function(arr) {
   -1   791 		return [].concat.apply([], arr);
   -1   792 	};
   -1   793 
   -1   794 	var normalizeRoles = function(roles$1, includeAbstract) {
   -1   795 		return unique(roles$1
   -1   796 			.map(r => aliases[r] || r)
   -1   797 			.filter(r => roles[r])
   -1   798 			.filter(r => includeAbstract || !roles[r].abstract)
   -1   799 		);
   -1   800 	};
   -1   801 
   -1   802 	// candidates can be passed for performance optimization
   -1   803 	const getRoleRaw = function(el, candidates) {
   -1   804 		// TODO: filter out any invalid roles (e.g. name or context required)
   -1   805 		const roles$1 = normalizeRoles(
   -1   806 			(el.getAttribute('role') || '').toLowerCase().split(/\s+/)
   -1   807 		);
   -1   808 
   -1   809 		if (roles$1.length > 1 && candidates) {
   -1   810 			return [roles$1, candidates];
   -1   811 		} else if (roles$1.length) {
   -1   812 			for (const role of roles$1) {
   -1   813 				if (!candidates || candidates.includes(role)) {
   -1   814 					return role;
   -1   815 				}
   -1   816 			}
  107   817 		} else {
  108    -1 			return searchUp(candidate, test);
   -1   818 			for (const role of (candidates || Object.keys(roles))) {
   -1   819 				const r = roles[role];
   -1   820 				if (!r.abstract && r.selectors && el.matches(r.selectors.join(','))) {
   -1   821 					return role;
   -1   822 				}
   -1   823 			}
  109   824 		}
  110    -1 	}
  111    -1 };
  112    -1 
  113    -1 module.exports = {
  114    -1 	'getParentNode': getParentNode,
  115    -1 	'getChildNodes': getChildNodes,
  116    -1 	'walk': walk,
  117    -1 	'searchUp': searchUp,
  118    -1 };
  119    -1 
  120    -1 },{"./attrs":3}],3:[function(require,module,exports){
  121    -1 const constants = require('./constants.js');
  122    -1 
  123    -1 var unique = function(arr) {
  124    -1 	return arr.filter((a, i) => arr.indexOf(a) === i);
  125    -1 };
  126    -1 
  127    -1 var flatten = function(arr) {
  128    -1 	return [].concat.apply([], arr);
  129    -1 };
  130    -1 
  131    -1 var normalizeRoles = function(roles, includeAbstract) {
  132    -1 	return unique(roles
  133    -1 		.map(r => constants.aliases[r] || r)
  134    -1 		.filter(r => constants.roles[r])
  135    -1 		.filter(r => includeAbstract || !constants.roles[r].abstract)
  136    -1 	);
  137    -1 };
  138    -1 
  139    -1 // candidates can be passed for performance optimization
  140    -1 const getRole = function(el, candidates) {
  141    -1 	// TODO: filter out any invalid roles (e.g. name or context required)
  142    -1 	const roles = normalizeRoles(
  143    -1 		(el.getAttribute('role') || '').toLowerCase().split(/\s+/)
  144    -1 	);
  145    -1 
  146    -1 	if (roles.length > 1 && candidates) {
  147    -1 		return [roles, candidates];
  148    -1 	} else if (roles.length) {
  149    -1 		for (const role of roles) {
  150    -1 			if (!candidates || candidates.includes(role)) {
  151    -1 				return role;
   -1   825 	};
   -1   826 
   -1   827 	const getRole = function(el) {
   -1   828 		return getRoleRaw(el);
   -1   829 	};
   -1   830 
   -1   831 	const hasRole = function(el, roles$1) {
   -1   832 		const subRoles = normalizeRoles(roles$1, true).map(role => {
   -1   833 			return roles[role].subRoles || [role];
   -1   834 		});
   -1   835 		return !!getRoleRaw(el, unique(flatten(subRoles)));
   -1   836 	};
   -1   837 
   -1   838 	const getAttribute = function(el, key) {
   -1   839 		if (attributeStrongMapping.hasOwnProperty(key)) {
   -1   840 			const value = el[attributeStrongMapping[key]];
   -1   841 			if (value) {
   -1   842 				return value;
  152   843 			}
  153   844 		}
  154    -1 	} else {
  155    -1 		for (const role of (candidates || Object.keys(constants.roles))) {
  156    -1 			const r = constants.roles[role];
  157    -1 			if (!r.abstract && r.selectors && el.matches(r.selectors.join(','))) {
  158    -1 				return role;
   -1   845 		if (key === 'readonly' && el.contentEditable) {
   -1   846 			return false;
   -1   847 		} else if (key === 'invalid' && el.checkValidity) {
   -1   848 			return !el.checkValidity();
   -1   849 		} else if (key === 'hidden') {
   -1   850 			// workaround for chromium
   -1   851 			if (el.matches('noscript')) {
   -1   852 				return true;
   -1   853 			}
   -1   854 			if (el.matches('details:not([open]) > :not(summary)')) {
   -1   855 				return true;
   -1   856 			}
   -1   857 			const style = window.getComputedStyle(el);
   -1   858 			if (style.display === 'none' || style.visibility === 'hidden' || style.visibility === 'collapse') {
   -1   859 				return true;
  159   860 			}
  160   861 		}
  161    -1 	}
  162    -1 };
  163    -1 
  164    -1 const hasRole = function(el, roles) {
  165    -1 	const subRoles = normalizeRoles(roles, true).map(role => {
  166    -1 		return constants.roles[role].subRoles || [role];
  167    -1 	});
  168    -1 	return !!getRole(el, unique(flatten(subRoles)));
  169    -1 };
  170    -1 
  171    -1 const getAttribute = function(el, key) {
  172    -1 	if (constants.attributeStrongMapping.hasOwnProperty(key)) {
  173    -1 		const value = el[constants.attributeStrongMapping[key]];
  174    -1 		if (value) {
  175    -1 			return value;
   -1   862 
   -1   863 		const type = attributes[key];
   -1   864 		const raw = el.getAttribute('aria-' + key);
   -1   865 
   -1   866 		if (raw) {
   -1   867 			if (type === 'bool') {
   -1   868 				return raw === 'true';
   -1   869 			} else if (type === 'tristate') {
   -1   870 				return raw === 'true' ? true : raw === 'false' ? false : 'mixed';
   -1   871 			} else if (type === 'bool-undefined') {
   -1   872 				return raw === 'true' ? true : raw === 'false' ? false : undefined;
   -1   873 			} else if (type === 'id-list') {
   -1   874 				return raw.split(/\s+/);
   -1   875 			} else if (type === 'integer') {
   -1   876 				return parseInt(raw, 10);
   -1   877 			} else if (type === 'number') {
   -1   878 				return parseFloat(raw);
   -1   879 			} else if (type === 'token-list') {
   -1   880 				return raw.split(/\s+/);
   -1   881 			} else {
   -1   882 				return raw;
   -1   883 			}
  176   884 		}
  177    -1 	}
  178    -1 	if (key === 'readonly' && el.contentEditable) {
  179    -1 		return false;
  180    -1 	} else if (key === 'invalid' && el.checkValidity) {
  181    -1 		return !el.checkValidity();
  182    -1 	} else if (key === 'hidden') {
  183    -1 		// workaround for chromium
  184    -1 		if (el.matches('noscript')) {
  185    -1 			return true;
   -1   885 
   -1   886 		// TODO
   -1   887 		// autocomplete
   -1   888 		// contextmenu -> aria-haspopup
   -1   889 		// indeterminate -> aria-checked="mixed"
   -1   890 		// list -> aria-controls
   -1   891 
   -1   892 		if (key === 'level') {
   -1   893 			for (let i = 1; i <= 6; i++) {
   -1   894 				if (el.tagName.toLowerCase() === 'h' + i) {
   -1   895 					return i;
   -1   896 				}
   -1   897 			}
   -1   898 		} else if (attributeWeakMapping.hasOwnProperty(key)) {
   -1   899 			return el[attributeWeakMapping[key]];
  186   900 		}
  187    -1 		if (el.matches('details:not([open]) > :not(summary)')) {
  188    -1 			return true;
   -1   901 
   -1   902 		if (key in attrsWithDefaults) {
   -1   903 			const role = getRole(el);
   -1   904 			const defaults = roles[role].defaults;
   -1   905 			if (defaults && defaults.hasOwnProperty(key)) {
   -1   906 				return defaults[key];
   -1   907 			}
  189   908 		}
  190    -1 		const style = window.getComputedStyle(el);
  191    -1 		if (style.display === 'none' || style.visibility === 'hidden' || style.visibility === 'collapse') {
  192    -1 			return true;
   -1   909 
   -1   910 		if (type === 'bool' || type === 'tristate') {
   -1   911 			return false;
  193   912 		}
  194    -1 	}
   -1   913 	};
  195   914 
  196    -1 	const type = constants.attributes[key];
  197    -1 	const raw = el.getAttribute('aria-' + key);
  198    -1 
  199    -1 	if (raw) {
  200    -1 		if (type === 'bool') {
  201    -1 			return raw === 'true';
  202    -1 		} else if (type === 'tristate') {
  203    -1 			return raw === 'true' ? true : raw === 'false' ? false : 'mixed';
  204    -1 		} else if (type === 'bool-undefined') {
  205    -1 			return raw === 'true' ? true : raw === 'false' ? false : undefined;
  206    -1 		} else if (type === 'id-list') {
  207    -1 			return raw.split(/\s+/);
  208    -1 		} else if (type === 'integer') {
  209    -1 			return parseInt(raw, 10);
  210    -1 		} else if (type === 'number') {
  211    -1 			return parseFloat(raw);
  212    -1 		} else if (type === 'token-list') {
  213    -1 			return raw.split(/\s+/);
  214    -1 		} else {
  215    -1 			return raw;
   -1   915 	const _getOwner = function(node, owners) {
   -1   916 		if (node.nodeType === node.ELEMENT_NODE && node.id) {
   -1   917 			const selector = '[aria-owns~="' + CSS.escape(node.id) + '"]';
   -1   918 			if (owners) {
   -1   919 				for (const owner of owners) {
   -1   920 					if (owner.matches(selector)) {
   -1   921 						return owner;
   -1   922 					}
   -1   923 				}
   -1   924 			} else {
   -1   925 				return document.querySelector(selector);
   -1   926 			}
  216   927 		}
  217    -1 	}
   -1   928 	};
  218   929 
  219    -1 	// TODO
  220    -1 	// autocomplete
  221    -1 	// contextmenu -> aria-haspopup
  222    -1 	// indeterminate -> aria-checked="mixed"
  223    -1 	// list -> aria-controls
   -1   930 	const _getParentNode = function(node, owners) {
   -1   931 		return _getOwner(node, owners) || node.parentNode;
   -1   932 	};
  224   933 
  225    -1 	if (key === 'level') {
  226    -1 		for (let i = 1; i <= 6; i++) {
  227    -1 			if (el.tagName.toLowerCase() === 'h' + i) {
  228    -1 				return i;
   -1   934 	const detectLoop = function(node, owners) {
   -1   935 		const seen = [node];
   -1   936 		while ((node = _getParentNode(node, owners))) {
   -1   937 			if (seen.includes(node)) {
   -1   938 				return true;
  229   939 			}
   -1   940 			seen.push(node);
  230   941 		}
  231    -1 	} else if (constants.attributeWeakMapping.hasOwnProperty(key)) {
  232    -1 		return el[constants.attributeWeakMapping[key]];
  233    -1 	}
   -1   942 	};
  234   943 
  235    -1 	if (key in constants.attrsWithDefaults) {
  236    -1 		const role = getRole(el);
  237    -1 		const defaults = constants.roles[role].defaults;
  238    -1 		if (defaults && defaults.hasOwnProperty(key)) {
  239    -1 			return defaults[key];
   -1   944 	const getOwner = function(node, owners) {
   -1   945 		const owner = _getOwner(node, owners);
   -1   946 		if (owner && !detectLoop(node, owners)) {
   -1   947 			return owner;
  240   948 		}
  241    -1 	}
   -1   949 	};
  242   950 
  243    -1 	if (type === 'bool' || type === 'tristate') {
  244    -1 		return false;
  245    -1 	}
  246    -1 };
  247    -1 
  248    -1 module.exports = {
  249    -1 	getRole: getRole,
  250    -1 	hasRole: hasRole,
  251    -1 	getAttribute: getAttribute,
  252    -1 };
  253    -1 
  254    -1 },{"./constants.js":4}],4:[function(require,module,exports){
  255    -1 // https://www.w3.org/TR/wai-aria/#state_prop_def
  256    -1 exports.attributes = {
  257    -1 	'activedescendant': 'id',
  258    -1 	'atomic': 'bool',
  259    -1 	'autocomplete': 'token',
  260    -1 	'braillelabel': 'string',
  261    -1 	'brailleroledescription': 'string',
  262    -1 	'busy': 'bool',
  263    -1 	'checked': 'tristate',
  264    -1 	'colcount': 'int',
  265    -1 	'colindex': 'int',
  266    -1 	'colindextext': 'string',
  267    -1 	'colspan': 'int',
  268    -1 	'controls': 'id-list',
  269    -1 	'current': 'token',
  270    -1 	'describedby': 'id-list',
  271    -1 	'description': 'string',
  272    -1 	'details': 'id',
  273    -1 	'disabled': 'bool',
  274    -1 	'dropeffect': 'token-list',
  275    -1 	'errormessage': 'id',
  276    -1 	'expanded': 'bool-undefined',
  277    -1 	'flowto': 'id-list',
  278    -1 	'grabbed': 'bool-undefined',
  279    -1 	'haspopup': 'token',
  280    -1 	'hidden': 'bool-undefined',
  281    -1 	'invalid': 'token',
  282    -1 	'keyshortcuts': 'string',
  283    -1 	'label': 'string',
  284    -1 	'labelledby': 'id-list',
  285    -1 	'level': 'int',
  286    -1 	'live': 'token',
  287    -1 	'modal': 'bool',
  288    -1 	'multiline': 'bool',
  289    -1 	'multiselectable': 'bool',
  290    -1 	'orientation': 'token',
  291    -1 	'owns': 'id-list',
  292    -1 	'placeholder': 'string',
  293    -1 	'posinset': 'int',
  294    -1 	'pressed': 'tristate',
  295    -1 	'readonly': 'bool',
  296    -1 	'relevant': 'token-list',
  297    -1 	'required': 'bool',
  298    -1 	'roledescription': 'string',
  299    -1 	'rowcount': 'int',
  300    -1 	'rowindex': 'int',
  301    -1 	'rowindextext': 'string',
  302    -1 	'rowspan': 'int',
  303    -1 	'selected': 'bool-undefined',
  304    -1 	'setsize': 'int',
  305    -1 	'sort': 'token',
  306    -1 	'valuemax': 'number',
  307    -1 	'valuemin': 'number',
  308    -1 	'valuenow': 'number',
  309    -1 	'valuetext': 'string',
  310    -1 };
  311    -1 
  312    -1 exports.attributeStrongMapping = {
  313    -1 	'disabled': 'disabled',
  314    -1 	'placeholder': 'placeholder',
  315    -1 	'readonly': 'readOnly',
  316    -1 	'required': 'required',
  317    -1 };
  318    -1 
  319    -1 exports.attributeWeakMapping = {
  320    -1 	'checked': 'checked',
  321    -1 	'colspan': 'colSpan',
  322    -1 	'expanded': 'open',
  323    -1 	'multiselectable': 'multiple',
  324    -1 	'rowspan': 'rowSpan',
  325    -1 	'selected': 'selected',
  326    -1 };
  327    -1 
  328    -1 // https://www.w3.org/TR/html/dom.html#sectioning-content-2
  329    -1 const scoped = ['article *', 'aside *', 'nav *', 'section *'].join(',');
  330    -1 
  331    -1 const svgSelectors = function(selector) {
  332    -1 	return [
  333    -1 		// `${selector}:has(> title:not(:empty))`,
  334    -1 		// `${selector}:has(> desc:not(:empty))`,
  335    -1 		`${selector}[aria-label]`,
  336    -1 		`${selector}[aria-roledescription]`,
  337    -1 		`${selector}[aria-labelledby]`,
  338    -1 		`${selector}[aria-describedby]`,
  339    -1 		`${selector}[tabindex]`,
  340    -1 		`${selector}[role]`,
  341    -1 	];
  342    -1 };
  343    -1 
  344    -1 // https://www.w3.org/TR/html-aam-1.0/#html-element-role-mappings
  345    -1 // https://www.w3.org/TR/wai-aria/roles
  346    -1 exports.roles = {
  347    -1 	alert: {
  348    -1 		childRoles: ['alertdialog'],
  349    -1 		defaults: {
  350    -1 			'live': 'assertive',
  351    -1 			'atomic': true,
  352    -1 		},
  353    -1 	},
  354    -1 	alertdialog: {},
  355    -1 	application: {},
  356    -1 	article: {
  357    -1 		selectors: ['article'],
  358    -1 		childRoles: ['comment'],
  359    -1 	},
  360    -1 	banner: {
  361    -1 		selectors: [`header:not(main *, ${scoped})`],
  362    -1 	},
  363    -1 	blockquote: {
  364    -1 		selectors: ['blockquote'],
  365    -1 	},
  366    -1 	button: {
  367    -1 		selectors: [
  368    -1 			'button',
  369    -1 			'input[type="button"]',
  370    -1 			'input[type="image"]',
  371    -1 			'input[type="reset"]',
  372    -1 			'input[type="submit"]',
  373    -1 			'summary',
  374    -1 		],
  375    -1 		nameFromContents: true,
  376    -1 	},
  377    -1 	caption: {
  378    -1 		selectors: ['caption', 'figcaption'],
  379    -1 	},
  380    -1 	cell: {
  381    -1 		selectors: ['td', 'td ~ th:not([scope])'],
  382    -1 		childRoles: ['columnheader', 'gridcell', 'rowheader'],
  383    -1 		nameFromContents: true,
  384    -1 	},
  385    -1 	checkbox: {
  386    -1 		selectors: ['input[type="checkbox"]'],
  387    -1 		childRoles: ['switch'],
  388    -1 		nameFromContents: true,
  389    -1 		defaults: {
  390    -1 			'checked': 'false',
  391    -1 		},
  392    -1 	},
  393    -1 	code: {
  394    -1 		selectors: ['code'],
  395    -1 	},
  396    -1 	columnheader: {
  397    -1 		selectors: ['th[scope="col"]'],
  398    -1 		nameFromContents: true,
  399    -1 	},
  400    -1 	combobox: {
  401    -1 		selectors: [
  402    -1 			'input:not([type])[list]',
  403    -1 			'input[type="email"][list]',
  404    -1 			'input[type="search"][list]',
  405    -1 			'input[type="tel"][list]',
  406    -1 			'input[type="text"][list]',
  407    -1 			'input[type="url"][list]',
  408    -1 			'select:not([size]):not([multiple])',
  409    -1 			'select[size="0"]:not([multiple])',
  410    -1 			'select[size="1"]:not([multiple])',
  411    -1 		],
  412    -1 		defaults: {
  413    -1 			'expanded': false,
  414    -1 			'haspopup': 'listbox',
  415    -1 		},
  416    -1 	},
  417    -1 	command: {
  418    -1 		abstract: true,
  419    -1 		childRoles: ['button', 'link', 'menuitem'],
  420    -1 	},
  421    -1 	comment: {
  422    -1 		nameFromContents: true,
  423    -1 	},
  424    -1 	complementary: {
  425    -1 		selectors: [
  426    -1 			`aside:not(${scoped})`,
  427    -1 			'aside[aria-label]',
  428    -1 			'aside[aria-labelledby]',
  429    -1 			'aside[title]',
  430    -1 		],
  431    -1 	},
  432    -1 	composite: {
  433    -1 		abstract: true,
  434    -1 		childRoles: ['grid', 'select', 'spinbutton', 'tablist'],
  435    -1 	},
  436    -1 	contentinfo: {
  437    -1 		selectors: [`footer:not(main *, ${scoped})`],
  438    -1 	},
  439    -1 	definition: {
  440    -1 		selectors: ['dd'],
  441    -1 	},
  442    -1 	deletion: {
  443    -1 		selectors: ['del', 's'],
  444    -1 	},
  445    -1 	dialog: {
  446    -1 		selectors: ['dialog'],
  447    -1 		childRoles: ['alertdialog'],
  448    -1 	},
  449    -1 	'doc-abstract': {},
  450    -1 	'doc-acknowledgments': {},
  451    -1 	'doc-afterword': {},
  452    -1 	'doc-appendix': {},
  453    -1 	'doc-backlink': {
  454    -1 		nameFromContents: true,
  455    -1 	},
  456    -1 	'doc-biblioentry': {},
  457    -1 	'doc-bibliography': {},
  458    -1 	'doc-biblioref': {
  459    -1 		nameFromContents: true,
  460    -1 	},
  461    -1 	'doc-chapter': {},
  462    -1 	'doc-colophon': {},
  463    -1 	'doc-conclusion': {},
  464    -1 	'doc-cover': {},
  465    -1 	'doc-credit': {},
  466    -1 	'doc-credits': {},
  467    -1 	'doc-dedication': {},
  468    -1 	'doc-endnote': {},
  469    -1 	'doc-endnotes': {},
  470    -1 	'doc-epilogue': {},
  471    -1 	'doc-epigraph': {},
  472    -1 	'doc-errata': {},
  473    -1 	'doc-example': {},
  474    -1 	'doc-footnote': {},
  475    -1 	'doc-foreword': {},
  476    -1 	'doc-glossary': {},
  477    -1 	'doc-glossref': {
  478    -1 		nameFromContents: true,
  479    -1 	},
  480    -1 	'doc-index': {},
  481    -1 	'doc-introduction': {},
  482    -1 	'doc-noteref': {
  483    -1 		nameFromContents: true,
  484    -1 	},
  485    -1 	'doc-notice': {},
  486    -1 	'doc-pagebreak': {
  487    -1 		nameFromContents: true,
  488    -1 	},
  489    -1 	'doc-pagefooter': {},
  490    -1 	'doc-pageheader': {},
  491    -1 	'doc-pagelist': {},
  492    -1 	'doc-part': {},
  493    -1 	'doc-preface': {},
  494    -1 	'doc-prologue': {},
  495    -1 	'doc-pullquote': {},
  496    -1 	'doc-qna': {},
  497    -1 	'doc-subtitle': {
  498    -1 		nameFromContents: true,
  499    -1 	},
  500    -1 	'doc-tip': {},
  501    -1 	'doc-toc': {},
  502    -1 	document: {
  503    -1 		selectors: ['html'],
  504    -1 		childRoles: ['article', 'graphics-document'],
  505    -1 	},
  506    -1 	emphasis: {
  507    -1 		selectors: ['em'],
  508    -1 	},
  509    -1 	feed: {},
  510    -1 	figure: {
  511    -1 		selectors: ['figure'],
  512    -1 		childRoles: ['doc-example'],
  513    -1 	},
  514    -1 	form: {
  515    -1 		selectors: ['form[aria-label]', 'form[aria-labelledby]', 'form[title]'],
  516    -1 	},
  517    -1 	generic: {
  518    -1 		selectors: [
  519    -1 			'a:not([*|href])',
  520    -1 			'area:not([*|href])',
  521    -1 			`aside:not(${scoped}):not([aria-label]):not([aria-labelledby]):not([title])`,
  522    -1 			'b',
  523    -1 			'bdi',
  524    -1 			'bdo',
  525    -1 			'body',
  526    -1 			'data',
  527    -1 			'div',
  528    -1 			// footer scoped
  529    -1 			// header scoped
  530    -1 			'i',
  531    -1 			'li:not(ul > li):not(ol > li)',
  532    -1 			'pre',
  533    -1 			'q',
  534    -1 			'samp',
  535    -1 			'section:not([aria-label]):not([aria-labelledby]):not([title])',
  536    -1 			'small',
  537    -1 			'span',
  538    -1 			'u',
  539    -1 		],
  540    -1 	},
  541    -1 	'graphics-document': {
  542    -1 		selectors: ['svg'],
  543    -1 	},
  544    -1 	'graphics-object': {
  545    -1 		selectors: [
  546    -1 			...svgSelectors('symbol'),
  547    -1 			...svgSelectors('use'),
  548    -1 		],
  549    -1 	},
  550    -1 	'graphics-symbol': {
  551    -1 		selectors: [
  552    -1 			...svgSelectors('circle'),
  553    -1 			...svgSelectors('ellipse'),
  554    -1 			...svgSelectors('line'),
  555    -1 			...svgSelectors('path'),
  556    -1 			...svgSelectors('polygon'),
  557    -1 			...svgSelectors('polyline'),
  558    -1 			...svgSelectors('rect'),
  559    -1 		],
  560    -1 	},
  561    -1 	grid: {
  562    -1 		childRoles: ['treegrid'],
  563    -1 	},
  564    -1 	gridcell: {
  565    -1 		childRoles: ['columnheader', 'rowheader'],
  566    -1 		nameFromContents: true,
  567    -1 	},
  568    -1 	group: {
  569    -1 		selectors: [
  570    -1 			'address',
  571    -1 			'details',
  572    -1 			'fieldset',
  573    -1 			'hgroup',
  574    -1 			'optgroup',
  575    -1 			...svgSelectors('foreignObject'),
  576    -1 			...svgSelectors('g'),
  577    -1 			'text',
  578    -1 			...svgSelectors('textPath'),
  579    -1 			...svgSelectors('tspan'),
  580    -1 		],
  581    -1 		childRoles: ['row', 'select', 'toolbar', 'graphics-object'],
  582    -1 	},
  583    -1 	heading: {
  584    -1 		selectors: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
  585    -1 		nameFromContents: true,
  586    -1 		defaults: {
  587    -1 			'level': 2,
  588    -1 		},
  589    -1 	},
  590    -1 	image: {
  591    -1 		selectors: [
  592    -1 			'img:not([alt=""])',
  593    -1 			'graphics-symbol',
  594    -1 			...svgSelectors('image'),
  595    -1 			...svgSelectors('mesh'),
  596    -1 		],
  597    -1 		childRoles: ['doc-cover'],
  598    -1 	},
  599    -1 	input: {
  600    -1 		abstract: true,
  601    -1 		childRoles: [
  602    -1 			'checkbox',
  603    -1 			'combobox',
  604    -1 			'option',
  605    -1 			'radio',
  606    -1 			'slider',
  607    -1 			'spinbutton',
  608    -1 			'textbox',
  609    -1 		],
  610    -1 	},
  611    -1 	insertion: {
  612    -1 		selectors: ['ins'],
  613    -1 	},
  614    -1 	landmark: {
  615    -1 		abstract: true,
  616    -1 		childRoles: [
  617    -1 			'banner',
  618    -1 			'complementary',
  619    -1 			'contentinfo',
  620    -1 			'doc-acknowledgments',
  621    -1 			'doc-afterword',
  622    -1 			'doc-appendix',
  623    -1 			'doc-bibliography',
  624    -1 			'doc-chapter',
  625    -1 			'doc-conclusion',
  626    -1 			'doc-credits',
  627    -1 			'doc-endnotes',
  628    -1 			'doc-epilogue',
  629    -1 			'doc-errata',
  630    -1 			'doc-foreword',
  631    -1 			'doc-glossary',
  632    -1 			'doc-introduction',
  633    -1 			'doc-part',
  634    -1 			'doc-preface',
  635    -1 			'doc-prologue',
  636    -1 			'form',
  637    -1 			'main',
  638    -1 			'navigation',
  639    -1 			'region',
  640    -1 			'search',
  641    -1 		],
  642    -1 	},
  643    -1 	link: {
  644    -1 		selectors: ['a[*|href]', 'area[href]'],
  645    -1 		childRoles: ['doc-backlink', 'doc-biblioref', 'doc-glossref', 'doc-noteref'],
  646    -1 		nameFromContents: true,
  647    -1 	},
  648    -1 	list: {
  649    -1 		selectors: ['dl', 'ol', 'ul', 'menu'],
  650    -1 		childRoles: ['feed'],
  651    -1 	},
  652    -1 	listbox: {
  653    -1 		selectors: [
  654    -1 			'datalist',
  655    -1 			'select[multiple]',
  656    -1 			'select[size]:not([size="0"]):not([size="1"])',
  657    -1 		],
  658    -1 		defaults: {
  659    -1 			'orientation': 'vertical',
  660    -1 		},
  661    -1 	},
  662    -1 	listitem: {
  663    -1 		selectors: ['ol > li', 'ul > li'],
  664    -1 		childRoles: ['doc-biblioentry', 'doc-endnote', 'treeitem'],
  665    -1 	},
  666    -1 	log: {
  667    -1 		defaults: {
  668    -1 			'live': 'polite',
  669    -1 		},
  670    -1 	},
  671    -1 	main: {
  672    -1 		selectors: ['main'],
  673    -1 	},
  674    -1 	mark: {
  675    -1 		selectors: ['mark'],
  676    -1 	},
  677    -1 	marquee: {},
  678    -1 	math: {
  679    -1 		selectors: ['math'],
  680    -1 	},
  681    -1 	meter: {
  682    -1 		selectors: ['meter'],
  683    -1 		defaults: {
  684    -1 			'valuemin': 0,
  685    -1 			'valuemax': 100,
  686    -1 		},
  687    -1 	},
  688    -1 	menu: {
  689    -1 		childRoles: ['menubar'],
  690    -1 		defaults: {
  691    -1 			'orientation': 'vertical',
  692    -1 		},
  693    -1 	},
  694    -1 	menubar: {
  695    -1 		defaults: {
  696    -1 			'orientation': 'horizontal',
  697    -1 		},
  698    -1 	},
  699    -1 	menuitem: {
  700    -1 		childRoles: ['menuitemcheckbox', 'menuitemradio'],
  701    -1 		nameFromContents: true,
  702    -1 	},
  703    -1 	menuitemcheckbox: {
  704    -1 		nameFromContents: true,
  705    -1 		defaults: {
  706    -1 			'checked': 'false',
  707    -1 		},
  708    -1 	},
  709    -1 	menuitemradio: {
  710    -1 		nameFromContents: true,
  711    -1 		defaults: {
  712    -1 			'checked': 'false',
  713    -1 		},
  714    -1 	},
  715    -1 	navigation: {
  716    -1 		selectors: ['nav'],
  717    -1 		childRoles: ['doc-index', 'doc-pagelist', 'doc-toc'],
  718    -1 	},
  719    -1 	none: {
  720    -1 		selectors: ['img[alt=""]'],
  721    -1 	},
  722    -1 	note: {
  723    -1 		childRoles: ['doc-notice', 'doc-tip'],
  724    -1 	},
  725    -1 	option: {
  726    -1 		selectors: ['option'],
  727    -1 		childRoles: ['treeitem'],
  728    -1 		nameFromContents: true,
  729    -1 		defaults: {
  730    -1 			'selected': 'false',
  731    -1 		},
  732    -1 	},
  733    -1 	paragraph: {
  734    -1 		selectors: ['p'],
  735    -1 	},
  736    -1 	progressbar: {
  737    -1 		selectors: ['progress'],
  738    -1 		defaults: {
  739    -1 			'valuemin': 0,
  740    -1 			'valuemax': 100,
  741    -1 		},
  742    -1 	},
  743    -1 	radio: {
  744    -1 		selectors: ['input[type="radio"]'],
  745    -1 		childRoles: ['menuitemradio'],
  746    -1 		nameFromContents: true,
  747    -1 		defaults: {
  748    -1 			'checked': 'false',
  749    -1 		},
  750    -1 	},
  751    -1 	radiogroup: {},
  752    -1 	range: {
  753    -1 		abstract: true,
  754    -1 		childRoles: ['meter', 'progressbar', 'scrollbar', 'slider', 'spinbutton'],
  755    -1 	},
  756    -1 	region: {
  757    -1 		selectors: ['section[aria-label]', 'section[aria-labelledby]', 'section[title]'],
  758    -1 	},
  759    -1 	roletype: {
  760    -1 		abstract: true,
  761    -1 		childRoles: ['structure', 'widget', 'window'],
  762    -1 	},
  763    -1 	row: {
  764    -1 		selectors: ['tr'],
  765    -1 		nameFromContents: true,
  766    -1 	},
  767    -1 	rowgroup: {
  768    -1 		selectors: ['tbody', 'thead', 'tfoot'],
  769    -1 	},
  770    -1 	rowheader: {
  771    -1 		selectors: ['th[scope="row"]', 'th:not([scope]):not(td ~ th)'],
  772    -1 		nameFromContents: true,
  773    -1 	},
  774    -1 	scrollbar: {
  775    -1 		defaults: {
  776    -1 			'orientation': 'vertical',
  777    -1 			'valuemin': 0,
  778    -1 			'valuemax': 100,
  779    -1 		},
  780    -1 	},
  781    -1 	search: {
  782    -1 		selectors: ['search'],
  783    -1 	},
  784    -1 	searchbox: {
  785    -1 		selectors: ['input[type="search"]:not([list])'],
  786    -1 	},
  787    -1 	section: {
  788    -1 		abstract: true,
  789    -1 		childRoles: [
  790    -1 			'alert',
  791    -1 			'blockquote',
  792    -1 			'caption',
  793    -1 			'cell',
  794    -1 			'code',
  795    -1 			'definition',
  796    -1 			'deletion',
  797    -1 			'doc-abstract',
  798    -1 			'doc-colophon',
  799    -1 			'doc-credit',
  800    -1 			'doc-dedication',
  801    -1 			'doc-epigraph',
  802    -1 			'doc-footnote',
  803    -1 			'doc-pagefooter',
  804    -1 			'doc-pageheader',
  805    -1 			'doc-pullquote',
  806    -1 			'doc-qna',
  807    -1 			'emphasis',
  808    -1 			'figure',
  809    -1 			'group',
  810    -1 			'image',
  811    -1 			'insertion',
  812    -1 			'landmark',
  813    -1 			'list',
  814    -1 			'listitem',
  815    -1 			'log',
  816    -1 			'mark',
  817    -1 			'marquee',
  818    -1 			'math',
  819    -1 			'note',
  820    -1 			'paragraph',
  821    -1 			'status',
  822    -1 			'strong',
  823    -1 			'subscript',
  824    -1 			'suggestion',
  825    -1 			'superscript',
  826    -1 			'table',
  827    -1 			'tabpanel',
  828    -1 			'term',
  829    -1 			'time',
  830    -1 			'tooltip',
  831    -1 		],
  832    -1 	},
  833    -1 	sectionhead: {
  834    -1 		abstract: true,
  835    -1 		childRoles: [
  836    -1 			'columnheader',
  837    -1 			'doc-subtitle',
  838    -1 			'heading',
  839    -1 			'rowheader',
  840    -1 			'tab',
  841    -1 		],
  842    -1 		nameFromContents: true,
  843    -1 	},
  844    -1 	select: {
  845    -1 		abstract: true,
  846    -1 		childRoles: ['listbox', 'menu', 'radiogroup', 'tree'],
  847    -1 	},
  848    -1 	separator: {
  849    -1 		// assume not focussable because <hr> is not
  850    -1 		selectors: ['hr'],
  851    -1 		childRoles: ['doc-pagebreak'],
  852    -1 		defaults: {
  853    -1 			'orientation': 'horizontal',
  854    -1 			'valuemin': 0,
  855    -1 			'valuemax': 100,
  856    -1 		},
  857    -1 	},
  858    -1 	slider: {
  859    -1 		selectors: ['input[type="range"]'],
  860    -1 		defaults: {
  861    -1 			'orientation': 'horizontal',
  862    -1 			'valuemin': 0,
  863    -1 			'valuemax': 100,
  864    -1 			// FIXME: halfway between actual valuemin and valuemax
  865    -1 			'valuenow': 50,
  866    -1 		},
  867    -1 	},
  868    -1 	spinbutton: {
  869    -1 		selectors: ['input[type="number"]'],
  870    -1 		defaults: {
  871    -1 			// FIXME: no valuemin/valuemax/valuenow
  872    -1 		},
  873    -1 	},
  874    -1 	status: {
  875    -1 		selectors: ['output'],
  876    -1 		childRoles: ['timer'],
  877    -1 		defaults: {
  878    -1 			'live': 'polite',
  879    -1 			'atomic': true,
  880    -1 		},
  881    -1 	},
  882    -1 	strong: {
  883    -1 		selectors: ['strong'],
  884    -1 	},
  885    -1 	structure: {
  886    -1 		abstract: true,
  887    -1 		childRoles: [
  888    -1 			'application',
  889    -1 			'document',
  890    -1 			'none',
  891    -1 			'generic',
  892    -1 			'range',
  893    -1 			'rowgroup',
  894    -1 			'section',
  895    -1 			'sectionhead',
  896    -1 			'separator',
  897    -1 		],
  898    -1 	},
  899    -1 	suggestion: {},
  900    -1 	subscript: {
  901    -1 		selectors: ['sub'],
  902    -1 	},
  903    -1 	superscript: {
  904    -1 		selectors: ['sup'],
  905    -1 	},
  906    -1 	switch: {
  907    -1 		nameFromContents: true,
  908    -1 		defaults: {
  909    -1 			'checked': false,
  910    -1 		},
  911    -1 	},
  912    -1 	tab: {
  913    -1 		nameFromContents: true,
  914    -1 		defaults: {
  915    -1 			'selected': false,
  916    -1 		},
  917    -1 	},
  918    -1 	table: {
  919    -1 		selectors: ['table'],
  920    -1 		childRoles: ['grid'],
  921    -1 	},
  922    -1 	tablist: {
  923    -1 		defaults: {
  924    -1 			'orientation': 'horizontal',
  925    -1 		},
  926    -1 	},
  927    -1 	tabpanel: {},
  928    -1 	term: {
  929    -1 		selectors: ['dfn', 'dt'],
  930    -1 	},
  931    -1 	textbox: {
  932    -1 		selectors: [
  933    -1 			'input:not([type]):not([list])',
  934    -1 			'input[type="email"]:not([list])',
  935    -1 			'input[type="tel"]:not([list])',
  936    -1 			'input[type="text"]:not([list])',
  937    -1 			'input[type="url"]:not([list])',
  938    -1 			'textarea',
  939    -1 		],
  940    -1 		childRoles: ['searchbox'],
  941    -1 	},
  942    -1 	time: {
  943    -1 		selectors: ['time'],
  944    -1 	},
  945    -1 	timer: {
  946    -1 		defaults: {
  947    -1 			'live': 'off',
  948    -1 		},
  949    -1 	},
  950    -1 	toolbar: {
  951    -1 		defaults: {
  952    -1 			'orientation': 'horizontal',
  953    -1 		},
  954    -1 	},
  955    -1 	tooltip: {
  956    -1 		nameFromContents: true,
  957    -1 	},
  958    -1 	tree: {
  959    -1 		childRoles: ['treegrid'],
  960    -1 		defaults: {
  961    -1 			'orientation': 'vertical',
  962    -1 		},
  963    -1 	},
  964    -1 	treegrid: {},
  965    -1 	treeitem: {
  966    -1 		nameFromContents: true,
  967    -1 	},
  968    -1 	widget: {
  969    -1 		abstract: true,
  970    -1 		childRoles: [
  971    -1 			'command',
  972    -1 			'composite',
  973    -1 			'gridcell',
  974    -1 			'input',
  975    -1 			'progressbar',
  976    -1 			'row',
  977    -1 			'scrollbar',
  978    -1 			'separator',
  979    -1 			'tab',
  980    -1 		],
  981    -1 	},
  982    -1 	window: {
  983    -1 		abstract: true,
  984    -1 		childRoles: ['dialog'],
  985    -1 	},
  986    -1 };
  987    -1 
  988    -1 const getSubRoles = function(role) {
  989    -1 	const children = (exports.roles[role]).childRoles || [];
  990    -1 	const descendents = children.map(getSubRoles);
  991    -1 
  992    -1 	const result = [role];
  993    -1 
  994    -1 	descendents.forEach(list => {
  995    -1 		list.forEach(r => {
  996    -1 			if (!result.includes(r)) {
  997    -1 				result.push(r);
  998    -1 			}
  999    -1 		});
 1000    -1 	});
   -1   951 	const getParentNode = function(node, owners) {
   -1   952 		return getOwner(node, owners) || node.parentNode;
   -1   953 	};
 1001   954 
 1002    -1 	return result;
 1003    -1 };
   -1   955 	const isHidden = function(node) {
   -1   956 		return node.nodeType === node.ELEMENT_NODE && getAttribute(node, 'hidden');
   -1   957 	};
 1004   958 
 1005    -1 exports.attrsWithDefaults = [];
   -1   959 	const getChildNodes = function(node, owners) {
   -1   960 		const childNodes = [];
 1006   961 
 1007    -1 for (const role in exports.roles) {
 1008    -1 	exports.roles[role].subRoles = getSubRoles(role);
 1009    -1 	for (const key in exports.roles[role].defaults) {
 1010    -1 		if (!exports.attrsWithDefaults.includes(key)) {
 1011    -1 			exports.attrsWithDefaults.push(key);
   -1   962 		for (let i = 0; i < node.childNodes.length; i++) {
   -1   963 			const child = node.childNodes[i];
   -1   964 			if (!getOwner(child, owners) && !isHidden(child)) {
   -1   965 				childNodes.push(child);
   -1   966 			}
 1012   967 		}
 1013    -1 	}
 1014    -1 }
 1015    -1 
 1016    -1 exports.aliases = {
 1017    -1 	'presentation': 'none',
 1018    -1 	'directory': 'list',
 1019    -1 	'img': 'image',
 1020    -1 };
 1021    -1 
 1022    -1 exports.nameFromDescendant = {
 1023    -1 	'figure': 'figcaption',
 1024    -1 	'table': 'caption',
 1025    -1 	'fieldset': 'legend',
 1026    -1 };
 1027    -1 
 1028    -1 exports.nameDefaults = {
 1029    -1 	'input[type="submit"]': 'Submit',
 1030    -1 	'input[type="reset"]': 'Reset',
 1031    -1 	'summary': 'Details',
 1032    -1 };
 1033    -1 
 1034    -1 },{}],5:[function(require,module,exports){
 1035    -1 const constants = require('./constants.js');
 1036    -1 const atree = require('./atree.js');
 1037    -1 const query = require('./query.js');
 1038    -1 
 1039    -1 const addSpaces = function(text, el, pseudoSelector) {
 1040    -1 	// https://github.com/w3c/accname/issues/3
 1041    -1 	const styles = window.getComputedStyle(el, pseudoSelector);
 1042    -1 	const inline = styles.display === 'inline';
 1043    -1 	return inline ? text : ` ${text} `;
 1044    -1 };
 1045    -1 
 1046    -1 const getPseudoContent = function(el, pseudoSelector) {
 1047    -1 	const styles = window.getComputedStyle(el, pseudoSelector);
 1048    -1 	let tail = styles.getPropertyValue('content').trim();
 1049    -1 	let ret = [];
 1050    -1 
 1051    -1 	let match;
 1052    -1 	while (tail.length) {
 1053    -1 		if (match = tail.match(/^"([^"]*)"/)) {
 1054    -1 			ret.push(match[1]);
 1055    -1 		} else if (match = tail.match(/^([a-z-]+)\(([^)]*)\)/)) {
 1056    -1 			if (match[1] === 'attr') {
 1057    -1 				ret.push(el.getAttribute(match[2]) || '');
   -1   968 
   -1   969 		if (node.nodeType === node.ELEMENT_NODE) {
   -1   970 			const owns = getAttribute(node, 'owns') || [];
   -1   971 			for (let i = 0; i < owns.length; i++) {
   -1   972 				const child = document.getElementById(owns[i]);
   -1   973 				// double check with getOwner for consistency
   -1   974 				if (child && getOwner(child, owners) === node && !isHidden(child)) {
   -1   975 					childNodes.push(child);
   -1   976 				}
 1058   977 			}
 1059    -1 		} else if (match = tail.match(/^([a-z-]+)/)) {
 1060    -1 			if (match[1] === 'open-quote' || match[1] === 'close-quote') {
 1061    -1 				ret.push('"');
   -1   978 		}
   -1   979 
   -1   980 		return childNodes;
   -1   981 	};
   -1   982 
   -1   983 	const walk = function(root, fn) {
   -1   984 		const owners = document.querySelectorAll('[aria-owns]');
   -1   985 		let queue = [root];
   -1   986 		while (queue.length) {
   -1   987 			const item = queue.shift();
   -1   988 			fn(item);
   -1   989 			queue = getChildNodes(item, owners).concat(queue);
   -1   990 		}
   -1   991 	};
   -1   992 
   -1   993 	const searchUp = function(node, test) {
   -1   994 		const candidate = getParentNode(node);
   -1   995 		if (candidate) {
   -1   996 			if (test(candidate)) {
   -1   997 				return candidate;
   -1   998 			} else {
   -1   999 				return searchUp(candidate, test);
 1062  1000 			}
 1063    -1 		} else if (match = tail.match(/^\//)) {
 1064    -1 			ret = [];
   -1  1001 		}
   -1  1002 	};
   -1  1003 
   -1  1004 	const matches = function(el, selector) {
   -1  1005 		if (selector.substr(0, 1) === ':') {
   -1  1006 			const attr = selector.substr(1);
   -1  1007 			return getAttribute(el, attr);
   -1  1008 		} else if (selector.substr(0, 1) === '[') {
   -1  1009 			const match = /\[([a-z]+)="(.*)"\]/.exec(selector);
   -1  1010 			const actual = getAttribute(el, match[1]);
   -1  1011 			const rawValue = match[2];
   -1  1012 			return actual.toString() === rawValue;
 1065  1013 		} else {
 1066    -1 			// invalid content, ignore
 1067    -1 			return '';
   -1  1014 			return hasRole(el, selector.split(','));
 1068  1015 		}
 1069    -1 		tail = tail.slice(match[0].length).trim();
 1070    -1 	}
   -1  1016 	};
 1071  1017 
 1072    -1 	return addSpaces(ret.join(''), el, pseudoSelector);
 1073    -1 };
   -1  1018 	const _querySelector = function(all) {
   -1  1019 		return function(root, selector) {
   -1  1020 			const results = [];
   -1  1021 			try {
   -1  1022 				walk(root, node => {
   -1  1023 					if (node.nodeType === node.ELEMENT_NODE) {
   -1  1024 						// FIXME: skip hidden elements
   -1  1025 						if (matches(node, selector)) {
   -1  1026 							results.push(node);
   -1  1027 							if (!all) {
   -1  1028 								throw 'StopIteration';
   -1  1029 							}
   -1  1030 						}
   -1  1031 					}
   -1  1032 				});
   -1  1033 			} catch (e) {
   -1  1034 				if (e !== 'StopIteration') {
   -1  1035 					throw e;
   -1  1036 				}
   -1  1037 			}
   -1  1038 			return all ? results : results[0];
   -1  1039 		};
   -1  1040 	};
   -1  1041 
   -1  1042 	const closest = function(el, selector) {
   -1  1043 		return searchUp(el, candidate => {
   -1  1044 			if (candidate.nodeType === candidate.ELEMENT_NODE) {
   -1  1045 				return matches(candidate, selector);
   -1  1046 			}
   -1  1047 		});
   -1  1048 	};
 1074  1049 
 1075    -1 const getContent = function(root, ongoingLabelledBy, visited) {
 1076    -1 	const children = atree.getChildNodes(root);
   -1  1050 	const querySelector = _querySelector();
   -1  1051 	const querySelectorAll = _querySelector(true);
   -1  1052 
   -1  1053 	const addSpaces = function(text, el, pseudoSelector) {
   -1  1054 		// https://github.com/w3c/accname/issues/3
   -1  1055 		const styles = window.getComputedStyle(el, pseudoSelector);
   -1  1056 		const inline = styles.display === 'inline';
   -1  1057 		return inline ? text : ` ${text} `;
   -1  1058 	};
 1077  1059 
 1078    -1 	let ret = '';
 1079    -1 	for (let i = 0; i < children.length; i++) {
 1080    -1 		const node = children[i];
 1081    -1 		if (node.nodeType === node.TEXT_NODE) {
 1082    -1 			ret += node.textContent;
 1083    -1 		} else if (node.nodeType === node.ELEMENT_NODE) {
 1084    -1 			if (node.tagName.toLowerCase() === 'br') {
 1085    -1 				ret += '\n';
   -1  1060 	const getPseudoContent = function(el, pseudoSelector) {
   -1  1061 		const styles = window.getComputedStyle(el, pseudoSelector);
   -1  1062 		let tail = styles.getPropertyValue('content').trim();
   -1  1063 		let ret = [];
   -1  1064 
   -1  1065 		let match;
   -1  1066 		while (tail.length) {
   -1  1067 			if ((match = tail.match(/^"([^"]*)"/))) {
   -1  1068 				ret.push(match[1]);
   -1  1069 			} else if ((match = tail.match(/^([a-z-]+)\(([^)]*)\)/))) {
   -1  1070 				if (match[1] === 'attr') {
   -1  1071 					ret.push(el.getAttribute(match[2]) || '');
   -1  1072 				}
   -1  1073 			} else if ((match = tail.match(/^([a-z-]+)/))) {
   -1  1074 				if (match[1] === 'open-quote' || match[1] === 'close-quote') {
   -1  1075 					ret.push('"');
   -1  1076 				}
   -1  1077 			} else if ((match = tail.match(/^\//))) {
   -1  1078 				ret = [];
 1086  1079 			} else {
 1087    -1 				ret += getName(node, true, ongoingLabelledBy, visited);
   -1  1080 				// invalid content, ignore
   -1  1081 				return '';
 1088  1082 			}
   -1  1083 			tail = tail.slice(match[0].length).trim();
 1089  1084 		}
 1090    -1 	}
 1091  1085 
 1092    -1 	return ret;
 1093    -1 };
   -1  1086 		return addSpaces(ret.join(''), el, pseudoSelector);
   -1  1087 	};
 1094  1088 
 1095    -1 const allowNameFromContent = function(el) {
 1096    -1 	const role = query.getRole(el);
 1097    -1 	if (role) {
 1098    -1 		return constants.roles[role].nameFromContents;
 1099    -1 	}
 1100    -1 };
   -1  1089 	const getContent = function(root, ongoingLabelledBy, visited) {
   -1  1090 		const children = getChildNodes(root);
   -1  1091 
   -1  1092 		let ret = '';
   -1  1093 		for (let i = 0; i < children.length; i++) {
   -1  1094 			const node = children[i];
   -1  1095 			if (node.nodeType === node.TEXT_NODE) {
   -1  1096 				const styles = window.getComputedStyle(node.parentElement);
   -1  1097 				if (styles.textTransform === 'uppercase') {
   -1  1098 					ret += node.textContent.toUpperCase();
   -1  1099 				} else if (styles.textTransform === 'lowercase') {
   -1  1100 					ret += node.textContent.toLowerCase();
   -1  1101 				} else if (styles.textTransform === 'capitalize') {
   -1  1102 					ret += node.textContent.replace(/\b\w/g, c => c.toUpperCase());
   -1  1103 				} else {
   -1  1104 					ret += node.textContent;
   -1  1105 				}
   -1  1106 			} else if (node.nodeType === node.ELEMENT_NODE) {
   -1  1107 				if (node.tagName.toLowerCase() === 'br') {
   -1  1108 					ret += '\n';
   -1  1109 				} else {
   -1  1110 					ret += getNameRaw(node, true, ongoingLabelledBy, visited);
   -1  1111 				}
   -1  1112 			}
   -1  1113 		}
 1101  1114 
 1102    -1 const getName = function(el, recursive, ongoingLabelledBy, visited, directReference) {
 1103    -1 	let ret = '';
   -1  1115 		return ret;
   -1  1116 	};
 1104  1117 
 1105    -1 	visited = visited || [];
 1106    -1 	if (visited.includes(el)) {
 1107    -1 		if (!directReference) {
 1108    -1 			return '';
   -1  1118 	const allowNameFromContent = function(el) {
   -1  1119 		const role = getRole(el);
   -1  1120 		if (role) {
   -1  1121 			return roles[role].nameFromContents;
 1109  1122 		}
 1110    -1 	} else {
 1111    -1 		visited.push(el);
 1112    -1 	}
   -1  1123 	};
 1113  1124 
 1114    -1 	// A
 1115    -1 	// handled in atree
   -1  1125 	const getNameRaw = function(el, recursive, ongoingLabelledBy, visited, directReference) {
   -1  1126 		let ret = '';
 1116  1127 
 1117    -1 	// B
 1118    -1 	if (!ongoingLabelledBy && el.matches('[aria-labelledby]')) {
 1119    -1 		const ids = el.getAttribute('aria-labelledby').split(/\s+/);
 1120    -1 		const strings = ids.map(id => {
 1121    -1 			const label = document.getElementById(id);
 1122    -1 			return label ? getName(label, true, true, visited, true) : '';
 1123    -1 		});
 1124    -1 		ret = strings.join(' ');
 1125    -1 	}
   -1  1128 		visited = visited || [];
   -1  1129 		if (visited.includes(el)) {
   -1  1130 			if (!directReference) {
   -1  1131 				return '';
   -1  1132 			}
   -1  1133 		} else {
   -1  1134 			visited.push(el);
   -1  1135 		}
 1126  1136 
 1127    -1 	// E (the current draft has this at this high priority)
 1128    -1 	if (!ret.trim() && recursive) {
 1129    -1 		if (query.matches(el, 'textbox')) {
 1130    -1 			ret = el.value || el.textContent;
 1131    -1 		} else if (query.matches(el, 'combobox,listbox')) {
 1132    -1 			const selected = query.querySelector(el, ':selected') || query.querySelector(el, 'option');
 1133    -1 			if (selected) {
 1134    -1 				ret = getName(selected, recursive, ongoingLabelledBy, visited);
 1135    -1 			} else {
 1136    -1 				ret = el.value || '';
   -1  1137 		// A
   -1  1138 		// handled in atree
   -1  1139 
   -1  1140 		// B
   -1  1141 		if (!ongoingLabelledBy && el.matches('[aria-labelledby]')) {
   -1  1142 			const ids = el.getAttribute('aria-labelledby').split(/\s+/);
   -1  1143 			const strings = ids.map(id => {
   -1  1144 				const label = document.getElementById(id);
   -1  1145 				return label ? getNameRaw(label, true, true, visited, true) : '';
   -1  1146 			});
   -1  1147 			ret = strings.join(' ');
   -1  1148 		}
   -1  1149 
   -1  1150 		// E (the current draft has this at this high priority)
   -1  1151 		if (!ret.trim() && recursive) {
   -1  1152 			if (matches(el, 'textbox')) {
   -1  1153 				ret = el.value || el.textContent;
   -1  1154 			} else if (matches(el, 'combobox,listbox')) {
   -1  1155 				const selected = querySelector(el, ':selected') || querySelector(el, 'option');
   -1  1156 				if (selected) {
   -1  1157 					ret = getNameRaw(selected, recursive, ongoingLabelledBy, visited);
   -1  1158 				} else {
   -1  1159 					ret = el.value || '';
   -1  1160 				}
   -1  1161 			} else if (matches(el, 'range')) {
   -1  1162 				ret = '' + (getAttribute(el, 'valuetext') || getAttribute(el, 'valuenow') || el.value);
 1137  1163 			}
 1138    -1 		} else if (query.matches(el, 'range')) {
 1139    -1 			ret = '' + (query.getAttribute(el, 'valuetext') || query.getAttribute(el, 'valuenow') || el.value);
 1140  1164 		}
 1141    -1 	}
 1142  1165 
 1143    -1 	// C
 1144    -1 	if (!ret.trim() && el.matches('[aria-label]')) {
 1145    -1 		// FIXME: may skip to 2E
 1146    -1 		ret = el.getAttribute('aria-label');
 1147    -1 	}
   -1  1166 		// C
   -1  1167 		if (!ret.trim() && el.matches('[aria-label]')) {
   -1  1168 			// FIXME: may skip to 2E
   -1  1169 			ret = el.getAttribute('aria-label');
   -1  1170 		}
 1148  1171 
 1149    -1 	// D
 1150    -1 	if (!ret.trim() && !recursive && el.labels) {
 1151    -1 		const strings = Array.prototype.map.call(el.labels, label => {
 1152    -1 			return getName(label, true, ongoingLabelledBy, visited);
 1153    -1 		});
 1154    -1 		ret = strings.join(' ');
 1155    -1 	}
 1156    -1 	if (!ret.trim()) {
 1157    -1 		ret = el.alt || '';
 1158    -1 	}
 1159    -1 	if (!ret.trim() && el.matches('abbr,acronym') && el.title) {
 1160    -1 		ret = el.title;
 1161    -1 	}
 1162    -1 	if (!ret.trim()) {
 1163    -1 		for (const selector in constants.nameFromDescendant) {
 1164    -1 			if (el.matches(selector)) {
 1165    -1 				const descendant = el.querySelector(constants.nameFromDescendant[selector]);
 1166    -1 				if (descendant) {
 1167    -1 					ret = getName(descendant, true, ongoingLabelledBy, visited);
   -1  1172 		// D
   -1  1173 		if (!ret.trim() && !recursive && el.labels) {
   -1  1174 			const strings = Array.prototype.map.call(el.labels, label => {
   -1  1175 				return getNameRaw(label, true, ongoingLabelledBy, visited);
   -1  1176 			});
   -1  1177 			ret = strings.join(' ');
   -1  1178 		}
   -1  1179 		if (!ret.trim()) {
   -1  1180 			ret = el.alt || '';
   -1  1181 		}
   -1  1182 		if (!ret.trim() && el.matches('abbr,acronym') && el.title) {
   -1  1183 			ret = el.title;
   -1  1184 		}
   -1  1185 		if (!ret.trim()) {
   -1  1186 			for (const selector in nameFromDescendant) {
   -1  1187 				if (el.matches(selector)) {
   -1  1188 					const descendant = el.querySelector(nameFromDescendant[selector]);
   -1  1189 					if (descendant) {
   -1  1190 						ret = getNameRaw(descendant, true, ongoingLabelledBy, visited);
   -1  1191 					}
 1168  1192 				}
 1169  1193 			}
 1170  1194 		}
 1171    -1 	}
 1172    -1 	if (!ret.trim() && el.matches('svg *')) {
 1173    -1 		const svgTitle = el.querySelector('title');
 1174    -1 		if (svgTitle && svgTitle.parentElement === el) {
 1175    -1 			ret = svgTitle.textContent;
   -1  1195 		if (!ret.trim() && el.matches('svg *')) {
   -1  1196 			const svgTitle = el.querySelector('title');
   -1  1197 			if (svgTitle && svgTitle.parentElement === el) {
   -1  1198 				ret = svgTitle.textContent;
   -1  1199 			}
   -1  1200 		}
   -1  1201 		if (!ret.trim() && el.matches('a')) {
   -1  1202 			ret = el.getAttribute('xlink:title') || '';
 1176  1203 		}
 1177    -1 	}
 1178    -1 	if (!ret.trim() && el.matches('a')) {
 1179    -1 		ret = el.getAttribute('xlink:title') || '';
 1180    -1 	}
 1181  1204 
 1182    -1 	// F
 1183    -1 	// FIXME: menu is not mentioned in the spec
 1184    -1 	if (!ret.trim() && (recursive || allowNameFromContent(el) || el.closest('label')) && !query.matches(el, 'menu')) {
 1185    -1 		ret = getContent(el, ongoingLabelledBy, visited);
 1186    -1 	}
   -1  1205 		// F
   -1  1206 		// FIXME: menu is not mentioned in the spec
   -1  1207 		if (!ret.trim() && (recursive || allowNameFromContent(el) || el.closest('label')) && !matches(el, 'menu')) {
   -1  1208 			ret = getContent(el, ongoingLabelledBy, visited);
   -1  1209 		}
 1187  1210 
 1188    -1 	if (!ret.trim() && query.matches(el, 'button')) {
 1189    -1 		ret = el.value || '';
 1190    -1 	}
   -1  1211 		if (!ret.trim() && matches(el, 'button')) {
   -1  1212 			ret = el.value || '';
   -1  1213 		}
 1191  1214 
 1192    -1 	if (!ret.trim()) {
 1193    -1 		for (const selector in constants.nameDefaults) {
 1194    -1 			if (el.matches(selector)) {
 1195    -1 				ret = constants.nameDefaults[selector];
   -1  1215 		if (!ret.trim()) {
   -1  1216 			for (const selector in nameDefaults) {
   -1  1217 				if (el.matches(selector)) {
   -1  1218 					ret = nameDefaults[selector];
   -1  1219 				}
 1196  1220 			}
 1197  1221 		}
 1198    -1 	}
 1199  1222 
 1200    -1 	// G/H
 1201    -1 	// handled in getContent
   -1  1223 		// G/H
   -1  1224 		// handled in getContent
 1202  1225 
 1203    -1 	// I
 1204    -1 	if (!ret.trim()) {
 1205    -1 		ret = el.title || el.placeholder || '';
 1206    -1 	}
 1207    -1 
 1208    -1 	// FIXME: not exactly sure about this, but it reduces the number of failing
 1209    -1 	// WPT tests. Whitespace is hard.
 1210    -1 	if (!ret.trim()) {
 1211    -1 		ret = ' ';
 1212    -1 	}
   -1  1226 		// I
   -1  1227 		if (!ret.trim()) {
   -1  1228 			ret = el.title || el.placeholder || '';
   -1  1229 		}
 1213  1230 
 1214    -1 	const before = getPseudoContent(el, ':before');
 1215    -1 	const after = getPseudoContent(el, ':after');
 1216    -1 	return addSpaces(before + ret + after, el);
 1217    -1 };
 1218    -1 
 1219    -1 const getNameTrimmed = function(el) {
 1220    -1 	return getName(el)
 1221    -1 		.replace(/[ \n\r\t\f]+/g, ' ')
 1222    -1 		.replace(/^ /, '')
 1223    -1 		.replace(/ $/, '');
 1224    -1 };
 1225    -1 
 1226    -1 const getDescription = function(el) {
 1227    -1 	let ret = '';
 1228    -1 
 1229    -1 	if (el.matches('[aria-describedby]')) {
 1230    -1 		const ids = el.getAttribute('aria-describedby').split(/\s+/);
 1231    -1 		const strings = ids.map(id => {
 1232    -1 			const label = document.getElementById(id);
 1233    -1 			return label ? getName(label, true, true) : '';
 1234    -1 		});
 1235    -1 		ret = strings.join(' ');
 1236    -1 	} else if (el.matches('[aria-description]')) {
 1237    -1 		ret = el.getAttribute('aria-description');
 1238    -1 	} else if (el.matches('svg *')) {
 1239    -1 		const svgDesc = el.querySelector('desc');
 1240    -1 		if (svgDesc && svgDesc.parentElement === el) {
 1241    -1 			ret = svgDesc.textContent;
   -1  1231 		// FIXME: not exactly sure about this, but it reduces the number of failing
   -1  1232 		// WPT tests. Whitespace is hard.
   -1  1233 		if (!ret.trim()) {
   -1  1234 			ret = ' ';
 1242  1235 		}
 1243    -1 	} else if (el.title) {
 1244    -1 		ret = el.title;
 1245    -1 	}
 1246    -1 	if (!ret.trim() && el.matches('a')) {
 1247    -1 		ret = el.getAttribute('xlink:title') || '';
 1248    -1 	}
 1249  1236 
 1250    -1 	ret = (ret || '').trim().replace(/\s+/g, ' ');
   -1  1237 		const before = getPseudoContent(el, ':before');
   -1  1238 		const after = getPseudoContent(el, ':after');
   -1  1239 		return addSpaces(before + ret + after, el);
   -1  1240 	};
 1251  1241 
 1252    -1 	if (ret === getNameTrimmed(el)) {
 1253    -1 		ret = '';
 1254    -1 	}
   -1  1242 	const getName = function(el) {
   -1  1243 		return getNameRaw(el)
   -1  1244 			.replace(/[ \n\r\t\f]+/g, ' ')
   -1  1245 			.replace(/^ /, '')
   -1  1246 			.replace(/ $/, '');
   -1  1247 	};
 1255  1248 
 1256    -1 	return ret;
 1257    -1 };
 1258    -1 
 1259    -1 module.exports = {
 1260    -1 	getName: getNameTrimmed,
 1261    -1 	getDescription: getDescription,
 1262    -1 };
 1263    -1 
 1264    -1 },{"./atree.js":2,"./constants.js":4,"./query.js":6}],6:[function(require,module,exports){
 1265    -1 const attrs = require('./attrs.js');
 1266    -1 const atree = require('./atree.js');
 1267    -1 
 1268    -1 
 1269    -1 const matches = function(el, selector) {
 1270    -1 	if (selector.substr(0, 1) === ':') {
 1271    -1 		const attr = selector.substr(1);
 1272    -1 		return attrs.getAttribute(el, attr);
 1273    -1 	} else if (selector.substr(0, 1) === '[') {
 1274    -1 		const match = /\[([a-z]+)="(.*)"\]/.exec(selector);
 1275    -1 		const actual = attrs.getAttribute(el, match[1]);
 1276    -1 		const rawValue = match[2];
 1277    -1 		return actual.toString() === rawValue;
 1278    -1 	} else {
 1279    -1 		return attrs.hasRole(el, selector.split(','));
 1280    -1 	}
 1281    -1 };
 1282    -1 
 1283    -1 const _querySelector = function(all) {
 1284    -1 	return function(root, selector) {
 1285    -1 		const results = [];
 1286    -1 		try {
 1287    -1 			atree.walk(root, node => {
 1288    -1 				if (node.nodeType === node.ELEMENT_NODE) {
 1289    -1 					// FIXME: skip hidden elements
 1290    -1 					if (matches(node, selector)) {
 1291    -1 						results.push(node);
 1292    -1 						if (!all) {
 1293    -1 							throw 'StopIteration';
 1294    -1 						}
 1295    -1 					}
 1296    -1 				}
   -1  1249 	const getDescription = function(el) {
   -1  1250 		let ret = '';
   -1  1251 
   -1  1252 		if (el.matches('[aria-describedby]')) {
   -1  1253 			const ids = el.getAttribute('aria-describedby').split(/\s+/);
   -1  1254 			const strings = ids.map(id => {
   -1  1255 				const label = document.getElementById(id);
   -1  1256 				return label ? getNameRaw(label, true, true) : '';
 1297  1257 			});
 1298    -1 		} catch (e) {
 1299    -1 			if (e !== 'StopIteration') {
 1300    -1 				throw e;
   -1  1258 			ret = strings.join(' ');
   -1  1259 		} else if (el.matches('[aria-description]')) {
   -1  1260 			ret = el.getAttribute('aria-description');
   -1  1261 		} else if (el.matches('svg *')) {
   -1  1262 			const svgDesc = el.querySelector('desc');
   -1  1263 			if (svgDesc && svgDesc.parentElement === el) {
   -1  1264 				ret = svgDesc.textContent;
 1301  1265 			}
   -1  1266 		} else if (el.title) {
   -1  1267 			ret = el.title;
   -1  1268 		}
   -1  1269 		if (!ret.trim() && el.matches('a')) {
   -1  1270 			ret = el.getAttribute('xlink:title') || '';
 1302  1271 		}
 1303    -1 		return all ? results : results[0];
 1304    -1 	};
 1305    -1 };
 1306  1272 
 1307    -1 const closest = function(el, selector) {
 1308    -1 	return atree.searchUp(el, candidate => {
 1309    -1 		if (candidate.nodeType === candidate.ELEMENT_NODE) {
 1310    -1 			return matches(candidate, selector);
   -1  1273 		ret = (ret || '').trim().replace(/\s+/g, ' ');
   -1  1274 
   -1  1275 		if (ret === getName(el)) {
   -1  1276 			ret = '';
 1311  1277 		}
 1312    -1 	});
 1313    -1 };
 1314    -1 
 1315    -1 module.exports = {
 1316    -1 	getRole: el => attrs.getRole(el),
 1317    -1 	getAttribute: attrs.getAttribute,
 1318    -1 	matches: matches,
 1319    -1 	querySelector: _querySelector(),
 1320    -1 	querySelectorAll: _querySelector(true),
 1321    -1 	closest: closest,
 1322    -1 };
 1323    -1 
 1324    -1 },{"./atree.js":2,"./attrs.js":3}]},{},[1])(1)
 1325    -1 });
   -1  1278 
   -1  1279 		return ret;
   -1  1280 	};
   -1  1281 
   -1  1282 	exports.closest = closest;
   -1  1283 	exports.getAttribute = getAttribute;
   -1  1284 	exports.getChildNodes = getChildNodes;
   -1  1285 	exports.getDescription = getDescription;
   -1  1286 	exports.getName = getName;
   -1  1287 	exports.getParentNode = getParentNode;
   -1  1288 	exports.getRole = getRole;
   -1  1289 	exports.matches = matches;
   -1  1290 	exports.querySelector = querySelector;
   -1  1291 	exports.querySelectorAll = querySelectorAll;
   -1  1292 
   -1  1293 }));

diff --git a/package.json b/package.json

@@ -1,6 +1,6 @@
    1     1 {
    2     2   "name": "aria-api",
    3    -1   "version": "0.7.0",
   -1     3   "version": "0.8.0",
    4     4   "description": "Access ARIA information from JavaScript",
    5     5   "module": "index.js",
    6     6   "keywords": [