ivya
Version:
Fork of Playwright's locator resolution
1,681 lines (1,672 loc) • 162 kB
JavaScript
//#region \0@oxc-project+runtime@0.115.0/helpers/typeof.js
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
return typeof o;
} : function(o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
//#endregion
//#region \0@oxc-project+runtime@0.115.0/helpers/toPrimitive.js
function toPrimitive(t, r) {
if ("object" != _typeof(t) || !t) return t;
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r || "default");
if ("object" != _typeof(i)) return i;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
//#endregion
//#region \0@oxc-project+runtime@0.115.0/helpers/toPropertyKey.js
function toPropertyKey(t) {
var i = toPrimitive(t, "string");
return "symbol" == _typeof(i) ? i : i + "";
}
//#endregion
//#region \0@oxc-project+runtime@0.115.0/helpers/defineProperty.js
function _defineProperty(e, r, t) {
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
value: t,
enumerable: !0,
configurable: !0,
writable: !0
}) : e[r] = t, e;
}
//#endregion
//#region src/cssTokenizer.ts
const between = function(num, first, last) {
return num >= first && num <= last;
};
function digit(code) {
return between(code, 48, 57);
}
function hexdigit(code) {
return digit(code) || between(code, 65, 70) || between(code, 97, 102);
}
function uppercaseletter(code) {
return between(code, 65, 90);
}
function lowercaseletter(code) {
return between(code, 97, 122);
}
function letter(code) {
return uppercaseletter(code) || lowercaseletter(code);
}
function nonascii(code) {
return code >= 128;
}
function namestartchar(code) {
return letter(code) || nonascii(code) || code === 95;
}
function namechar(code) {
return namestartchar(code) || digit(code) || code === 45;
}
function nonprintable(code) {
return between(code, 0, 8) || code === 11 || between(code, 14, 31) || code === 127;
}
function newline(code) {
return code === 10;
}
function whitespace(code) {
return newline(code) || code === 9 || code === 32;
}
const maximumallowedcodepoint = 1114111;
var InvalidCharacterError = class extends Error {
constructor(message) {
super(message);
this.name = "InvalidCharacterError";
}
};
function preprocess(str) {
const codepoints = [];
for (let i = 0; i < str.length; i++) {
let code = str.charCodeAt(i);
if (code === 13 && str.charCodeAt(i + 1) === 10) {
code = 10;
i++;
}
if (code === 13 || code === 12) code = 10;
if (code === 0) code = 65533;
if (between(code, 55296, 56319) && between(str.charCodeAt(i + 1), 56320, 57343)) {
const lead = code - 55296;
const trail = str.charCodeAt(i + 1) - 56320;
code = 2 ** 16 + lead * 2 ** 10 + trail;
i++;
}
codepoints.push(code);
}
return codepoints;
}
function stringFromCode(code) {
if (code <= 65535) return String.fromCharCode(code);
code -= 2 ** 16;
const lead = Math.floor(code / 2 ** 10) + 55296;
const trail = code % 2 ** 10 + 56320;
return String.fromCharCode(lead) + String.fromCharCode(trail);
}
function tokenize(str1) {
const str = preprocess(str1);
let i = -1;
const tokens = [];
let code;
let line = 0;
let column = 0;
let lastLineLength = 0;
const incrLineno = function() {
line += 1;
lastLineLength = column;
column = 0;
};
const locStart = {
line,
column
};
const codepoint = function(i) {
if (i >= str.length) return -1;
return str[i];
};
const next = function(num) {
if (num === void 0) num = 1;
if (num > 3) throw "Spec Error: no more than three codepoints of lookahead.";
return codepoint(i + num);
};
const consume = function(num) {
if (num === void 0) num = 1;
i += num;
code = codepoint(i);
if (newline(code)) incrLineno();
else column += num;
return true;
};
const reconsume = function() {
i -= 1;
if (newline(code)) {
line -= 1;
column = lastLineLength;
} else column -= 1;
locStart.line = line;
locStart.column = column;
return true;
};
const eof = function(codepoint) {
if (codepoint === void 0) codepoint = code;
return codepoint === -1;
};
const donothing = function() {};
const parseerror = function() {};
const consumeAToken = function() {
consumeComments();
consume();
if (whitespace(code)) {
while (whitespace(next())) consume();
return new WhitespaceToken();
} else if (code === 34) return consumeAStringToken();
else if (code === 35) if (namechar(next()) || areAValidEscape(next(1), next(2))) {
const token = new HashToken("");
if (wouldStartAnIdentifier(next(1), next(2), next(3))) token.type = "id";
token.value = consumeAName();
return token;
} else return new DelimToken(code);
else if (code === 36) if (next() === 61) {
consume();
return new SuffixMatchToken();
} else return new DelimToken(code);
else if (code === 39) return consumeAStringToken();
else if (code === 40) return new OpenParenToken();
else if (code === 41) return new CloseParenToken();
else if (code === 42) if (next() === 61) {
consume();
return new SubstringMatchToken();
} else return new DelimToken(code);
else if (code === 43) if (startsWithANumber()) {
reconsume();
return consumeANumericToken();
} else return new DelimToken(code);
else if (code === 44) return new CommaToken();
else if (code === 45) if (startsWithANumber()) {
reconsume();
return consumeANumericToken();
} else if (next(1) === 45 && next(2) === 62) {
consume(2);
return new CDCToken();
} else if (startsWithAnIdentifier()) {
reconsume();
return consumeAnIdentlikeToken();
} else return new DelimToken(code);
else if (code === 46) if (startsWithANumber()) {
reconsume();
return consumeANumericToken();
} else return new DelimToken(code);
else if (code === 58) return new ColonToken();
else if (code === 59) return new SemicolonToken();
else if (code === 60) if (next(1) === 33 && next(2) === 45 && next(3) === 45) {
consume(3);
return new CDOToken();
} else return new DelimToken(code);
else if (code === 64) if (wouldStartAnIdentifier(next(1), next(2), next(3))) return new AtKeywordToken(consumeAName());
else return new DelimToken(code);
else if (code === 91) return new OpenSquareToken();
else if (code === 92) if (startsWithAValidEscape()) {
reconsume();
return consumeAnIdentlikeToken();
} else {
parseerror();
return new DelimToken(code);
}
else if (code === 93) return new CloseSquareToken();
else if (code === 94) if (next() === 61) {
consume();
return new PrefixMatchToken();
} else return new DelimToken(code);
else if (code === 123) return new OpenCurlyToken();
else if (code === 124) if (next() === 61) {
consume();
return new DashMatchToken();
} else if (next() === 124) {
consume();
return new ColumnToken();
} else return new DelimToken(code);
else if (code === 125) return new CloseCurlyToken();
else if (code === 126) if (next() === 61) {
consume();
return new IncludeMatchToken();
} else return new DelimToken(code);
else if (digit(code)) {
reconsume();
return consumeANumericToken();
} else if (namestartchar(code)) {
reconsume();
return consumeAnIdentlikeToken();
} else if (eof()) return new EOFToken();
else return new DelimToken(code);
};
const consumeComments = function() {
while (next(1) === 47 && next(2) === 42) {
consume(2);
while (true) {
consume();
if (code === 42 && next() === 47) {
consume();
break;
} else if (eof()) {
parseerror();
return;
}
}
}
};
const consumeANumericToken = function() {
const num = consumeANumber();
if (wouldStartAnIdentifier(next(1), next(2), next(3))) {
const token = new DimensionToken();
token.value = num.value;
token.repr = num.repr;
token.type = num.type;
token.unit = consumeAName();
return token;
} else if (next() === 37) {
consume();
const token = new PercentageToken();
token.value = num.value;
token.repr = num.repr;
return token;
} else {
const token = new NumberToken();
token.value = num.value;
token.repr = num.repr;
token.type = num.type;
return token;
}
};
const consumeAnIdentlikeToken = function() {
const str = consumeAName();
if (str.toLowerCase() === "url" && next() === 40) {
consume();
while (whitespace(next(1)) && whitespace(next(2))) consume();
if (next() === 34 || next() === 39) return new FunctionToken(str);
else if (whitespace(next()) && (next(2) === 34 || next(2) === 39)) return new FunctionToken(str);
else return consumeAURLToken();
} else if (next() === 40) {
consume();
return new FunctionToken(str);
} else return new IdentToken(str);
};
const consumeAStringToken = function(endingCodePoint) {
if (endingCodePoint === void 0) endingCodePoint = code;
let string = "";
while (consume()) if (code === endingCodePoint || eof()) return new StringToken(string);
else if (newline(code)) {
parseerror();
reconsume();
return new BadStringToken();
} else if (code === 92) if (eof(next())) donothing();
else if (newline(next())) consume();
else string += stringFromCode(consumeEscape());
else string += stringFromCode(code);
throw new Error("Internal error");
};
const consumeAURLToken = function() {
const token = new URLToken("");
while (whitespace(next())) consume();
if (eof(next())) return token;
while (consume()) if (code === 41 || eof()) return token;
else if (whitespace(code)) {
while (whitespace(next())) consume();
if (next() === 41 || eof(next())) {
consume();
return token;
} else {
consumeTheRemnantsOfABadURL();
return new BadURLToken();
}
} else if (code === 34 || code === 39 || code === 40 || nonprintable(code)) {
parseerror();
consumeTheRemnantsOfABadURL();
return new BadURLToken();
} else if (code === 92) if (startsWithAValidEscape()) token.value += stringFromCode(consumeEscape());
else {
parseerror();
consumeTheRemnantsOfABadURL();
return new BadURLToken();
}
else token.value += stringFromCode(code);
throw new Error("Internal error");
};
const consumeEscape = function() {
consume();
if (hexdigit(code)) {
const digits = [code];
for (let total = 0; total < 5; total++) if (hexdigit(next())) {
consume();
digits.push(code);
} else break;
if (whitespace(next())) consume();
let value = Number.parseInt(digits.map((x) => {
return String.fromCharCode(x);
}).join(""), 16);
if (value > maximumallowedcodepoint) value = 65533;
return value;
} else if (eof()) return 65533;
else return code;
};
const areAValidEscape = function(c1, c2) {
if (c1 !== 92) return false;
if (newline(c2)) return false;
return true;
};
const startsWithAValidEscape = function() {
return areAValidEscape(code, next());
};
const wouldStartAnIdentifier = function(c1, c2, c3) {
if (c1 === 45) return namestartchar(c2) || c2 === 45 || areAValidEscape(c2, c3);
else if (namestartchar(c1)) return true;
else if (c1 === 92) return areAValidEscape(c1, c2);
else return false;
};
const startsWithAnIdentifier = function() {
return wouldStartAnIdentifier(code, next(1), next(2));
};
const wouldStartANumber = function(c1, c2, c3) {
if (c1 === 43 || c1 === 45) {
if (digit(c2)) return true;
if (c2 === 46 && digit(c3)) return true;
return false;
} else if (c1 === 46) {
if (digit(c2)) return true;
return false;
} else if (digit(c1)) return true;
else return false;
};
const startsWithANumber = function() {
return wouldStartANumber(code, next(1), next(2));
};
const consumeAName = function() {
let result = "";
while (consume()) if (namechar(code)) result += stringFromCode(code);
else if (startsWithAValidEscape()) result += stringFromCode(consumeEscape());
else {
reconsume();
return result;
}
throw new Error("Internal parse error");
};
const consumeANumber = function() {
let repr = "";
let type = "integer";
if (next() === 43 || next() === 45) {
consume();
repr += stringFromCode(code);
}
while (digit(next())) {
consume();
repr += stringFromCode(code);
}
if (next(1) === 46 && digit(next(2))) {
consume();
repr += stringFromCode(code);
consume();
repr += stringFromCode(code);
type = "number";
while (digit(next())) {
consume();
repr += stringFromCode(code);
}
}
const c1 = next(1);
const c2 = next(2);
const c3 = next(3);
if ((c1 === 69 || c1 === 101) && digit(c2)) {
consume();
repr += stringFromCode(code);
consume();
repr += stringFromCode(code);
type = "number";
while (digit(next())) {
consume();
repr += stringFromCode(code);
}
} else if ((c1 === 69 || c1 === 101) && (c2 === 43 || c2 === 45) && digit(c3)) {
consume();
repr += stringFromCode(code);
consume();
repr += stringFromCode(code);
consume();
repr += stringFromCode(code);
type = "number";
while (digit(next())) {
consume();
repr += stringFromCode(code);
}
}
const value = convertAStringToANumber(repr);
return {
type,
value,
repr
};
};
const convertAStringToANumber = function(string) {
return +string;
};
const consumeTheRemnantsOfABadURL = function() {
while (consume()) if (code === 41 || eof()) return;
else if (startsWithAValidEscape()) {
consumeEscape();
donothing();
} else donothing();
};
let iterationCount = 0;
while (!eof(next())) {
tokens.push(consumeAToken());
iterationCount++;
if (iterationCount > str.length * 2) throw new Error("I'm infinite-looping!");
}
return tokens;
}
var CSSParserToken = class {
constructor() {
_defineProperty(this, "tokenType", "");
_defineProperty(this, "value", void 0);
}
toJSON() {
return { token: this.tokenType };
}
toString() {
return this.tokenType;
}
toSource() {
return `${this}`;
}
};
var BadStringToken = class extends CSSParserToken {
constructor(..._args) {
super(..._args);
_defineProperty(this, "tokenType", "BADSTRING");
}
};
var BadURLToken = class extends CSSParserToken {
constructor(..._args2) {
super(..._args2);
_defineProperty(this, "tokenType", "BADURL");
}
};
var WhitespaceToken = class extends CSSParserToken {
constructor(..._args3) {
super(..._args3);
_defineProperty(this, "tokenType", "WHITESPACE");
}
toString() {
return "WS";
}
toSource() {
return " ";
}
};
var CDOToken = class extends CSSParserToken {
constructor(..._args4) {
super(..._args4);
_defineProperty(this, "tokenType", "CDO");
}
toSource() {
return "<!--";
}
};
var CDCToken = class extends CSSParserToken {
constructor(..._args5) {
super(..._args5);
_defineProperty(this, "tokenType", "CDC");
}
toSource() {
return "-->";
}
};
var ColonToken = class extends CSSParserToken {
constructor(..._args6) {
super(..._args6);
_defineProperty(this, "tokenType", ":");
}
};
var SemicolonToken = class extends CSSParserToken {
constructor(..._args7) {
super(..._args7);
_defineProperty(this, "tokenType", ";");
}
};
var CommaToken = class extends CSSParserToken {
constructor(..._args8) {
super(..._args8);
_defineProperty(this, "tokenType", ",");
}
};
var GroupingToken = class extends CSSParserToken {
constructor(..._args9) {
super(..._args9);
_defineProperty(this, "value", "");
_defineProperty(this, "mirror", "");
}
};
var OpenCurlyToken = class extends GroupingToken {
constructor() {
super();
_defineProperty(this, "tokenType", "{");
this.value = "{";
this.mirror = "}";
}
};
var CloseCurlyToken = class extends GroupingToken {
constructor() {
super();
_defineProperty(this, "tokenType", "}");
this.value = "}";
this.mirror = "{";
}
};
var OpenSquareToken = class extends GroupingToken {
constructor() {
super();
_defineProperty(this, "tokenType", "[");
this.value = "[";
this.mirror = "]";
}
};
var CloseSquareToken = class extends GroupingToken {
constructor() {
super();
_defineProperty(this, "tokenType", "]");
this.value = "]";
this.mirror = "[";
}
};
var OpenParenToken = class extends GroupingToken {
constructor() {
super();
_defineProperty(this, "tokenType", "(");
this.value = "(";
this.mirror = ")";
}
};
var CloseParenToken = class extends GroupingToken {
constructor() {
super();
_defineProperty(this, "tokenType", ")");
this.value = ")";
this.mirror = "(";
}
};
var IncludeMatchToken = class extends CSSParserToken {
constructor(..._args10) {
super(..._args10);
_defineProperty(this, "tokenType", "~=");
}
};
var DashMatchToken = class extends CSSParserToken {
constructor(..._args11) {
super(..._args11);
_defineProperty(this, "tokenType", "|=");
}
};
var PrefixMatchToken = class extends CSSParserToken {
constructor(..._args12) {
super(..._args12);
_defineProperty(this, "tokenType", "^=");
}
};
var SuffixMatchToken = class extends CSSParserToken {
constructor(..._args13) {
super(..._args13);
_defineProperty(this, "tokenType", "$=");
}
};
var SubstringMatchToken = class extends CSSParserToken {
constructor(..._args14) {
super(..._args14);
_defineProperty(this, "tokenType", "*=");
}
};
var ColumnToken = class extends CSSParserToken {
constructor(..._args15) {
super(..._args15);
_defineProperty(this, "tokenType", "||");
}
};
var EOFToken = class extends CSSParserToken {
constructor(..._args16) {
super(..._args16);
_defineProperty(this, "tokenType", "EOF");
}
toSource() {
return "";
}
};
var DelimToken = class extends CSSParserToken {
constructor(code) {
super();
_defineProperty(this, "tokenType", "DELIM");
_defineProperty(this, "value", "");
this.value = stringFromCode(code);
}
toString() {
return `DELIM(${this.value})`;
}
toJSON() {
const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
json.value = this.value;
return json;
}
toSource() {
if (this.value === "\\") return "\\\n";
else return this.value;
}
};
var StringValuedToken = class extends CSSParserToken {
constructor(..._args17) {
super(..._args17);
_defineProperty(this, "value", "");
}
ASCIIMatch(str) {
return this.value.toLowerCase() === str.toLowerCase();
}
toJSON() {
const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
json.value = this.value;
return json;
}
};
var IdentToken = class extends StringValuedToken {
constructor(val) {
super();
_defineProperty(this, "tokenType", "IDENT");
this.value = val;
}
toString() {
return `IDENT(${this.value})`;
}
toSource() {
return escapeIdent(this.value);
}
};
var FunctionToken = class extends StringValuedToken {
constructor(val) {
super();
_defineProperty(this, "tokenType", "FUNCTION");
_defineProperty(this, "mirror", void 0);
this.value = val;
this.mirror = ")";
}
toString() {
return `FUNCTION(${this.value})`;
}
toSource() {
return `${escapeIdent(this.value)}(`;
}
};
var AtKeywordToken = class extends StringValuedToken {
constructor(val) {
super();
_defineProperty(this, "tokenType", "AT-KEYWORD");
this.value = val;
}
toString() {
return `AT(${this.value})`;
}
toSource() {
return `@${escapeIdent(this.value)}`;
}
};
var HashToken = class extends StringValuedToken {
constructor(val) {
super();
_defineProperty(this, "tokenType", "HASH");
_defineProperty(this, "type", void 0);
this.value = val;
this.type = "unrestricted";
}
toString() {
return `HASH(${this.value})`;
}
toJSON() {
const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
json.value = this.value;
json.type = this.type;
return json;
}
toSource() {
if (this.type === "id") return `#${escapeIdent(this.value)}`;
else return `#${escapeHash(this.value)}`;
}
};
var StringToken = class extends StringValuedToken {
constructor(val) {
super();
_defineProperty(this, "tokenType", "STRING");
this.value = val;
}
toString() {
return `"${escapeString(this.value)}"`;
}
};
var URLToken = class extends StringValuedToken {
constructor(val) {
super();
_defineProperty(this, "tokenType", "URL");
this.value = val;
}
toString() {
return `URL(${this.value})`;
}
toSource() {
return `url("${escapeString(this.value)}")`;
}
};
var NumberToken = class extends CSSParserToken {
constructor() {
super();
_defineProperty(this, "tokenType", "NUMBER");
_defineProperty(this, "type", void 0);
_defineProperty(this, "repr", void 0);
this.type = "integer";
this.repr = "";
}
toString() {
if (this.type === "integer") return `INT(${this.value})`;
return `NUMBER(${this.value})`;
}
toJSON() {
const json = super.toJSON();
json.value = this.value;
json.type = this.type;
json.repr = this.repr;
return json;
}
toSource() {
return this.repr;
}
};
var PercentageToken = class extends CSSParserToken {
constructor() {
super();
_defineProperty(this, "tokenType", "PERCENTAGE");
_defineProperty(this, "repr", void 0);
this.repr = "";
}
toString() {
return `PERCENTAGE(${this.value})`;
}
toJSON() {
const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
json.value = this.value;
json.repr = this.repr;
return json;
}
toSource() {
return `${this.repr}%`;
}
};
var DimensionToken = class extends CSSParserToken {
constructor() {
super();
_defineProperty(this, "tokenType", "DIMENSION");
_defineProperty(this, "type", void 0);
_defineProperty(this, "repr", void 0);
_defineProperty(this, "unit", void 0);
this.type = "integer";
this.repr = "";
this.unit = "";
}
toString() {
return `DIM(${this.value},${this.unit})`;
}
toJSON() {
const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
json.value = this.value;
json.type = this.type;
json.repr = this.repr;
json.unit = this.unit;
return json;
}
toSource() {
const source = this.repr;
let unit = escapeIdent(this.unit);
if (unit[0].toLowerCase() === "e" && (unit[1] === "-" || between(unit.charCodeAt(1), 48, 57))) unit = `\\65 ${unit.slice(1, unit.length)}`;
return source + unit;
}
};
function escapeIdent(string) {
string = `${string}`;
let result = "";
const firstcode = string.charCodeAt(0);
for (let i = 0; i < string.length; i++) {
const code = string.charCodeAt(i);
if (code === 0) throw new InvalidCharacterError("Invalid character: the input contains U+0000.");
if (between(code, 1, 31) || code === 127 || i === 0 && between(code, 48, 57) || i === 1 && between(code, 48, 57) && firstcode === 45) result += `\\${code.toString(16)} `;
else if (code >= 128 || code === 45 || code === 95 || between(code, 48, 57) || between(code, 65, 90) || between(code, 97, 122)) result += string[i];
else result += `\\${string[i]}`;
}
return result;
}
function escapeHash(string) {
string = `${string}`;
let result = "";
for (let i = 0; i < string.length; i++) {
const code = string.charCodeAt(i);
if (code === 0) throw new InvalidCharacterError("Invalid character: the input contains U+0000.");
if (code >= 128 || code === 45 || code === 95 || between(code, 48, 57) || between(code, 65, 90) || between(code, 97, 122)) result += string[i];
else result += `\\${code.toString(16)} `;
}
return result;
}
function escapeString(string) {
string = `${string}`;
let result = "";
for (let i = 0; i < string.length; i++) {
const code = string.charCodeAt(i);
if (code === 0) throw new InvalidCharacterError("Invalid character: the input contains U+0000.");
if (between(code, 1, 31) || code === 127) result += `\\${code.toString(16)} `;
else if (code === 34 || code === 92) result += `\\${string[i]}`;
else result += string[i];
}
return result;
}
//#endregion
//#region src/cssParser.ts
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var InvalidSelectorError = class extends Error {};
function parseCSS(selector, customNames) {
let tokens;
try {
tokens = tokenize(selector);
if (!(tokens[tokens.length - 1] instanceof EOFToken)) tokens.push(new EOFToken());
} catch (e) {
const newMessage = `${e.message} while parsing selector "${selector}"`;
const index = (e.stack || "").indexOf(e.message);
if (index !== -1) e.stack = e.stack.substring(0, index) + newMessage + e.stack.substring(index + e.message.length);
e.message = newMessage;
throw e;
}
const unsupportedToken = tokens.find((token) => {
return token instanceof AtKeywordToken || token instanceof BadStringToken || token instanceof BadURLToken || token instanceof ColumnToken || token instanceof CDOToken || token instanceof CDCToken || token instanceof SemicolonToken || token instanceof OpenCurlyToken || token instanceof CloseCurlyToken || token instanceof URLToken || token instanceof PercentageToken;
});
if (unsupportedToken) throw new InvalidSelectorError(`Unsupported token "${unsupportedToken.toSource()}" while parsing selector "${selector}"`);
let pos = 0;
const names = /* @__PURE__ */ new Set();
function unexpected() {
return new InvalidSelectorError(`Unexpected token "${tokens[pos].toSource()}" while parsing selector "${selector}"`);
}
function skipWhitespace() {
while (tokens[pos] instanceof WhitespaceToken) pos++;
}
function isIdent(p = pos) {
return tokens[p] instanceof IdentToken;
}
function isString(p = pos) {
return tokens[p] instanceof StringToken;
}
function isNumber(p = pos) {
return tokens[p] instanceof NumberToken;
}
function isComma(p = pos) {
return tokens[p] instanceof CommaToken;
}
function isOpenParen(p = pos) {
return tokens[p] instanceof OpenParenToken;
}
function isCloseParen(p = pos) {
return tokens[p] instanceof CloseParenToken;
}
function isFunction(p = pos) {
return tokens[p] instanceof FunctionToken;
}
function isStar(p = pos) {
return tokens[p] instanceof DelimToken && tokens[p].value === "*";
}
function isEOF(p = pos) {
return tokens[p] instanceof EOFToken;
}
function isClauseCombinator(p = pos) {
return tokens[p] instanceof DelimToken && [
">",
"+",
"~"
].includes(tokens[p].value);
}
function isSelectorClauseEnd(p = pos) {
return isComma(p) || isCloseParen(p) || isEOF(p) || isClauseCombinator(p) || tokens[p] instanceof WhitespaceToken;
}
function consumeFunctionArguments() {
const result = [consumeArgument()];
while (true) {
skipWhitespace();
if (!isComma()) break;
pos++;
result.push(consumeArgument());
}
return result;
}
function consumeArgument() {
skipWhitespace();
if (isNumber()) return tokens[pos++].value;
if (isString()) return tokens[pos++].value;
return consumeComplexSelector();
}
function consumeComplexSelector() {
const result = { simples: [] };
skipWhitespace();
if (isClauseCombinator()) result.simples.push({
selector: { functions: [{
name: "scope",
args: []
}] },
combinator: ""
});
else result.simples.push({
selector: consumeSimpleSelector(),
combinator: ""
});
while (true) {
skipWhitespace();
if (isClauseCombinator()) {
result.simples[result.simples.length - 1].combinator = tokens[pos++].value;
skipWhitespace();
} else if (isSelectorClauseEnd()) break;
result.simples.push({
combinator: "",
selector: consumeSimpleSelector()
});
}
return result;
}
function consumeSimpleSelector() {
let rawCSSString = "";
const functions = [];
while (!isSelectorClauseEnd()) if (isIdent() || isStar()) rawCSSString += tokens[pos++].toSource();
else if (tokens[pos] instanceof HashToken) rawCSSString += tokens[pos++].toSource();
else if (tokens[pos] instanceof DelimToken && tokens[pos].value === ".") {
pos++;
if (isIdent()) rawCSSString += `.${tokens[pos++].toSource()}`;
else throw unexpected();
} else if (tokens[pos] instanceof ColonToken) {
pos++;
if (isIdent()) if (!customNames.has(tokens[pos].value.toLowerCase())) rawCSSString += `:${tokens[pos++].toSource()}`;
else {
const name = tokens[pos++].value.toLowerCase();
functions.push({
name,
args: []
});
names.add(name);
}
else if (isFunction()) {
const name = tokens[pos++].value.toLowerCase();
if (!customNames.has(name)) rawCSSString += `:${name}(${consumeBuiltinFunctionArguments()})`;
else {
functions.push({
name,
args: consumeFunctionArguments()
});
names.add(name);
}
skipWhitespace();
if (!isCloseParen()) throw unexpected();
pos++;
} else throw unexpected();
} else if (tokens[pos] instanceof OpenSquareToken) {
rawCSSString += "[";
pos++;
while (!(tokens[pos] instanceof CloseSquareToken) && !isEOF()) rawCSSString += tokens[pos++].toSource();
if (!(tokens[pos] instanceof CloseSquareToken)) throw unexpected();
rawCSSString += "]";
pos++;
} else throw unexpected();
if (!rawCSSString && !functions.length) throw unexpected();
return {
css: rawCSSString || void 0,
functions
};
}
function consumeBuiltinFunctionArguments() {
let s = "";
let balance = 1;
while (!isEOF()) {
if (isOpenParen() || isFunction()) balance++;
if (isCloseParen()) balance--;
if (!balance) break;
s += tokens[pos++].toSource();
}
return s;
}
const result = consumeFunctionArguments();
if (!isEOF()) throw unexpected();
if (result.some((arg) => typeof arg !== "object" || !("simples" in arg))) throw new InvalidSelectorError(`Error while parsing selector "${selector}"`);
return {
selector: result,
names: Array.from(names)
};
}
//#endregion
//#region src/selectorParser.ts
const kNestedSelectorNames = new Set([
"internal:has",
"internal:has-not",
"internal:and",
"internal:or",
"internal:chain",
"left-of",
"right-of",
"above",
"below",
"near"
]);
const kNestedSelectorNamesWithDistance = new Set([
"left-of",
"right-of",
"above",
"below",
"near"
]);
const customCSSNames = new Set([
"not",
"is",
"where",
"has",
"scope",
"light",
"visible",
"text",
"text-matches",
"text-is",
"has-text",
"above",
"below",
"right-of",
"left-of",
"near",
"nth-match"
]);
function parseSelector(selector) {
const parsedStrings = parseSelectorString(selector);
const parts = [];
for (const part of parsedStrings.parts) {
if (part.name === "css" || part.name === "css:light") {
if (part.name === "css:light") part.body = `:light(${part.body})`;
const parsedCSS = parseCSS(part.body, customCSSNames);
parts.push({
name: "css",
body: parsedCSS.selector,
source: part.body
});
continue;
}
if (kNestedSelectorNames.has(part.name)) {
let innerSelector;
let distance;
try {
const unescaped = JSON.parse(`[${part.body}]`);
if (!Array.isArray(unescaped) || unescaped.length < 1 || unescaped.length > 2 || typeof unescaped[0] !== "string") throw new InvalidSelectorError(`Malformed selector: ${part.name}=${part.body}`);
innerSelector = unescaped[0];
if (unescaped.length === 2) {
if (typeof unescaped[1] !== "number" || !kNestedSelectorNamesWithDistance.has(part.name)) throw new InvalidSelectorError(`Malformed selector: ${part.name}=${part.body}`);
distance = unescaped[1];
}
} catch (e) {
throw new InvalidSelectorError(`Malformed selector: ${part.name}=${part.body}`);
}
const nested = {
name: part.name,
source: part.body,
body: {
parsed: parseSelector(innerSelector),
distance
}
};
const lastFrame = [...nested.body.parsed.parts].reverse().find((part) => part.name === "internal:control" && part.body === "enter-frame");
const lastFrameIndex = lastFrame ? nested.body.parsed.parts.indexOf(lastFrame) : -1;
if (lastFrameIndex !== -1 && selectorPartsEqual(nested.body.parsed.parts.slice(0, lastFrameIndex + 1), parts.slice(0, lastFrameIndex + 1))) nested.body.parsed.parts.splice(0, lastFrameIndex + 1);
parts.push(nested);
continue;
}
parts.push({
...part,
source: part.body
});
}
if (kNestedSelectorNames.has(parts[0].name)) throw new InvalidSelectorError(`"${parts[0].name}" selector cannot be first`);
return {
capture: parsedStrings.capture,
parts
};
}
function selectorPartsEqual(list1, list2) {
return stringifySelector({ parts: list1 }) === stringifySelector({ parts: list2 });
}
function stringifySelector(selector, forceEngineName) {
if (typeof selector === "string") return selector;
return selector.parts.map((p, i) => {
let includeEngine = true;
if (!forceEngineName && i !== selector.capture) {
if (p.name === "css") includeEngine = false;
else if (p.name === "xpath" && p.source.startsWith("//") || p.source.startsWith("..")) includeEngine = false;
}
const prefix = includeEngine ? `${p.name}=` : "";
return `${i === selector.capture ? "*" : ""}${prefix}${p.source}`;
}).join(" >> ");
}
function visitAllSelectorParts(selector, visitor) {
const visit = (selector, nested) => {
for (const part of selector.parts) {
visitor(part, nested);
if (kNestedSelectorNames.has(part.name)) visit(part.body.parsed, true);
}
};
visit(selector, false);
}
function parseSelectorString(selector) {
let index = 0;
let quote;
let start = 0;
const result = { parts: [] };
const append = () => {
const part = selector.substring(start, index).trim();
const eqIndex = part.indexOf("=");
let name;
let body;
if (eqIndex !== -1 && part.substring(0, eqIndex).trim().match(/^[\w\-+:*]+$/)) {
name = part.substring(0, eqIndex).trim();
body = part.substring(eqIndex + 1);
} else if (part.length > 1 && part[0] === "\"" && part[part.length - 1] === "\"") {
name = "text";
body = part;
} else if (part.length > 1 && part[0] === "'" && part[part.length - 1] === "'") {
name = "text";
body = part;
} else if (/^\(*\/\//.test(part) || part.startsWith("..")) {
name = "xpath";
body = part;
} else {
name = "css";
body = part;
}
let capture = false;
if (name[0] === "*") {
capture = true;
name = name.substring(1);
}
result.parts.push({
name,
body
});
if (capture) {
if (result.capture !== void 0) throw new InvalidSelectorError(`Only one of the selectors can capture using * modifier`);
result.capture = result.parts.length - 1;
}
};
if (!selector.includes(">>")) {
index = selector.length;
append();
return result;
}
const shouldIgnoreTextSelectorQuote = () => {
const match = selector.substring(start, index).match(/^\s*text\s*=(.*)$/);
return !!match && !!match[1];
};
while (index < selector.length) {
const c = selector[index];
if (c === "\\" && index + 1 < selector.length) index += 2;
else if (c === quote) {
quote = void 0;
index++;
} else if (!quote && (c === "\"" || c === "'" || c === "`") && !shouldIgnoreTextSelectorQuote()) {
quote = c;
index++;
} else if (!quote && c === ">" && selector[index + 1] === ">") {
append();
index += 2;
start = index;
} else index++;
}
append();
return result;
}
function parseAttributeSelector(selector, allowUnquotedStrings) {
let wp = 0;
let EOL = selector.length === 0;
const next = () => selector[wp] || "";
const eat1 = () => {
const result = next();
++wp;
EOL = wp >= selector.length;
return result;
};
const syntaxError = (stage) => {
if (EOL) throw new InvalidSelectorError(`Unexpected end of selector while parsing selector \`${selector}\``);
throw new InvalidSelectorError(`Error while parsing selector \`${selector}\` - unexpected symbol "${next()}" at position ${wp}${stage ? ` during ${stage}` : ""}`);
};
function skipSpaces() {
while (!EOL && /\s/.test(next())) eat1();
}
function isCSSNameChar(char) {
return char >= "" || char >= "0" && char <= "9" || char >= "A" && char <= "Z" || char >= "a" && char <= "z" || char >= "0" && char <= "9" || char === "_" || char === "-";
}
function readIdentifier() {
let result = "";
skipSpaces();
while (!EOL && isCSSNameChar(next())) result += eat1();
return result;
}
function readQuotedString(quote) {
let result = eat1();
if (result !== quote) syntaxError("parsing quoted string");
while (!EOL && next() !== quote) {
if (next() === "\\") eat1();
result += eat1();
}
if (next() !== quote) syntaxError("parsing quoted string");
result += eat1();
return result;
}
function readRegularExpression() {
if (eat1() !== "/") syntaxError("parsing regular expression");
let source = "";
let inClass = false;
while (!EOL) {
if (next() === "\\") {
source += eat1();
if (EOL) syntaxError("parsing regular expression");
} else if (inClass && next() === "]") inClass = false;
else if (!inClass && next() === "[") inClass = true;
else if (!inClass && next() === "/") break;
source += eat1();
}
if (eat1() !== "/") syntaxError("parsing regular expression");
let flags = "";
while (!EOL && next().match(/[dgimsuy]/)) flags += eat1();
try {
return new RegExp(source, flags);
} catch (e) {
throw new InvalidSelectorError(`Error while parsing selector \`${selector}\`: ${e.message}`);
}
}
function readAttributeToken() {
let token = "";
skipSpaces();
if (next() === `'` || next() === `"`) token = readQuotedString(next()).slice(1, -1);
else token = readIdentifier();
if (!token) syntaxError("parsing property path");
return token;
}
function readOperator() {
skipSpaces();
let op = "";
if (!EOL) op += eat1();
if (!EOL && op !== "=") op += eat1();
if (![
"=",
"*=",
"^=",
"$=",
"|=",
"~="
].includes(op)) syntaxError("parsing operator");
return op;
}
function readAttribute() {
eat1();
const jsonPath = [];
jsonPath.push(readAttributeToken());
skipSpaces();
while (next() === ".") {
eat1();
jsonPath.push(readAttributeToken());
skipSpaces();
}
if (next() === "]") {
eat1();
return {
name: jsonPath.join("."),
jsonPath,
op: "<truthy>",
value: null,
caseSensitive: false
};
}
const operator = readOperator();
let value;
let caseSensitive = true;
skipSpaces();
if (next() === "/") {
if (operator !== "=") throw new InvalidSelectorError(`Error while parsing selector \`${selector}\` - cannot use ${operator} in attribute with regular expression`);
value = readRegularExpression();
} else if (next() === `'` || next() === `"`) {
value = readQuotedString(next()).slice(1, -1);
skipSpaces();
if (next() === "i" || next() === "I") {
caseSensitive = false;
eat1();
} else if (next() === "s" || next() === "S") {
caseSensitive = true;
eat1();
}
} else {
value = "";
while (!EOL && (isCSSNameChar(next()) || next() === "+" || next() === ".")) value += eat1();
if (value === "true") value = true;
else if (value === "false") value = false;
else if (!allowUnquotedStrings) {
value = +value;
if (Number.isNaN(value)) syntaxError("parsing attribute value");
}
}
skipSpaces();
if (next() !== "]") syntaxError("parsing attribute value");
eat1();
if (operator !== "=" && typeof value !== "string") throw new InvalidSelectorError(`Error while parsing selector \`${selector}\` - cannot use ${operator} in attribute with non-string matching value - ${value}`);
return {
name: jsonPath.join("."),
jsonPath,
op: operator,
value,
caseSensitive
};
}
const result = {
name: "",
attributes: []
};
result.name = readIdentifier();
skipSpaces();
while (next() === "[") {
result.attributes.push(readAttribute());
skipSpaces();
}
if (!EOL) syntaxError(void 0);
if (!result.name && !result.attributes.length) throw new InvalidSelectorError(`Error while parsing selector \`${selector}\` - selector cannot be empty`);
return result;
}
//#endregion
//#region src/stringUtils.ts
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function escapeWithQuotes(text, char = "'") {
const stringified = JSON.stringify(text);
const escapedText = stringified.substring(1, stringified.length - 1).replace(/\\"/g, "\"");
if (char === "'") return char + escapedText.replace(/'/g, "\\'") + char;
if (char === "\"") return char + escapedText.replace(/"/g, "\\\"") + char;
if (char === "`") return char + escapedText.replace(/`/g, "`") + char;
throw new Error("Invalid escape char");
}
function cssEscape(s) {
let result = "";
for (let i = 0; i < s.length; i++) result += cssEscapeOne(s, i);
return result;
}
function quoteCSSAttributeValue(text) {
return `"${cssEscape(text).replace(/\\ /g, " ")}"`;
}
function cssEscapeOne(s, i) {
const c = s.charCodeAt(i);
if (c === 0) return "�";
if (c >= 1 && c <= 31 || c >= 48 && c <= 57 && (i === 0 || i === 1 && s.charCodeAt(0) === 45)) return `\\${c.toString(16)} `;
if (i === 0 && c === 45 && s.length === 1) return `\\${s.charAt(i)}`;
if (c >= 128 || c === 45 || c === 95 || c >= 48 && c <= 57 || c >= 65 && c <= 90 || c >= 97 && c <= 122) return s.charAt(i);
return `\\${s.charAt(i)}`;
}
function normalizeWhiteSpace(text) {
return text.replace(/[\u200b\u00ad]/g, "").trim().replace(/\s+/g, " ");
}
function normalizeEscapedRegexQuotes(source) {
return source.replace(/(^|[^\\])(\\\\)*\\(['"`])/g, "$1$2$3");
}
function escapeRegexForSelector(re) {
if (re.unicode || re.unicodeSets) return String(re);
return String(re).replace(/(^|[^\\])(\\\\)*(["'`])/g, "$1$2\\$3").replace(/>>/g, "\\>\\>");
}
function escapeForTextSelector(text, exact) {
if (typeof text !== "string") return escapeRegexForSelector(text);
return `${JSON.stringify(text)}${exact ? "s" : "i"}`;
}
function escapeForAttributeSelector(value, exact) {
if (typeof value !== "string") return escapeRegexForSelector(value);
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"${exact ? "s" : "i"}`;
}
function trimString(input, cap, suffix = "") {
if (input.length <= cap) return input;
const chars = [...input];
if (chars.length > cap) return chars.slice(0, cap - suffix.length).join("") + suffix;
return chars.join("");
}
function trimStringWithEllipsis(input, cap) {
return trimString(input, cap, "…");
}
function escapeRegExp(s) {
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
//#endregion
//#region src/domUtils.ts
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function parentElementOrShadowHost(element) {
if (element.parentElement) return element.parentElement;
if (!element.parentNode) return;
if (element.parentNode.nodeType === 11 && element.parentNode.host) return element.parentNode.host;
}
function enclosingShadowRootOrDocument(element) {
let node = element;
while (node.parentNode) node = node.parentNode;
if (node.nodeType === 11 || node.nodeType === 9) return node;
}
function enclosingShadowHost(element) {
while (element.parentElement) element = element.parentElement;
return parentElementOrShadowHost(element);
}
function closestCrossShadow(element, css) {
while (element) {
const closest = element.closest(css);
if (closest) return closest;
element = enclosingShadowHost(element);
}
}
function getElementComputedStyle(element, pseudo) {
return element.ownerDocument && element.ownerDocument.defaultView ? element.ownerDocument.defaultView.getComputedStyle(element, pseudo) : void 0;
}
function isElementStyleVisibilityVisible(element, style) {
var _style;
style = (_style = style) !== null && _style !== void 0 ? _style : getElementComputedStyle(element);
if (!style) return true;
if (Element.prototype.checkVisibility && Ivya.options.browser !== "webkit") {
if (!element.checkVisibility()) return false;
} else {
const detailsOrSummary = element.closest("details,summary");
if (detailsOrSummary !== element && (detailsOrSummary === null || detailsOrSummary === void 0 ? void 0 : detailsOrSummary.nodeName) === "DETAILS" && !detailsOrSummary.open) return false;
}
if (style.visibility !== "visible") return false;
return true;
}
function isElementVisible(element) {
const style = getElementComputedStyle(element);
if (!style) return true;
if (style.display === "contents") {
for (let child = element.firstChild; child; child = child.nextSibling) {
if (child.nodeType === 1 && isElementVisible(child)) return true;
if (child.nodeType === 3 && isVisibleTextNode(child)) return true;
}
return false;
}
if (!isElementStyleVisibilityVisible(element, style)) return false;
const rect = element.getBoundingClientRect();
return rect.width > 0 && rect.height > 0;
}
function isVisibleTextNode(node) {
const range = node.ownerDocument.createRange();
range.selectNode(node);
const rect = range.getBoundingClientRect();
return rect.width > 0 && rect.height > 0;
}
function elementSafeTagName(element) {
if (element instanceof HTMLFormElement) return "FORM";
return element.tagName.toUpperCase();
}
//#endregion
//#region src/roleUtils.ts
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function hasExplicitAccessibleName(e) {
return e.hasAttribute("aria-label") || e.hasAttribute("aria-labelledby");
}
const kAncestorPreventingLandmark = "article:not([role]), aside:not([role]), main:not([role]), nav:not([role]), section:not([role]), [role=article], [role=complementary], [role=main], [role=navigation], [role=region]";
const kGlobalAriaAttributes = new Map([
["aria-atomic", void 0],
["aria-busy", void 0],
["aria-controls", void 0],
["aria-current", void 0],
["aria-describedby", void 0],
["aria-details", void 0],
["aria-dropeffect", void 0],
["aria-flowto", void 0],
["aria-grabbed", void 0],
["aria-hidden", void 0],
["aria-keyshortcuts", void 0],
["aria-label", new Set([
"caption",
"code",
"deletion",
"emphasis",
"generic",
"insertion",
"paragraph",
"presentation",
"strong",
"subscript",
"superscript"
])],
["aria-labelledby", new Set([
"caption",
"code",
"deletion",
"emphasis",
"generic",
"insertion",
"paragraph",
"presentation",
"strong",
"subscript",
"superscript"
])],
["aria-live", void 0],
["aria-owns", void 0],
["aria-relevant", void 0],
["aria-roledescription", new Set(["generic"])]
]);
function hasGlobalAriaAttribute(element, forRole) {
return [...kGlobalAriaAttributes].some(([attr, prohibited]) => {
return !(prohibited === null || prohibited === void 0 ? void 0 : prohibited.has(forRole || "")) && element.hasAttribute(attr);
});
}
function hasTabIndex(element) {
return !Number.isNaN(Number(String(element.getAttribute("tabindex"))));
}
function isFocusable(element) {
return !isNativelyDisabled(element) && (isNativelyFocusable(element) || hasTabIndex(element));
}
function isNativelyFocusable(element) {
const tagName = elementSafeTagName(element);
if ([
"BUTTON",
"DETAILS",
"SELECT",
"TEXTAREA"
].includes(tagName)) return true;
if (tagName === "A" || tagName === "AREA") return element.hasAttribute("href");
if (tagName === "INPUT") return !element.hidden;
return false;
}
const kImplicitRoleByTagName = {
A: (e) => {
return e.hasAttribute("href") ? "link" : null;
},
AREA: (e) => {
return e.hasAttribute("href") ? "link" : null;
},
ARTICLE: () => "article",
ASIDE: () => "complementary",
BLOCKQUOTE: () => "blockquote",
BUTTON: () => "button",
CAPTION: () => "caption",
CODE: () => "code",
DATALIST: () => "listbox",
DD: () => "definition",
DEL: () => "deletion",
DETAILS: () => "group",
DFN: () => "term",
DIALOG: () => "dialog",
DT: () => "term",
EM: () => "emphasis",
FIELDSET: () => "group",
FIGURE: () => "figure",
FOOTER: (e) => closestCrossShadow(e, kAncestorPreventingLandmark) ? null : "contentinfo",
FORM: (e) => hasExplicitAccessibleName(e) ? "form" : null,
H1: () => "heading",
H2: () => "heading",
H3: () => "heading",
H4: () => "heading",
H5: () => "heading",
H6: () => "heading",
HEADER: (e) => closestCrossShadow(e, kAncestorPreventingLandmark) ? null : "banner",
HR: () => "separator",
HTML: () => "document",
IMG: (e) => e.getAttribute("alt") === "" && !e.getAttribute("title") && !hasGlobalAriaAttribute(e) && !hasTabIndex(e) ? "presentation" : "img",
INPUT