Files
HomeAssistantVS/.storage/ha_mcp_tools/linkedom-0.18.13.js
T

12652 lines
403 KiB
JavaScript

(function () {
// used in Attr to signal changes
const CHANGED = Symbol('changed');
// used in Element to setup once classList
const CLASS_LIST = Symbol('classList');
// used in Document to attach once customElements
const CUSTOM_ELEMENTS = Symbol('CustomElements');
// used in HTMLTemplateElement
const CONTENT = Symbol('content');
// used in Element for data attributes
const DATASET = Symbol('dataset');
// used in Document to attach the DocType
const DOCTYPE = Symbol('doctype');
// used in parser and Document to attach once a DOMParser
const DOM_PARSER = Symbol('DOMParser');
// used to reference an end node
const END = Symbol('end');
// used in Document to make the globalThis an event target
const EVENT_TARGET = Symbol('EventTarget');
// used to augment a created document defaultView
const GLOBALS = Symbol('globals');
// used in both Canvas and Document to provide images
const IMAGE = Symbol('image');
// used to define Document mime type
const MIME = Symbol('mime');
// used in Document to attach once MutationObserver
const MUTATION_OBSERVER = Symbol('MutationObserver');
// used to define next node reference
const NEXT = Symbol('next');
// used to define Attr owner elements
const OWNER_ELEMENT = Symbol('ownerElement');
// used to define previous node reference
const PREV = Symbol('prev');
// used to define various "private" properties
const PRIVATE = Symbol('private');
// used to define the CSSStyleSheet.sheet
const SHEET = Symbol('sheet');
// used to define start node reference
const START = Symbol('start');
// used to define special CSS style attribute
const STYLE = Symbol('style');
// used to upgrade Custom Elements
const UPGRADE = Symbol('upgrade');
// used to define generic values
const VALUE = Symbol('value');
// Adapted from https://github.com/mathiasbynens/he/blob/36afe179392226cf1b6ccdb16ebbb7a5a844d93a/src/he.js#L106-L134
var _a;
const decodeMap = new Map([
[0, 65533],
// C1 Unicode control character reference replacements
[128, 8364],
[130, 8218],
[131, 402],
[132, 8222],
[133, 8230],
[134, 8224],
[135, 8225],
[136, 710],
[137, 8240],
[138, 352],
[139, 8249],
[140, 338],
[142, 381],
[145, 8216],
[146, 8217],
[147, 8220],
[148, 8221],
[149, 8226],
[150, 8211],
[151, 8212],
[152, 732],
[153, 8482],
[154, 353],
[155, 8250],
[156, 339],
[158, 382],
[159, 376],
]);
/**
* Polyfill for `String.fromCodePoint`. It is used to create a string from a Unicode code point.
*/
const fromCodePoint =
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, n/no-unsupported-features/es-builtins
(_a = String.fromCodePoint) !== null && _a !== void 0 ? _a : ((codePoint) => {
let output = "";
if (codePoint > 65535) {
codePoint -= 65536;
output += String.fromCharCode(((codePoint >>> 10) & 1023) | 55296);
codePoint = 56320 | (codePoint & 1023);
}
output += String.fromCharCode(codePoint);
return output;
});
/**
* Replace the given code point with a replacement character if it is a
* surrogate or is outside the valid range. Otherwise return the code
* point unchanged.
*/
function replaceCodePoint(codePoint) {
var _a;
if ((codePoint >= 55296 && codePoint <= 57343) ||
codePoint > 1114111) {
return 65533;
}
return (_a = decodeMap.get(codePoint)) !== null && _a !== void 0 ? _a : codePoint;
}
/*
* Shared base64 decode helper for generated decode data.
* Assumes global atob is available.
*/
function decodeBase64(input) {
const binary =
// eslint-disable-next-line n/no-unsupported-features/node-builtins
typeof atob === "function"
? // Browser (and Node >=16)
// eslint-disable-next-line n/no-unsupported-features/node-builtins
atob(input)
: // Older Node versions (<16)
// eslint-disable-next-line n/no-unsupported-features/node-builtins
typeof Buffer.from === "function"
? // eslint-disable-next-line n/no-unsupported-features/node-builtins
Buffer.from(input, "base64").toString("binary")
: // eslint-disable-next-line unicorn/no-new-buffer, n/no-deprecated-api
new Buffer(input, "base64").toString("binary");
const evenLength = binary.length & -2; // Round down to even length
const out = new Uint16Array(evenLength / 2);
for (let index = 0, outIndex = 0; index < evenLength; index += 2) {
const lo = binary.charCodeAt(index);
const hi = binary.charCodeAt(index + 1);
out[outIndex++] = lo | (hi << 8);
}
return out;
}
// Generated using scripts/write-decode-map.ts
const htmlDecodeTree = /* #__PURE__ */ decodeBase64("QR08ALkAAgH6AYsDNQR2BO0EPgXZBQEGLAbdBxMISQrvCmQLfQurDKQNLw4fD4YPpA+6D/IPAAAAAAAAAAAAAAAAKhBMEY8TmxUWF2EYLBkxGuAa3RsJHDscWR8YIC8jSCSIJcMl6ie3Ku8rEC0CLjoupS7kLgAIRU1hYmNmZ2xtbm9wcnN0dVQAWgBeAGUAaQBzAHcAfgCBAIQAhwCSAJoAoACsALMAbABpAGcAO4DGAMZAUAA7gCYAJkBjAHUAdABlADuAwQDBQHIiZXZlAAJhAAFpeW0AcgByAGMAO4DCAMJAEGRyAADgNdgE3XIAYQB2AGUAO4DAAMBA8CFoYZFj4SFjcgBhZAAAoFMqAAFncIsAjgBvAG4ABGFmAADgNdg43fAlbHlGdW5jdGlvbgCgYSBpAG4AZwA7gMUAxUAAAWNzpACoAHIAAOA12Jzc6SFnbgCgVCJpAGwAZABlADuAwwDDQG0AbAA7gMQAxEAABGFjZWZvcnN1xQDYANoA7QDxAPYA+QD8AAABY3LJAM8AayNzbGFzaAAAoBYidgHTANUAAKDnKmUAZAAAoAYjeQARZIABY3J0AOAA5QDrAGEidXNlAACgNSLuI291bGxpcwCgLCFhAJJjcgAA4DXYBd1wAGYAAOA12Dnd5SF2ZdhiYwDyAOoAbSJwZXEAAKBOIgAHSE9hY2RlZmhpbG9yc3UXARoBHwE6AVIBVQFiAWQBZgGCAakB6QHtAfIBYwB5ACdkUABZADuAqQCpQIABY3B5ACUBKAE1AfUhdGUGYWmg0iJ0KGFsRGlmZmVyZW50aWFsRAAAoEUhbCJleXMAAKAtIQACYWVpb0EBRAFKAU0B8iFvbgxhZABpAGwAO4DHAMdAcgBjAAhhbiJpbnQAAKAwIm8AdAAKYQABZG5ZAV0BaSJsbGEAuGB0I2VyRG90ALdg8gA5AWkAp2NyImNsZQAAAkRNUFRwAXQBeQF9AW8AdAAAoJkiaSJudXMAAKCWIuwhdXMAoJUiaSJtZXMAAKCXIm8AAAFjc4cBlAFrKndpc2VDb250b3VySW50ZWdyYWwAAKAyImUjQ3VybHkAAAFEUZwBpAFvJXVibGVRdW90ZQAAoB0gdSJvdGUAAKAZIAACbG5wdbABtgHNAdgBbwBuAGWgNyIAoHQqgAFnaXQAvAHBAcUB8iJ1ZW50AKBhIm4AdAAAoC8i7yV1ckludGVncmFsAKAuIgABZnLRAdMBAKACIe8iZHVjdACgECJuLnRlckNsb2Nrd2lzZUNvbnRvdXJJbnRlZ3JhbAAAoDMi7yFzcwCgLypjAHIAAOA12J7ccABDoNMiYQBwAACgTSKABURKU1phY2VmaW9zAAsCEgIVAhgCGwIsAjQCOQI9AnMCfwNvoEUh9CJyYWhkAKARKWMAeQACZGMAeQAFZGMAeQAPZIABZ3JzACECJQIoAuchZXIAoCEgcgAAoKEhaAB2AACg5CoAAWF5MAIzAvIhb24OYRRkbAB0oAciYQCUY3IAAOA12AfdAAFhZkECawIAAWNtRQJnAvIjaXRpY2FsAAJBREdUUAJUAl8CYwJjInV0ZQC0YG8AdAFZAloC2WJiJGxlQWN1dGUA3WJyImF2ZQBgYGkibGRlANxi7yFuZACgxCJmJWVyZW50aWFsRAAAoEYhcAR9AgAAAAAAAIECjgIAABoDZgAA4DXYO91EoagAhQKJAm8AdAAAoNwgcSJ1YWwAAKBQIuIhbGUAA0NETFJVVpkCqAK1Au8C/wIRA28AbgB0AG8AdQByAEkAbgB0AGUAZwByAGEA7ADEAW8AdAKvAgAAAACwAqhgbiNBcnJvdwAAoNMhAAFlb7kC0AJmAHQAgAFBUlQAwQLGAs0CciJyb3cAAKDQIekkZ2h0QXJyb3cAoNQhZQDlACsCbgBnAAABTFLWAugC5SFmdAABQVLcAuECciJyb3cAAKD4J+kkZ2h0QXJyb3cAoPon6SRnaHRBcnJvdwCg+SdpImdodAAAAUFU9gL7AnIicm93AACg0iFlAGUAAKCoInAAQQIGAwAAAAALA3Iicm93AACg0SFvJHduQXJyb3cAAKDVIWUlcnRpY2FsQmFyAACgJSJuAAADQUJMUlRhJAM2AzoDWgNxA3oDciJyb3cAAKGTIUJVLAMwA2EAcgAAoBMpcCNBcnJvdwAAoPUhciJldmUAEWPlIWZ00gJDAwAASwMAAFIDaSVnaHRWZWN0b3IAAKBQKWUkZVZlY3RvcgAAoF4p5SJjdG9yQqC9IWEAcgAAoFYpaSJnaHQA1AFiAwAAaQNlJGVWZWN0b3IAAKBfKeUiY3RvckKgwSFhAHIAAKBXKWUAZQBBoKQiciJyb3cAAKCnIXIAcgBvAPcAtAIAAWN0gwOHA3IA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YwAAoN8i4SFycnCgtiEAoD0pgKIqImJjZG9zACsVMBU6FT4VQRVyImNhcAAAoEgqAAFhdTQVNxVwAACgRipwAACgSipvAHQAAKCNInIAAKBFKgDgKiIA/gACYWxydksVURVuFXMVcgByAG2gtyEAoDwpeQCAAWV2dwBYFWUVaRVxAHACXxUAAAAAYxVyAGUA4wAXFXUA4wAZFWUAZQAAoM4iZSJkZ2UAAKDPImUAbgA7gKQApEBlI2Fycm93AAABbHJ7FX8V5SFmdACgtiFpImdodAAAoLchZQDkAG0VAAFjaYsVkRVvAG4AaQBuAPQAkwFuAHQAAKAxImwiY3R5AACgLSOACUFIYWJjZGVmaGlqbG9yc3R1d3oAuBW7Fb8V1RXgFegV+RUKFhUWHxZUFlcWZRbFFtsW7xb7FgUXChdyAPIAtAJhAHIAAKBlKQACZ2xyc8YVyhXOFdAV5yFlcgCgICDlIXRoAKA4IfIA9QxoAHagECAAoKMiawHZFd4VYSJyb3cAAKAPKWEA4wBfAgABYXnkFecV8iFvbg9hNGQAoUYhYW/tFfQVAAFnciEC8RVyAACgyiF0InNlcQAAoHcqgAFnbG0A/xUCFgUWO4CwALBAdABhALRjcCJ0eXYAAKCxKQABaXIOFhIW8yFodACgfykA4DXYId1hAHIAAAFschsWHRYAoMMhAKDCIYACYWVnc3YAKBauAjYWOhY+Fm0AAKHEIm9zLhY0Fm4AZABzoMQi9SFpdACgZiZhIm1tYQDdY2kAbgAAoPIiAKH3AGlvQxZRFmQAZQAAgfcAO29KFksW90BuI3RpbWVzAACgxyJuAPgAUBZjAHkAUmRjAG8CXhYAAAAAYhZyAG4AAKAeI28AcAAAoA0jgAJscHR1dwBuFnEWdRaSFp4W7CFhciRgZgAA4DXYVd0AotkCZW1wc30WhBaJFo0WcQBkoFAibwB0AACgUSJpIm51cwAAoDgi7CF1cwCgFCLxInVhcmUAoKEiYgBsAGUAYgBhAHIAdwBlAGQAZwDlANcAbgCAAWFkaAClFqoWtBZyAHIAbwD3APUMbwB3AG4AYQByAHIAbwB3APMA8xVhI3Jwb29uAAABbHK8FsAWZQBmAPQAHBZpAGcAaAD0AB4WYgHJFs8WawBhAHIAbwD3AJILbwLUFgAAAADYFnIAbgAAoB8jbwBwAACgDCOAAWNvdADhFukW7BYAAXJ55RboFgDgNdi53FVkbAAAoPYp8iFvaxFhAAFkcvMW9xZvAHQAAKDxImkA5qC/JVsSAAFhaP8WAhdyAPIANQNhAPIA1wvhIm5nbGUAoKYpAAFjaQ4XEBd5AF9k5yJyYXJyAKD/JwAJRGFjZGVmZ2xtbm9wcXJzdHV4MRc4F0YXWxcyBF4XaRd5F40XrBe0F78X2RcVGCEYLRg1GEAYAAFEbzUXgRZvAPQA+BUAAWNzPBdCF3UAdABlADuA6QDpQPQhZXIAoG4qAAJhaW95TRdQF1YXWhfyIW9uG2FyAGOgViI7gOoA6kDsIW9uAKBVIk1kbwB0ABdhAAFEcmIXZhdvAHQAAKBSIgDgNdgi3XKhmipuF3QXYQB2AGUAO4DoAOhAZKCWKm8AdAAAoJgqgKGZKmlscwCAF4UXhxfuInRlcnMAoOcjAKATIWSglSpvAHQAAKCXKoABYXBzAJMXlheiF2MAcgATYXQAeQBzogUinxcAAAAAoRdlAHQAAKAFInAAMaADIDMBqRerFwCgBCAAoAUgAAFnc7AXsRdLYXAAAKACIAABZ3C4F7sXbwBuABlhZgAA4DXYVt2AAWFscwDFF8sXzxdyAHOg1SJsAACg4yl1AHMAAKBxKmkAAKG1A2x21RfYF28AbgC1Y/VjAAJjc3V24BfoF/0XEBgAAWlv5BdWF3IAYwAAoFYiaQLuFwAAAADwF+0ADQThIW50AAFnbPUX+Rd0AHIAAKCWKuUhc3MAoJUqgAFhZWkAAxgGGAoYbABzAD1gcwB0AACgXyJ2AESgYSJEAACgeCrwImFyc2wAoOUpAAFEYRkYHRhvAHQAAKBTInIAcgAAoHEpgAFjZGkAJxgqGO0XcgAAoC8hbwD0AIwCAAFhaDEYMhi3YzuA8ADwQAABbXI5GD0YbAA7gOsA60BvAACgrCCAAWNpcABGGEgYSxhsACFgcwD0ACwEAAFlb08YVxhjAHQAYQB0AGkAbwDuABoEbgBlAG4AdABpAGEAbADlADME4Ql1GAAAgRgAAIMYiBgAAAAAoRilGAAAqhgAALsYvhjRGAAA1xgnGWwAbABpAG4AZwBkAG8AdABzAGUA8QBlF3kARGRtImFsZQAAoEAmgAFpbHIAjRiRGJ0Y7CFpZwCgA/tpApcYAAAAAJoYZwAAoAD7aQBnAACgBPsA4DXYI93sIWlnAKAB++whaWcA4GYAagCAAWFsdACvGLIYthh0AACgbSZpAGcAAKAC+24AcwAAoLElbwBmAJJh8AHCGAAAxhhmAADgNdhX3QABYWvJGMwYbADsAGsEdqDUIgCg2SphI3J0aW50AACgDSoAAWFv2hgiGQABY3PeGB8ZsQPnGP0YBRkSGRUZAAAdGbID7xjyGPQY9xj5GAAA+xg7gL0AvUAAoFMhO4C8ALxAAKBVIQCgWSEAoFshswEBGQAAAxkAoFQhAKBWIbQCCxkOGQAAAAAQGTuAvgC+QACgVyEAoFwhNQAAoFghtgEZGQAAGxkAoFohAKBdITgAAKBeIWwAAKBEIHcAbgAAoCIjYwByAADgNdi73IAIRWFiY2RlZmdpamxub3JzdHYARhlKGVoZXhlmGWkZkhmWGZkZnRmgGa0ZxhnLGc8Z4BkjGmygZyIAoIwqgAFjbXAAUBlTGVgZ9SF0ZfVhbQBhAOSgswM6FgCghipyImV2ZQAfYQABaXliGWUZcgBjAB1hM2RvAHQAIWGAoWUibHFzAMYEcBl6GfGhZSLOBAAAdhlsAGEAbgD0AN8EgKF+KmNkbACBGYQZjBljAACgqSpvAHQAb6CAKmyggioAoIQqZeDbIgD+cwAAoJQqcgAA4DXYJN3noGsirATtIWVsAKA3IWMAeQBTZIChdyJFYWoApxmpGasZAKCSKgCgpSoAoKQqAAJFYWVztBm2Gb0ZwhkAoGkicABwoIoq8iFveACgiipxoIgq8aCIKrUZaQBtAACg5yJwAGYAAOA12FjdYQB2AOUAYwIAAWNp0xnWGXIAAKAKIW0AAKFzImVs3BneGQCgjioAoJAqAIM+ADtjZGxxco0E6xn0GfgZ/BkBGgABY2nvGfEZAKCnKnIAAKB6Km8AdAAAoNci0CFhcgCglSl1ImVzdAAAoHwqgAJhZGVscwAKGvQZFhrVBCAa8AEPGgAAFBpwAHIAbwD4AFkZcgAAoHgpcQAAAWxxxAQbGmwAZQBzAPMASRlpAO0A5AQAAWVuJxouGnIjdG5lcXEAAOBpIgD+xQAsGgAFQWFiY2Vma29zeUAaQxpmGmoabRqDGocalhrCGtMacgDyAMwCAAJpbG1yShpOGlAaVBpyAHMA8ABxD2YAvWBpAGwA9AASBQABZHJYGlsaYwB5AEpkAKGUIWN3YBpkGmkAcgAAoEgpAKCtIWEAcgAAoA8h6SFyYyVhgAFhbHIAcxp7Gn8a8iF0c3WgZSZpAHQAAKBlJuwhaXAAoCYg4yFvbgCguSJyAADgNdgl3XMAAAFld4wakRphInJvdwAAoCUpYSJyb3cAAKAmKYACYW1vcHIAnxqjGqcauhq+GnIAcgAAoP8h9CFodACgOyJrAAABbHKsGrMaZSRmdGFycm93AACgqSHpJGdodGFycm93AKCqIWYAAOA12Fnd4iFhcgCgFSCAAWNsdADIGswa0BpyAADgNdi93GEAcwDoAGka8iFvaydhAAFicNca2xr1IWxsAKBDIOghZW4AoBAg4Qr2GgAA/RoAAAgbExsaGwAAIRs7GwAAAAA+G2IbmRuVG6sbAACyG80b0htjAHUAdABlADuA7QDtQAChYyBpeQEbBhtyAGMAO4DuAO5AOGQAAWN4CxsNG3kANWRjAGwAO4ChAKFAAAFmcssCFhsA4DXYJt1yAGEAdgBlADuA7ADsQIChSCFpbm8AJxsyGzYbAAFpbisbLxtuAHQAAKAMKnQAAKAtIuYhaW4AoNwpdABhAACgKSHsIWlnM2GAAWFvcABDG1sbXhuAAWNndABJG0sbWRtyACthgAFlbHAAcQVRG1UbaQBuAOUAyAVhAHIA9AByBWgAMWFmAACgtyJlAGQAtWEAoggiY2ZvdGkbbRt1G3kb4SFyZQCgBSFpAG4AdKAeImkAZQAAoN0pZABvAPQAWxsAoisiY2VscIEbhRuPG5QbYQBsAACguiIAAWdyiRuNG2UAcgDzACMQ4wCCG2EicmhrAACgFyryIW9kAKA8KgACY2dwdJ8boRukG6gbeQBRZG8AbgAvYWYAAOA12FrdYQC5Y3UAZQBzAHQAO4C/AL9AAAFjabUbuRtyAADgNdi+3G4AAKIIIkVkc3bCG8QbyBvQAwCg+SJvAHQAAKD1Inag9CIAoPMiaaBiIOwhZGUpYesB1hsAANkbYwB5AFZkbAA7gO8A70AAA2NmbW9zdeYb7hvyG/Ub+hsFHAABaXnqG+0bcgBjADVhOWRyAADgNdgn3eEhdGg3YnAAZgAA4DXYW93jAf8bAAADHHIAAOA12L/c8iFjeVhk6yFjeVRkAARhY2ZnaGpvcxUcGhwiHCYcKhwtHDAcNRzwIXBhdqC6A/BjAAFleR4cIRzkIWls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ZmdobG1vcHJzdHV3CiwNLBEsHSwnLDEsQCxLLFIsYix6LIQsjyzLLOgs7Sz/LAotcgDyAAkDYQByAACgYykAAWNyFSwbLHUAdABlADuA+gD6QPIACQ1yAOMBIywAACUseQBeZHYAZQBtYQABaXkrLDAscgBjADuA+wD7QENkgAFhYmgANyw6LD0scgDyANEO7CFhY3FhYQDyAOAOAAFpckQsSCzzIWh0AKB+KQDgNdgy3XIAYQB2AGUAO4D5APlAYQFWLF8scgAAAWxyWixcLACgvyEAoL4hbABrAACggCUAAWN0Zix2LG8CbCwAAAAAcyxyAG4AZaAcI3IAAKAcI28AcAAAoA8jcgBpAACg+CUAAWFsfiyBLGMAcgBrYTuAqACoQAABZ3CILIssbwBuAHNhZgAA4DXYZt0AA2FkaGxzdZksniynLLgsuyzFLHIAcgBvAPcACQ1vAHcAbgBhAHIAcgBvAPcA2A5hI3Jwb29uAAABbHKvLLMsZQBmAPQAWyxpAGcAaAD0AF0sdQDzAKYOaQAAocUDaGzBLMIs0mNvAG4AxWPwI2Fycm93cwCgyCGAAWNpdADRLOEs5CxvAtcsAAAAAN4scgBuAGWgHSNyAACgHSNvAHAAAKAOI24AZwBvYXIAaQAAoPklYwByAADgNdjK3IABZGlyAPMs9yz6LG8AdAAAoPAi7CFkZWlhaQBmoLUlAKC0JQABYW0DLQYtcgDyAMosbAA7gPwA/EDhIm5nbGUAoKcpgAdBQkRhY2RlZmxub3Byc3oAJy0qLTAtNC2bLZ0toS2/LcMtxy3TLdgt3C3gLfwtcgDyABADYQByAHag6CoAoOkqYQBzAOgA/gIAAW5yOC08LechcnQAoJwpgANla25wcnN0AJkpSC1NLVQtXi1iLYItYQBwAHAA4QAaHG8AdABoAGkAbgDnAKEXgAFoaXIAoSmzJFotbwBwAPQAdCVooJUh7wD4JgABaXVmLWotZwBtAOEAuygAAWJwbi14LXMjZXRuZXEAceCKIgD+AODLKgD+cyNldG5lcQBx4IsiAP4A4MwqAP4AAWhyhi2KLWUAdADhABIraSNhbmdsZQAAAWxyki2WLeUhZnQAoLIiaSJnaHQAAKCzInkAMmThIXNoAKCiIoABZWxyAKcttC24LWKiKCKuLQAAAACyLWEAcgAAoLsicQAAoFoi7CFpcACg7iIAAWJ0vC1eD2EA8gBfD3IAAOA12DPddAByAOkAlS1zAHUAAAFicM0t0C0A4IIi0iAA4IMi0iBwAGYAAOA12GfdcgBvAPAAWQt0AHIA6QCaLQABY3XkLegtcgAA4DXYy9wAAWJw7C30LW4AAAFFZXUt8S0A4IoiAP5uAAABRWV/LfktAOCLIgD+6SJnemFnAKCaKYADY2Vmb3BycwANLhAuJS4pLiMuLi40LukhcmN1YQABZGkULiEuAAFiZxguHC5hAHIAAKBfKmUAcaAnIgCgWSLlIXJwAKAYIXIAAOA12DTdcABmAADgNdho3WWgQCJhAHQA6ABqD2MAcgAA4DXYzNzjCuQRUC4AAFQuAABYLmIuAAAAAGMubS5wLnQuAAAAAIguki4AAJouJxIqEnQAcgDpAB0ScgAA4DXYNd0AAUFhWy5eLnIA8gDnAnIA8gCTB75jAAFBYWYuaS5yAPIA4AJyAPIAjAdhAPAAeh5pAHMAAKD7IoABZHB0APgReS6DLgABZmx9LoAuAOA12GnddQDzAP8RaQBtAOUABBIAAUFhiy6OLnIA8gDuAnIA8gCaBwABY3GVLgoScgAA4DXYzdwAAXB0nS6hLmwAdQDzACUScgDpACASAARhY2VmaW9zdbEuvC7ELsguzC7PLtQu2S5jAAABdXm2LrsudABlADuA/QD9QE9kAAFpecAuwy5yAGMAd2FLZG4AO4ClAKVAcgAA4DXYNt1jAHkAV2RwAGYAAOA12GrdYwByAADgNdjO3AABY23dLt8ueQBOZGwAO4D/AP9AAAVhY2RlZmhpb3N38y73Lv8uAi8MLxAvEy8YLx0vIi9jInV0ZQB6YQABYXn7Lv4u8iFvbn5hN2RvAHQAfGEAAWV0Bi8KL3QAcgDmAB8QYQC2Y3IAAOA12DfdYwB5ADZk5yJyYXJyAKDdIXAAZgAA4DXYa91jAHIAAOA12M/cAAFqbiYvKC8AoA0gagAAoAwg");
// Generated using scripts/write-decode-map.ts
const xmlDecodeTree = /* #__PURE__ */ decodeBase64("AAJhZ2xxBwARABMAFQBtAg0AAAAAAA8AcAAmYG8AcwAnYHQAPmB0ADxg9SFvdCJg");
/**
* Bit flags & masks for the binary trie encoding used for entity decoding.
*
* Bit layout (16 bits total):
* 15..14 VALUE_LENGTH (+1 encoding; 0 => no value)
* 13 FLAG13. If valueLength>0: semicolon required flag (implicit ';').
* If valueLength==0: compact run flag.
* 12..7 BRANCH_LENGTH Branch length (0 => single branch in 6..0 if jumpOffset==char) OR run length (when compact run)
* 6..0 JUMP_TABLE Jump offset (jump table) OR single-branch char code OR first run char
*/
var BinTrieFlags;
(function (BinTrieFlags) {
BinTrieFlags[BinTrieFlags["VALUE_LENGTH"] = 49152] = "VALUE_LENGTH";
BinTrieFlags[BinTrieFlags["FLAG13"] = 8192] = "FLAG13";
BinTrieFlags[BinTrieFlags["BRANCH_LENGTH"] = 8064] = "BRANCH_LENGTH";
BinTrieFlags[BinTrieFlags["JUMP_TABLE"] = 127] = "JUMP_TABLE";
})(BinTrieFlags || (BinTrieFlags = {}));
var CharCodes$1;
(function (CharCodes) {
CharCodes[CharCodes["NUM"] = 35] = "NUM";
CharCodes[CharCodes["SEMI"] = 59] = "SEMI";
CharCodes[CharCodes["EQUALS"] = 61] = "EQUALS";
CharCodes[CharCodes["ZERO"] = 48] = "ZERO";
CharCodes[CharCodes["NINE"] = 57] = "NINE";
CharCodes[CharCodes["LOWER_A"] = 97] = "LOWER_A";
CharCodes[CharCodes["LOWER_F"] = 102] = "LOWER_F";
CharCodes[CharCodes["LOWER_X"] = 120] = "LOWER_X";
CharCodes[CharCodes["LOWER_Z"] = 122] = "LOWER_Z";
CharCodes[CharCodes["UPPER_A"] = 65] = "UPPER_A";
CharCodes[CharCodes["UPPER_F"] = 70] = "UPPER_F";
CharCodes[CharCodes["UPPER_Z"] = 90] = "UPPER_Z";
})(CharCodes$1 || (CharCodes$1 = {}));
/** Bit that needs to be set to convert an upper case ASCII character to lower case */
const TO_LOWER_BIT = 32;
function isNumber(code) {
return code >= CharCodes$1.ZERO && code <= CharCodes$1.NINE;
}
function isHexadecimalCharacter(code) {
return ((code >= CharCodes$1.UPPER_A && code <= CharCodes$1.UPPER_F) ||
(code >= CharCodes$1.LOWER_A && code <= CharCodes$1.LOWER_F));
}
function isAsciiAlphaNumeric(code) {
return ((code >= CharCodes$1.UPPER_A && code <= CharCodes$1.UPPER_Z) ||
(code >= CharCodes$1.LOWER_A && code <= CharCodes$1.LOWER_Z) ||
isNumber(code));
}
/**
* Checks if the given character is a valid end character for an entity in an attribute.
*
* Attribute values that aren't terminated properly aren't parsed, and shouldn't lead to a parser error.
* See the example in https://html.spec.whatwg.org/multipage/parsing.html#named-character-reference-state
*/
function isEntityInAttributeInvalidEnd(code) {
return code === CharCodes$1.EQUALS || isAsciiAlphaNumeric(code);
}
var EntityDecoderState;
(function (EntityDecoderState) {
EntityDecoderState[EntityDecoderState["EntityStart"] = 0] = "EntityStart";
EntityDecoderState[EntityDecoderState["NumericStart"] = 1] = "NumericStart";
EntityDecoderState[EntityDecoderState["NumericDecimal"] = 2] = "NumericDecimal";
EntityDecoderState[EntityDecoderState["NumericHex"] = 3] = "NumericHex";
EntityDecoderState[EntityDecoderState["NamedEntity"] = 4] = "NamedEntity";
})(EntityDecoderState || (EntityDecoderState = {}));
var DecodingMode;
(function (DecodingMode) {
/** Entities in text nodes that can end with any character. */
DecodingMode[DecodingMode["Legacy"] = 0] = "Legacy";
/** Only allow entities terminated with a semicolon. */
DecodingMode[DecodingMode["Strict"] = 1] = "Strict";
/** Entities in attributes have limitations on ending characters. */
DecodingMode[DecodingMode["Attribute"] = 2] = "Attribute";
})(DecodingMode || (DecodingMode = {}));
/**
* Token decoder with support of writing partial entities.
*/
class EntityDecoder {
constructor(
/** The tree used to decode entities. */
// biome-ignore lint/correctness/noUnusedPrivateClassMembers: False positive
decodeTree,
/**
* The function that is called when a codepoint is decoded.
*
* For multi-byte named entities, this will be called multiple times,
* with the second codepoint, and the same `consumed` value.
*
* @param codepoint The decoded codepoint.
* @param consumed The number of bytes consumed by the decoder.
*/
emitCodePoint,
/** An object that is used to produce errors. */
errors) {
this.decodeTree = decodeTree;
this.emitCodePoint = emitCodePoint;
this.errors = errors;
/** The current state of the decoder. */
this.state = EntityDecoderState.EntityStart;
/** Characters that were consumed while parsing an entity. */
this.consumed = 1;
/**
* The result of the entity.
*
* Either the result index of a numeric entity, or the codepoint of a
* numeric entity.
*/
this.result = 0;
/** The current index in the decode tree. */
this.treeIndex = 0;
/** The number of characters that were consumed in excess. */
this.excess = 1;
/** The mode in which the decoder is operating. */
this.decodeMode = DecodingMode.Strict;
/** The number of characters that have been consumed in the current run. */
this.runConsumed = 0;
}
/** Resets the instance to make it reusable. */
startEntity(decodeMode) {
this.decodeMode = decodeMode;
this.state = EntityDecoderState.EntityStart;
this.result = 0;
this.treeIndex = 0;
this.excess = 1;
this.consumed = 1;
this.runConsumed = 0;
}
/**
* Write an entity to the decoder. This can be called multiple times with partial entities.
* If the entity is incomplete, the decoder will return -1.
*
* Mirrors the implementation of `getDecoder`, but with the ability to stop decoding if the
* entity is incomplete, and resume when the next string is written.
*
* @param input The string containing the entity (or a continuation of the entity).
* @param offset The offset at which the entity begins. Should be 0 if this is not the first call.
* @returns The number of characters that were consumed, or -1 if the entity is incomplete.
*/
write(input, offset) {
switch (this.state) {
case EntityDecoderState.EntityStart: {
if (input.charCodeAt(offset) === CharCodes$1.NUM) {
this.state = EntityDecoderState.NumericStart;
this.consumed += 1;
return this.stateNumericStart(input, offset + 1);
}
this.state = EntityDecoderState.NamedEntity;
return this.stateNamedEntity(input, offset);
}
case EntityDecoderState.NumericStart: {
return this.stateNumericStart(input, offset);
}
case EntityDecoderState.NumericDecimal: {
return this.stateNumericDecimal(input, offset);
}
case EntityDecoderState.NumericHex: {
return this.stateNumericHex(input, offset);
}
case EntityDecoderState.NamedEntity: {
return this.stateNamedEntity(input, offset);
}
}
}
/**
* Switches between the numeric decimal and hexadecimal states.
*
* Equivalent to the `Numeric character reference state` in the HTML spec.
*
* @param input The string containing the entity (or a continuation of the entity).
* @param offset The current offset.
* @returns The number of characters that were consumed, or -1 if the entity is incomplete.
*/
stateNumericStart(input, offset) {
if (offset >= input.length) {
return -1;
}
if ((input.charCodeAt(offset) | TO_LOWER_BIT) === CharCodes$1.LOWER_X) {
this.state = EntityDecoderState.NumericHex;
this.consumed += 1;
return this.stateNumericHex(input, offset + 1);
}
this.state = EntityDecoderState.NumericDecimal;
return this.stateNumericDecimal(input, offset);
}
/**
* Parses a hexadecimal numeric entity.
*
* Equivalent to the `Hexademical character reference state` in the HTML spec.
*
* @param input The string containing the entity (or a continuation of the entity).
* @param offset The current offset.
* @returns The number of characters that were consumed, or -1 if the entity is incomplete.
*/
stateNumericHex(input, offset) {
while (offset < input.length) {
const char = input.charCodeAt(offset);
if (isNumber(char) || isHexadecimalCharacter(char)) {
// Convert hex digit to value (0-15); 'a'/'A' -> 10.
const digit = char <= CharCodes$1.NINE
? char - CharCodes$1.ZERO
: (char | TO_LOWER_BIT) - CharCodes$1.LOWER_A + 10;
this.result = this.result * 16 + digit;
this.consumed++;
offset++;
}
else {
return this.emitNumericEntity(char, 3);
}
}
return -1; // Incomplete entity
}
/**
* Parses a decimal numeric entity.
*
* Equivalent to the `Decimal character reference state` in the HTML spec.
*
* @param input The string containing the entity (or a continuation of the entity).
* @param offset The current offset.
* @returns The number of characters that were consumed, or -1 if the entity is incomplete.
*/
stateNumericDecimal(input, offset) {
while (offset < input.length) {
const char = input.charCodeAt(offset);
if (isNumber(char)) {
this.result = this.result * 10 + (char - CharCodes$1.ZERO);
this.consumed++;
offset++;
}
else {
return this.emitNumericEntity(char, 2);
}
}
return -1; // Incomplete entity
}
/**
* Validate and emit a numeric entity.
*
* Implements the logic from the `Hexademical character reference start
* state` and `Numeric character reference end state` in the HTML spec.
*
* @param lastCp The last code point of the entity. Used to see if the
* entity was terminated with a semicolon.
* @param expectedLength The minimum number of characters that should be
* consumed. Used to validate that at least one digit
* was consumed.
* @returns The number of characters that were consumed.
*/
emitNumericEntity(lastCp, expectedLength) {
var _a;
// Ensure we consumed at least one digit.
if (this.consumed <= expectedLength) {
(_a = this.errors) === null || _a === void 0 ? void 0 : _a.absenceOfDigitsInNumericCharacterReference(this.consumed);
return 0;
}
// Figure out if this is a legit end of the entity
if (lastCp === CharCodes$1.SEMI) {
this.consumed += 1;
}
else if (this.decodeMode === DecodingMode.Strict) {
return 0;
}
this.emitCodePoint(replaceCodePoint(this.result), this.consumed);
if (this.errors) {
if (lastCp !== CharCodes$1.SEMI) {
this.errors.missingSemicolonAfterCharacterReference();
}
this.errors.validateNumericCharacterReference(this.result);
}
return this.consumed;
}
/**
* Parses a named entity.
*
* Equivalent to the `Named character reference state` in the HTML spec.
*
* @param input The string containing the entity (or a continuation of the entity).
* @param offset The current offset.
* @returns The number of characters that were consumed, or -1 if the entity is incomplete.
*/
stateNamedEntity(input, offset) {
const { decodeTree } = this;
let current = decodeTree[this.treeIndex];
// The length is the number of bytes of the value, including the current byte.
let valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14;
while (offset < input.length) {
// Handle compact runs (possibly inline): valueLength == 0 and SEMI_REQUIRED bit set.
if (valueLength === 0 && (current & BinTrieFlags.FLAG13) !== 0) {
const runLength = (current & BinTrieFlags.BRANCH_LENGTH) >> 7; /* 2..63 */
// If we are starting a run, check the first char.
if (this.runConsumed === 0) {
const firstChar = current & BinTrieFlags.JUMP_TABLE;
if (input.charCodeAt(offset) !== firstChar) {
return this.result === 0
? 0
: this.emitNotTerminatedNamedEntity();
}
offset++;
this.excess++;
this.runConsumed++;
}
// Check remaining characters in the run.
while (this.runConsumed < runLength) {
if (offset >= input.length) {
return -1;
}
const charIndexInPacked = this.runConsumed - 1;
const packedWord = decodeTree[this.treeIndex + 1 + (charIndexInPacked >> 1)];
const expectedChar = charIndexInPacked % 2 === 0
? packedWord & 0xff
: (packedWord >> 8) & 0xff;
if (input.charCodeAt(offset) !== expectedChar) {
this.runConsumed = 0;
return this.result === 0
? 0
: this.emitNotTerminatedNamedEntity();
}
offset++;
this.excess++;
this.runConsumed++;
}
this.runConsumed = 0;
this.treeIndex += 1 + (runLength >> 1);
current = decodeTree[this.treeIndex];
valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14;
}
if (offset >= input.length)
break;
const char = input.charCodeAt(offset);
/*
* Implicit semicolon handling for nodes that require a semicolon but
* don't have an explicit ';' branch stored in the trie. If we have
* a value on the current node, it requires a semicolon, and the
* current input character is a semicolon, emit the entity using the
* current node (without descending further).
*/
if (char === CharCodes$1.SEMI &&
valueLength !== 0 &&
(current & BinTrieFlags.FLAG13) !== 0) {
return this.emitNamedEntityData(this.treeIndex, valueLength, this.consumed + this.excess);
}
this.treeIndex = determineBranch(decodeTree, current, this.treeIndex + Math.max(1, valueLength), char);
if (this.treeIndex < 0) {
return this.result === 0 ||
// If we are parsing an attribute
(this.decodeMode === DecodingMode.Attribute &&
// We shouldn't have consumed any characters after the entity,
(valueLength === 0 ||
// And there should be no invalid characters.
isEntityInAttributeInvalidEnd(char)))
? 0
: this.emitNotTerminatedNamedEntity();
}
current = decodeTree[this.treeIndex];
valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14;
// If the branch is a value, store it and continue
if (valueLength !== 0) {
// If the entity is terminated by a semicolon, we are done.
if (char === CharCodes$1.SEMI) {
return this.emitNamedEntityData(this.treeIndex, valueLength, this.consumed + this.excess);
}
// If we encounter a non-terminated (legacy) entity while parsing strictly, then ignore it.
if (this.decodeMode !== DecodingMode.Strict &&
(current & BinTrieFlags.FLAG13) === 0) {
this.result = this.treeIndex;
this.consumed += this.excess;
this.excess = 0;
}
}
// Increment offset & excess for next iteration
offset++;
this.excess++;
}
return -1;
}
/**
* Emit a named entity that was not terminated with a semicolon.
*
* @returns The number of characters consumed.
*/
emitNotTerminatedNamedEntity() {
var _a;
const { result, decodeTree } = this;
const valueLength = (decodeTree[result] & BinTrieFlags.VALUE_LENGTH) >> 14;
this.emitNamedEntityData(result, valueLength, this.consumed);
(_a = this.errors) === null || _a === void 0 ? void 0 : _a.missingSemicolonAfterCharacterReference();
return this.consumed;
}
/**
* Emit a named entity.
*
* @param result The index of the entity in the decode tree.
* @param valueLength The number of bytes in the entity.
* @param consumed The number of characters consumed.
*
* @returns The number of characters consumed.
*/
emitNamedEntityData(result, valueLength, consumed) {
const { decodeTree } = this;
this.emitCodePoint(valueLength === 1
? decodeTree[result] &
~(BinTrieFlags.VALUE_LENGTH | BinTrieFlags.FLAG13)
: decodeTree[result + 1], consumed);
if (valueLength === 3) {
// For multi-byte values, we need to emit the second byte.
this.emitCodePoint(decodeTree[result + 2], consumed);
}
return consumed;
}
/**
* Signal to the parser that the end of the input was reached.
*
* Remaining data will be emitted and relevant errors will be produced.
*
* @returns The number of characters consumed.
*/
end() {
var _a;
switch (this.state) {
case EntityDecoderState.NamedEntity: {
// Emit a named entity if we have one.
return this.result !== 0 &&
(this.decodeMode !== DecodingMode.Attribute ||
this.result === this.treeIndex)
? this.emitNotTerminatedNamedEntity()
: 0;
}
// Otherwise, emit a numeric entity if we have one.
case EntityDecoderState.NumericDecimal: {
return this.emitNumericEntity(0, 2);
}
case EntityDecoderState.NumericHex: {
return this.emitNumericEntity(0, 3);
}
case EntityDecoderState.NumericStart: {
(_a = this.errors) === null || _a === void 0 ? void 0 : _a.absenceOfDigitsInNumericCharacterReference(this.consumed);
return 0;
}
case EntityDecoderState.EntityStart: {
// Return 0 if we have no entity.
return 0;
}
}
}
}
/**
* Determines the branch of the current node that is taken given the current
* character. This function is used to traverse the trie.
*
* @param decodeTree The trie.
* @param current The current node.
* @param nodeIdx The index right after the current node and its value.
* @param char The current character.
* @returns The index of the next node, or -1 if no branch is taken.
*/
function determineBranch(decodeTree, current, nodeIndex, char) {
const branchCount = (current & BinTrieFlags.BRANCH_LENGTH) >> 7;
const jumpOffset = current & BinTrieFlags.JUMP_TABLE;
// Case 1: Single branch encoded in jump offset
if (branchCount === 0) {
return jumpOffset !== 0 && char === jumpOffset ? nodeIndex : -1;
}
// Case 2: Multiple branches encoded in jump table
if (jumpOffset) {
const value = char - jumpOffset;
return value < 0 || value >= branchCount
? -1
: decodeTree[nodeIndex + value] - 1;
}
// Case 3: Multiple branches encoded in packed dictionary (two keys per uint16)
const packedKeySlots = (branchCount + 1) >> 1;
/*
* Treat packed keys as a virtual sorted array of length `branchCount`.
* Key(i) = low byte for even i, high byte for odd i in slot i>>1.
*/
let lo = 0;
let hi = branchCount - 1;
while (lo <= hi) {
const mid = (lo + hi) >>> 1;
const slot = mid >> 1;
const packed = decodeTree[nodeIndex + slot];
const midKey = (packed >> ((mid & 1) * 8)) & 0xff;
if (midKey < char) {
lo = mid + 1;
}
else if (midKey > char) {
hi = mid - 1;
}
else {
return decodeTree[nodeIndex + packedKeySlots + mid];
}
}
return -1;
}
var CharCodes;
(function (CharCodes) {
CharCodes[CharCodes["Tab"] = 9] = "Tab";
CharCodes[CharCodes["NewLine"] = 10] = "NewLine";
CharCodes[CharCodes["FormFeed"] = 12] = "FormFeed";
CharCodes[CharCodes["CarriageReturn"] = 13] = "CarriageReturn";
CharCodes[CharCodes["Space"] = 32] = "Space";
CharCodes[CharCodes["ExclamationMark"] = 33] = "ExclamationMark";
CharCodes[CharCodes["Number"] = 35] = "Number";
CharCodes[CharCodes["Amp"] = 38] = "Amp";
CharCodes[CharCodes["SingleQuote"] = 39] = "SingleQuote";
CharCodes[CharCodes["DoubleQuote"] = 34] = "DoubleQuote";
CharCodes[CharCodes["Dash"] = 45] = "Dash";
CharCodes[CharCodes["Slash"] = 47] = "Slash";
CharCodes[CharCodes["Zero"] = 48] = "Zero";
CharCodes[CharCodes["Nine"] = 57] = "Nine";
CharCodes[CharCodes["Semi"] = 59] = "Semi";
CharCodes[CharCodes["Lt"] = 60] = "Lt";
CharCodes[CharCodes["Eq"] = 61] = "Eq";
CharCodes[CharCodes["Gt"] = 62] = "Gt";
CharCodes[CharCodes["Questionmark"] = 63] = "Questionmark";
CharCodes[CharCodes["UpperA"] = 65] = "UpperA";
CharCodes[CharCodes["LowerA"] = 97] = "LowerA";
CharCodes[CharCodes["UpperF"] = 70] = "UpperF";
CharCodes[CharCodes["LowerF"] = 102] = "LowerF";
CharCodes[CharCodes["UpperZ"] = 90] = "UpperZ";
CharCodes[CharCodes["LowerZ"] = 122] = "LowerZ";
CharCodes[CharCodes["LowerX"] = 120] = "LowerX";
CharCodes[CharCodes["OpeningSquareBracket"] = 91] = "OpeningSquareBracket";
})(CharCodes || (CharCodes = {}));
/** All the states the tokenizer can be in. */
var State;
(function (State) {
State[State["Text"] = 1] = "Text";
State[State["BeforeTagName"] = 2] = "BeforeTagName";
State[State["InTagName"] = 3] = "InTagName";
State[State["InSelfClosingTag"] = 4] = "InSelfClosingTag";
State[State["BeforeClosingTagName"] = 5] = "BeforeClosingTagName";
State[State["InClosingTagName"] = 6] = "InClosingTagName";
State[State["AfterClosingTagName"] = 7] = "AfterClosingTagName";
// Attributes
State[State["BeforeAttributeName"] = 8] = "BeforeAttributeName";
State[State["InAttributeName"] = 9] = "InAttributeName";
State[State["AfterAttributeName"] = 10] = "AfterAttributeName";
State[State["BeforeAttributeValue"] = 11] = "BeforeAttributeValue";
State[State["InAttributeValueDq"] = 12] = "InAttributeValueDq";
State[State["InAttributeValueSq"] = 13] = "InAttributeValueSq";
State[State["InAttributeValueNq"] = 14] = "InAttributeValueNq";
// Declarations
State[State["BeforeDeclaration"] = 15] = "BeforeDeclaration";
State[State["InDeclaration"] = 16] = "InDeclaration";
// Processing instructions
State[State["InProcessingInstruction"] = 17] = "InProcessingInstruction";
// Comments & CDATA
State[State["BeforeComment"] = 18] = "BeforeComment";
State[State["CDATASequence"] = 19] = "CDATASequence";
State[State["InSpecialComment"] = 20] = "InSpecialComment";
State[State["InCommentLike"] = 21] = "InCommentLike";
// Special tags
State[State["BeforeSpecialS"] = 22] = "BeforeSpecialS";
State[State["BeforeSpecialT"] = 23] = "BeforeSpecialT";
State[State["SpecialStartSequence"] = 24] = "SpecialStartSequence";
State[State["InSpecialTag"] = 25] = "InSpecialTag";
State[State["InEntity"] = 26] = "InEntity";
})(State || (State = {}));
function isWhitespace$1(c) {
return (c === CharCodes.Space ||
c === CharCodes.NewLine ||
c === CharCodes.Tab ||
c === CharCodes.FormFeed ||
c === CharCodes.CarriageReturn);
}
function isEndOfTagSection(c) {
return c === CharCodes.Slash || c === CharCodes.Gt || isWhitespace$1(c);
}
function isASCIIAlpha(c) {
return ((c >= CharCodes.LowerA && c <= CharCodes.LowerZ) ||
(c >= CharCodes.UpperA && c <= CharCodes.UpperZ));
}
var QuoteType;
(function (QuoteType) {
QuoteType[QuoteType["NoValue"] = 0] = "NoValue";
QuoteType[QuoteType["Unquoted"] = 1] = "Unquoted";
QuoteType[QuoteType["Single"] = 2] = "Single";
QuoteType[QuoteType["Double"] = 3] = "Double";
})(QuoteType || (QuoteType = {}));
/**
* Sequences used to match longer strings.
*
* We don't have `Script`, `Style`, or `Title` here. Instead, we re-use the *End
* sequences with an increased offset.
*/
const Sequences = {
Cdata: new Uint8Array([0x43, 0x44, 0x41, 0x54, 0x41, 0x5b]), // CDATA[
CdataEnd: new Uint8Array([0x5d, 0x5d, 0x3e]), // ]]>
CommentEnd: new Uint8Array([0x2d, 0x2d, 0x3e]), // `-->`
ScriptEnd: new Uint8Array([0x3c, 0x2f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74]), // `</script`
StyleEnd: new Uint8Array([0x3c, 0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65]), // `</style`
TitleEnd: new Uint8Array([0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65]), // `</title`
TextareaEnd: new Uint8Array([
0x3c, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x61, 0x72, 0x65, 0x61,
]), // `</textarea`
XmpEnd: new Uint8Array([0x3c, 0x2f, 0x78, 0x6d, 0x70]), // `</xmp`
};
class Tokenizer {
constructor({ xmlMode = false, decodeEntities = true, }, cbs) {
this.cbs = cbs;
/** The current state the tokenizer is in. */
this.state = State.Text;
/** The read buffer. */
this.buffer = "";
/** The beginning of the section that is currently being read. */
this.sectionStart = 0;
/** The index within the buffer that we are currently looking at. */
this.index = 0;
/** The start of the last entity. */
this.entityStart = 0;
/** Some behavior, eg. when decoding entities, is done while we are in another state. This keeps track of the other state type. */
this.baseState = State.Text;
/** For special parsing behavior inside of script and style tags. */
this.isSpecial = false;
/** Indicates whether the tokenizer has been paused. */
this.running = true;
/** The offset of the current buffer. */
this.offset = 0;
this.currentSequence = undefined;
this.sequenceIndex = 0;
this.xmlMode = xmlMode;
this.decodeEntities = decodeEntities;
this.entityDecoder = new EntityDecoder(xmlMode ? xmlDecodeTree : htmlDecodeTree, (cp, consumed) => this.emitCodePoint(cp, consumed));
}
reset() {
this.state = State.Text;
this.buffer = "";
this.sectionStart = 0;
this.index = 0;
this.baseState = State.Text;
this.currentSequence = undefined;
this.running = true;
this.offset = 0;
}
write(chunk) {
this.offset += this.buffer.length;
this.buffer = chunk;
this.parse();
}
end() {
if (this.running)
this.finish();
}
pause() {
this.running = false;
}
resume() {
this.running = true;
if (this.index < this.buffer.length + this.offset) {
this.parse();
}
}
stateText(c) {
if (c === CharCodes.Lt ||
(!this.decodeEntities && this.fastForwardTo(CharCodes.Lt))) {
if (this.index > this.sectionStart) {
this.cbs.ontext(this.sectionStart, this.index);
}
this.state = State.BeforeTagName;
this.sectionStart = this.index;
}
else if (this.decodeEntities && c === CharCodes.Amp) {
this.startEntity();
}
}
stateSpecialStartSequence(c) {
const isEnd = this.sequenceIndex === this.currentSequence.length;
const isMatch = isEnd
? // If we are at the end of the sequence, make sure the tag name has ended
isEndOfTagSection(c)
: // Otherwise, do a case-insensitive comparison
(c | 0x20) === this.currentSequence[this.sequenceIndex];
if (!isMatch) {
this.isSpecial = false;
}
else if (!isEnd) {
this.sequenceIndex++;
return;
}
this.sequenceIndex = 0;
this.state = State.InTagName;
this.stateInTagName(c);
}
/** Look for an end tag. For <title> tags, also decode entities. */
stateInSpecialTag(c) {
if (this.sequenceIndex === this.currentSequence.length) {
if (c === CharCodes.Gt || isWhitespace$1(c)) {
const endOfText = this.index - this.currentSequence.length;
if (this.sectionStart < endOfText) {
// Spoof the index so that reported locations match up.
const actualIndex = this.index;
this.index = endOfText;
this.cbs.ontext(this.sectionStart, endOfText);
this.index = actualIndex;
}
this.isSpecial = false;
this.sectionStart = endOfText + 2; // Skip over the `</`
this.stateInClosingTagName(c);
return; // We are done; skip the rest of the function.
}
this.sequenceIndex = 0;
}
if ((c | 0x20) === this.currentSequence[this.sequenceIndex]) {
this.sequenceIndex += 1;
}
else if (this.sequenceIndex === 0) {
if (this.currentSequence === Sequences.TitleEnd) {
// We have to parse entities in <title> tags.
if (this.decodeEntities && c === CharCodes.Amp) {
this.startEntity();
}
}
else if (this.fastForwardTo(CharCodes.Lt)) {
// Outside of <title> tags, we can fast-forward.
this.sequenceIndex = 1;
}
}
else {
// If we see a `<`, set the sequence index to 1; useful for eg. `<</script>`.
this.sequenceIndex = Number(c === CharCodes.Lt);
}
}
stateCDATASequence(c) {
if (c === Sequences.Cdata[this.sequenceIndex]) {
if (++this.sequenceIndex === Sequences.Cdata.length) {
this.state = State.InCommentLike;
this.currentSequence = Sequences.CdataEnd;
this.sequenceIndex = 0;
this.sectionStart = this.index + 1;
}
}
else {
this.sequenceIndex = 0;
this.state = State.InDeclaration;
this.stateInDeclaration(c); // Reconsume the character
}
}
/**
* When we wait for one specific character, we can speed things up
* by skipping through the buffer until we find it.
*
* @returns Whether the character was found.
*/
fastForwardTo(c) {
while (++this.index < this.buffer.length + this.offset) {
if (this.buffer.charCodeAt(this.index - this.offset) === c) {
return true;
}
}
/*
* We increment the index at the end of the `parse` loop,
* so set it to `buffer.length - 1` here.
*
* TODO: Refactor `parse` to increment index before calling states.
*/
this.index = this.buffer.length + this.offset - 1;
return false;
}
/**
* Comments and CDATA end with `-->` and `]]>`.
*
* Their common qualities are:
* - Their end sequences have a distinct character they start with.
* - That character is then repeated, so we have to check multiple repeats.
* - All characters but the start character of the sequence can be skipped.
*/
stateInCommentLike(c) {
if (c === this.currentSequence[this.sequenceIndex]) {
if (++this.sequenceIndex === this.currentSequence.length) {
if (this.currentSequence === Sequences.CdataEnd) {
this.cbs.oncdata(this.sectionStart, this.index, 2);
}
else {
this.cbs.oncomment(this.sectionStart, this.index, 2);
}
this.sequenceIndex = 0;
this.sectionStart = this.index + 1;
this.state = State.Text;
}
}
else if (this.sequenceIndex === 0) {
// Fast-forward to the first character of the sequence
if (this.fastForwardTo(this.currentSequence[0])) {
this.sequenceIndex = 1;
}
}
else if (c !== this.currentSequence[this.sequenceIndex - 1]) {
// Allow long sequences, eg. --->, ]]]>
this.sequenceIndex = 0;
}
}
/**
* HTML only allows ASCII alpha characters (a-z and A-Z) at the beginning of a tag name.
*
* XML allows a lot more characters here (@see https://www.w3.org/TR/REC-xml/#NT-NameStartChar).
* We allow anything that wouldn't end the tag.
*/
isTagStartChar(c) {
return this.xmlMode ? !isEndOfTagSection(c) : isASCIIAlpha(c);
}
startSpecial(sequence, offset) {
this.isSpecial = true;
this.currentSequence = sequence;
this.sequenceIndex = offset;
this.state = State.SpecialStartSequence;
}
stateBeforeTagName(c) {
if (c === CharCodes.ExclamationMark) {
this.state = State.BeforeDeclaration;
this.sectionStart = this.index + 1;
}
else if (c === CharCodes.Questionmark) {
this.state = State.InProcessingInstruction;
this.sectionStart = this.index + 1;
}
else if (this.isTagStartChar(c)) {
const lower = c | 0x20;
this.sectionStart = this.index;
if (this.xmlMode) {
this.state = State.InTagName;
}
else if (lower === Sequences.ScriptEnd[2]) {
this.state = State.BeforeSpecialS;
}
else if (lower === Sequences.TitleEnd[2] ||
lower === Sequences.XmpEnd[2]) {
this.state = State.BeforeSpecialT;
}
else {
this.state = State.InTagName;
}
}
else if (c === CharCodes.Slash) {
this.state = State.BeforeClosingTagName;
}
else {
this.state = State.Text;
this.stateText(c);
}
}
stateInTagName(c) {
if (isEndOfTagSection(c)) {
this.cbs.onopentagname(this.sectionStart, this.index);
this.sectionStart = -1;
this.state = State.BeforeAttributeName;
this.stateBeforeAttributeName(c);
}
}
stateBeforeClosingTagName(c) {
if (isWhitespace$1(c)) ;
else if (c === CharCodes.Gt) {
this.state = State.Text;
}
else {
this.state = this.isTagStartChar(c)
? State.InClosingTagName
: State.InSpecialComment;
this.sectionStart = this.index;
}
}
stateInClosingTagName(c) {
if (c === CharCodes.Gt || isWhitespace$1(c)) {
this.cbs.onclosetag(this.sectionStart, this.index);
this.sectionStart = -1;
this.state = State.AfterClosingTagName;
this.stateAfterClosingTagName(c);
}
}
stateAfterClosingTagName(c) {
// Skip everything until ">"
if (c === CharCodes.Gt || this.fastForwardTo(CharCodes.Gt)) {
this.state = State.Text;
this.sectionStart = this.index + 1;
}
}
stateBeforeAttributeName(c) {
if (c === CharCodes.Gt) {
this.cbs.onopentagend(this.index);
if (this.isSpecial) {
this.state = State.InSpecialTag;
this.sequenceIndex = 0;
}
else {
this.state = State.Text;
}
this.sectionStart = this.index + 1;
}
else if (c === CharCodes.Slash) {
this.state = State.InSelfClosingTag;
}
else if (!isWhitespace$1(c)) {
this.state = State.InAttributeName;
this.sectionStart = this.index;
}
}
stateInSelfClosingTag(c) {
if (c === CharCodes.Gt) {
this.cbs.onselfclosingtag(this.index);
this.state = State.Text;
this.sectionStart = this.index + 1;
this.isSpecial = false; // Reset special state, in case of self-closing special tags
}
else if (!isWhitespace$1(c)) {
this.state = State.BeforeAttributeName;
this.stateBeforeAttributeName(c);
}
}
stateInAttributeName(c) {
if (c === CharCodes.Eq || isEndOfTagSection(c)) {
this.cbs.onattribname(this.sectionStart, this.index);
this.sectionStart = this.index;
this.state = State.AfterAttributeName;
this.stateAfterAttributeName(c);
}
}
stateAfterAttributeName(c) {
if (c === CharCodes.Eq) {
this.state = State.BeforeAttributeValue;
}
else if (c === CharCodes.Slash || c === CharCodes.Gt) {
this.cbs.onattribend(QuoteType.NoValue, this.sectionStart);
this.sectionStart = -1;
this.state = State.BeforeAttributeName;
this.stateBeforeAttributeName(c);
}
else if (!isWhitespace$1(c)) {
this.cbs.onattribend(QuoteType.NoValue, this.sectionStart);
this.state = State.InAttributeName;
this.sectionStart = this.index;
}
}
stateBeforeAttributeValue(c) {
if (c === CharCodes.DoubleQuote) {
this.state = State.InAttributeValueDq;
this.sectionStart = this.index + 1;
}
else if (c === CharCodes.SingleQuote) {
this.state = State.InAttributeValueSq;
this.sectionStart = this.index + 1;
}
else if (!isWhitespace$1(c)) {
this.sectionStart = this.index;
this.state = State.InAttributeValueNq;
this.stateInAttributeValueNoQuotes(c); // Reconsume token
}
}
handleInAttributeValue(c, quote) {
if (c === quote ||
(!this.decodeEntities && this.fastForwardTo(quote))) {
this.cbs.onattribdata(this.sectionStart, this.index);
this.sectionStart = -1;
this.cbs.onattribend(quote === CharCodes.DoubleQuote
? QuoteType.Double
: QuoteType.Single, this.index + 1);
this.state = State.BeforeAttributeName;
}
else if (this.decodeEntities && c === CharCodes.Amp) {
this.startEntity();
}
}
stateInAttributeValueDoubleQuotes(c) {
this.handleInAttributeValue(c, CharCodes.DoubleQuote);
}
stateInAttributeValueSingleQuotes(c) {
this.handleInAttributeValue(c, CharCodes.SingleQuote);
}
stateInAttributeValueNoQuotes(c) {
if (isWhitespace$1(c) || c === CharCodes.Gt) {
this.cbs.onattribdata(this.sectionStart, this.index);
this.sectionStart = -1;
this.cbs.onattribend(QuoteType.Unquoted, this.index);
this.state = State.BeforeAttributeName;
this.stateBeforeAttributeName(c);
}
else if (this.decodeEntities && c === CharCodes.Amp) {
this.startEntity();
}
}
stateBeforeDeclaration(c) {
if (c === CharCodes.OpeningSquareBracket) {
this.state = State.CDATASequence;
this.sequenceIndex = 0;
}
else {
this.state =
c === CharCodes.Dash
? State.BeforeComment
: State.InDeclaration;
}
}
stateInDeclaration(c) {
if (c === CharCodes.Gt || this.fastForwardTo(CharCodes.Gt)) {
this.cbs.ondeclaration(this.sectionStart, this.index);
this.state = State.Text;
this.sectionStart = this.index + 1;
}
}
stateInProcessingInstruction(c) {
if (c === CharCodes.Gt || this.fastForwardTo(CharCodes.Gt)) {
this.cbs.onprocessinginstruction(this.sectionStart, this.index);
this.state = State.Text;
this.sectionStart = this.index + 1;
}
}
stateBeforeComment(c) {
if (c === CharCodes.Dash) {
this.state = State.InCommentLike;
this.currentSequence = Sequences.CommentEnd;
// Allow short comments (eg. <!-->)
this.sequenceIndex = 2;
this.sectionStart = this.index + 1;
}
else {
this.state = State.InDeclaration;
}
}
stateInSpecialComment(c) {
if (c === CharCodes.Gt || this.fastForwardTo(CharCodes.Gt)) {
this.cbs.oncomment(this.sectionStart, this.index, 0);
this.state = State.Text;
this.sectionStart = this.index + 1;
}
}
stateBeforeSpecialS(c) {
const lower = c | 0x20;
if (lower === Sequences.ScriptEnd[3]) {
this.startSpecial(Sequences.ScriptEnd, 4);
}
else if (lower === Sequences.StyleEnd[3]) {
this.startSpecial(Sequences.StyleEnd, 4);
}
else {
this.state = State.InTagName;
this.stateInTagName(c); // Consume the token again
}
}
stateBeforeSpecialT(c) {
const lower = c | 0x20;
switch (lower) {
case Sequences.TitleEnd[3]: {
this.startSpecial(Sequences.TitleEnd, 4);
break;
}
case Sequences.TextareaEnd[3]: {
this.startSpecial(Sequences.TextareaEnd, 4);
break;
}
case Sequences.XmpEnd[3]: {
this.startSpecial(Sequences.XmpEnd, 4);
break;
}
default: {
this.state = State.InTagName;
this.stateInTagName(c); // Consume the token again
}
}
}
startEntity() {
this.baseState = this.state;
this.state = State.InEntity;
this.entityStart = this.index;
this.entityDecoder.startEntity(this.xmlMode
? DecodingMode.Strict
: this.baseState === State.Text ||
this.baseState === State.InSpecialTag
? DecodingMode.Legacy
: DecodingMode.Attribute);
}
stateInEntity() {
const indexInBuffer = this.index - this.offset;
const length = this.entityDecoder.write(this.buffer, indexInBuffer);
// If `length` is positive, we are done with the entity.
if (length >= 0) {
this.state = this.baseState;
if (length === 0) {
this.index -= 1;
}
}
else {
if (indexInBuffer < this.buffer.length &&
this.buffer.charCodeAt(indexInBuffer) === CharCodes.Amp) {
this.state = this.baseState;
this.index -= 1;
return;
}
// Mark buffer as consumed.
this.index = this.offset + this.buffer.length - 1;
}
}
/**
* Remove data that has already been consumed from the buffer.
*/
cleanup() {
// If we are inside of text or attributes, emit what we already have.
if (this.running && this.sectionStart !== this.index) {
if (this.state === State.Text ||
(this.state === State.InSpecialTag && this.sequenceIndex === 0)) {
this.cbs.ontext(this.sectionStart, this.index);
this.sectionStart = this.index;
}
else if (this.state === State.InAttributeValueDq ||
this.state === State.InAttributeValueSq ||
this.state === State.InAttributeValueNq) {
this.cbs.onattribdata(this.sectionStart, this.index);
this.sectionStart = this.index;
}
}
}
shouldContinue() {
return this.index < this.buffer.length + this.offset && this.running;
}
/**
* Iterates through the buffer, calling the function corresponding to the current state.
*
* States that are more likely to be hit are higher up, as a performance improvement.
*/
parse() {
while (this.shouldContinue()) {
const c = this.buffer.charCodeAt(this.index - this.offset);
switch (this.state) {
case State.Text: {
this.stateText(c);
break;
}
case State.SpecialStartSequence: {
this.stateSpecialStartSequence(c);
break;
}
case State.InSpecialTag: {
this.stateInSpecialTag(c);
break;
}
case State.CDATASequence: {
this.stateCDATASequence(c);
break;
}
case State.InAttributeValueDq: {
this.stateInAttributeValueDoubleQuotes(c);
break;
}
case State.InAttributeName: {
this.stateInAttributeName(c);
break;
}
case State.InCommentLike: {
this.stateInCommentLike(c);
break;
}
case State.InSpecialComment: {
this.stateInSpecialComment(c);
break;
}
case State.BeforeAttributeName: {
this.stateBeforeAttributeName(c);
break;
}
case State.InTagName: {
this.stateInTagName(c);
break;
}
case State.InClosingTagName: {
this.stateInClosingTagName(c);
break;
}
case State.BeforeTagName: {
this.stateBeforeTagName(c);
break;
}
case State.AfterAttributeName: {
this.stateAfterAttributeName(c);
break;
}
case State.InAttributeValueSq: {
this.stateInAttributeValueSingleQuotes(c);
break;
}
case State.BeforeAttributeValue: {
this.stateBeforeAttributeValue(c);
break;
}
case State.BeforeClosingTagName: {
this.stateBeforeClosingTagName(c);
break;
}
case State.AfterClosingTagName: {
this.stateAfterClosingTagName(c);
break;
}
case State.BeforeSpecialS: {
this.stateBeforeSpecialS(c);
break;
}
case State.BeforeSpecialT: {
this.stateBeforeSpecialT(c);
break;
}
case State.InAttributeValueNq: {
this.stateInAttributeValueNoQuotes(c);
break;
}
case State.InSelfClosingTag: {
this.stateInSelfClosingTag(c);
break;
}
case State.InDeclaration: {
this.stateInDeclaration(c);
break;
}
case State.BeforeDeclaration: {
this.stateBeforeDeclaration(c);
break;
}
case State.BeforeComment: {
this.stateBeforeComment(c);
break;
}
case State.InProcessingInstruction: {
this.stateInProcessingInstruction(c);
break;
}
case State.InEntity: {
this.stateInEntity();
break;
}
}
this.index++;
}
this.cleanup();
}
finish() {
if (this.state === State.InEntity) {
this.entityDecoder.end();
this.state = this.baseState;
}
this.handleTrailingData();
this.cbs.onend();
}
/** Handle any trailing data. */
handleTrailingData() {
const endIndex = this.buffer.length + this.offset;
// If there is no remaining data, we are done.
if (this.sectionStart >= endIndex) {
return;
}
if (this.state === State.InCommentLike) {
if (this.currentSequence === Sequences.CdataEnd) {
this.cbs.oncdata(this.sectionStart, endIndex, 0);
}
else {
this.cbs.oncomment(this.sectionStart, endIndex, 0);
}
}
else if (this.state === State.InTagName ||
this.state === State.BeforeAttributeName ||
this.state === State.BeforeAttributeValue ||
this.state === State.AfterAttributeName ||
this.state === State.InAttributeName ||
this.state === State.InAttributeValueSq ||
this.state === State.InAttributeValueDq ||
this.state === State.InAttributeValueNq ||
this.state === State.InClosingTagName) ;
else {
this.cbs.ontext(this.sectionStart, endIndex);
}
}
emitCodePoint(cp, consumed) {
if (this.baseState !== State.Text &&
this.baseState !== State.InSpecialTag) {
if (this.sectionStart < this.entityStart) {
this.cbs.onattribdata(this.sectionStart, this.entityStart);
}
this.sectionStart = this.entityStart + consumed;
this.index = this.sectionStart - 1;
this.cbs.onattribentity(cp);
}
else {
if (this.sectionStart < this.entityStart) {
this.cbs.ontext(this.sectionStart, this.entityStart);
}
this.sectionStart = this.entityStart + consumed;
this.index = this.sectionStart - 1;
this.cbs.ontextentity(cp, this.sectionStart);
}
}
}
const formTags = new Set([
"input",
"option",
"optgroup",
"select",
"button",
"datalist",
"textarea",
]);
const pTag = new Set(["p"]);
const tableSectionTags = new Set(["thead", "tbody"]);
const ddtTags = new Set(["dd", "dt"]);
const rtpTags = new Set(["rt", "rp"]);
const openImpliesClose = new Map([
["tr", new Set(["tr", "th", "td"])],
["th", new Set(["th"])],
["td", new Set(["thead", "th", "td"])],
["body", new Set(["head", "link", "script"])],
["li", new Set(["li"])],
["p", pTag],
["h1", pTag],
["h2", pTag],
["h3", pTag],
["h4", pTag],
["h5", pTag],
["h6", pTag],
["select", formTags],
["input", formTags],
["output", formTags],
["button", formTags],
["datalist", formTags],
["textarea", formTags],
["option", new Set(["option"])],
["optgroup", new Set(["optgroup", "option"])],
["dd", ddtTags],
["dt", ddtTags],
["address", pTag],
["article", pTag],
["aside", pTag],
["blockquote", pTag],
["details", pTag],
["div", pTag],
["dl", pTag],
["fieldset", pTag],
["figcaption", pTag],
["figure", pTag],
["footer", pTag],
["form", pTag],
["header", pTag],
["hr", pTag],
["main", pTag],
["nav", pTag],
["ol", pTag],
["pre", pTag],
["section", pTag],
["table", pTag],
["ul", pTag],
["rt", rtpTags],
["rp", rtpTags],
["tbody", tableSectionTags],
["tfoot", tableSectionTags],
]);
const voidElements$1 = new Set([
"area",
"base",
"basefont",
"br",
"col",
"command",
"embed",
"frame",
"hr",
"img",
"input",
"isindex",
"keygen",
"link",
"meta",
"param",
"source",
"track",
"wbr",
]);
const foreignContextElements = new Set(["math", "svg"]);
const htmlIntegrationElements = new Set([
"mi",
"mo",
"mn",
"ms",
"mtext",
"annotation-xml",
"foreignobject",
"desc",
"title",
]);
const reNameEnd = /\s|\//;
let Parser$1 = class Parser {
constructor(cbs, options = {}) {
var _a, _b, _c, _d, _e, _f;
this.options = options;
/** The start index of the last event. */
this.startIndex = 0;
/** The end index of the last event. */
this.endIndex = 0;
/**
* Store the start index of the current open tag,
* so we can update the start index for attributes.
*/
this.openTagStart = 0;
this.tagname = "";
this.attribname = "";
this.attribvalue = "";
this.attribs = null;
this.stack = [];
this.buffers = [];
this.bufferOffset = 0;
/** The index of the last written buffer. Used when resuming after a `pause()`. */
this.writeIndex = 0;
/** Indicates whether the parser has finished running / `.end` has been called. */
this.ended = false;
this.cbs = cbs !== null && cbs !== void 0 ? cbs : {};
this.htmlMode = !this.options.xmlMode;
this.lowerCaseTagNames = (_a = options.lowerCaseTags) !== null && _a !== void 0 ? _a : this.htmlMode;
this.lowerCaseAttributeNames =
(_b = options.lowerCaseAttributeNames) !== null && _b !== void 0 ? _b : this.htmlMode;
this.recognizeSelfClosing =
(_c = options.recognizeSelfClosing) !== null && _c !== void 0 ? _c : !this.htmlMode;
this.tokenizer = new ((_d = options.Tokenizer) !== null && _d !== void 0 ? _d : Tokenizer)(this.options, this);
this.foreignContext = [!this.htmlMode];
(_f = (_e = this.cbs).onparserinit) === null || _f === void 0 ? void 0 : _f.call(_e, this);
}
// Tokenizer event handlers
/** @internal */
ontext(start, endIndex) {
var _a, _b;
const data = this.getSlice(start, endIndex);
this.endIndex = endIndex - 1;
(_b = (_a = this.cbs).ontext) === null || _b === void 0 ? void 0 : _b.call(_a, data);
this.startIndex = endIndex;
}
/** @internal */
ontextentity(cp, endIndex) {
var _a, _b;
this.endIndex = endIndex - 1;
(_b = (_a = this.cbs).ontext) === null || _b === void 0 ? void 0 : _b.call(_a, fromCodePoint(cp));
this.startIndex = endIndex;
}
/**
* Checks if the current tag is a void element. Override this if you want
* to specify your own additional void elements.
*/
isVoidElement(name) {
return this.htmlMode && voidElements$1.has(name);
}
/** @internal */
onopentagname(start, endIndex) {
this.endIndex = endIndex;
let name = this.getSlice(start, endIndex);
if (this.lowerCaseTagNames) {
name = name.toLowerCase();
}
this.emitOpenTag(name);
}
emitOpenTag(name) {
var _a, _b, _c, _d;
this.openTagStart = this.startIndex;
this.tagname = name;
const impliesClose = this.htmlMode && openImpliesClose.get(name);
if (impliesClose) {
while (this.stack.length > 0 && impliesClose.has(this.stack[0])) {
const element = this.stack.shift();
(_b = (_a = this.cbs).onclosetag) === null || _b === void 0 ? void 0 : _b.call(_a, element, true);
}
}
if (!this.isVoidElement(name)) {
this.stack.unshift(name);
if (this.htmlMode) {
if (foreignContextElements.has(name)) {
this.foreignContext.unshift(true);
}
else if (htmlIntegrationElements.has(name)) {
this.foreignContext.unshift(false);
}
}
}
(_d = (_c = this.cbs).onopentagname) === null || _d === void 0 ? void 0 : _d.call(_c, name);
if (this.cbs.onopentag)
this.attribs = {};
}
endOpenTag(isImplied) {
var _a, _b;
this.startIndex = this.openTagStart;
if (this.attribs) {
(_b = (_a = this.cbs).onopentag) === null || _b === void 0 ? void 0 : _b.call(_a, this.tagname, this.attribs, isImplied);
this.attribs = null;
}
if (this.cbs.onclosetag && this.isVoidElement(this.tagname)) {
this.cbs.onclosetag(this.tagname, true);
}
this.tagname = "";
}
/** @internal */
onopentagend(endIndex) {
this.endIndex = endIndex;
this.endOpenTag(false);
// Set `startIndex` for next node
this.startIndex = endIndex + 1;
}
/** @internal */
onclosetag(start, endIndex) {
var _a, _b, _c, _d, _e, _f, _g, _h;
this.endIndex = endIndex;
let name = this.getSlice(start, endIndex);
if (this.lowerCaseTagNames) {
name = name.toLowerCase();
}
if (this.htmlMode &&
(foreignContextElements.has(name) ||
htmlIntegrationElements.has(name))) {
this.foreignContext.shift();
}
if (!this.isVoidElement(name)) {
const pos = this.stack.indexOf(name);
if (pos !== -1) {
for (let index = 0; index <= pos; index++) {
const element = this.stack.shift();
// We know the stack has sufficient elements.
(_b = (_a = this.cbs).onclosetag) === null || _b === void 0 ? void 0 : _b.call(_a, element, index !== pos);
}
}
else if (this.htmlMode && name === "p") {
// Implicit open before close
this.emitOpenTag("p");
this.closeCurrentTag(true);
}
}
else if (this.htmlMode && name === "br") {
// We can't use `emitOpenTag` for implicit open, as `br` would be implicitly closed.
(_d = (_c = this.cbs).onopentagname) === null || _d === void 0 ? void 0 : _d.call(_c, "br");
(_f = (_e = this.cbs).onopentag) === null || _f === void 0 ? void 0 : _f.call(_e, "br", {}, true);
(_h = (_g = this.cbs).onclosetag) === null || _h === void 0 ? void 0 : _h.call(_g, "br", false);
}
// Set `startIndex` for next node
this.startIndex = endIndex + 1;
}
/** @internal */
onselfclosingtag(endIndex) {
this.endIndex = endIndex;
if (this.recognizeSelfClosing || this.foreignContext[0]) {
this.closeCurrentTag(false);
// Set `startIndex` for next node
this.startIndex = endIndex + 1;
}
else {
// Ignore the fact that the tag is self-closing.
this.onopentagend(endIndex);
}
}
closeCurrentTag(isOpenImplied) {
var _a, _b;
const name = this.tagname;
this.endOpenTag(isOpenImplied);
// Self-closing tags will be on the top of the stack
if (this.stack[0] === name) {
// If the opening tag isn't implied, the closing tag has to be implied.
(_b = (_a = this.cbs).onclosetag) === null || _b === void 0 ? void 0 : _b.call(_a, name, !isOpenImplied);
this.stack.shift();
}
}
/** @internal */
onattribname(start, endIndex) {
this.startIndex = start;
const name = this.getSlice(start, endIndex);
this.attribname = this.lowerCaseAttributeNames
? name.toLowerCase()
: name;
}
/** @internal */
onattribdata(start, endIndex) {
this.attribvalue += this.getSlice(start, endIndex);
}
/** @internal */
onattribentity(cp) {
this.attribvalue += fromCodePoint(cp);
}
/** @internal */
onattribend(quote, endIndex) {
var _a, _b;
this.endIndex = endIndex;
(_b = (_a = this.cbs).onattribute) === null || _b === void 0 ? void 0 : _b.call(_a, this.attribname, this.attribvalue, quote === QuoteType.Double
? '"'
: quote === QuoteType.Single
? "'"
: quote === QuoteType.NoValue
? undefined
: null);
if (this.attribs &&
!Object.prototype.hasOwnProperty.call(this.attribs, this.attribname)) {
this.attribs[this.attribname] = this.attribvalue;
}
this.attribvalue = "";
}
getInstructionName(value) {
const index = value.search(reNameEnd);
let name = index < 0 ? value : value.substr(0, index);
if (this.lowerCaseTagNames) {
name = name.toLowerCase();
}
return name;
}
/** @internal */
ondeclaration(start, endIndex) {
this.endIndex = endIndex;
const value = this.getSlice(start, endIndex);
if (this.cbs.onprocessinginstruction) {
const name = this.getInstructionName(value);
this.cbs.onprocessinginstruction(`!${name}`, `!${value}`);
}
// Set `startIndex` for next node
this.startIndex = endIndex + 1;
}
/** @internal */
onprocessinginstruction(start, endIndex) {
this.endIndex = endIndex;
const value = this.getSlice(start, endIndex);
if (this.cbs.onprocessinginstruction) {
const name = this.getInstructionName(value);
this.cbs.onprocessinginstruction(`?${name}`, `?${value}`);
}
// Set `startIndex` for next node
this.startIndex = endIndex + 1;
}
/** @internal */
oncomment(start, endIndex, offset) {
var _a, _b, _c, _d;
this.endIndex = endIndex;
(_b = (_a = this.cbs).oncomment) === null || _b === void 0 ? void 0 : _b.call(_a, this.getSlice(start, endIndex - offset));
(_d = (_c = this.cbs).oncommentend) === null || _d === void 0 ? void 0 : _d.call(_c);
// Set `startIndex` for next node
this.startIndex = endIndex + 1;
}
/** @internal */
oncdata(start, endIndex, offset) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
this.endIndex = endIndex;
const value = this.getSlice(start, endIndex - offset);
if (!this.htmlMode || this.options.recognizeCDATA) {
(_b = (_a = this.cbs).oncdatastart) === null || _b === void 0 ? void 0 : _b.call(_a);
(_d = (_c = this.cbs).ontext) === null || _d === void 0 ? void 0 : _d.call(_c, value);
(_f = (_e = this.cbs).oncdataend) === null || _f === void 0 ? void 0 : _f.call(_e);
}
else {
(_h = (_g = this.cbs).oncomment) === null || _h === void 0 ? void 0 : _h.call(_g, `[CDATA[${value}]]`);
(_k = (_j = this.cbs).oncommentend) === null || _k === void 0 ? void 0 : _k.call(_j);
}
// Set `startIndex` for next node
this.startIndex = endIndex + 1;
}
/** @internal */
onend() {
var _a, _b;
if (this.cbs.onclosetag) {
// Set the end index for all remaining tags
this.endIndex = this.startIndex;
for (let index = 0; index < this.stack.length; index++) {
this.cbs.onclosetag(this.stack[index], true);
}
}
(_b = (_a = this.cbs).onend) === null || _b === void 0 ? void 0 : _b.call(_a);
}
/**
* Resets the parser to a blank state, ready to parse a new HTML document
*/
reset() {
var _a, _b, _c, _d;
(_b = (_a = this.cbs).onreset) === null || _b === void 0 ? void 0 : _b.call(_a);
this.tokenizer.reset();
this.tagname = "";
this.attribname = "";
this.attribs = null;
this.stack.length = 0;
this.startIndex = 0;
this.endIndex = 0;
(_d = (_c = this.cbs).onparserinit) === null || _d === void 0 ? void 0 : _d.call(_c, this);
this.buffers.length = 0;
this.foreignContext.length = 0;
this.foreignContext.unshift(!this.htmlMode);
this.bufferOffset = 0;
this.writeIndex = 0;
this.ended = false;
}
/**
* Resets the parser, then parses a complete document and
* pushes it to the handler.
*
* @param data Document to parse.
*/
parseComplete(data) {
this.reset();
this.end(data);
}
getSlice(start, end) {
while (start - this.bufferOffset >= this.buffers[0].length) {
this.shiftBuffer();
}
let slice = this.buffers[0].slice(start - this.bufferOffset, end - this.bufferOffset);
while (end - this.bufferOffset > this.buffers[0].length) {
this.shiftBuffer();
slice += this.buffers[0].slice(0, end - this.bufferOffset);
}
return slice;
}
shiftBuffer() {
this.bufferOffset += this.buffers[0].length;
this.writeIndex--;
this.buffers.shift();
}
/**
* Parses a chunk of data and calls the corresponding callbacks.
*
* @param chunk Chunk to parse.
*/
write(chunk) {
var _a, _b;
if (this.ended) {
(_b = (_a = this.cbs).onerror) === null || _b === void 0 ? void 0 : _b.call(_a, new Error(".write() after done!"));
return;
}
this.buffers.push(chunk);
if (this.tokenizer.running) {
this.tokenizer.write(chunk);
this.writeIndex++;
}
}
/**
* Parses the end of the buffer and clears the stack, calls onend.
*
* @param chunk Optional final chunk to parse.
*/
end(chunk) {
var _a, _b;
if (this.ended) {
(_b = (_a = this.cbs).onerror) === null || _b === void 0 ? void 0 : _b.call(_a, new Error(".end() after done!"));
return;
}
if (chunk)
this.write(chunk);
this.ended = true;
this.tokenizer.end();
}
/**
* Pauses parsing. The parser won't emit events until `resume` is called.
*/
pause() {
this.tokenizer.pause();
}
/**
* Resumes parsing after `pause` was called.
*/
resume() {
this.tokenizer.resume();
while (this.tokenizer.running &&
this.writeIndex < this.buffers.length) {
this.tokenizer.write(this.buffers[this.writeIndex++]);
}
if (this.ended)
this.tokenizer.end();
}
/**
* Alias of `write`, for backwards compatibility.
*
* @param chunk Chunk to parse.
* @deprecated
*/
parseChunk(chunk) {
this.write(chunk);
}
/**
* Alias of `end`, for backwards compatibility.
*
* @param chunk Optional final chunk to parse.
* @deprecated
*/
done(chunk) {
this.end(chunk);
}
};
var HTMLParser2 = /*#__PURE__*/Object.freeze({
__proto__: null,
Parser: Parser$1,
get QuoteType () { return QuoteType; },
Tokenizer: Tokenizer
});
// Internal
const NODE_END = -1;
// Node
const ELEMENT_NODE = 1;
const ATTRIBUTE_NODE = 2;
const TEXT_NODE = 3;
const CDATA_SECTION_NODE = 4;
const COMMENT_NODE = 8;
const DOCUMENT_NODE = 9;
const DOCUMENT_TYPE_NODE = 10;
const DOCUMENT_FRAGMENT_NODE = 11;
// Elements
const BLOCK_ELEMENTS = new Set(['ARTICLE', 'ASIDE', 'BLOCKQUOTE', 'BODY', 'BR', 'BUTTON', 'CANVAS', 'CAPTION', 'COL', 'COLGROUP', 'DD', 'DIV', 'DL', 'DT', 'EMBED', 'FIELDSET', 'FIGCAPTION', 'FIGURE', 'FOOTER', 'FORM', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'LI', 'UL', 'OL', 'P']);
// TreeWalker
const SHOW_ALL = -1;
const SHOW_ELEMENT = 1;
const SHOW_TEXT = 4;
const SHOW_CDATA_SECTION = 8;
const SHOW_COMMENT = 128;
// Document position
const DOCUMENT_POSITION_DISCONNECTED = 0x01;
const DOCUMENT_POSITION_PRECEDING = 0x02;
const DOCUMENT_POSITION_FOLLOWING = 0x04;
const DOCUMENT_POSITION_CONTAINS = 0x08;
const DOCUMENT_POSITION_CONTAINED_BY = 0x10;
const DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20;
// SVG
const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
const {
assign,
create: create$1,
defineProperties,
entries,
keys,
setPrototypeOf
} = Object;
const $String = String;
const getEnd = node => node.nodeType === ELEMENT_NODE ? node[END] : node;
const ignoreCase = ({ownerDocument}) => ownerDocument[MIME].ignoreCase;
const knownAdjacent = (prev, next) => {
prev[NEXT] = next;
next[PREV] = prev;
};
const knownBoundaries = (prev, current, next) => {
knownAdjacent(prev, current);
knownAdjacent(getEnd(current), next);
};
const knownSegment = (prev, start, end, next) => {
knownAdjacent(prev, start);
knownAdjacent(getEnd(end), next);
};
const knownSiblings = (prev, current, next) => {
knownAdjacent(prev, current);
knownAdjacent(current, next);
};
const localCase = ({localName, ownerDocument}) => {
return ownerDocument[MIME].ignoreCase ? localName.toUpperCase() : localName;
};
const setAdjacent = (prev, next) => {
if (prev)
prev[NEXT] = next;
if (next)
next[PREV] = prev;
};
/**
* @param {import("../interface/document.js").Document} ownerDocument
* @param {string} html
* @return {import("../interface/document-fragment.js").DocumentFragment}
*/
const htmlToFragment = (ownerDocument, html) => {
const fragment = ownerDocument.createDocumentFragment();
const elem = ownerDocument.createElement('');
elem.innerHTML = html;
const { firstChild, lastChild } = elem;
if (firstChild) {
knownSegment(fragment, firstChild, lastChild, fragment[END]);
let child = firstChild;
do {
child.parentNode = fragment;
} while (child !== lastChild && (child = getEnd(child)[NEXT]));
}
return fragment;
};
const shadowRoots = new WeakMap;
let reactive = false;
const Classes = new WeakMap;
const customElements = new WeakMap;
const attributeChangedCallback$1 = (element, attributeName, oldValue, newValue) => {
if (
reactive &&
customElements.has(element) &&
element.attributeChangedCallback &&
element.constructor.observedAttributes.includes(attributeName)
) {
element.attributeChangedCallback(attributeName, oldValue, newValue);
}
};
const createTrigger = (method, isConnected) => element => {
if (customElements.has(element)) {
const info = customElements.get(element);
if (info.connected !== isConnected && element.isConnected === isConnected) {
info.connected = isConnected;
if (method in element)
element[method]();
}
}
};
const triggerConnected = createTrigger('connectedCallback', true);
const connectedCallback = element => {
if (reactive) {
triggerConnected(element);
if (shadowRoots.has(element))
element = shadowRoots.get(element).shadowRoot;
let {[NEXT]: next, [END]: end} = element;
while (next !== end) {
if (next.nodeType === ELEMENT_NODE)
triggerConnected(next);
next = next[NEXT];
}
}
};
const triggerDisconnected = createTrigger('disconnectedCallback', false);
const disconnectedCallback = element => {
if (reactive) {
triggerDisconnected(element);
if (shadowRoots.has(element))
element = shadowRoots.get(element).shadowRoot;
let {[NEXT]: next, [END]: end} = element;
while (next !== end) {
if (next.nodeType === ELEMENT_NODE)
triggerDisconnected(next);
next = next[NEXT];
}
}
};
/**
* @implements globalThis.CustomElementRegistry
*/
class CustomElementRegistry {
/**
* @param {Document} ownerDocument
*/
constructor(ownerDocument) {
/**
* @private
*/
this.ownerDocument = ownerDocument;
/**
* @private
*/
this.registry = new Map;
/**
* @private
*/
this.waiting = new Map;
/**
* @private
*/
this.active = false;
}
/**
* @param {string} localName the custom element definition name
* @param {Function} Class the custom element **Class** definition
* @param {object?} options the optional object with an `extends` property
*/
define(localName, Class, options = {}) {
const {ownerDocument, registry, waiting} = this;
if (registry.has(localName))
throw new Error('unable to redefine ' + localName);
if (Classes.has(Class))
throw new Error('unable to redefine the same class: ' + Class);
this.active = (reactive = true);
const {extends: extend} = options;
Classes.set(Class, {
ownerDocument,
options: {is: extend ? localName : ''},
localName: extend || localName
});
const check = extend ?
element => {
return element.localName === extend &&
element.getAttribute('is') === localName;
} :
element => element.localName === localName;
registry.set(localName, {Class, check});
if (waiting.has(localName)) {
for (const resolve of waiting.get(localName))
resolve(Class);
waiting.delete(localName);
}
ownerDocument.querySelectorAll(
extend ? `${extend}[is="${localName}"]` : localName
).forEach(this.upgrade, this);
}
/**
* @param {Element} element
*/
upgrade(element) {
if (customElements.has(element))
return;
const {ownerDocument, registry} = this;
const ce = element.getAttribute('is') || element.localName;
if (registry.has(ce)) {
const {Class, check} = registry.get(ce);
if (check(element)) {
const {attributes, isConnected} = element;
for (const attr of attributes)
element.removeAttributeNode(attr);
const values = entries(element);
for (const [key] of values)
delete element[key];
setPrototypeOf(element, Class.prototype);
ownerDocument[UPGRADE] = {element, values};
new Class(ownerDocument, ce);
customElements.set(element, {connected: isConnected});
for (const attr of attributes)
element.setAttributeNode(attr);
if (isConnected && element.connectedCallback)
element.connectedCallback();
}
}
}
/**
* @param {string} localName the custom element definition name
*/
whenDefined(localName) {
const {registry, waiting} = this;
return new Promise(resolve => {
if (registry.has(localName))
resolve(registry.get(localName).Class);
else {
if (!waiting.has(localName))
waiting.set(localName, []);
waiting.get(localName).push(resolve);
}
});
}
/**
* @param {string} localName the custom element definition name
* @returns {Function?} the custom element **Class**, if any
*/
get(localName) {
const info = this.registry.get(localName);
return info && info.Class;
}
/**
* @param {Function} Class **Class** of custom element
* @returns {string?} found tag name or null
*/
getName(Class) {
if (Classes.has(Class)) {
const { localName } = Classes.get(Class);
return localName;
}
return null;
}
}
const {Parser} = HTMLParser2;
const append$2 = (self, node, active) => {
const end = self[END];
node.parentNode = self;
knownBoundaries(end[PREV], node, end);
if (active && node.nodeType === ELEMENT_NODE)
connectedCallback(node);
return node;
};
const attribute = (element, end, attribute, value, active) => {
attribute[VALUE] = value;
attribute.ownerElement = element;
knownSiblings(end[PREV], attribute, end);
if (attribute.name === 'class')
element.className = value;
if (active)
attributeChangedCallback$1(element, attribute.name, null, value);
};
const parseFromString = (document, isHTML, markupLanguage) => {
const {active, registry} = document[CUSTOM_ELEMENTS];
let node = document;
let ownerSVGElement = null;
let parsingCData = false;
const content = new Parser({
// <!DOCTYPE ...>
onprocessinginstruction(name, data) {
if (name.toLowerCase() === '!doctype')
document.doctype = data.slice(name.length).trim();
},
// <tagName>
onopentag(name, attributes) {
let create = true;
if (isHTML) {
if (ownerSVGElement) {
node = append$2(node, document.createElementNS(SVG_NAMESPACE, name), active);
node.ownerSVGElement = ownerSVGElement;
create = false;
}
else if (name === 'svg' || name === 'SVG') {
ownerSVGElement = document.createElementNS(SVG_NAMESPACE, name);
node = append$2(node, ownerSVGElement, active);
create = false;
}
else if (active) {
const ce = name.includes('-') ? name : (attributes.is || '');
if (ce && registry.has(ce)) {
const {Class} = registry.get(ce);
node = append$2(node, new Class, active);
delete attributes.is;
create = false;
}
}
}
if (create)
node = append$2(node, document.createElement(name), false);
let end = node[END];
for (const name of keys(attributes))
attribute(node, end, document.createAttribute(name), attributes[name], active);
},
// #text, #comment
oncomment(data) { append$2(node, document.createComment(data), active); },
ontext(text) {
if (parsingCData) {
append$2(node, document.createCDATASection(text), active);
} else {
append$2(node, document.createTextNode(text), active);
}
},
// #cdata
oncdatastart() { parsingCData = true; },
oncdataend() { parsingCData = false; },
// </tagName>
onclosetag() {
if (isHTML && node === ownerSVGElement)
ownerSVGElement = null;
node = node.parentNode;
}
}, {
lowerCaseAttributeNames: false,
decodeEntities: true,
xmlMode: !isHTML
});
content.write(markupLanguage);
content.end();
return document;
};
const htmlClasses = new Map;
const registerHTMLClass = (names, Class) => {
for (const name of [].concat(names)) {
htmlClasses.set(name, Class);
htmlClasses.set(name.toUpperCase(), Class);
}
};
const loopSegment = ({[NEXT]: next, [END]: end}, json) => {
while (next !== end) {
switch (next.nodeType) {
case ATTRIBUTE_NODE:
attrAsJSON(next, json);
break;
case TEXT_NODE:
case COMMENT_NODE:
case CDATA_SECTION_NODE:
characterDataAsJSON(next, json);
break;
case ELEMENT_NODE:
elementAsJSON(next, json);
next = getEnd(next);
break;
case DOCUMENT_TYPE_NODE:
documentTypeAsJSON(next, json);
break;
}
next = next[NEXT];
}
const last = json.length - 1;
const value = json[last];
if (typeof value === 'number' && value < 0)
json[last] += NODE_END;
else
json.push(NODE_END);
};
const attrAsJSON = (attr, json) => {
json.push(ATTRIBUTE_NODE, attr.name);
const value = attr[VALUE].trim();
if (value)
json.push(value);
};
const characterDataAsJSON = (node, json) => {
const value = node[VALUE];
if (value.trim())
json.push(node.nodeType, value);
};
const nonElementAsJSON = (node, json) => {
json.push(node.nodeType);
loopSegment(node, json);
};
const documentTypeAsJSON = ({name, publicId, systemId}, json) => {
json.push(DOCUMENT_TYPE_NODE, name);
if (publicId)
json.push(publicId);
if (systemId)
json.push(systemId);
};
const elementAsJSON = (element, json) => {
json.push(ELEMENT_NODE, element.localName);
loopSegment(element, json);
};
const createRecord =
(type, target, element, addedNodes, removedNodes, attributeName, oldValue) =>
({
type,
target,
addedNodes,
removedNodes,
attributeName,
oldValue,
previousSibling: element?.previousSibling || null,
nextSibling: element?.nextSibling || null,
});
const queueAttribute = (
observer, target, attributeName, attributeFilter, attributeOldValue, oldValue
) => {
if ((!attributeFilter || attributeFilter.includes(attributeName))) {
const {callback, records, scheduled} = observer;
records.push(createRecord(
'attributes', target, null,
[], [],
attributeName, attributeOldValue ? oldValue : void 0
));
if (!scheduled) {
observer.scheduled = true;
Promise.resolve().then(() => {
observer.scheduled = false;
callback(records.splice(0), observer);
});
}
}
};
const attributeChangedCallback = (element, attributeName, oldValue) => {
const {ownerDocument} = element;
const {active, observers} = ownerDocument[MUTATION_OBSERVER];
if (active) {
for (const observer of observers) {
for (const [
target,
{
childList,
subtree,
attributes,
attributeFilter,
attributeOldValue
}
] of observer.nodes) {
if (childList) {
if (
(subtree && (target === ownerDocument || target.contains(element))) ||
(!subtree && target.children.includes(element))
) {
queueAttribute(
observer, element,
attributeName, attributeFilter, attributeOldValue, oldValue
);
break;
}
}
else if (
attributes &&
target === element
) {
queueAttribute(
observer, element,
attributeName, attributeFilter, attributeOldValue, oldValue
);
break;
}
}
}
}
};
const moCallback = (element, parentNode) => {
const {ownerDocument} = element;
const {active, observers} = ownerDocument[MUTATION_OBSERVER];
if (active) {
for (const observer of observers) {
for (const [target, {subtree, childList, characterData}] of observer.nodes) {
if (childList) {
if (
(parentNode && (target === parentNode || /* c8 ignore next */(subtree && target.contains(parentNode)))) ||
(!parentNode && ((subtree && (target === ownerDocument || /* c8 ignore next */target.contains(element))) ||
(!subtree && target[characterData ? 'childNodes' : 'children'].includes(element))))
) {
const {callback, records, scheduled} = observer;
records.push(createRecord(
'childList', target, element,
parentNode ? [] : [element], parentNode ? [element] : []
));
if (!scheduled) {
observer.scheduled = true;
Promise.resolve().then(() => {
observer.scheduled = false;
callback(records.splice(0), observer);
});
}
break;
}
}
}
}
}
};
class MutationObserverClass {
constructor(ownerDocument) {
const observers = new Set;
this.observers = observers;
this.active = false;
/**
* @implements globalThis.MutationObserver
*/
this.class = class MutationObserver {
constructor(callback) {
/**
* @private
*/
this.callback = callback;
/**
* @private
*/
this.nodes = new Map;
/**
* @private
*/
this.records = [];
/**
* @private
*/
this.scheduled = false;
}
disconnect() {
this.records.splice(0);
this.nodes.clear();
observers.delete(this);
ownerDocument[MUTATION_OBSERVER].active = !!observers.size;
}
/**
* @param {Element} target
* @param {MutationObserverInit} options
*/
observe(target, options = {
subtree: false,
childList: false,
attributes: false,
attributeFilter: null,
attributeOldValue: false,
characterData: false,
// TODO: not implemented yet
// characterDataOldValue: false
}) {
if (('attributeOldValue' in options) || ('attributeFilter' in options))
options.attributes = true;
// if ('characterDataOldValue' in options)
// options.characterData = true;
options.childList = !!options.childList;
options.subtree = !!options.subtree;
this.nodes.set(target, options);
observers.add(this);
ownerDocument[MUTATION_OBSERVER].active = true;
}
/**
* @returns {MutationRecord[]}
*/
takeRecords() { return this.records.splice(0); }
};
}
}
const emptyAttributes = new Set([
'allowfullscreen',
'allowpaymentrequest',
'async',
'autofocus',
'autoplay',
'checked',
'class',
'contenteditable',
'controls',
'default',
'defer',
'disabled',
'draggable',
'formnovalidate',
'hidden',
'id',
'ismap',
'itemscope',
'loop',
'multiple',
'muted',
'nomodule',
'novalidate',
'open',
'playsinline',
'readonly',
'required',
'reversed',
'selected',
'style',
'truespeed'
]);
const setAttribute = (element, attribute) => {
const {[VALUE]: value, name} = attribute;
attribute.ownerElement = element;
knownSiblings(element, attribute, element[NEXT]);
if (name === 'class')
element.className = value;
attributeChangedCallback(element, name, null);
attributeChangedCallback$1(element, name, null, value);
};
const removeAttribute = (element, attribute) => {
const {[VALUE]: value, name} = attribute;
knownAdjacent(attribute[PREV], attribute[NEXT]);
attribute.ownerElement = attribute[PREV] = attribute[NEXT] = null;
if (name === 'class')
element[CLASS_LIST] = null;
attributeChangedCallback(element, name, value);
attributeChangedCallback$1(element, name, value, null);
};
const booleanAttribute = {
get(element, name) {
return element.hasAttribute(name);
},
set(element, name, value) {
if (value)
element.setAttribute(name, '');
else
element.removeAttribute(name);
}
};
const numericAttribute = {
get(element, name) {
return parseFloat(element.getAttribute(name) || 0);
},
set(element, name, value) {
element.setAttribute(name, value);
}
};
const stringAttribute = {
get(element, name) {
return element.getAttribute(name) || '';
},
set(element, name, value) {
element.setAttribute(name, value);
}
};
/* oddly enough, this apparently is not a thing
const nullableAttribute = {
get(element, name) {
return element.getAttribute(name);
},
set(element, name, value) {
if (value === null)
element.removeAttribute(name);
else
element.setAttribute(name, value);
}
};
*/
// https://dom.spec.whatwg.org/#interface-eventtarget
const wm = new WeakMap();
function dispatch(event, listener) {
if (typeof listener === 'function')
listener.call(event.target, event);
else
listener.handleEvent(event);
return event._stopImmediatePropagationFlag;
}
function invokeListeners({currentTarget, target}) {
const map = wm.get(currentTarget);
if (map && map.has(this.type)) {
const listeners = map.get(this.type);
if (currentTarget === target) {
this.eventPhase = this.AT_TARGET;
} else {
this.eventPhase = this.BUBBLING_PHASE;
}
this.currentTarget = currentTarget;
this.target = target;
for (const [listener, options] of listeners) {
if (options && options.once)
listeners.delete(listener);
if (dispatch(this, listener))
break;
}
delete this.currentTarget;
delete this.target;
return this.cancelBubble;
}
}
/**
* @implements globalThis.EventTarget
*/
class DOMEventTarget {
constructor() {
wm.set(this, new Map);
}
/**
* @protected
*/
_getParent() {
return null;
}
addEventListener(type, listener, options) {
const map = wm.get(this);
if (!map.has(type))
map.set(type, new Map);
map.get(type).set(listener, options);
}
removeEventListener(type, listener) {
const map = wm.get(this);
if (map.has(type)) {
const listeners = map.get(type);
if (listeners.delete(listener) && !listeners.size)
map.delete(type);
}
}
dispatchEvent(event) {
let node = this;
event.eventPhase = event.CAPTURING_PHASE;
// intentionally simplified, specs imply way more code: https://dom.spec.whatwg.org/#event-path
while (node) {
if (node.dispatchEvent)
event._path.push({currentTarget: node, target: this});
node = event.bubbles && node._getParent && node._getParent();
}
event._path.some(invokeListeners, event);
event._path = [];
event.eventPhase = event.NONE;
return !event.defaultPrevented;
}
}
// https://dom.spec.whatwg.org/#interface-nodelist
/**
* @implements globalThis.NodeList
*/
class NodeList extends Array {
item(i) { return i < this.length ? this[i] : null; }
}
// https://dom.spec.whatwg.org/#node
const getParentNodeCount = ({parentNode}) => {
let count = 0;
while (parentNode) {
count++;
parentNode = parentNode.parentNode;
}
return count;
};
/**
* @implements globalThis.Node
*/
let Node$1 = class Node extends DOMEventTarget {
static get ELEMENT_NODE() { return ELEMENT_NODE; }
static get ATTRIBUTE_NODE() { return ATTRIBUTE_NODE; }
static get TEXT_NODE() { return TEXT_NODE; }
static get CDATA_SECTION_NODE() { return CDATA_SECTION_NODE; }
static get COMMENT_NODE() { return COMMENT_NODE; }
static get DOCUMENT_NODE() { return DOCUMENT_NODE; }
static get DOCUMENT_FRAGMENT_NODE() { return DOCUMENT_FRAGMENT_NODE; }
static get DOCUMENT_TYPE_NODE() { return DOCUMENT_TYPE_NODE; }
constructor(ownerDocument, localName, nodeType) {
super();
this.ownerDocument = ownerDocument;
this.localName = localName;
this.nodeType = nodeType;
this.parentNode = null;
this[NEXT] = null;
this[PREV] = null;
}
get ELEMENT_NODE() { return ELEMENT_NODE; }
get ATTRIBUTE_NODE() { return ATTRIBUTE_NODE; }
get TEXT_NODE() { return TEXT_NODE; }
get CDATA_SECTION_NODE() { return CDATA_SECTION_NODE; }
get COMMENT_NODE() { return COMMENT_NODE; }
get DOCUMENT_NODE() { return DOCUMENT_NODE; }
get DOCUMENT_FRAGMENT_NODE() { return DOCUMENT_FRAGMENT_NODE; }
get DOCUMENT_TYPE_NODE() { return DOCUMENT_TYPE_NODE; }
get baseURI() {
const ownerDocument = this.nodeType === DOCUMENT_NODE ?
this : this.ownerDocument;
if (ownerDocument) {
const base = ownerDocument.querySelector('base');
if (base)
return base.getAttribute('href');
const {location} = ownerDocument.defaultView;
if (location)
return location.href;
}
return null;
}
/* c8 ignore start */
// mixin: node
get isConnected() { return false; }
get nodeName() { return this.localName; }
get parentElement() { return null; }
get previousSibling() { return null; }
get previousElementSibling() { return null; }
get nextSibling() { return null; }
get nextElementSibling() { return null; }
get childNodes() { return new NodeList; }
get firstChild() { return null; }
get lastChild() { return null; }
// default values
get nodeValue() { return null; }
set nodeValue(value) {}
get textContent() { return null; }
set textContent(value) {}
normalize() {}
cloneNode() { return null; }
contains() { return false; }
/**
* Inserts a node before a reference node as a child of this parent node.
* @param {Node} newNode The node to be inserted.
* @param {Node} referenceNode The node before which newNode is inserted. If this is null, then newNode is inserted at the end of node's child nodes.
* @returns The added child
*/
// eslint-disable-next-line no-unused-vars
insertBefore(newNode, referenceNode) { return newNode }
/**
* Adds a node to the end of the list of children of this node.
* @param {Node} child The node to append to the given parent node.
* @returns The appended child.
*/
appendChild(child) { return child }
/**
* Replaces a child node within this node
* @param {Node} newChild The new node to replace oldChild.
* @param {Node} oldChild The child to be replaced.
* @returns The replaced Node. This is the same node as oldChild.
*/
replaceChild(newChild, oldChild) { return oldChild }
/**
* Removes a child node from the DOM.
* @param {Node} child A Node that is the child node to be removed from the DOM.
* @returns The removed node.
*/
removeChild(child) { return child }
toString() { return ''; }
/* c8 ignore stop */
hasChildNodes() { return !!this.lastChild; }
isSameNode(node) { return this === node; }
// TODO: attributes?
compareDocumentPosition(target) {
let result = 0;
if (this !== target) {
let self = getParentNodeCount(this);
let other = getParentNodeCount(target);
if (self < other) {
result += DOCUMENT_POSITION_FOLLOWING;
if (this.contains(target))
result += DOCUMENT_POSITION_CONTAINED_BY;
}
else if (other < self) {
result += DOCUMENT_POSITION_PRECEDING;
if (target.contains(this))
result += DOCUMENT_POSITION_CONTAINS;
}
else if (self && other) {
const {childNodes} = this.parentNode;
if (childNodes.indexOf(this) < childNodes.indexOf(target))
result += DOCUMENT_POSITION_FOLLOWING;
else
result += DOCUMENT_POSITION_PRECEDING;
}
if (!self || !other) {
result += DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
result += DOCUMENT_POSITION_DISCONNECTED;
}
}
return result;
}
isEqualNode(node) {
if (this === node)
return true;
if (this.nodeType === node.nodeType) {
switch (this.nodeType) {
case DOCUMENT_NODE:
case DOCUMENT_FRAGMENT_NODE: {
const aNodes = this.childNodes;
const bNodes = node.childNodes;
return aNodes.length === bNodes.length && aNodes.every((node, i) => node.isEqualNode(bNodes[i]));
}
}
return this.toString() === node.toString();
}
return false;
}
/**
* @protected
*/
_getParent() {
return this.parentNode;
}
/**
* Calling it on an element inside a standard web page will return an HTMLDocument object representing the entire page (or <iframe>).
* Calling it on an element inside a shadow DOM will return the associated ShadowRoot.
* @return {ShadowRoot | HTMLDocument}
*/
getRootNode() {
let root = this;
while (root.parentNode)
root = root.parentNode;
return root;
}
};
const {replace} = '';
// escape
const ca = /[<>&\xA0]/g;
const esca = {
'\xA0': '&#160;',
'&': '&amp;',
'<': '&lt;',
'>': '&gt;'
};
const pe = m => esca[m];
/**
* Safely escape HTML entities such as `&`, `<`, `>` only.
* @param {string} es the input to safely escape
* @returns {string} the escaped input, and it **throws** an error if
* the input type is unexpected, except for boolean and numbers,
* converted as string.
*/
const escape = es => replace.call(es, ca, pe);
const QUOTE = /"/g;
/**
* @implements globalThis.Attr
*/
let Attr$1 = class Attr extends Node$1 {
constructor(ownerDocument, name, value = '') {
super(ownerDocument, name, ATTRIBUTE_NODE);
this.ownerElement = null;
this.name = $String(name);
this[VALUE] = $String(value);
this[CHANGED] = false;
}
get value() { return this[VALUE]; }
set value(newValue) {
const {[VALUE]: oldValue, name, ownerElement} = this;
this[VALUE] = $String(newValue);
this[CHANGED] = true;
if (ownerElement) {
attributeChangedCallback(ownerElement, name, oldValue);
attributeChangedCallback$1(ownerElement, name, oldValue, this[VALUE]);
}
}
cloneNode() {
const {ownerDocument, name, [VALUE]: value} = this;
return new Attr(ownerDocument, name, value);
}
toString() {
const {name, [VALUE]: value} = this;
if (emptyAttributes.has(name) && !value) {
return ignoreCase(this) ? name : `${name}=""`;
}
const escapedValue = (ignoreCase(this) ? value : escape(value)).replace(QUOTE, '&quot;');
return `${name}="${escapedValue}"`;
}
toJSON() {
const json = [];
attrAsJSON(this, json);
return json;
}
};
const isConnected = ({ownerDocument, parentNode}) => {
while (parentNode) {
if (parentNode === ownerDocument)
return true;
parentNode = parentNode.parentNode || parentNode.host;
}
return false;
};
const parentElement = ({parentNode}) => {
if (parentNode) {
switch (parentNode.nodeType) {
case DOCUMENT_NODE:
case DOCUMENT_FRAGMENT_NODE:
return null;
}
}
return parentNode;
};
const previousSibling = ({[PREV]: prev}) => {
switch (prev ? prev.nodeType : 0) {
case NODE_END:
return prev[START];
case TEXT_NODE:
case COMMENT_NODE:
case CDATA_SECTION_NODE:
return prev;
}
return null;
};
const nextSibling = node => {
const next = getEnd(node)[NEXT];
return next && (next.nodeType === NODE_END ? null : next);
};
// https://dom.spec.whatwg.org/#nondocumenttypechildnode
// CharacterData, Element
const nextElementSibling$1 = node => {
let next = nextSibling(node);
while (next && next.nodeType !== ELEMENT_NODE)
next = nextSibling(next);
return next;
};
const previousElementSibling = node => {
let prev = previousSibling(node);
while (prev && prev.nodeType !== ELEMENT_NODE)
prev = previousSibling(prev);
return prev;
};
// https://dom.spec.whatwg.org/#childnode
// CharacterData, DocumentType, Element
const asFragment = (ownerDocument, nodes) => {
const fragment = ownerDocument.createDocumentFragment();
fragment.append(...nodes);
return fragment;
};
const before = (node, nodes) => {
const {ownerDocument, parentNode} = node;
if (parentNode)
parentNode.insertBefore(
asFragment(ownerDocument, nodes),
node
);
};
const after = (node, nodes) => {
const {ownerDocument, parentNode} = node;
if (parentNode)
parentNode.insertBefore(
asFragment(ownerDocument, nodes),
getEnd(node)[NEXT]
);
};
const replaceWith = (node, nodes) => {
const {ownerDocument, parentNode} = node;
if (parentNode) {
if (nodes.includes(node))
replaceWith(node, [node = node.cloneNode()]);
parentNode.insertBefore(
asFragment(ownerDocument, nodes),
node
);
node.remove();
}
};
const remove = (prev, current, next) => {
const {parentNode, nodeType} = current;
if (prev || next) {
setAdjacent(prev, next);
current[PREV] = null;
getEnd(current)[NEXT] = null;
}
if (parentNode) {
current.parentNode = null;
moCallback(current, parentNode);
if (nodeType === ELEMENT_NODE)
disconnectedCallback(current);
}
};
// https://dom.spec.whatwg.org/#interface-characterdata
/**
* @implements globalThis.CharacterData
*/
let CharacterData$1 = class CharacterData extends Node$1 {
constructor(ownerDocument, localName, nodeType, data) {
super(ownerDocument, localName, nodeType);
this[VALUE] = $String(data);
}
// <Mixins>
get isConnected() { return isConnected(this); }
get parentElement() { return parentElement(this); }
get previousSibling() { return previousSibling(this); }
get nextSibling() { return nextSibling(this); }
get previousElementSibling() { return previousElementSibling(this); }
get nextElementSibling() { return nextElementSibling$1(this); }
before(...nodes) { before(this, nodes); }
after(...nodes) { after(this, nodes); }
replaceWith(...nodes) { replaceWith(this, nodes); }
remove() { remove(this[PREV], this, this[NEXT]); }
// </Mixins>
// CharacterData only
/* c8 ignore start */
get data() { return this[VALUE]; }
set data(value) {
this[VALUE] = $String(value);
moCallback(this, this.parentNode);
}
get nodeValue() { return this.data; }
set nodeValue(value) { this.data = value; }
get textContent() { return this.data; }
set textContent(value) { this.data = value; }
get length() { return this.data.length; }
substringData(offset, count) {
return this.data.substr(offset, count);
}
appendData(data) {
this.data += data;
}
insertData(offset, data) {
const {data: t} = this;
this.data = t.slice(0, offset) + data + t.slice(offset);
}
deleteData(offset, count) {
const {data: t} = this;
this.data = t.slice(0, offset) + t.slice(offset + count);
}
replaceData(offset, count, data) {
const {data: t} = this;
this.data = t.slice(0, offset) + data + t.slice(offset + count);
}
/* c8 ignore stop */
toJSON() {
const json = [];
characterDataAsJSON(this, json);
return json;
}
};
/**
* @implements globalThis.CDATASection
*/
let CDATASection$1 = class CDATASection extends CharacterData$1 {
constructor(ownerDocument, data = '') {
super(ownerDocument, '#cdatasection', CDATA_SECTION_NODE, data);
}
cloneNode() {
const {ownerDocument, [VALUE]: data} = this;
return new CDATASection(ownerDocument, data);
}
toString() { return `<![CDATA[${this[VALUE]}]]>`; }
};
/**
* @implements globalThis.Comment
*/
let Comment$2 = class Comment extends CharacterData$1 {
constructor(ownerDocument, data = '') {
super(ownerDocument, '#comment', COMMENT_NODE, data);
}
cloneNode() {
const {ownerDocument, [VALUE]: data} = this;
return new Comment(ownerDocument, data);
}
toString() { return `<!--${this[VALUE]}-->`; }
};
function trueFunc() {
return true;
}
function falseFunc() {
return false;
}
/** Discriminants for selector token kinds. */
var SelectorType;
(function (SelectorType) {
SelectorType["Attribute"] = "attribute";
SelectorType["Pseudo"] = "pseudo";
SelectorType["PseudoElement"] = "pseudo-element";
SelectorType["Tag"] = "tag";
SelectorType["Universal"] = "universal";
// Traversals
SelectorType["Adjacent"] = "adjacent";
SelectorType["Child"] = "child";
SelectorType["Descendant"] = "descendant";
SelectorType["Parent"] = "parent";
SelectorType["Sibling"] = "sibling";
SelectorType["ColumnCombinator"] = "column-combinator";
})(SelectorType || (SelectorType = {}));
/** Operators available for attribute selectors. */
var AttributeAction;
(function (AttributeAction) {
AttributeAction["Any"] = "any";
AttributeAction["Element"] = "element";
AttributeAction["End"] = "end";
AttributeAction["Equals"] = "equals";
AttributeAction["Exists"] = "exists";
AttributeAction["Hyphen"] = "hyphen";
AttributeAction["Not"] = "not";
AttributeAction["Start"] = "start";
})(AttributeAction || (AttributeAction = {}));
const reName = /^[^#\\]?(?:\\(?:[\da-f]{1,6}\s?|.)|[\w\u00B0-\uFFFF-])+/;
const reEscape = /\\([\da-f]{1,6}\s?|(\s)|.)/gi;
var CharCode;
(function (CharCode) {
CharCode[CharCode["LeftParenthesis"] = 40] = "LeftParenthesis";
CharCode[CharCode["RightParenthesis"] = 41] = "RightParenthesis";
CharCode[CharCode["LeftSquareBracket"] = 91] = "LeftSquareBracket";
CharCode[CharCode["RightSquareBracket"] = 93] = "RightSquareBracket";
CharCode[CharCode["Comma"] = 44] = "Comma";
CharCode[CharCode["Period"] = 46] = "Period";
CharCode[CharCode["Colon"] = 58] = "Colon";
CharCode[CharCode["SingleQuote"] = 39] = "SingleQuote";
CharCode[CharCode["DoubleQuote"] = 34] = "DoubleQuote";
CharCode[CharCode["Plus"] = 43] = "Plus";
CharCode[CharCode["Tilde"] = 126] = "Tilde";
CharCode[CharCode["QuestionMark"] = 63] = "QuestionMark";
CharCode[CharCode["ExclamationMark"] = 33] = "ExclamationMark";
CharCode[CharCode["Slash"] = 47] = "Slash";
CharCode[CharCode["Equal"] = 61] = "Equal";
CharCode[CharCode["Dollar"] = 36] = "Dollar";
CharCode[CharCode["Pipe"] = 124] = "Pipe";
CharCode[CharCode["Circumflex"] = 94] = "Circumflex";
CharCode[CharCode["Asterisk"] = 42] = "Asterisk";
CharCode[CharCode["GreaterThan"] = 62] = "GreaterThan";
CharCode[CharCode["LessThan"] = 60] = "LessThan";
CharCode[CharCode["Hash"] = 35] = "Hash";
CharCode[CharCode["LowerI"] = 105] = "LowerI";
CharCode[CharCode["LowerS"] = 115] = "LowerS";
CharCode[CharCode["BackSlash"] = 92] = "BackSlash";
// Whitespace
CharCode[CharCode["Space"] = 32] = "Space";
CharCode[CharCode["Tab"] = 9] = "Tab";
CharCode[CharCode["NewLine"] = 10] = "NewLine";
CharCode[CharCode["FormFeed"] = 12] = "FormFeed";
CharCode[CharCode["CarriageReturn"] = 13] = "CarriageReturn";
})(CharCode || (CharCode = {}));
const actionTypes = new Map([
[CharCode.Tilde, AttributeAction.Element],
[CharCode.Circumflex, AttributeAction.Start],
[CharCode.Dollar, AttributeAction.End],
[CharCode.Asterisk, AttributeAction.Any],
[CharCode.ExclamationMark, AttributeAction.Not],
[CharCode.Pipe, AttributeAction.Hyphen],
]);
// Pseudos, whose data property is parsed as well.
const unpackPseudos = new Set([
"has",
"not",
"matches",
"is",
"where",
"host",
"host-context",
]);
/**
* Pseudo elements defined in CSS Level 1 and CSS Level 2 can be written with
* a single colon; eg. :before will turn into ::before.
* @see {@link https://www.w3.org/TR/2018/WD-selectors-4-20181121/#pseudo-element-syntax}
*/
const pseudosToPseudoElements = new Set([
"before",
"after",
"first-line",
"first-letter",
]);
/**
* Checks whether a specific selector is a traversal.
* This is useful eg. in swapping the order of elements that
* are not traversals.
* @param selector Selector to check.
*/
function isTraversal$1(selector) {
switch (selector.type) {
case SelectorType.Adjacent:
case SelectorType.Child:
case SelectorType.Descendant:
case SelectorType.Parent:
case SelectorType.Sibling:
case SelectorType.ColumnCombinator: {
return true;
}
case SelectorType.Attribute:
case SelectorType.Pseudo:
case SelectorType.PseudoElement:
case SelectorType.Tag:
case SelectorType.Universal: {
return false;
}
}
}
const stripQuotesFromPseudos = new Set(["contains", "icontains"]);
// Unescape function taken from https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L152
function funescape(_, escaped, escapedWhitespace) {
const high = Number.parseInt(escaped, 16) - 0x1_00_00;
// NaN means non-codepoint
return Number.isNaN(high) || escapedWhitespace
? escaped
: high < 0
? // BMP codepoint
String.fromCharCode(high + 0x1_00_00)
: // Supplemental Plane codepoint (surrogate pair)
String.fromCharCode((high >> 10) | 0xd8_00, (high & 0x3_ff) | 0xdc_00);
}
function unescapeCSS(cssString) {
return cssString.replace(reEscape, funescape);
}
function isQuote(c) {
return c === CharCode.SingleQuote || c === CharCode.DoubleQuote;
}
function isWhitespace(c) {
return (c === CharCode.Space ||
c === CharCode.Tab ||
c === CharCode.NewLine ||
c === CharCode.FormFeed ||
c === CharCode.CarriageReturn);
}
/**
* Parses `selector`.
* @param selector Selector to parse.
* @returns Returns a two-dimensional array.
* The first dimension represents selectors separated by commas (eg. `sub1, sub2`),
* the second contains the relevant tokens for that selector.
*/
function parse$3(selector) {
const subselects = [];
const endIndex = parseSelector(subselects, `${selector}`, 0);
if (endIndex < selector.length) {
throw new Error(`Unmatched selector: ${selector.slice(endIndex)}`);
}
return subselects;
}
function parseSelector(subselects, selector, selectorIndex) {
let tokens = [];
function getName(offset) {
const match = selector.slice(selectorIndex + offset).match(reName);
if (!match) {
throw new Error(`Expected name, found ${selector.slice(selectorIndex)}`);
}
const [name] = match;
selectorIndex += offset + name.length;
return unescapeCSS(name);
}
function stripWhitespace(offset) {
selectorIndex += offset;
while (selectorIndex < selector.length &&
isWhitespace(selector.charCodeAt(selectorIndex))) {
selectorIndex++;
}
}
function readValueWithParenthesis() {
selectorIndex += 1;
const start = selectorIndex;
for (let counter = 1; selectorIndex < selector.length; selectorIndex++) {
switch (selector.charCodeAt(selectorIndex)) {
case CharCode.BackSlash: {
// Skip next character
selectorIndex += 1;
break;
}
case CharCode.LeftParenthesis: {
counter += 1;
break;
}
case CharCode.RightParenthesis: {
counter -= 1;
if (counter === 0) {
return unescapeCSS(selector.slice(start, selectorIndex++));
}
break;
}
}
}
throw new Error("Parenthesis not matched");
}
function ensureNotTraversal() {
if (tokens.length > 0 && isTraversal$1(tokens[tokens.length - 1])) {
throw new Error("Did not expect successive traversals.");
}
}
function addTraversal(type) {
if (tokens.length > 0 &&
tokens[tokens.length - 1].type === SelectorType.Descendant) {
tokens[tokens.length - 1].type = type;
return;
}
ensureNotTraversal();
tokens.push({ type });
}
function addSpecialAttribute(name, action) {
tokens.push({
type: SelectorType.Attribute,
name,
action,
value: getName(1),
namespace: null,
ignoreCase: "quirks",
});
}
/**
* We have finished parsing the current part of the selector.
*
* Remove descendant tokens at the end if they exist,
* and return the last index, so that parsing can be
* picked up from here.
*/
function finalizeSubselector() {
if (tokens.length > 0 &&
tokens[tokens.length - 1].type === SelectorType.Descendant) {
tokens.pop();
}
if (tokens.length === 0) {
throw new Error("Empty sub-selector");
}
subselects.push(tokens);
}
stripWhitespace(0);
if (selector.length === selectorIndex) {
return selectorIndex;
}
loop: while (selectorIndex < selector.length) {
const firstChar = selector.charCodeAt(selectorIndex);
switch (firstChar) {
// Whitespace
case CharCode.Space:
case CharCode.Tab:
case CharCode.NewLine:
case CharCode.FormFeed:
case CharCode.CarriageReturn: {
if (tokens.length === 0 ||
tokens[0].type !== SelectorType.Descendant) {
ensureNotTraversal();
tokens.push({ type: SelectorType.Descendant });
}
stripWhitespace(1);
break;
}
// Traversals
case CharCode.GreaterThan: {
addTraversal(SelectorType.Child);
stripWhitespace(1);
break;
}
case CharCode.LessThan: {
addTraversal(SelectorType.Parent);
stripWhitespace(1);
break;
}
case CharCode.Tilde: {
addTraversal(SelectorType.Sibling);
stripWhitespace(1);
break;
}
case CharCode.Plus: {
addTraversal(SelectorType.Adjacent);
stripWhitespace(1);
break;
}
// Special attribute selectors: .class, #id
case CharCode.Period: {
addSpecialAttribute("class", AttributeAction.Element);
break;
}
case CharCode.Hash: {
addSpecialAttribute("id", AttributeAction.Equals);
break;
}
case CharCode.LeftSquareBracket: {
stripWhitespace(1);
// Determine attribute name and namespace
let name;
let namespace = null;
if (selector.charCodeAt(selectorIndex) === CharCode.Pipe) {
// Equivalent to no namespace
name = getName(1);
}
else if (selector.startsWith("*|", selectorIndex)) {
namespace = "*";
name = getName(2);
}
else {
name = getName(0);
if (selector.charCodeAt(selectorIndex) === CharCode.Pipe &&
selector.charCodeAt(selectorIndex + 1) !==
CharCode.Equal) {
namespace = name;
name = getName(1);
}
}
stripWhitespace(0);
// Determine comparison operation
let action = AttributeAction.Exists;
const possibleAction = actionTypes.get(selector.charCodeAt(selectorIndex));
if (possibleAction) {
action = possibleAction;
if (selector.charCodeAt(selectorIndex + 1) !==
CharCode.Equal) {
throw new Error("Expected `=`");
}
stripWhitespace(2);
}
else if (selector.charCodeAt(selectorIndex) === CharCode.Equal) {
action = AttributeAction.Equals;
stripWhitespace(1);
}
// Determine value
let value = "";
let ignoreCase = null;
if (action !== "exists") {
if (isQuote(selector.charCodeAt(selectorIndex))) {
const quote = selector.charCodeAt(selectorIndex);
selectorIndex += 1;
const sectionStart = selectorIndex;
while (selectorIndex < selector.length &&
selector.charCodeAt(selectorIndex) !== quote) {
selectorIndex +=
// Skip next character if it is escaped
selector.charCodeAt(selectorIndex) ===
CharCode.BackSlash
? 2
: 1;
}
if (selector.charCodeAt(selectorIndex) !== quote) {
throw new Error("Attribute value didn't end");
}
value = unescapeCSS(selector.slice(sectionStart, selectorIndex));
selectorIndex += 1;
}
else {
const valueStart = selectorIndex;
while (selectorIndex < selector.length &&
!isWhitespace(selector.charCodeAt(selectorIndex)) &&
selector.charCodeAt(selectorIndex) !==
CharCode.RightSquareBracket) {
selectorIndex +=
// Skip next character if it is escaped
selector.charCodeAt(selectorIndex) ===
CharCode.BackSlash
? 2
: 1;
}
value = unescapeCSS(selector.slice(valueStart, selectorIndex));
}
stripWhitespace(0);
// See if we have a force ignore flag
switch (selector.charCodeAt(selectorIndex) | 0x20) {
// If the forceIgnore flag is set (either `i` or `s`), use that value
case CharCode.LowerI: {
ignoreCase = true;
stripWhitespace(1);
break;
}
case CharCode.LowerS: {
ignoreCase = false;
stripWhitespace(1);
break;
}
}
}
if (selector.charCodeAt(selectorIndex) !==
CharCode.RightSquareBracket) {
throw new Error("Attribute selector didn't terminate");
}
selectorIndex += 1;
const attributeSelector = {
type: SelectorType.Attribute,
name,
action,
value,
namespace,
ignoreCase,
};
tokens.push(attributeSelector);
break;
}
case CharCode.Colon: {
if (selector.charCodeAt(selectorIndex + 1) === CharCode.Colon) {
tokens.push({
type: SelectorType.PseudoElement,
name: getName(2).toLowerCase(),
data: selector.charCodeAt(selectorIndex) ===
CharCode.LeftParenthesis
? readValueWithParenthesis()
: null,
});
break;
}
const name = getName(1).toLowerCase();
if (pseudosToPseudoElements.has(name)) {
tokens.push({
type: SelectorType.PseudoElement,
name,
data: null,
});
break;
}
let data = null;
if (selector.charCodeAt(selectorIndex) ===
CharCode.LeftParenthesis) {
if (unpackPseudos.has(name)) {
if (isQuote(selector.charCodeAt(selectorIndex + 1))) {
throw new Error(`Pseudo-selector ${name} cannot be quoted`);
}
data = [];
selectorIndex = parseSelector(data, selector, selectorIndex + 1);
if (selector.charCodeAt(selectorIndex) !==
CharCode.RightParenthesis) {
throw new Error(`Missing closing parenthesis in :${name} (${selector})`);
}
selectorIndex += 1;
}
else {
data = readValueWithParenthesis();
if (stripQuotesFromPseudos.has(name)) {
const quot = data.charCodeAt(0);
if (quot === data.charCodeAt(data.length - 1) &&
isQuote(quot)) {
data = data.slice(1, -1);
}
}
data = unescapeCSS(data);
}
}
tokens.push({ type: SelectorType.Pseudo, name, data });
break;
}
case CharCode.Comma: {
finalizeSubselector();
tokens = [];
stripWhitespace(1);
break;
}
default: {
if (selector.startsWith("/*", selectorIndex)) {
const endIndex = selector.indexOf("*/", selectorIndex + 2);
if (endIndex === -1) {
throw new Error("Comment was not terminated");
}
selectorIndex = endIndex + 2;
// Remove leading whitespace
if (tokens.length === 0) {
stripWhitespace(0);
}
break;
}
let namespace = null;
let name;
if (firstChar === CharCode.Asterisk) {
selectorIndex += 1;
name = "*";
}
else if (firstChar === CharCode.Pipe) {
name = "";
if (selector.charCodeAt(selectorIndex + 1) === CharCode.Pipe) {
addTraversal(SelectorType.ColumnCombinator);
stripWhitespace(2);
break;
}
}
else if (reName.test(selector.slice(selectorIndex))) {
name = getName(0);
}
else {
break loop;
}
if (selector.charCodeAt(selectorIndex) === CharCode.Pipe &&
selector.charCodeAt(selectorIndex + 1) !== CharCode.Pipe) {
namespace = name;
if (selector.charCodeAt(selectorIndex + 1) ===
CharCode.Asterisk) {
name = "*";
selectorIndex += 2;
}
else {
name = getName(1);
}
}
tokens.push(name === "*"
? { type: SelectorType.Universal, namespace }
: { type: SelectorType.Tag, name, namespace });
}
}
}
finalizeSubselector();
return selectorIndex;
}
/** Types of elements found in htmlparser2's DOM */
var ElementType;
(function (ElementType) {
/** Type for the root element of a document */
ElementType["Root"] = "root";
/** Type for Text */
ElementType["Text"] = "text";
/** Type for <? ... ?> */
ElementType["Directive"] = "directive";
/** Type for <!-- ... --> */
ElementType["Comment"] = "comment";
/** Type for <script> tags */
ElementType["Script"] = "script";
/** Type for <style> tags */
ElementType["Style"] = "style";
/** Type for Any tag */
ElementType["Tag"] = "tag";
/** Type for <![CDATA[ ... ]]> */
ElementType["CDATA"] = "cdata";
/** Type for <!doctype ...> */
ElementType["Doctype"] = "doctype";
})(ElementType || (ElementType = {}));
/**
* Tests whether an element is a tag or not.
* @param element Element to test
* @param element.type Node type discriminator to check.
*/
function isTag$2(element) {
return (element.type === ElementType.Tag ||
element.type === ElementType.Script ||
element.type === ElementType.Style);
}
// Exports for backwards compatibility
/** Type for the root element of a document */
// eslint-disable-next-line prefer-destructuring
const Root = ElementType.Root;
/** Type for Text */
// eslint-disable-next-line prefer-destructuring
const Text$2 = ElementType.Text;
/** Type for <? ... ?> */
// eslint-disable-next-line prefer-destructuring
const Directive = ElementType.Directive;
/** Type for <!-- ... --> */
// eslint-disable-next-line prefer-destructuring
const Comment$1 = ElementType.Comment;
/** Type for <script> tags */
// eslint-disable-next-line prefer-destructuring
const Script = ElementType.Script;
/** Type for <style> tags */
// eslint-disable-next-line prefer-destructuring
const Style = ElementType.Style;
/** Type for Any tag */
// eslint-disable-next-line prefer-destructuring
const Tag = ElementType.Tag;
/** Type for <![CDATA[ ... ]]> */
// eslint-disable-next-line prefer-destructuring
const CDATA = ElementType.CDATA;
/** Type for <!doctype ...> */
// eslint-disable-next-line prefer-destructuring
const Doctype = ElementType.Doctype;
/**
* Checks if `node` is an element node.
* @param node Node to check.
* @returns `true` if the node is an element node.
*/
function isTag$1(node) {
return isTag$2(node);
}
/**
* Checks if `node` is a CDATA node.
* @param node Node to check.
* @returns `true` if the node is a CDATA node.
*/
function isCDATA(node) {
return node.type === ElementType.CDATA;
}
/**
* Checks if `node` is a text node.
* @param node Node to check.
* @returns `true` if the node is a text node.
*/
function isText(node) {
return node.type === ElementType.Text;
}
/**
* Checks if `node` is a comment node.
* @param node Node to check.
* @returns `true` if the node is a comment node.
*/
function isComment(node) {
return node.type === ElementType.Comment;
}
/**
* Checks if `node` has children.
* @param node Node to check.
* @returns `true` if the node has children.
*/
function hasChildren(node) {
return Object.hasOwn(node, "children");
}
/**
* Search a node and its children for nodes passing a test function. If `node` is not an array, it will be wrapped in one.
*
* @category Querying
* @param test Function to test nodes on.
* @param node Node to search. Will be included in the result set if it matches.
* @param recurse Also consider child nodes.
* @param limit Maximum number of nodes to return.
* @returns All nodes passing `test`.
*/
function filter(test, node, recurse = true, limit = Number.POSITIVE_INFINITY) {
return find(test, Array.isArray(node) ? node : [node], recurse, limit);
}
/**
* Search an array of nodes and their children for nodes passing a test function.
*
* @category Querying
* @param test Function to test nodes on.
* @param nodes Array of nodes to search.
* @param recurse Also consider child nodes.
* @param limit Maximum number of nodes to return.
* @returns All nodes passing `test`.
*/
function find(test, nodes, recurse, limit) {
const result = [];
/** Stack of the arrays we are looking at. */
const nodeStack = [Array.isArray(nodes) ? nodes : [nodes]];
/** Stack of the indices within the arrays. */
const indexStack = [0];
for (;;) {
// First, check if the current array has any more elements to look at.
if (indexStack[0] >= nodeStack[0].length) {
// If we have no more arrays to look at, we are done.
if (indexStack.length === 1) {
return result;
}
// Otherwise, remove the current array from the stack.
nodeStack.shift();
indexStack.shift();
// Loop back to the start to continue with the next array.
continue;
}
const element = nodeStack[0][indexStack[0]++];
if (test(element)) {
result.push(element);
if (--limit <= 0)
return result;
}
if (recurse && hasChildren(element) && element.children.length > 0) {
/*
* Add the children to the stack. We are depth-first, so this is
* the next array we look at.
*/
indexStack.unshift(0);
nodeStack.unshift(element.children);
}
}
}
/**
* Finds one element in a tree that passes a test.
*
* @category Querying
* @param test Function to test nodes on.
* @param nodes Node or array of nodes to search.
* @param recurse Also consider child nodes.
* @returns The first node that passes `test`.
*/
function findOne$2(test, nodes, recurse = true) {
const searchedNodes = Array.isArray(nodes) ? nodes : [nodes];
for (const node of searchedNodes) {
if (isTag$1(node) && test(node)) {
return node;
}
if (recurse && hasChildren(node) && node.children.length > 0) {
const found = findOne$2(test, node.children, true);
if (found)
return found;
}
}
return null;
}
/**
* Checks if a tree of nodes contains at least one node passing a test.
*
* @category Querying
* @param test Function to test nodes on.
* @param nodes Array of nodes to search.
* @returns Whether a tree of nodes contains at least one node passing the test.
*/
function existsOne$1(test, nodes) {
return (Array.isArray(nodes) ? nodes : [nodes]).some((node) => (isTag$1(node) && test(node)) ||
(hasChildren(node) && existsOne$1(test, node.children)));
}
/**
* Search an array of nodes and their children for elements passing a test function.
*
* Same as `find`, but limited to elements and with less options, leading to reduced complexity.
*
* @category Querying
* @param test Function to test nodes on.
* @param nodes Array of nodes to search.
* @returns All nodes passing `test`.
*/
function findAll$1(test, nodes) {
const result = [];
const nodeStack = [Array.isArray(nodes) ? nodes : [nodes]];
const indexStack = [0];
for (;;) {
if (indexStack[0] >= nodeStack[0].length) {
if (nodeStack.length === 1) {
return result;
}
// Otherwise, remove the current array from the stack.
nodeStack.shift();
indexStack.shift();
// Loop back to the start to continue with the next array.
continue;
}
const element = nodeStack[0][indexStack[0]++];
if (isTag$1(element) && test(element))
result.push(element);
if (hasChildren(element) && element.children.length > 0) {
indexStack.unshift(0);
nodeStack.unshift(element.children);
}
}
}
/**
* A map of functions to check nodes against.
*/
const Checks = {
tag_name(name) {
if (typeof name === "function") {
return (element) => isTag$1(element) && name(element.name);
}
if (name === "*") {
return isTag$1;
}
return (element) => isTag$1(element) && element.name === name;
},
tag_type(type) {
if (typeof type === "function") {
return (element) => type(element.type);
}
return (element) => element.type === type;
},
tag_contains(data) {
if (typeof data === "function") {
return (element) => isText(element) && data(element.data);
}
return (element) => isText(element) && element.data === data;
},
};
/**
* Returns a function to check whether a node has an attribute with a particular
* value.
*
* @param attrib Attribute to check.
* @param value Attribute value to look for.
* @returns A function to check whether the a node has an attribute with a
* particular value.
*/
function getAttribCheck(attrib, value) {
if (typeof value === "function") {
return (element) => isTag$1(element) && value(element.attribs[attrib]);
}
return (element) => isTag$1(element) && element.attribs[attrib] === value;
}
/**
* Returns a function that returns `true` if either of the input functions
* returns `true` for a node.
*
* @param a First function to combine.
* @param b Second function to combine.
* @returns A function taking a node and returning `true` if either of the input
* functions returns `true` for the node.
*/
function combineFuncs(a, b) {
return (element) => a(element) || b(element);
}
/**
* Returns a function that executes all checks in `options` and returns `true`
* if any of them match a node.
*
* @param options An object describing nodes to look for.
* @returns A function that executes all checks in `options` and returns `true`
* if any of them match a node.
*/
function compileTest(options) {
const funcs = Object.keys(options).map((key) => {
const value = options[key];
return Object.hasOwn(Checks, key)
? Checks[key](value)
: getAttribCheck(key, value);
});
return funcs.length === 0 ? null : funcs.reduce(combineFuncs);
}
/**
* Checks whether a node matches the description in `options`.
*
* @category Legacy Query Functions
* @param options An object describing nodes to look for.
* @param node The element to test.
* @returns Whether the element matches the description in `options`.
*/
function testElement(options, node) {
const test = compileTest(options);
return test ? test(node) : true;
}
/**
* Returns all nodes that match `options`.
*
* @category Legacy Query Functions
* @param options An object describing nodes to look for.
* @param nodes Nodes to search through.
* @param recurse Also consider child nodes.
* @param limit Maximum number of nodes to return.
* @returns All nodes that match `options`.
*/
function getElements(options, nodes, recurse, limit = Number.POSITIVE_INFINITY) {
const test = compileTest(options);
return test ? filter(test, nodes, recurse, limit) : [];
}
/**
* Returns the node with the supplied ID.
*
* @category Legacy Query Functions
* @param id The unique ID attribute value to look for.
* @param nodes Nodes to search through.
* @param recurse Also consider child nodes.
* @returns The node with the supplied ID.
*/
function getElementById(id, nodes, recurse = true) {
if (!Array.isArray(nodes))
nodes = [nodes];
return findOne$2(getAttribCheck("id", id), nodes, recurse);
}
/**
* Returns all nodes with the supplied `tagName`.
*
* @category Legacy Query Functions
* @param tagName Tag name to search for.
* @param nodes Nodes to search through.
* @param recurse Also consider child nodes.
* @param limit Maximum number of nodes to return.
* @returns All nodes with the supplied `tagName`.
*/
function getElementsByTagName(tagName, nodes, recurse = true, limit = Number.POSITIVE_INFINITY) {
return filter(Checks["tag_name"](tagName), nodes, recurse, limit);
}
/**
* Returns all nodes with the supplied `className`.
*
* @category Legacy Query Functions
* @param className Class name to search for.
* @param nodes Nodes to search through.
* @param recurse Also consider child nodes.
* @param limit Maximum number of nodes to return.
* @returns All nodes with the supplied `className`.
*/
function getElementsByClassName(className, nodes, recurse = true, limit = Number.POSITIVE_INFINITY) {
return filter(getAttribCheck("class", className), nodes, recurse, limit);
}
/**
* Returns all nodes with the supplied `type`.
*
* @category Legacy Query Functions
* @param type Element type to look for.
* @param nodes Nodes to search through.
* @param recurse Also consider child nodes.
* @param limit Maximum number of nodes to return.
* @returns All nodes with the supplied `type`.
*/
function getElementsByTagType(type, nodes, recurse = true, limit = Number.POSITIVE_INFINITY) {
return filter(Checks["tag_type"](type), nodes, recurse, limit);
}
const xmlCodeMap = new Map([
[34, "&quot;"],
[38, "&amp;"],
[39, "&apos;"],
[60, "&lt;"],
[62, "&gt;"],
]);
// For compatibility with node < 4, we wrap `codePointAt`
/**
* Read a code point at a given index.
* @param input Input string to encode or decode.
* @param index Current read position in the input string.
*/
const getCodePoint = typeof String.prototype.codePointAt === "function"
? (input, index) => input.codePointAt(index)
: // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
(c, index) => (c.charCodeAt(index) & 0xfc_00) === 0xd8_00
? (c.charCodeAt(index) - 0xd8_00) * 0x4_00 +
c.charCodeAt(index + 1) -
0xdc_00 +
0x1_00_00
: c.charCodeAt(index);
/**
* Bitset for ASCII characters that need to be escaped in XML.
*/
const XML_BITSET_VALUE = 0x50_00_00_c4; // 32..63 -> 34 ("),38 (&),39 ('),60 (<),62 (>)
/**
* Encodes all non-ASCII characters, as well as characters not valid in XML
* documents using XML entities. Uses a fast bitset scan instead of RegExp.
*
* If a character has no equivalent entity, a numeric hexadecimal reference
* (eg. `&#xfc;`) will be used.
* @param input Input string to encode or decode.
*/
function encodeXML(input) {
let out;
let last = 0;
const { length } = input;
for (let index = 0; index < length; index++) {
const char = input.charCodeAt(index);
// Check for ASCII chars that don't need escaping
if (char < 0x80 &&
(((XML_BITSET_VALUE >>> char) & 1) === 0 || char >= 64 || char < 32)) {
continue;
}
if (out === undefined)
out = input.substring(0, index);
else if (last !== index)
out += input.substring(last, index);
if (char < 64) {
// Known replacement
out += xmlCodeMap.get(char);
last = index + 1;
continue;
}
// Non-ASCII: encode as numeric entity (handle surrogate pair)
const cp = getCodePoint(input, index);
out += `&#x${cp.toString(16)};`;
if (cp !== char)
index++; // Skip trailing surrogate
last = index + 1;
}
if (out === undefined)
return input;
if (last < length)
out += input.substr(last);
return out;
}
/**
* Creates a function that escapes all characters matched by the given regular
* expression using the given map of characters to escape to their entities.
* @param regex Regular expression to match characters to escape.
* @param map Map of characters to escape to their entities.
* @returns Function that escapes all characters matched by the given regular
* expression using the given map of characters to escape to their entities.
*/
function getEscaper(regex, map) {
return function escape(data) {
let match;
let lastIndex = 0;
let result = "";
while ((match = regex.exec(data))) {
if (lastIndex !== match.index) {
result += data.substring(lastIndex, match.index);
}
// We know that this character will be in the map.
result += map.get(match[0].charCodeAt(0));
// Every match will be of length 1
lastIndex = match.index + 1;
}
return result + data.substring(lastIndex);
};
}
/**
* Encodes all characters that have to be escaped in HTML attributes,
* following {@link https://html.spec.whatwg.org/multipage/parsing.html#escapingString}.
* @param data String to escape.
*/
const escapeAttribute =
/* #__PURE__ */ getEscaper(/["&\u00A0]/g, new Map([
[34, "&quot;"],
[38, "&amp;"],
[160, "&nbsp;"],
]));
/**
* Encodes all characters that have to be escaped in HTML text,
* following {@link https://html.spec.whatwg.org/multipage/parsing.html#escapingString}.
* @param data String to escape.
*/
const escapeText = /* #__PURE__ */ getEscaper(/[&<>\u00A0]/g, new Map([
[38, "&amp;"],
[60, "&lt;"],
[62, "&gt;"],
[160, "&nbsp;"],
]));
/**
* Mixed-case SVG and MathML element names recognized in foreign content.
*/
const elementNames = new Map([
"altGlyph",
"altGlyphDef",
"altGlyphItem",
"animateColor",
"animateMotion",
"animateTransform",
"clipPath",
"feBlend",
"feColorMatrix",
"feComponentTransfer",
"feComposite",
"feConvolveMatrix",
"feDiffuseLighting",
"feDisplacementMap",
"feDistantLight",
"feDropShadow",
"feFlood",
"feFuncA",
"feFuncB",
"feFuncG",
"feFuncR",
"feGaussianBlur",
"feImage",
"feMerge",
"feMergeNode",
"feMorphology",
"feOffset",
"fePointLight",
"feSpecularLighting",
"feSpotLight",
"feTile",
"feTurbulence",
"foreignObject",
"glyphRef",
"linearGradient",
"radialGradient",
"textPath",
].map((value) => [value.toLowerCase(), value]));
/**
* Mixed-case SVG and MathML attribute names recognized in foreign content.
*/
const attributeNames = new Map([
"definitionURL",
"attributeName",
"attributeType",
"baseFrequency",
"baseProfile",
"calcMode",
"clipPathUnits",
"diffuseConstant",
"edgeMode",
"filterUnits",
"glyphRef",
"gradientTransform",
"gradientUnits",
"kernelMatrix",
"kernelUnitLength",
"keyPoints",
"keySplines",
"keyTimes",
"lengthAdjust",
"limitingConeAngle",
"markerHeight",
"markerUnits",
"markerWidth",
"maskContentUnits",
"maskUnits",
"numOctaves",
"pathLength",
"patternContentUnits",
"patternTransform",
"patternUnits",
"pointsAtX",
"pointsAtY",
"pointsAtZ",
"preserveAlpha",
"preserveAspectRatio",
"primitiveUnits",
"refX",
"refY",
"repeatCount",
"repeatDur",
"requiredExtensions",
"requiredFeatures",
"specularConstant",
"specularExponent",
"spreadMethod",
"startOffset",
"stdDeviation",
"stitchTiles",
"surfaceScale",
"systemLanguage",
"tableValues",
"targetX",
"targetY",
"textLength",
"viewBox",
"viewTarget",
"xChannelSelector",
"yChannelSelector",
"zoomAndPan",
].map((value) => [value.toLowerCase(), value]));
/*
* Module dependencies
*/
const unencodedElements = new Set([
"style",
"script",
"xmp",
"iframe",
"noembed",
"noframes",
"plaintext",
"noscript",
]);
function replaceQuotes(value) {
return value.replace(/"/g, "&quot;");
}
/**
* Format attributes
* @param attributes Attribute map to serialize.
* @param options Options that control this operation.
*/
function formatAttributes(attributes, options) {
if (!attributes)
return;
const encode = (options.encodeEntities ?? options.decodeEntities) === false
? replaceQuotes
: !!options.xmlMode || options.encodeEntities !== "utf8"
? encodeXML
: escapeAttribute;
return Object.keys(attributes)
.map((key) => {
const value = attributes[key];
const normalizedValue = value == null ? "" : String(value);
if (options.xmlMode === "foreign") {
/* Fix up mixed-case attribute names */
key = attributeNames.get(key) ?? key;
}
if (!(options.emptyAttrs || options.xmlMode) && normalizedValue === "") {
return key;
}
return `${key}="${encode(normalizedValue)}"`;
})
.join(" ");
}
/**
* Self-enclosing tags
*/
const singleTag = new Set([
"area",
"base",
"basefont",
"br",
"col",
"command",
"embed",
"frame",
"hr",
"img",
"input",
"isindex",
"keygen",
"link",
"meta",
"param",
"source",
"track",
"wbr",
]);
/**
* Renders a DOM node or an array of DOM nodes to a string.
*
* Can be thought of as the equivalent of the `outerHTML` of the passed node(s).
* @param node Node to be rendered.
* @param options Changes serialization behavior
*/
function render(node, options = {}) {
const nodes = "length" in node ? node : [node];
let output = "";
let index = 0;
while (index < nodes.length) {
output += renderNode(nodes[index], options);
index++;
}
return output;
}
function renderNode(node, options) {
switch (node.type) {
case Root: {
return render(node.children, options);
}
// @ts-expect-error We don't use `Doctype` yet
case Doctype:
case Directive: {
return renderDirective(node);
}
case Comment$1: {
return renderComment(node);
}
case CDATA: {
return renderCdata(node);
}
case Script:
case Style:
case Tag: {
return renderTag(node, options);
}
case Text$2: {
return renderText(node, options);
}
}
}
const foreignModeIntegrationPoints = new Set([
"mi",
"mo",
"mn",
"ms",
"mtext",
"annotation-xml",
"foreignObject",
"desc",
"title",
]);
const foreignElements = new Set(["svg", "math"]);
function renderTag(element, options) {
// Handle SVG / MathML in HTML
if (options.xmlMode === "foreign") {
/* Fix up mixed-case element names */
element.name = elementNames.get(element.name) ?? element.name;
/* Exit foreign mode at integration points */
if (element.parent &&
foreignModeIntegrationPoints.has(element.parent.name)) {
options = { ...options, xmlMode: false };
}
}
if (!options.xmlMode && foreignElements.has(element.name)) {
options = { ...options, xmlMode: "foreign" };
}
let tag = `<${element.name}`;
const attribs = formatAttributes(element.attribs, options);
if (attribs) {
tag += ` ${attribs}`;
}
if (element.children.length === 0 &&
(options.xmlMode
? // In XML mode or foreign mode, and user hasn't explicitly turned off self-closing tags
options.selfClosingTags !== false
: // User explicitly asked for self-closing tags, even in HTML mode
options.selfClosingTags && singleTag.has(element.name))) {
if (!options.xmlMode)
tag += " ";
tag += "/>";
}
else {
tag += ">";
if (element.children.length > 0) {
tag += render(element.children, options);
}
if (!!options.xmlMode || !singleTag.has(element.name)) {
tag += `</${element.name}>`;
}
}
return tag;
}
function renderDirective(element) {
return `<${element.data}>`;
}
function renderText(element, options) {
let data = element.data || "";
// If entities weren't decoded, no need to encode them back
if ((options.encodeEntities ?? options.decodeEntities) !== false &&
!(!options.xmlMode &&
element.parent &&
unencodedElements.has(element.parent.name))) {
data =
!!options.xmlMode || options.encodeEntities !== "utf8"
? encodeXML(data)
: escapeText(data);
}
return data;
}
function renderCdata(element) {
return `<![CDATA[${element.children[0].data}]]>`;
}
function renderComment(element) {
return `<!--${element.data}-->`;
}
/**
* @category Stringify
* @deprecated Use the `dom-serializer` module directly.
* @param node Node to get the outer HTML of.
* @param options Options for serialization.
* @returns `node`'s outer HTML.
*/
function getOuterHTML(node, options) {
return render(node, options);
}
/**
* @category Stringify
* @deprecated Use the `dom-serializer` module directly.
* @param node Node to get the inner HTML of.
* @param options Options for serialization.
* @returns `node`'s inner HTML.
*/
function getInnerHTML(node, options) {
return hasChildren(node)
? node.children.map((node) => getOuterHTML(node, options)).join("")
: "";
}
/**
* Get a node's inner text. Same as `textContent`, but inserts newlines for `<br>` tags. Ignores comments.
*
* @category Stringify
* @deprecated Use `textContent` instead.
* @param node Node to get the inner text of.
* @returns `node`'s inner text.
*/
function getText$1(node) {
if (Array.isArray(node))
return node.map(getText$1).join("");
if (isTag$1(node))
return node.name === "br" ? "\n" : getText$1(node.children);
if (isCDATA(node))
return getText$1(node.children);
if (isText(node))
return node.data;
return "";
}
/**
* Get a node's text content. Ignores comments.
*
* @category Stringify
* @param node Node to get the text content of.
* @returns `node`'s text content.
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent}
*/
function textContent(node) {
if (Array.isArray(node))
return node.map(textContent).join("");
if (hasChildren(node) && !isComment(node)) {
return textContent(node.children);
}
if (isText(node))
return node.data;
return "";
}
/**
* Get a node's inner text, ignoring `<script>` and `<style>` tags. Ignores comments.
*
* @category Stringify
* @param node Node to get the inner text of.
* @returns `node`'s inner text.
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Node/innerText}
*/
function innerText(node) {
if (Array.isArray(node))
return node.map(innerText).join("");
if (hasChildren(node) && (node.type === ElementType.Tag || isCDATA(node))) {
return innerText(node.children);
}
if (isText(node))
return node.data;
return "";
}
/**
* Get the feed object from the root of a DOM tree.
*
* @category Feeds
* @param document The DOM to extract the feed from.
* @returns The feed.
*/
function getFeed(document) {
const feedRoot = getOneElement(isValidFeed, document);
return feedRoot
? feedRoot.name === "feed"
? getAtomFeed(feedRoot)
: getRssFeed(feedRoot)
: null;
}
/**
* Parse an Atom feed.
*
* @param feedRoot The root of the feed.
* @returns The parsed feed.
*/
function getAtomFeed(feedRoot) {
const childs = feedRoot.children;
const feed = {
type: "atom",
items: getElementsByTagName("entry", childs).map((item) => {
const { children } = item;
const entry = { media: getMediaElements(children) };
addConditionally(entry, "id", "id", children);
addConditionally(entry, "title", "title", children);
const href = getOneElement("link", children)?.attribs["href"];
if (href) {
entry.link = href;
}
const description = fetch("summary", children) || fetch("content", children);
if (description) {
entry.description = description;
}
const pubDate = fetch("updated", children);
if (pubDate) {
entry.pubDate = new Date(pubDate);
}
return entry;
}),
};
addConditionally(feed, "id", "id", childs);
addConditionally(feed, "title", "title", childs);
const href = getOneElement("link", childs)?.attribs["href"];
if (href) {
feed.link = href;
}
addConditionally(feed, "description", "subtitle", childs);
const updated = fetch("updated", childs);
if (updated) {
feed.updated = new Date(updated);
}
addConditionally(feed, "author", "email", childs, true);
return feed;
}
/**
* Parse a RSS feed.
*
* @param feedRoot The root of the feed.
* @returns The parsed feed.
*/
function getRssFeed(feedRoot) {
const childs = getOneElement("channel", feedRoot.children)?.children ?? [];
const feed = {
type: feedRoot.name.substr(0, 3),
id: "",
items: getElementsByTagName("item", feedRoot.children).map((item) => {
const { children } = item;
const entry = { media: getMediaElements(children) };
addConditionally(entry, "id", "guid", children);
addConditionally(entry, "title", "title", children);
addConditionally(entry, "link", "link", children);
addConditionally(entry, "description", "description", children);
const pubDate = fetch("pubDate", children) || fetch("dc:date", children);
if (pubDate)
entry.pubDate = new Date(pubDate);
return entry;
}),
};
addConditionally(feed, "title", "title", childs);
addConditionally(feed, "link", "link", childs);
addConditionally(feed, "description", "description", childs);
const updated = fetch("lastBuildDate", childs);
if (updated) {
feed.updated = new Date(updated);
}
addConditionally(feed, "author", "managingEditor", childs, true);
return feed;
}
const MEDIA_KEYS_STRING = ["url", "type", "lang"];
const MEDIA_KEYS_INT = [
"fileSize",
"bitrate",
"framerate",
"samplingrate",
"channels",
"duration",
"height",
"width",
];
/**
* Get all media elements of a feed item.
*
* @param where Nodes to search in.
* @returns Media elements.
*/
function getMediaElements(where) {
return getElementsByTagName("media:content", where).map((element) => {
const { attribs } = element;
const media = {
medium: attribs["medium"],
isDefault: !!attribs["isDefault"],
};
for (const attrib of MEDIA_KEYS_STRING) {
if (attribs[attrib]) {
media[attrib] = attribs[attrib];
}
}
for (const attrib of MEDIA_KEYS_INT) {
if (attribs[attrib]) {
media[attrib] = Number.parseInt(attribs[attrib], 10);
}
}
if (attribs["expression"]) {
media.expression = attribs["expression"];
}
return media;
});
}
/**
* Get one element by tag name.
*
* @param tagName Tag name to look for
* @param node Node to search in
* @returns The element or null
*/
function getOneElement(tagName, node) {
return getElementsByTagName(tagName, node, true, 1)[0];
}
/**
* Get the text content of an element with a certain tag name.
*
* @param tagName Tag name to look for.
* @param where Node to search in.
* @param recurse Whether to recurse into child nodes.
* @returns The text content of the element.
*/
function fetch(tagName, where, recurse = false) {
return textContent(getElementsByTagName(tagName, where, recurse, 1)).trim();
}
/**
* Adds a property to an object if it has a value.
*
* @param object Object to be extended.
* @param property Property name.
* @param tagName Tag name that contains the conditionally added property.
* @param where Element to search for the property.
* @param recurse Whether to recurse into child nodes.
*/
function addConditionally(object, property, tagName, where, recurse = false) {
const value = fetch(tagName, where, recurse);
if (value)
object[property] = value;
}
/**
* Checks if an element is a feed root node.
*
* @param value The name of the element to check.
* @returns Whether an element is a feed root node.
*/
function isValidFeed(value) {
return value === "rss" || value === "feed" || value === "rdf:RDF";
}
/**
* Given an array of nodes, remove any member that is contained by another
* member.
*
* @category Helpers
* @param nodes Nodes to filter.
* @returns Remaining nodes that aren't contained by other nodes.
*/
function removeSubsets$1(nodes) {
let index = nodes.length;
/*
* Check if each node (or one of its ancestors) is already contained in the
* array.
*/
while (--index >= 0) {
const node = nodes[index];
/*
* Remove the node if it is not unique.
* We are going through the array from the end, so we only
* have to check nodes that preceed the node under consideration in the array.
*/
if (index > 0 && nodes.lastIndexOf(node, index - 1) >= 0) {
nodes.splice(index, 1);
continue;
}
for (let ancestor = node.parent; ancestor; ancestor = ancestor.parent) {
if (nodes.includes(ancestor)) {
nodes.splice(index, 1);
break;
}
}
}
return nodes;
}
/**
* @category Helpers
* @see {@link http://dom.spec.whatwg.org/#dom-node-comparedocumentposition}
*/
var DocumentPosition;
(function (DocumentPosition) {
DocumentPosition[DocumentPosition["DISCONNECTED"] = 1] = "DISCONNECTED";
DocumentPosition[DocumentPosition["PRECEDING"] = 2] = "PRECEDING";
DocumentPosition[DocumentPosition["FOLLOWING"] = 4] = "FOLLOWING";
DocumentPosition[DocumentPosition["CONTAINS"] = 8] = "CONTAINS";
DocumentPosition[DocumentPosition["CONTAINED_BY"] = 16] = "CONTAINED_BY";
})(DocumentPosition || (DocumentPosition = {}));
/**
* Compare the position of one node against another node in any other document,
* returning a bitmask with the values from {@link DocumentPosition}.
*
* Document order:
* > There is an ordering, document order, defined on all the nodes in the
* > document corresponding to the order in which the first character of the
* > XML representation of each node occurs in the XML representation of the
* > document after expansion of general entities. Thus, the document element
* > node will be the first node. Element nodes occur before their children.
* > Thus, document order orders element nodes in order of the occurrence of
* > their start-tag in the XML (after expansion of entities). The attribute
* > nodes of an element occur after the element and before its children. The
* > relative order of attribute nodes is implementation-dependent.
*
* Source:
* http://www.w3.org/TR/DOM-Level-3-Core/glossary.html#dt-document-order
*
* @category Helpers
* @param nodeA The first node to use in the comparison
* @param nodeB The second node to use in the comparison
* @returns A bitmask describing the input nodes' relative position.
*
* See http://dom.spec.whatwg.org/#dom-node-comparedocumentposition for
* a description of these values.
*/
function compareDocumentPosition(nodeA, nodeB) {
const aParents = [];
const bParents = [];
if (nodeA === nodeB) {
return 0;
}
let current = hasChildren(nodeA) ? nodeA : nodeA.parent;
while (current) {
aParents.unshift(current);
current = current.parent;
}
current = hasChildren(nodeB) ? nodeB : nodeB.parent;
while (current) {
bParents.unshift(current);
current = current.parent;
}
const maxIndex = Math.min(aParents.length, bParents.length);
let index = 0;
while (index < maxIndex && aParents[index] === bParents[index]) {
index++;
}
if (index === 0) {
return DocumentPosition.DISCONNECTED;
}
const sharedParent = aParents[index - 1];
const siblings = sharedParent.children;
const aSibling = aParents[index];
const bSibling = bParents[index];
if (siblings.indexOf(aSibling) > siblings.indexOf(bSibling)) {
if (sharedParent === nodeB) {
return DocumentPosition.FOLLOWING | DocumentPosition.CONTAINED_BY;
}
return DocumentPosition.FOLLOWING;
}
if (sharedParent === nodeA) {
return DocumentPosition.PRECEDING | DocumentPosition.CONTAINS;
}
return DocumentPosition.PRECEDING;
}
/**
* Sort an array of nodes based on their relative position in the document,
* removing any duplicate nodes. If the array contains nodes that do not belong
* to the same document, sort order is unspecified.
*
* @category Helpers
* @param nodes Array of DOM nodes.
* @returns Collection of unique nodes, sorted in document order.
*/
function uniqueSort(nodes) {
nodes = nodes.filter((node, index, array) => !array.includes(node, index + 1));
nodes.sort((a, b) => {
const relative = compareDocumentPosition(a, b);
if (relative & DocumentPosition.PRECEDING) {
return -1;
}
if (relative & DocumentPosition.FOLLOWING) {
return 1;
}
return 0;
});
return nodes;
}
/**
* Remove an element from the dom
*
* @category Manipulation
* @param element The element to be removed.
*/
function removeElement(element) {
if (element.prev)
element.prev.next = element.next;
if (element.next)
element.next.prev = element.prev;
if (element.parent) {
const childs = element.parent.children;
const childsIndex = childs.lastIndexOf(element);
if (childsIndex !== -1) {
childs.splice(childsIndex, 1);
}
}
element.next = null;
element.prev = null;
element.parent = null;
}
/**
* Replace an element in the dom
*
* @category Manipulation
* @param element The element to be replaced.
* @param replacement The element to be added
*/
function replaceElement(element, replacement) {
replacement.prev = element.prev;
if (replacement.prev) {
replacement.prev.next = replacement;
}
replacement.next = element.next;
if (replacement.next) {
replacement.next.prev = replacement;
}
replacement.parent = element.parent;
if (replacement.parent) {
const { children } = replacement.parent;
const elementIndex = children.lastIndexOf(element);
if (elementIndex === -1) {
return;
}
children[elementIndex] = replacement;
element.parent = null;
}
}
/**
* Append a child to an element.
*
* @category Manipulation
* @param parent The element to append to.
* @param child The element to be added as a child.
*/
function appendChild(parent, child) {
removeElement(child);
child.next = null;
child.parent = parent;
if (parent.children.push(child) > 1) {
const sibling = parent.children[parent.children.length - 2];
sibling.next = child;
child.prev = sibling;
}
else {
child.prev = null;
}
}
/**
* Append an element after another.
*
* @category Manipulation
* @param element The element to append after.
* @param next The element be added.
*/
function append$1(element, next) {
removeElement(next);
const { parent } = element;
const currentNext = element.next;
next.next = currentNext;
next.prev = element;
element.next = next;
next.parent = parent;
if (currentNext) {
currentNext.prev = next;
if (parent) {
const childs = parent.children;
childs.splice(childs.lastIndexOf(currentNext), 0, next);
}
}
else if (parent) {
parent.children.push(next);
}
}
/**
* Prepend a child to an element.
*
* @category Manipulation
* @param parent The element to prepend before.
* @param child The element to be added as a child.
*/
function prependChild(parent, child) {
removeElement(child);
child.parent = parent;
child.prev = null;
if (parent.children.unshift(child) === 1) {
child.next = null;
}
else {
const sibling = parent.children[1];
sibling.prev = child;
child.next = sibling;
}
}
/**
* Prepend an element before another.
*
* @category Manipulation
* @param element The element to prepend before.
* @param previous The element to be added.
*/
function prepend(element, previous) {
removeElement(previous);
const { parent } = element;
if (parent) {
const childs = parent.children;
childs.splice(childs.indexOf(element), 0, previous);
}
if (element.prev) {
element.prev.next = previous;
}
previous.parent = parent;
previous.prev = element.prev;
previous.next = element;
element.prev = previous;
}
/**
* Get a node's children.
*
* @category Traversal
* @param element Node to get the children of.
* @returns `element`'s children, or an empty array.
*/
function getChildren$1(element) {
return hasChildren(element) ? element.children : [];
}
function getParent$1(element) {
return element.parent || null;
}
/**
* Gets an elements siblings, including the element itself.
*
* Attempts to get the children through the element's parent first. If we don't
* have a parent (the element is a root node), we walk the element's `prev` &
* `next` to get all remaining nodes.
*
* @category Traversal
* @param element Element to get the siblings of.
* @returns `element`'s siblings, including `element`.
*/
function getSiblings$1(element) {
const parent = getParent$1(element);
if (parent != null)
return getChildren$1(parent);
const siblings = [element];
let { prev, next } = element;
while (prev != null) {
siblings.unshift(prev);
({ prev } = prev);
}
while (next != null) {
siblings.push(next);
({ next } = next);
}
return siblings;
}
/**
* Gets an attribute from an element.
*
* @category Traversal
* @param element Element to check.
* @param name Attribute name to retrieve.
* @returns The element's attribute value, or `undefined`.
*/
function getAttributeValue$1(element, name) {
const { attribs } = element;
return attribs?.[name];
}
/**
* Checks whether an element has an attribute.
*
* @category Traversal
* @param element Element to check.
* @param name Attribute name to look for.
* @returns Returns whether `element` has the attribute `name`.
*/
function hasAttrib$1(element, name) {
const { attribs } = element;
return (attribs != null && Object.hasOwn(attribs, name) && attribs[name] != null);
}
/**
* Get the tag name of an element.
*
* @category Traversal
* @param element The element to get the name for.
* @returns The tag name of `element`.
*/
function getName$1(element) {
return element.name;
}
/**
* Returns the next element sibling of a node.
*
* @category Traversal
* @param element The element to get the next sibling of.
* @returns `element`'s next sibling that is a tag, or `null` if there is no next
* sibling.
*/
function nextElementSibling(element) {
let { next } = element;
while (next !== null && !isTag$1(next))
({ next } = next);
return next;
}
/**
* Returns the previous element sibling of a node.
*
* @category Traversal
* @param element The element to get the previous sibling of.
* @returns `element`'s previous sibling that is a tag, or `null` if there is no
* previous sibling.
*/
// eslint-disable-next-line unicorn/prevent-abbreviations -- Keep public API name for backwards compatibility.
function prevElementSibling(element) {
let { prev } = element;
while (prev !== null && !isTag$1(prev))
({ prev } = prev);
return prev;
}
var DomUtils = /*#__PURE__*/Object.freeze({
__proto__: null,
get DocumentPosition () { return DocumentPosition; },
append: append$1,
appendChild: appendChild,
compareDocumentPosition: compareDocumentPosition,
existsOne: existsOne$1,
filter: filter,
find: find,
findAll: findAll$1,
findOne: findOne$2,
getAttributeValue: getAttributeValue$1,
getChildren: getChildren$1,
getElementById: getElementById,
getElements: getElements,
getElementsByClassName: getElementsByClassName,
getElementsByTagName: getElementsByTagName,
getElementsByTagType: getElementsByTagType,
getFeed: getFeed,
getInnerHTML: getInnerHTML,
getName: getName$1,
getOuterHTML: getOuterHTML,
getParent: getParent$1,
getSiblings: getSiblings$1,
getText: getText$1,
hasAttrib: hasAttrib$1,
innerText: innerText,
nextElementSibling: nextElementSibling,
prepend: prepend,
prependChild: prependChild,
prevElementSibling: prevElementSibling,
removeElement: removeElement,
removeSubsets: removeSubsets$1,
replaceElement: replaceElement,
testElement: testElement,
textContent: textContent,
uniqueSort: uniqueSort
});
/**
* All reserved characters in a regex, used for escaping.
*
* Taken from XRegExp, (c) 2007-2020 Steven Levithan under the MIT license
* https://github.com/slevithan/xregexp/blob/95eeebeb8fac8754d54eafe2b4743661ac1cf028/src/xregexp.js#L794
*/
const reChars = /[-[\]{}()*+?.,\\^$|#\s]/g;
const whitespaceRe = /\s/;
function escapeRegex(value) {
return value.replace(reChars, "\\$&");
}
/**
* Attributes that are case-insensitive in HTML.
* @see https://html.spec.whatwg.org/multipage/semantics-other.html#case-sensitivity-of-selectors
*/
const caseInsensitiveAttributes = new Set([
"accept",
"accept-charset",
"align",
"alink",
"axis",
"bgcolor",
"charset",
"checked",
"clear",
"codetype",
"color",
"compact",
"declare",
"defer",
"dir",
"direction",
"disabled",
"enctype",
"face",
"frame",
"hreflang",
"http-equiv",
"lang",
"language",
"link",
"media",
"method",
"multiple",
"nohref",
"noresize",
"noshade",
"nowrap",
"readonly",
"rel",
"rev",
"rules",
"scope",
"scrolling",
"selected",
"shape",
"target",
"text",
"type",
"valign",
"valuetype",
"vlink",
]);
function shouldIgnoreCase(selector, options) {
return typeof selector.ignoreCase === "boolean"
? selector.ignoreCase
: selector.ignoreCase === "quirks"
? !!options.quirksMode
: !options.xmlMode && caseInsensitiveAttributes.has(selector.name);
}
/**
* Attribute selectors
*/
const attributeRules = {
equals(next, data, options) {
const { adapter } = options;
const { name } = data;
let { value } = data;
if (shouldIgnoreCase(data, options)) {
value = value.toLowerCase();
return (element) => {
const attribute = adapter.getAttributeValue(element, name);
return (attribute != null &&
attribute.length === value.length &&
attribute.toLowerCase() === value &&
next(element));
};
}
return (element) => adapter.getAttributeValue(element, name) === value && next(element);
},
hyphen(next, data, options) {
const { adapter } = options;
const { name } = data;
let { value } = data;
const { length } = value;
if (shouldIgnoreCase(data, options)) {
value = value.toLowerCase();
return function hyphenIC(element) {
const attribute = adapter.getAttributeValue(element, name);
return (attribute != null &&
(attribute.length === length ||
attribute.charAt(length) === "-") &&
attribute.substr(0, length).toLowerCase() === value &&
next(element));
};
}
return function hyphen(element) {
const attribute = adapter.getAttributeValue(element, name);
return (attribute != null &&
(attribute.length === length ||
attribute.charAt(length) === "-") &&
attribute.substr(0, length) === value &&
next(element));
};
},
element(next, data, options) {
const { adapter } = options;
const { name, value } = data;
if (whitespaceRe.test(value)) {
return falseFunc;
}
const regex = new RegExp(`(?:^|\\s)${escapeRegex(value)}(?:$|\\s)`, shouldIgnoreCase(data, options) ? "i" : "");
return function element(node) {
const attribute = adapter.getAttributeValue(node, name);
return (attribute != null &&
attribute.length >= value.length &&
regex.test(attribute) &&
next(node));
};
},
exists(next, { name }, { adapter }) {
return (element) => adapter.hasAttrib(element, name) && next(element);
},
start(next, data, options) {
const { adapter } = options;
const { name } = data;
let { value } = data;
const { length } = value;
if (length === 0) {
return falseFunc;
}
if (shouldIgnoreCase(data, options)) {
value = value.toLowerCase();
return (element) => {
const attribute = adapter.getAttributeValue(element, name);
return (attribute != null &&
attribute.length >= length &&
attribute.substr(0, length).toLowerCase() === value &&
next(element));
};
}
return (element) => !!adapter.getAttributeValue(element, name)?.startsWith(value) &&
next(element);
},
end(next, data, options) {
const { adapter } = options;
const { name } = data;
let { value } = data;
const length = -value.length;
if (length === 0) {
return falseFunc;
}
if (shouldIgnoreCase(data, options)) {
value = value.toLowerCase();
return (element) => adapter
.getAttributeValue(element, name)
?.substr(length)
.toLowerCase() === value && next(element);
}
return (element) => !!adapter.getAttributeValue(element, name)?.endsWith(value) &&
next(element);
},
any(next, data, options) {
const { adapter } = options;
const { name, value } = data;
if (value === "") {
return falseFunc;
}
if (shouldIgnoreCase(data, options)) {
const regex = new RegExp(escapeRegex(value), "i");
return function anyIC(element) {
const attribute = adapter.getAttributeValue(element, name);
return (attribute != null &&
attribute.length >= value.length &&
regex.test(attribute) &&
next(element));
};
}
return (element) => !!adapter.getAttributeValue(element, name)?.includes(value) &&
next(element);
},
not(next, data, options) {
const { adapter } = options;
const { name } = data;
let { value } = data;
if (value === "") {
return (element) => !!adapter.getAttributeValue(element, name) && next(element);
}
if (shouldIgnoreCase(data, options)) {
value = value.toLowerCase();
return (element) => {
const attribute = adapter.getAttributeValue(element, name);
return ((attribute == null ||
attribute.length !== value.length ||
attribute.toLowerCase() !== value) &&
next(element));
};
}
return (element) => adapter.getAttributeValue(element, name) !== value && next(element);
},
};
/**
* Find all elements matching the query. If not in XML mode, the query will ignore
* the contents of `<template>` elements.
* @param query - Function that returns true if the element matches the query.
* @param nodes - Nodes to query. If a node is an element, its children will be queried.
* @param options - Options for querying the document.
* @returns All matching elements.
*/
/**
* Find the first element matching the query. If not in XML mode, the query will ignore
* the contents of `<template>` elements.
* @param query - Function that returns true if the element matches the query.
* @param nodes - Nodes to query. If a node is an element, its children will be queried.
* @param options - Options for querying the document.
* @returns The first matching element, or null if there was no match.
*/
function findOne$1(query, nodes, options) {
const { adapter, xmlMode = false } = options;
/** Stack of the arrays we are looking at. */
const nodeStack = [nodes];
/** Stack of the indices within the arrays. */
const indexStack = [0];
for (;;) {
// First, check if the current array has any more elements to look at.
if (indexStack[0] >= nodeStack[0].length) {
// If we have no more arrays to look at, we are done.
if (nodeStack.length === 1) {
return null;
}
nodeStack.shift();
indexStack.shift();
// Loop back to the start to continue with the next array.
continue;
}
const element = nodeStack[0][indexStack[0]++];
if (!adapter.isTag(element)) {
continue;
}
if (query(element)) {
return element;
}
if (xmlMode || adapter.getName(element) !== "template") {
/*
* Add the children to the stack. We are depth-first, so this is
* the next array we look at.
*/
const children = adapter.getChildren(element);
if (children.length > 0) {
nodeStack.unshift(children);
indexStack.unshift(0);
}
}
}
}
/**
* Get all element siblings after the provided node.
* @param element Element candidate being tested.
* @param adapter Adapter implementation used for DOM operations.
*/
function getNextSiblings(element, adapter) {
const siblings = adapter.getSiblings(element);
if (siblings.length <= 1) {
return [];
}
const elementIndex = siblings.indexOf(element);
if (elementIndex === -1 || elementIndex === siblings.length - 1) {
return [];
}
return siblings.slice(elementIndex + 1).filter(adapter.isTag);
}
/**
* Get the parent element of a node.
* @param node Node to inspect.
* @param adapter Adapter implementation used for DOM operations.
*/
function getElementParent(node, adapter) {
const parent = adapter.getParent(node);
return parent != null && adapter.isTag(parent) ? parent : null;
}
/**
* Only text controls can be made read-only, since for other controls (such
* as checkboxes and buttons) there is no useful distinction between being
* read-only and being disabled.
* @see {@link https://html.spec.whatwg.org/multipage/input.html#attr-input-readonly}
*/
const textControl = "input:is([type=text i],[type=search i],[type=url i],[type=tel i],[type=email i],[type=password i],[type=date i],[type=month i],[type=week i],[type=time i],[type=datetime-local i],[type=number i])";
/**
* Aliases are pseudos that are expressed as selectors.
*/
const aliases = {
// Links
"any-link": ":is(a, area, link)[href]",
link: ":any-link:not(:visited)",
// Forms
// https://html.spec.whatwg.org/multipage/scripting.html#disabled-elements
disabled: `:is(
:is(button, input, select, textarea, optgroup, option)[disabled],
optgroup[disabled] > option,
fieldset[disabled]:not(fieldset[disabled] legend:first-of-type *)
)`,
enabled: ":is(button, input, select, textarea, optgroup, option, fieldset):not(:disabled)",
checked: ":is(:is(input[type=radio], input[type=checkbox])[checked], :selected)",
required: ":is(input, select, textarea)[required]",
optional: ":is(input, select, textarea):not([required])",
"read-only": `[readonly]:is(textarea, ${textControl})`,
"read-write": `:not([readonly]):is(textarea, ${textControl})`,
// JQuery extensions
/**
* `:selected` matches option elements that have the `selected` attribute,
* or are the first option element in a select element that does not have
* the `multiple` attribute and does not have any option elements with the
* `selected` attribute.
* @see https://html.spec.whatwg.org/multipage/form-elements.html#concept-option-selectedness
*/
selected: "option:is([selected], select:not([multiple]):not(:has(> option[selected])) > :first-of-type)",
checkbox: "[type=checkbox]",
file: "[type=file]",
password: "[type=password]",
radio: "[type=radio]",
reset: "[type=reset]",
image: "[type=image]",
submit: "[type=submit]",
parent: ":not(:empty)",
header: ":is(h1, h2, h3, h4, h5, h6)",
button: ":is(button, input[type=button])",
input: ":is(input, textarea, select, button)",
text: "input:is(:not([type!='']), [type=text])",
};
/**
* Returns a function that checks if an elements index matches the given rule
* highly optimized to return the fastest solution.
* @param parsed A tuple [a, b], as returned by `parse`.
* @returns A highly optimized function that returns whether an index matches the nth-check.
* @example
*
* ```js
* const check = nthCheck.compile([2, 3]);
*
* check(0); // `false`
* check(1); // `false`
* check(2); // `true`
* check(3); // `false`
* check(4); // `true`
* check(5); // `false`
* check(6); // `true`
* ```
*/
function compile$1(parsed) {
const a = parsed[0];
// Subtract 1 from `b`, to convert from one- to zero-indexed.
const b = parsed[1] - 1;
/*
* When `b <= 0`, `a * n` won't be lead to any matches for `a < 0`.
* Besides, the specification states that no elements are
* matched when `a` and `b` are 0.
*
* `b < 0` here as we subtracted 1 from `b` above.
*/
if (b < 0 && a <= 0)
return falseFunc;
// When `a` is in the range -1..1, it matches any element (so only `b` is checked).
if (a === -1)
return (index) => index <= b;
if (a === 0)
return (index) => index === b;
// When `b <= 0` and `a === 1`, they match any element.
if (a === 1)
return b < 0 ? trueFunc : (index) => index >= b;
/*
* Otherwise, modulo can be used to check if there is a match.
*
* Modulo doesn't care about the sign, so let's use `a`s absolute value.
*/
const absA = Math.abs(a);
// Get `b mod a`, + a if this is negative.
const bModulo = ((b % absA) + absA) % absA;
return a > 1
? (index) => index >= b && index % absA === bModulo
: (index) => index <= b && index % absA === bModulo;
}
// Following http://www.w3.org/TR/css3-selectors/#nth-child-pseudo
// Whitespace as per https://www.w3.org/TR/selectors-3/#lex is " \t\r\n\f"
const whitespace = new Set([9, 10, 12, 13, 32]);
const ZERO = "0".charCodeAt(0);
const NINE = "9".charCodeAt(0);
/**
* Parses an expression.
* @param formula CSS nth-formula to parse.
* @throws {Error} An `Error` if parsing fails.
* @returns An array containing the integer step size and the integer offset of the nth rule.
* @example nthCheck.parse("2n+3"); // returns [2, 3]
*/
function parse$2(formula) {
formula = formula.trim().toLowerCase();
switch (formula) {
case "even": {
return [2, 0];
}
case "odd": {
return [2, 1];
}
}
// Parse [ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]?
let index = 0;
let a = 0;
let sign = readSign();
let number = readNumber();
if (index < formula.length && formula.charAt(index) === "n") {
index++;
a = sign * (number ?? 1);
skipWhitespace();
if (index < formula.length) {
sign = readSign();
skipWhitespace();
number = readNumber();
}
else {
sign = number = 0;
}
}
// Throw if there is anything else
if (number === null || index < formula.length) {
throw new Error(`n-th rule couldn't be parsed ('${formula}')`);
}
return [a, sign * number];
function readSign() {
switch (formula.charAt(index)) {
case "-": {
index++;
return -1;
}
case "+": {
index++;
break;
}
}
return 1;
}
function readNumber() {
const start = index;
let value = 0;
while (index < formula.length &&
formula.charCodeAt(index) >= ZERO &&
formula.charCodeAt(index) <= NINE) {
value = value * 10 + (formula.charCodeAt(index) - ZERO);
index++;
}
// Return `null` if we didn't read anything.
return index === start ? null : value;
}
function skipWhitespace() {
while (index < formula.length &&
whitespace.has(formula.charCodeAt(index))) {
index++;
}
}
}
/**
* Parses and compiles a formula to a highly optimized function.
* Combination of {@link parse} and {@link compile}.
*
* If the formula doesn't match any elements,
* it returns [`boolbase`](https://github.com/fb55/boolbase)'s `falseFunc`.
* Otherwise, a function accepting an _index_ is returned, which returns
* whether or not the passed _index_ matches the formula.
*
* Note: The nth-rule starts counting at `1`, the returned function at `0`.
* @param formula The formula to compile.
* @example
* const check = nthCheck("2n+3");
*
* check(0); // `false`
* check(1); // `false`
* check(2); // `true`
* check(3); // `false`
* check(4); // `true`
* check(5); // `false`
* check(6); // `true`
*/
function nthCheck(formula) {
return compile$1(parse$2(formula));
}
/**
* Some selectors such as `:contains` and (non-relative) `:has` will only be
* able to match elements if their parents match the selector (as they contain
* a subset of the elements that the parent contains).
*
* This function wraps the given `matches` function in a function that caches
* the results of the parent elements, so that the `matches` function only
* needs to be called once for each subtree.
* @param next Matcher to run after this matcher succeeds.
* @param options Configuration object for cache behavior.
* @param options.adapter Adapter implementation used for DOM access.
* @param options.cacheResults Whether results should be memoized by input root.
* @param matches Compiled matcher function to wrap with caching.
*/
function cacheParentResults(next, { adapter, cacheResults }, matches) {
if (cacheResults === false || typeof WeakMap === "undefined") {
return (element) => next(element) && matches(element);
}
// Use a cache to avoid re-checking children of an element.
// @ts-expect-error `Node` is not extending object
const resultCache = new WeakMap();
function addResultToCache(element) {
const result = matches(element);
resultCache.set(element, result);
return result;
}
return function cachedMatcher(element) {
if (!next(element)) {
return false;
}
if (resultCache.has(element)) {
return resultCache.get(element) ?? false;
}
// Check all of the element's parents.
let node = element;
do {
const parent = getElementParent(node, adapter);
if (parent === null) {
return addResultToCache(element);
}
node = parent;
} while (!resultCache.has(node));
return resultCache.get(node) ? addResultToCache(element) : false;
};
}
/**
* Create a copy of options, omitting `context` and `rootFunc`.
*
* This is used when compiling nested selectors (e.g. inside `:is`, `:not`,
* `:nth-child(… of S)`) so that the parent compilation state doesn't leak.
*/
function copyOptions(options) {
// Omit context and rootFunc so parent compilation state doesn't leak.
const { context: _, rootFunc: __, ...copied } = options;
return copied;
}
/**
* RFC 4647 extended filtering with pre-split subtags.
* @param tag - Lowercased subtags of the element's language value.
* @param range - Lowercased subtags of the language range to match against.
*/
function extendedFilter(tag, range) {
if (range[0] !== "*" && range[0] !== tag[0])
return false;
let tagIndex = 1;
for (let rangeIndex = 1; rangeIndex < range.length; rangeIndex++) {
if (range[rangeIndex] === "*")
continue;
// Skip non-singleton tag subtags until we find a match.
while (tagIndex < tag.length && tag[tagIndex] !== range[rangeIndex]) {
if (tag[tagIndex++].length <= 1)
return false;
}
if (tagIndex >= tag.length)
return false;
tagIndex++;
}
return true;
}
/** @see {@link https://www.w3.org/TR/selectors-4/#the-nth-child-pseudo} */
const nthOfRegex = /^(.+?)\s+of\s+(.+)$/is;
function compileNth(reverse, ofType) {
return function nth(next, rule, options, context, compileToken) {
const { adapter, equals } = options;
const ofMatch = ofType ? null : rule.match(nthOfRegex);
const nthCheck$1 = nthCheck(ofMatch ? ofMatch[1].trim() : rule);
if (nthCheck$1 === falseFunc)
return falseFunc;
const ofSelector = ofMatch && compileToken
? compileToken(parse$3(ofMatch[2].trim()), copyOptions(options), context)
: undefined;
if (ofSelector === falseFunc)
return falseFunc;
if (nthCheck$1 === trueFunc && !ofSelector) {
return (element) => getElementParent(element, adapter) !== null && next(element);
}
const shouldCount = ofSelector
? (_element, sibling) => ofSelector(sibling)
: ofType
? (element, sibling) => adapter.getName(sibling) === adapter.getName(element)
: trueFunc;
if (reverse) {
return function nthLast(element) {
if (ofSelector && !ofSelector(element))
return false;
const siblings = adapter.getSiblings(element);
let pos = 0;
for (let index = siblings.length - 1; index >= 0; index--) {
const sibling = siblings[index];
if (equals(element, sibling))
break;
if (adapter.isTag(sibling) && shouldCount(element, sibling))
pos++;
}
return nthCheck$1(pos) && next(element);
};
}
return function nth(element) {
if (ofSelector && !ofSelector(element))
return false;
const siblings = adapter.getSiblings(element);
let pos = 0;
for (const sibling of siblings) {
if (equals(element, sibling))
break;
if (adapter.isTag(sibling) && shouldCount(element, sibling))
pos++;
}
return nthCheck$1(pos) && next(element);
};
};
}
/**
* Pre-compiled pseudo filters.
*/
const filters = {
contains(next, text, options) {
const { getText } = options.adapter;
return cacheParentResults(next, options, (element) => getText(element).includes(text));
},
icontains(next, text, options) {
const itext = text.toLowerCase();
const { getText } = options.adapter;
return cacheParentResults(next, options, (element) => getText(element).toLowerCase().includes(itext));
},
// Location specific methods
"nth-child": compileNth(false, false),
"nth-last-child": compileNth(true, false),
"nth-of-type": compileNth(false, true),
"nth-last-of-type": compileNth(true, true),
// TODO determine the actual root element
root(next, _rule, { adapter }) {
return (element) => getElementParent(element, adapter) === null && next(element);
},
scope(next, rule, options, context) {
const { equals } = options;
if (!context || context.length === 0) {
// Equivalent to :root
return filters["root"](next, rule, options);
}
if (context.length === 1) {
// NOTE: can't be unpacked, as :has uses this for side-effects
return (element) => equals(context[0], element) && next(element);
}
return (element) => context.includes(element) && next(element);
},
lang(next, code, { adapter }) {
const ranges = code
.split(",")
.map((r) => r.trim())
.filter((r) => r.length > 0)
.map((r) => r
.replace(/^['"]|['"]$/g, "")
.toLowerCase()
.split("-"));
return function lang(element) {
let node = element;
while (node != null) {
const value = adapter.getAttributeValue(node, "xml:lang") ??
adapter.getAttributeValue(node, "lang");
if (value != null) {
if (!value) {
return ranges.some((r) => r[0] === "") && next(element);
}
const tag = value.toLowerCase().split("-");
return (ranges.some((r) => extendedFilter(tag, r)) &&
next(element));
}
const parent = adapter.getParent(node);
node =
parent != null && adapter.isTag(parent)
? parent
: null;
}
return ranges.some((r) => r[0] === "") && next(element);
};
},
hover: dynamicStatePseudo("isHovered"),
visited: dynamicStatePseudo("isVisited"),
active: dynamicStatePseudo("isActive"),
};
/**
* Dynamic state pseudos. These depend on optional Adapter methods.
* @param name The name of the adapter method to call.
* @returns Pseudo for the `filters` object.
*/
function dynamicStatePseudo(name) {
return function dynamicPseudo(next, _rule, { adapter }) {
const filterFunction = adapter[name];
if (typeof filterFunction !== "function") {
return falseFunc;
}
return function active(element) {
return filterFunction(element) && next(element);
};
};
}
/**
* CSS limits the characters considered as whitespace to space, tab & line
* feed. We add carriage returns as htmlparser2 doesn't normalize them to
* line feeds.
* @see {@link https://www.w3.org/TR/css-text-3/#white-space}
*/
const isDocumentWhiteSpace = /^[ \t\r\n]*$/;
// While filters are precompiled, pseudos get called when they are needed
/** Runtime pseudo selector implementations. */
const pseudos = {
empty(element, { adapter }) {
const children = adapter.getChildren(element);
return (
// First, make sure the tag does not have any element children.
children.every((element) => !adapter.isTag(element)) &&
// Then, check that the text content is only whitespace.
children.every((element) =>
// FIXME: `getText` call is potentially expensive.
isDocumentWhiteSpace.test(adapter.getText(element))));
},
"first-child"(element, { adapter, equals }) {
if (adapter.prevElementSibling) {
return adapter.prevElementSibling(element) == null;
}
const firstChild = adapter
.getSiblings(element)
.find((sibling) => adapter.isTag(sibling));
return firstChild != null && equals(element, firstChild);
},
"last-child"(element, { adapter, equals }) {
const siblings = adapter.getSiblings(element);
for (let index = siblings.length - 1; index >= 0; index--) {
if (equals(element, siblings[index])) {
return true;
}
if (adapter.isTag(siblings[index])) {
break;
}
}
return false;
},
"first-of-type"(element, { adapter, equals }) {
const siblings = adapter.getSiblings(element);
const elementName = adapter.getName(element);
for (const currentSibling of siblings) {
if (equals(element, currentSibling)) {
return true;
}
if (adapter.isTag(currentSibling) &&
adapter.getName(currentSibling) === elementName) {
break;
}
}
return false;
},
"last-of-type"(element, { adapter, equals }) {
const siblings = adapter.getSiblings(element);
const elementName = adapter.getName(element);
for (let index = siblings.length - 1; index >= 0; index--) {
const currentSibling = siblings[index];
if (equals(element, currentSibling)) {
return true;
}
if (adapter.isTag(currentSibling) &&
adapter.getName(currentSibling) === elementName) {
break;
}
}
return false;
},
"only-of-type"(element, { adapter, equals }) {
const elementName = adapter.getName(element);
return adapter
.getSiblings(element)
.every((sibling) => equals(element, sibling) ||
!adapter.isTag(sibling) ||
adapter.getName(sibling) !== elementName);
},
"only-child"(element, { adapter, equals }) {
return adapter
.getSiblings(element)
.every((sibling) => equals(element, sibling) || !adapter.isTag(sibling));
},
};
/**
* Validate pseudo selector argument arity.
* @param pseudoClassCondition Pseudo-function implementation to wrap.
* @param name Name of the pseudo selector.
* @param subselect Subselector passed to the pseudo-function.
* @param argumentIndex Index of the argument parser to apply.
*/
function verifyPseudoArguments(pseudoClassCondition, name, subselect, argumentIndex) {
if (subselect === null) {
if (pseudoClassCondition.length > argumentIndex) {
throw new Error(`Pseudo-class :${name} requires an argument`);
}
}
else if (pseudoClassCondition.length === argumentIndex) {
throw new Error(`Pseudo-class :${name} doesn't have any arguments`);
}
}
/**
* Check whether a selector token performs traversal.
* @param token Selector token(s) to compile.
*/
function isTraversal(token) {
return token.type === "_flexibleDescendant" || isTraversal$1(token);
}
/**
* Sort the parts of the passed selector, as there is potential for
* optimization (some types of selectors are faster than others).
* @param array Selector to sort
*/
function sortRules(array) {
const ratings = array.map(getQuality);
for (let index = 1; index < array.length; index++) {
const procNew = ratings[index];
if (procNew < 0) {
continue;
}
// Use insertion sort to move the token to the correct position.
for (let currentIndex = index; currentIndex > 0 && procNew < ratings[currentIndex - 1]; currentIndex--) {
const token = array[currentIndex];
array[currentIndex] = array[currentIndex - 1];
array[currentIndex - 1] = token;
ratings[currentIndex] = ratings[currentIndex - 1];
ratings[currentIndex - 1] = procNew;
}
}
}
function getAttributeQuality(token) {
switch (token.action) {
case AttributeAction.Exists: {
return 10;
}
case AttributeAction.Equals: {
// Prefer ID selectors (eg. #ID)
return token.name === "id" ? 9 : 8;
}
case AttributeAction.Not: {
return 7;
}
case AttributeAction.Start: {
return 6;
}
case AttributeAction.End: {
return 6;
}
case AttributeAction.Any: {
return 5;
}
case AttributeAction.Hyphen: {
return 4;
}
case AttributeAction.Element: {
return 3;
}
}
}
/**
* Determine the quality of the passed token. The higher the number, the
* faster the token is to execute.
* @param token Token to get the quality of.
* @returns The token's quality.
*/
function getQuality(token) {
switch (token.type) {
case SelectorType.Universal: {
return 50;
}
case SelectorType.Tag: {
return 30;
}
case SelectorType.Attribute: {
return Math.floor(getAttributeQuality(token) /
// `ignoreCase` adds some overhead, half the result if applicable.
(token.ignoreCase ? 2 : 1));
}
case SelectorType.Pseudo: {
return token.data
? token.name === "has" ||
token.name === "contains" ||
token.name === "icontains"
? // Expensive in any case — run as late as possible.
0
: Array.isArray(token.data)
? // Eg. `:is`, `:not`
Math.max(
// If we have traversals, try to avoid executing this selector
0, Math.min(...token.data.map((d) => Math.min(...d.map(getQuality)))))
: 2
: 3;
}
default: {
return -1;
}
}
}
/**
* Check whether a token or nested token includes `:scope`.
* @param t Selector token under inspection.
*/
function includesScopePseudo(t) {
return (t.type === SelectorType.Pseudo &&
(t.name === "scope" ||
(Array.isArray(t.data) &&
t.data.some((data) => data.some(includesScopePseudo)))));
}
/** Used as a placeholder for :has. Will be replaced with the actual element. */
const PLACEHOLDER_ELEMENT = {};
/**
* Check if the selector has any properties that rely on the current element.
* If not, we can cache the result of the selector.
*
* We can't cache selectors that start with a traversal (e.g. `>`, `+`, `~`),
* or include a `:scope`.
* @param selector - The selector to check.
* @returns Whether the selector has any properties that rely on the current element.
*/
function hasDependsOnCurrentElement(selector) {
return selector.some((sel) => sel.length > 0 &&
(isTraversal(sel[0]) || sel.some(includesScopePseudo)));
}
const is$1 = (next, token, options, context, compileToken) => {
const compiledToken = compileToken(token, copyOptions(options), context);
return compiledToken === trueFunc
? next
: compiledToken === falseFunc
? falseFunc
: (element) => compiledToken(element) && next(element);
};
/*
* :not, :has, :is, :matches and :where have to compile selectors
* doing this in src/pseudos.ts would lead to circular dependencies,
* so we add them here
*/
/** Pseudo selectors that compile nested selectors. */
const subselects = {
is: is$1,
/**
* `:matches` and `:where` are aliases for `:is`.
*/
matches: is$1,
where: is$1,
not(next, token, options, context, compileToken) {
const compiledToken = compileToken(token, copyOptions(options), context);
return compiledToken === falseFunc
? next
: compiledToken === trueFunc
? falseFunc
: (element) => !compiledToken(element) && next(element);
},
has(next, subselect, options, _context, compileToken) {
const { adapter } = options;
const copiedOptions = copyOptions(options);
copiedOptions.relativeSelector = true;
const context = subselect.some((s) => s.some(isTraversal))
? // Used as a placeholder. Will be replaced with the actual element.
[PLACEHOLDER_ELEMENT]
: undefined;
const skipCache = hasDependsOnCurrentElement(subselect);
const compiled = compileToken(subselect, copiedOptions, context);
if (compiled === falseFunc) {
return falseFunc;
}
// If `compiled` is `trueFunc`, we can skip this.
if (context && compiled !== trueFunc) {
return skipCache
? (element) => {
if (!next(element)) {
return false;
}
context[0] = element;
const childs = adapter.getChildren(element);
return (findOne$1(compiled, compiled.shouldTestNextSiblings
? [
...childs,
...getNextSiblings(element, adapter),
]
: childs, options) !== null);
}
: cacheParentResults(next, options, (element) => {
context[0] = element;
return (findOne$1(compiled, adapter.getChildren(element), options) !== null);
});
}
const hasOne = (element) => findOne$1(compiled, adapter.getChildren(element), options) !== null;
return skipCache
? (element) => next(element) && hasOne(element)
: cacheParentResults(next, options, hasOne);
},
};
/*
* Pseudo selectors
*
* Pseudo selectors are available in three forms:
*
* 1. Filters are called when the selector is compiled and return a function
* that has to return either false, or the results of `next()`.
* 2. Pseudos are called on execution. They have to return a boolean.
* 3. Subselects work like filters, but have an embedded selector that will be run separately.
*
* Filters are great if you want to do some pre-processing, or change the call order
* of `next()` and your code.
* Pseudos should be used to implement simple checks.
*/
/**
* Compile a pseudo selector into an executable query function.
* @param next Matcher to run after this matcher succeeds.
* @param selector Selector used to match elements.
* @param options Options that control this operation.
* @param context Context nodes used to scope selector matching.
* @param compileToken Function used to compile nested selector tokens.
*/
function compilePseudoSelector(next, selector, options, context, compileToken) {
const { name, data } = selector;
if (Array.isArray(data)) {
if (!(name in subselects)) {
throw new Error(`Unknown pseudo-class :${name}(${data})`);
}
return subselects[name](next, data, options, context, compileToken);
}
const userPseudo = options.pseudos?.[name];
const stringPseudo = typeof userPseudo === "string" ? userPseudo : aliases[name];
if (typeof stringPseudo === "string") {
if (data != null) {
throw new Error(`Pseudo ${name} doesn't have any arguments`);
}
// The alias has to be parsed here, to make sure options are respected.
const alias = parse$3(stringPseudo);
return subselects["is"](next, alias, options, context, compileToken);
}
if (typeof userPseudo === "function") {
verifyPseudoArguments(userPseudo, name, data, 1);
return (element) => userPseudo(element, data) && next(element);
}
if (name in filters) {
return filters[name](next, data, options, context, compileToken);
}
if (name in pseudos) {
const pseudo = pseudos[name];
verifyPseudoArguments(pseudo, name, data, 2);
return (element) => pseudo(element, options, data) && next(element);
}
throw new Error(`Unknown pseudo-class :${name}`);
}
/*
* All available rules
*/
/**
* Compile a single selector token.
* @param next Matcher to run after this matcher succeeds.
* @param selector Selector used to match elements.
* @param options Options that control this operation.
* @param context Context nodes used to scope selector matching.
* @param compileToken Function used to compile nested selector tokens.
* @param hasExpensiveSubselector Whether the selector contains expensive subselectors.
*/
function compileGeneralSelector(next, selector, options, context, compileToken, hasExpensiveSubselector) {
const { adapter, equals, cacheResults } = options;
switch (selector.type) {
case SelectorType.PseudoElement: {
throw new Error("Pseudo-elements are not supported by css-select");
}
case SelectorType.ColumnCombinator: {
throw new Error("Column combinators are not yet supported by css-select");
}
case SelectorType.Attribute: {
if (selector.namespace != null) {
throw new Error("Namespaced attributes are not yet supported by css-select");
}
if (!options.xmlMode || options.lowerCaseAttributeNames) {
selector.name = selector.name.toLowerCase();
}
return attributeRules[selector.action](next, selector, options);
}
case SelectorType.Pseudo: {
return compilePseudoSelector(next, selector, options, context, compileToken);
}
// Tags
case SelectorType.Tag: {
if (selector.namespace != null) {
throw new Error("Namespaced tag names are not yet supported by css-select");
}
let { name } = selector;
if (!options.xmlMode || options.lowerCaseTags) {
name = name.toLowerCase();
}
return function tag(element) {
return adapter.getName(element) === name && next(element);
};
}
// Traversal
case SelectorType.Descendant: {
if (!hasExpensiveSubselector ||
cacheResults === false ||
typeof WeakMap === "undefined") {
return function descendant(element) {
let current = element;
while ((current = getElementParent(current, adapter))) {
if (next(current)) {
return true;
}
}
return false;
};
}
const resultCache = new WeakMap();
return function cachedDescendant(element) {
let current = element;
let result;
while ((current = getElementParent(current, adapter))) {
const cached = resultCache.get(current);
if (cached === undefined) {
result ??= { matches: false };
result.matches = next(current);
resultCache.set(current, result);
if (result.matches) {
return true;
}
}
else {
if (result) {
result.matches = cached.matches;
}
return cached.matches;
}
}
return false;
};
}
case "_flexibleDescendant": {
// Include element itself, only used while querying an array
return function flexibleDescendant(element) {
let current = element;
do {
if (next(current)) {
return true;
}
current = getElementParent(current, adapter);
} while (current);
return false;
};
}
case SelectorType.Parent: {
return function parent(element) {
return adapter
.getChildren(element)
.some((element) => adapter.isTag(element) && next(element));
};
}
case SelectorType.Child: {
return function child(element) {
const parent = getElementParent(element, adapter);
return parent !== null && next(parent);
};
}
case SelectorType.Sibling: {
return function sibling(element) {
const siblings = adapter.getSiblings(element);
for (const currentSibling of siblings) {
if (equals(element, currentSibling)) {
break;
}
if (adapter.isTag(currentSibling) && next(currentSibling)) {
return true;
}
}
return false;
};
}
case SelectorType.Adjacent: {
if (adapter.prevElementSibling) {
return function adjacent(element) {
// biome-ignore lint/style/noNonNullAssertion: checked by if statement
const previous = adapter.prevElementSibling(element);
return previous != null && next(previous);
};
}
return function adjacent(element) {
const siblings = adapter.getSiblings(element);
let lastElement;
for (const currentSibling of siblings) {
if (equals(element, currentSibling)) {
break;
}
if (adapter.isTag(currentSibling)) {
lastElement = currentSibling;
}
}
return !!lastElement && next(lastElement);
};
}
case SelectorType.Universal: {
if (selector.namespace != null && selector.namespace !== "*") {
throw new Error("Namespaced universal selectors are not yet supported by css-select");
}
return next;
}
}
}
const DESCENDANT_TOKEN = { type: SelectorType.Descendant };
const FLEXIBLE_DESCENDANT_TOKEN = {
type: "_flexibleDescendant",
};
const SCOPE_TOKEN = {
type: SelectorType.Pseudo,
name: "scope",
data: null,
};
/*
* CSS 4 Spec (Draft): 3.4.1. Absolutizing a Relative Selector
* http://www.w3.org/TR/selectors4/#absolutizing
*/
function absolutize(token, { adapter }, context) {
// TODO Use better check if the context is a document
const hasContext = !!context?.every((element) => element === PLACEHOLDER_ELEMENT ||
(adapter.isTag(element) &&
getElementParent(element, adapter) !== null));
for (const t of token) {
if (t.length > 0 &&
isTraversal(t[0]) &&
t[0].type !== SelectorType.Descendant) ;
else if (hasContext && !t.some(includesScopePseudo)) {
t.unshift(DESCENDANT_TOKEN);
}
else {
continue;
}
t.unshift(SCOPE_TOKEN);
}
}
/**
* Compile a parsed selector token into an executable query function.
* @param token Selector token(s) to compile.
* @param options Options that control this operation.
* @param compilationContext Compilation context for relative selector handling.
*/
function compileToken(token, options, compilationContext) {
for (const rules of token) {
sortRules(rules);
}
const { context = compilationContext, rootFunc: rootFunction = trueFunc, } = options;
const isArrayContext = Array.isArray(context);
const finalContext = context && (Array.isArray(context) ? context : [context]);
// Check if the selector is relative
if (options.relativeSelector !== false) {
absolutize(token, options, finalContext);
}
else if (token.some((t) => t.length > 0 && isTraversal(t[0]))) {
throw new Error("Relative selectors are not allowed when the `relativeSelector` option is disabled");
}
let shouldTestNextSiblings = false;
let query = falseFunc;
combineLoop: for (const rules of token) {
if (rules.length >= 2) {
const [first, second] = rules;
if (first.type !== SelectorType.Pseudo || first.name !== "scope") ;
else if (isArrayContext &&
second.type === SelectorType.Descendant) {
rules[1] = FLEXIBLE_DESCENDANT_TOKEN;
}
else if (second.type === SelectorType.Adjacent ||
second.type === SelectorType.Sibling) {
shouldTestNextSiblings = true;
}
}
let next = rootFunction;
let hasExpensiveSubselector = false;
for (const rule of rules) {
next = compileGeneralSelector(next, rule, options, finalContext, compileToken, hasExpensiveSubselector);
const quality = getQuality(rule);
if (quality === 0) {
hasExpensiveSubselector = true;
}
// If the sub-selector won't match any elements, skip it.
if (next === falseFunc) {
continue combineLoop;
}
}
// If we have a function that always returns true, we can stop here.
if (next === rootFunction) {
return rootFunction;
}
query = query === falseFunc ? next : or(query, next);
}
query.shouldTestNextSiblings = shouldTestNextSiblings;
return query;
}
function or(a, b) {
return (element) => a(element) || b(element);
}
const defaultEquals = (a, b) => a === b;
const defaultOptions = {
adapter: { ...DomUtils, isTag: isTag$1 },
equals: defaultEquals,
};
function convertOptionFormats(options) {
/*
* We force one format of options to the other one.
*/
// @ts-expect-error Default options may have incompatible `Node` / `ElementNode`.
const finalOptions = options ?? defaultOptions;
// @ts-expect-error Same as above.
finalOptions.adapter ??= defaultOptions.adapter;
// @ts-expect-error `equals` does not exist on `Options`
finalOptions.equals ??= finalOptions.adapter?.equals ?? defaultEquals;
return finalOptions;
}
/**
* Compiles a selector to an executable function.
*
* The returned function checks if each passed node is an element. Use
* `_compileUnsafe` to skip this check.
* @param selector Selector to compile.
* @param options Compilation options.
* @param context Optional context for the selector.
*/
function compile(selector, options, context) {
const convertedOptions = convertOptionFormats(options);
const next = _compileUnsafe(selector, convertedOptions, context);
return next === falseFunc
? falseFunc
: (element) => convertedOptions.adapter.isTag(element) && next(element);
}
/**
* Like `compile`, but does not add a check if elements are tags.
* @param selector Selector used to match elements.
* @param options Options that control this operation.
* @param context Context nodes used to scope selector matching.
*/
function _compileUnsafe(selector, options, context) {
return compileToken(typeof selector === "string" ? parse$3(selector) : selector, convertOptionFormats(options), context);
}
/**
* Tests whether or not an element is matched by query.
* @template Node The generic Node type for the DOM adapter being used.
* @template ElementNode The Node type for elements for the DOM adapter being used.
* @param element The element to test if it matches the query.
* @param query can be either a CSS selector string or a compiled query function.
* @param [options] options for querying the document.
* @see compile for supported selector queries.
* @returns Whether the element matches the query.
*/
function is(element, query, options) {
return (typeof query === "function" ? query : compile(query, options))(element);
}
const {isArray} = Array;
/* c8 ignore start */
const isTag = ({nodeType}) => nodeType === ELEMENT_NODE;
const existsOne = (test, elements) => elements.some(
element => isTag(element) && (
test(element) ||
existsOne(test, getChildren(element))
)
);
const getAttributeValue = (element, name) => name === 'class' ?
element.classList.value : element.getAttribute(name);
const getChildren = ({childNodes}) => childNodes;
const getName = (element) => {
const {localName} = element;
return ignoreCase(element) ? localName.toLowerCase() : localName;
};
const getParent = ({parentNode}) => parentNode;
const getSiblings = element => {
const {parentNode} = element;
return parentNode ? getChildren(parentNode) : element;
};
const getText = node => {
if (isArray(node))
return node.map(getText).join('');
if (isTag(node))
return getText(getChildren(node));
if (node.nodeType === TEXT_NODE)
return node.data;
return '';
};
const hasAttrib = (element, name) => element.hasAttribute(name);
const removeSubsets = nodes => {
let {length} = nodes;
while (length--) {
const node = nodes[length];
if (length && -1 < nodes.lastIndexOf(node, length - 1)) {
nodes.splice(length, 1);
continue;
}
for (let {parentNode} = node; parentNode; parentNode = parentNode.parentNode) {
if (nodes.includes(parentNode)) {
nodes.splice(length, 1);
break;
}
}
}
return nodes;
};
const findAll = (test, nodes) => {
const matches = [];
for (const node of nodes) {
if (isTag(node)) {
if (test(node))
matches.push(node);
matches.push(...findAll(test, getChildren(node)));
}
}
return matches;
};
const findOne = (test, nodes) => {
for (let node of nodes)
if (test(node) || (node = findOne(test, getChildren(node))))
return node;
return null;
};
/* c8 ignore stop */
const adapter = {
isTag,
existsOne,
getAttributeValue,
getChildren,
getName,
getParent,
getSiblings,
getText,
hasAttrib,
removeSubsets,
findAll,
findOne
};
const prepareMatch = (element, selectors) => compile(
selectors,
{
context: selectors.includes(':scope') ? element : void 0,
xmlMode: !ignoreCase(element),
adapter
}
);
const matches = (element, selectors) => is(
element,
selectors,
{
strict: true,
context: selectors.includes(':scope') ? element : void 0,
xmlMode: !ignoreCase(element),
adapter
}
);
/**
* @implements globalThis.Text
*/
let Text$1 = class Text extends CharacterData$1 {
constructor(ownerDocument, data = '') {
super(ownerDocument, '#text', TEXT_NODE, data);
}
get wholeText() {
const text = [];
let {previousSibling, nextSibling} = this;
while (previousSibling) {
if (previousSibling.nodeType === TEXT_NODE)
text.unshift(previousSibling[VALUE]);
else
break;
previousSibling = previousSibling.previousSibling;
}
text.push(this[VALUE]);
while (nextSibling) {
if (nextSibling.nodeType === TEXT_NODE)
text.push(nextSibling[VALUE]);
else
break;
nextSibling = nextSibling.nextSibling;
}
return text.join('');
}
cloneNode() {
const {ownerDocument, [VALUE]: data} = this;
return new Text(ownerDocument, data);
}
toString() { return escape(this[VALUE]); }
};
// https://dom.spec.whatwg.org/#interface-parentnode
// Document, DocumentFragment, Element
const isNode = node => node instanceof Node$1;
const insert = (parentNode, child, nodes) => {
const {ownerDocument} = parentNode;
for (const node of nodes)
parentNode.insertBefore(
isNode(node) ? node : new Text$1(ownerDocument, node),
child
);
};
/** @typedef { import('../interface/element.js').Element & {
[typeof NEXT]: NodeStruct,
[typeof PREV]: NodeStruct,
[typeof START]: NodeStruct,
nodeType: typeof ATTRIBUTE_NODE | typeof DOCUMENT_FRAGMENT_NODE | typeof ELEMENT_NODE | typeof TEXT_NODE | typeof NODE_END | typeof COMMENT_NODE | typeof CDATA_SECTION_NODE,
ownerDocument: Document,
parentNode: ParentNode,
}} NodeStruct */
class ParentNode extends Node$1 {
constructor(ownerDocument, localName, nodeType) {
super(ownerDocument, localName, nodeType);
this[PRIVATE] = null;
/** @type {NodeStruct} */
this[NEXT] = this[END] = {
[NEXT]: null,
[PREV]: this,
[START]: this,
nodeType: NODE_END,
ownerDocument: this.ownerDocument,
parentNode: null
};
}
get childNodes() {
const childNodes = new NodeList;
let {firstChild} = this;
while (firstChild) {
childNodes.push(firstChild);
firstChild = nextSibling(firstChild);
}
return childNodes;
}
get children() {
const children = new NodeList;
let {firstElementChild} = this;
while (firstElementChild) {
children.push(firstElementChild);
firstElementChild = nextElementSibling$1(firstElementChild);
}
return children;
}
/**
* @returns {NodeStruct | null}
*/
get firstChild() {
let {[NEXT]: next, [END]: end} = this;
while (next.nodeType === ATTRIBUTE_NODE)
next = next[NEXT];
return next === end ? null : next;
}
/**
* @returns {NodeStruct | null}
*/
get firstElementChild() {
let {firstChild} = this;
while (firstChild) {
if (firstChild.nodeType === ELEMENT_NODE)
return firstChild;
firstChild = nextSibling(firstChild);
}
return null;
}
get lastChild() {
const prev = this[END][PREV];
switch (prev.nodeType) {
case NODE_END:
return prev[START];
case ATTRIBUTE_NODE:
return null;
}
return prev === this ? null : prev;
}
get lastElementChild() {
let {lastChild} = this;
while (lastChild) {
if (lastChild.nodeType === ELEMENT_NODE)
return lastChild;
lastChild = previousSibling(lastChild);
}
return null;
}
get childElementCount() {
return this.children.length;
}
prepend(...nodes) {
insert(this, this.firstChild, nodes);
}
append(...nodes) {
insert(this, this[END], nodes);
}
replaceChildren(...nodes) {
let {[NEXT]: next, [END]: end} = this;
while (next !== end && next.nodeType === ATTRIBUTE_NODE)
next = next[NEXT];
while (next !== end) {
const after = getEnd(next)[NEXT];
next.remove();
next = after;
}
if (nodes.length)
insert(this, end, nodes);
}
getElementsByClassName(className) {
const elements = new NodeList;
let {[NEXT]: next, [END]: end} = this;
while (next !== end) {
if (
next.nodeType === ELEMENT_NODE &&
next.hasAttribute('class') &&
next.classList.has(className)
)
elements.push(next);
next = next[NEXT];
}
return elements;
}
getElementsByTagName(tagName) {
const elements = new NodeList;
let {[NEXT]: next, [END]: end} = this;
while (next !== end) {
if (next.nodeType === ELEMENT_NODE && (
next.localName === tagName ||
localCase(next) === tagName
))
elements.push(next);
next = next[NEXT];
}
return elements;
}
querySelector(selectors) {
const matches = prepareMatch(this, selectors);
let {[NEXT]: next, [END]: end} = this;
while (next !== end) {
if (next.nodeType === ELEMENT_NODE && matches(next))
return next;
next = next.nodeType === ELEMENT_NODE && next.localName === 'template' ? next[END] : next[NEXT];
}
return null;
}
querySelectorAll(selectors) {
const matches = prepareMatch(this, selectors);
const elements = new NodeList;
let {[NEXT]: next, [END]: end} = this;
while (next !== end) {
if (next.nodeType === ELEMENT_NODE && matches(next))
elements.push(next);
next = next.nodeType === ELEMENT_NODE && next.localName === 'template' ? next[END] : next[NEXT];
}
return elements;
}
appendChild(node) {
return this.insertBefore(node, this[END]);
}
contains(node) {
let parentNode = node;
while (parentNode && parentNode !== this)
parentNode = parentNode.parentNode;
return parentNode === this;
}
insertBefore(node, before = null) {
if (node === before)
return node;
if (node === this)
throw new Error('unable to append a node to itself');
const next = before || this[END];
switch (node.nodeType) {
case ELEMENT_NODE:
node.remove();
node.parentNode = this;
knownBoundaries(next[PREV], node, next);
moCallback(node, null);
connectedCallback(node);
break;
case DOCUMENT_FRAGMENT_NODE: {
let {[PRIVATE]: parentNode, firstChild, lastChild} = node;
if (firstChild) {
knownSegment(next[PREV], firstChild, lastChild, next);
knownAdjacent(node, node[END]);
if (parentNode)
parentNode.replaceChildren();
do {
firstChild.parentNode = this;
moCallback(firstChild, null);
if (firstChild.nodeType === ELEMENT_NODE)
connectedCallback(firstChild);
} while (
firstChild !== lastChild &&
(firstChild = nextSibling(firstChild))
);
}
break;
}
case TEXT_NODE:
case COMMENT_NODE:
case CDATA_SECTION_NODE:
node.remove();
/* eslint no-fallthrough:0 */
// this covers DOCUMENT_TYPE_NODE too
default:
node.parentNode = this;
knownSiblings(next[PREV], node, next);
moCallback(node, null);
break;
}
return node;
}
normalize() {
let {[NEXT]: next, [END]: end} = this;
while (next !== end) {
const {[NEXT]: $next, [PREV]: $prev, nodeType} = next;
if (nodeType === TEXT_NODE) {
if (!next[VALUE])
next.remove();
else if ($prev && $prev.nodeType === TEXT_NODE) {
$prev.textContent += next.textContent;
next.remove();
}
}
next = $next;
}
}
removeChild(node) {
if (node.parentNode !== this)
throw new Error('node is not a child');
node.remove();
return node;
}
replaceChild(node, replaced) {
const next = getEnd(replaced)[NEXT];
replaced.remove();
this.insertBefore(node, next);
return replaced;
}
}
// https://dom.spec.whatwg.org/#interface-nonelementparentnode
// Document, DocumentFragment
class NonElementParentNode extends ParentNode {
getElementById(id) {
let {[NEXT]: next, [END]: end} = this;
while (next !== end) {
if (next.nodeType === ELEMENT_NODE && next.id === id)
return next;
next = next[NEXT];
}
return null;
}
cloneNode(deep) {
const {ownerDocument, constructor} = this;
const nonEPN = new constructor(ownerDocument);
if (deep) {
const {[END]: end} = nonEPN;
for (const node of this.childNodes)
nonEPN.insertBefore(node.cloneNode(deep), end);
}
return nonEPN;
}
toString() {
const {childNodes, localName} = this;
return `<${localName}>${childNodes.join('')}</${localName}>`;
}
toJSON() {
const json = [];
nonElementAsJSON(this, json);
return json;
}
}
/**
* @implements globalThis.DocumentFragment
*/
let DocumentFragment$1 = class DocumentFragment extends NonElementParentNode {
constructor(ownerDocument) {
super(ownerDocument, '#document-fragment', DOCUMENT_FRAGMENT_NODE);
}
};
/**
* @implements globalThis.DocumentType
*/
let DocumentType$1 = class DocumentType extends Node$1 {
constructor(ownerDocument, name, publicId = '', systemId = '') {
super(ownerDocument, '#document-type', DOCUMENT_TYPE_NODE);
this.name = name;
this.publicId = publicId;
this.systemId = systemId;
}
cloneNode() {
const {ownerDocument, name, publicId, systemId} = this;
return new DocumentType(ownerDocument, name, publicId, systemId);
}
toString() {
const {name, publicId, systemId} = this;
const hasPublic = 0 < publicId.length;
const str = [name];
if (hasPublic)
str.push('PUBLIC', `"${publicId}"`);
if (systemId.length) {
if (!hasPublic)
str.push('SYSTEM');
str.push(`"${systemId}"`);
}
return `<!DOCTYPE ${str.join(' ')}>`;
}
toJSON() {
const json = [];
documentTypeAsJSON(this, json);
return json;
}
};
/**
* @param {Node} node
* @returns {String}
*/
const getInnerHtml = node => node.childNodes.join('');
/**
* @param {Node} node
* @param {String} html
*/
const setInnerHtml = (node, html) => {
const {ownerDocument} = node;
const {constructor} = ownerDocument;
const document = new constructor;
document[CUSTOM_ELEMENTS] = ownerDocument[CUSTOM_ELEMENTS];
const {childNodes} = parseFromString(document, ignoreCase(node), html);
node.replaceChildren(...childNodes.map(setOwnerDocument, ownerDocument));
};
function setOwnerDocument(node) {
node.ownerDocument = this;
switch (node.nodeType) {
case ELEMENT_NODE:
case DOCUMENT_FRAGMENT_NODE:
node.childNodes.forEach(setOwnerDocument, this);
break;
}
return node;
}
var uhyphen = camel => camel.replace(/(([A-Z0-9])([A-Z0-9][a-z]))|(([a-z0-9]+)([A-Z]))/g, '$2$5-$3$6')
.toLowerCase();
const refs$1 = new WeakMap;
const key = name => `data-${uhyphen(name)}`;
const prop = name => name.slice(5).replace(/-([a-z])/g, (_, $1) => $1.toUpperCase());
const handler$2 = {
get(dataset, name) {
if (name in dataset)
return refs$1.get(dataset).getAttribute(key(name));
},
set(dataset, name, value) {
dataset[name] = value;
refs$1.get(dataset).setAttribute(key(name), value);
return true;
},
deleteProperty(dataset, name) {
if (name in dataset)
refs$1.get(dataset).removeAttribute(key(name));
return delete dataset[name];
}
};
/**
* @implements globalThis.DOMStringMap
*/
class DOMStringMap {
/**
* @param {Element} ref
*/
constructor(ref) {
for (const {name, value} of ref.attributes) {
if (/^data-/.test(name))
this[prop(name)] = value;
}
refs$1.set(this, ref);
return new Proxy(this, handler$2);
}
}
setPrototypeOf(DOMStringMap.prototype, null);
const {add} = Set.prototype;
const addTokens = (self, tokens) => {
for (const token of tokens) {
if (token)
add.call(self, token);
}
};
const update = ({[OWNER_ELEMENT]: ownerElement, value}) => {
const attribute = ownerElement.getAttributeNode('class');
if (attribute)
attribute.value = value;
else
setAttribute(
ownerElement,
new Attr$1(ownerElement.ownerDocument, 'class', value)
);
};
/**
* @implements globalThis.DOMTokenList
*/
class DOMTokenList extends Set {
constructor(ownerElement) {
super();
this[OWNER_ELEMENT] = ownerElement;
const attribute = ownerElement.getAttributeNode('class');
if (attribute)
addTokens(this, attribute.value.split(/\s+/));
}
get length() { return this.size; }
get value() { return [...this].join(' '); }
/**
* @param {...string} tokens
*/
add(...tokens) {
addTokens(this, tokens);
update(this);
}
/**
* @param {string} token
*/
contains(token) { return this.has(token); }
/**
* @param {...string} tokens
*/
remove(...tokens) {
for (const token of tokens)
this.delete(token);
update(this);
}
/**
* @param {string} token
* @param {boolean?} force
*/
toggle(token, force) {
if (this.has(token)) {
if (force)
return true;
this.delete(token);
update(this);
}
else if (force || arguments.length === 1) {
super.add(token);
update(this);
return true;
}
return false;
}
/**
* @param {string} token
* @param {string} newToken
*/
replace(token, newToken) {
if (this.has(token)) {
this.delete(token);
super.add(newToken);
update(this);
return true;
}
return false;
}
/**
* @param {string} token
*/
supports() { return true; }
}
const refs = new WeakMap;
const getKeys = style => [...style.keys()].filter(key => key !== PRIVATE);
const updateKeys = style => {
const attr = refs.get(style).getAttributeNode('style');
if (!attr || attr[CHANGED] || style.get(PRIVATE) !== attr) {
style.clear();
if (attr) {
style.set(PRIVATE, attr);
for (const rule of attr[VALUE].split(/\s*;\s*/)) {
let [key, ...rest] = rule.split(':');
if (rest.length > 0) {
key = key.trim();
const value = rest.join(':').trim();
if (key && value)
style.set(key, value);
}
}
}
}
return attr;
};
const handler$1 = {
get(style, name) {
if (name in prototype)
return style[name];
updateKeys(style);
if (name === 'length')
return getKeys(style).length;
if (/^\d+$/.test(name))
return getKeys(style)[name];
return style.get(uhyphen(name)) ?? '';
},
set(style, name, value) {
if (name === 'cssText')
style[name] = value;
else {
let attr = updateKeys(style);
if (value == null)
style.delete(uhyphen(name));
else
style.set(uhyphen(name), value);
if (!attr) {
const element = refs.get(style);
attr = element.ownerDocument.createAttribute('style');
element.setAttributeNode(attr);
style.set(PRIVATE, attr);
}
attr[CHANGED] = false;
attr[VALUE] = style.toString();
}
return true;
}
};
/**
* @implements globalThis.CSSStyleDeclaration
*/
let CSSStyleDeclaration$1 = class CSSStyleDeclaration extends Map {
constructor(element) {
super();
refs.set(this, element);
/* c8 ignore start */
return new Proxy(this, handler$1);
/* c8 ignore stop */
}
get cssText() {
return this.toString();
}
set cssText(value) {
refs.get(this).setAttribute('style', value);
}
getPropertyValue(name) {
const self = this[PRIVATE];
return handler$1.get(self, name);
}
setProperty(name, value) {
const self = this[PRIVATE];
handler$1.set(self, name, value);
}
removeProperty(name) {
const self = this[PRIVATE];
handler$1.set(self, name, null);
}
[Symbol.iterator]() {
const self = this[PRIVATE];
updateKeys(self);
const keys = getKeys(self);
const {length} = keys;
let i = 0;
return {
next() {
const done = i === length;
return {done, value: done ? null : keys[i++]};
}
};
}
get[PRIVATE]() { return this; }
toString() {
const self = this[PRIVATE];
updateKeys(self);
const cssText = [];
self.forEach(push, cssText);
return cssText.join(';');
}
};
const {prototype} = CSSStyleDeclaration$1;
function push(value, key) {
if (key !== PRIVATE)
this.push(`${key}:${value}`);
}
// https://dom.spec.whatwg.org/#interface-event
/* c8 ignore start */
// Node 15 has Event but 14 and 12 don't
const BUBBLING_PHASE = 3;
const AT_TARGET = 2;
const CAPTURING_PHASE = 1;
const NONE = 0;
function getCurrentTarget(ev) {
return ev.currentTarget;
}
/**
* @implements globalThis.Event
*/
class GlobalEvent {
static get BUBBLING_PHASE() { return BUBBLING_PHASE; }
static get AT_TARGET() { return AT_TARGET; }
static get CAPTURING_PHASE() { return CAPTURING_PHASE; }
static get NONE() { return NONE; }
constructor(type, eventInitDict = {}) {
this.type = type;
this.bubbles = !!eventInitDict.bubbles;
this.cancelBubble = false;
this._stopImmediatePropagationFlag = false;
this.cancelable = !!eventInitDict.cancelable;
this.eventPhase = this.NONE;
this.timeStamp = Date.now();
this.defaultPrevented = false;
this.originalTarget = null;
this.returnValue = null;
this.srcElement = null;
this.target = null;
this._path = [];
}
get BUBBLING_PHASE() { return BUBBLING_PHASE; }
get AT_TARGET() { return AT_TARGET; }
get CAPTURING_PHASE() { return CAPTURING_PHASE; }
get NONE() { return NONE; }
preventDefault() { this.defaultPrevented = true; }
// simplified implementation, should be https://dom.spec.whatwg.org/#dom-event-composedpath
composedPath() {
return this._path.map(getCurrentTarget);
}
stopPropagation() {
this.cancelBubble = true;
}
stopImmediatePropagation() {
this.stopPropagation();
this._stopImmediatePropagationFlag = true;
}
}
/* c8 ignore stop */
/**
* @implements globalThis.NamedNodeMap
*/
class NamedNodeMap extends Array {
constructor(ownerElement) {
super();
this.ownerElement = ownerElement;
}
getNamedItem(name) {
return this.ownerElement.getAttributeNode(name);
}
setNamedItem(attr) {
this.ownerElement.setAttributeNode(attr);
this.unshift(attr);
}
removeNamedItem(name) {
const item = this.getNamedItem(name);
this.ownerElement.removeAttribute(name);
this.splice(this.indexOf(item), 1);
}
item(index) {
return index < this.length ? this[index] : null;
}
/* c8 ignore start */
getNamedItemNS(_, name) {
return this.getNamedItem(name);
}
setNamedItemNS(_, attr) {
return this.setNamedItem(attr);
}
removeNamedItemNS(_, name) {
return this.removeNamedItem(name);
}
/* c8 ignore stop */
}
/**
* @implements globalThis.ShadowRoot
*/
let ShadowRoot$1 = class ShadowRoot extends NonElementParentNode {
constructor(host) {
super(host.ownerDocument, '#shadow-root', DOCUMENT_FRAGMENT_NODE);
this.host = host;
}
get innerHTML() {
return getInnerHtml(this);
}
set innerHTML(html) {
setInnerHtml(this, html);
}
};
// https://dom.spec.whatwg.org/#interface-element
// <utils>
const attributesHandler = {
get(target, key) {
return key in target ? target[key] : target.find(({name}) => name === key);
}
};
const create = (ownerDocument, element, localName) => {
if ('ownerSVGElement' in element) {
const svg = ownerDocument.createElementNS(SVG_NAMESPACE, localName);
svg.ownerSVGElement = element.ownerSVGElement;
return svg;
}
return ownerDocument.createElement(localName);
};
const isVoid = ({localName, ownerDocument}) => {
return ownerDocument[MIME].voidElements.test(localName);
};
// </utils>
/**
* @implements globalThis.Element
*/
let Element$1 = class Element extends ParentNode {
constructor(ownerDocument, localName) {
super(ownerDocument, localName, ELEMENT_NODE);
this[CLASS_LIST] = null;
this[DATASET] = null;
this[STYLE] = null;
}
// <Mixins>
get isConnected() { return isConnected(this); }
get parentElement() { return parentElement(this); }
get previousSibling() { return previousSibling(this); }
get nextSibling() { return nextSibling(this); }
get namespaceURI() {
return 'http://www.w3.org/1999/xhtml';
}
get previousElementSibling() { return previousElementSibling(this); }
get nextElementSibling() { return nextElementSibling$1(this); }
before(...nodes) { before(this, nodes); }
after(...nodes) { after(this, nodes); }
replaceWith(...nodes) { replaceWith(this, nodes); }
remove() { remove(this[PREV], this, this[END][NEXT]); }
// </Mixins>
// <specialGetters>
get id() { return stringAttribute.get(this, 'id'); }
set id(value) { stringAttribute.set(this, 'id', value); }
get className() { return this.classList.value; }
set className(value) {
const {classList} = this;
classList.clear();
classList.add(...($String(value).split(/\s+/)));
}
get nodeName() { return localCase(this); }
get tagName() { return localCase(this); }
get classList() {
return this[CLASS_LIST] || (
this[CLASS_LIST] = new DOMTokenList(this)
);
}
get dataset() {
return this[DATASET] || (
this[DATASET] = new DOMStringMap(this)
);
}
getBoundingClientRect() {
return {
x: 0,
y: 0,
bottom: 0,
height: 0,
left: 0,
right: 0,
top: 0,
width: 0
};
}
get nonce() { return stringAttribute.get(this, 'nonce'); }
set nonce(value) { stringAttribute.set(this, 'nonce', value); }
get style() {
return this[STYLE] || (
this[STYLE] = new CSSStyleDeclaration$1(this)
);
}
get tabIndex() { return numericAttribute.get(this, 'tabindex') || -1; }
set tabIndex(value) { numericAttribute.set(this, 'tabindex', value); }
get slot() { return stringAttribute.get(this, 'slot'); }
set slot(value) { stringAttribute.set(this, 'slot', value); }
// </specialGetters>
// <contentRelated>
get innerText() {
const text = [];
let {[NEXT]: next, [END]: end} = this;
while (next !== end) {
if (next.nodeType === TEXT_NODE) {
text.push(next.textContent.replace(/\s+/g, ' '));
} else if(
text.length && next[NEXT] != end &&
BLOCK_ELEMENTS.has(next.tagName)
) {
text.push('\n');
}
next = next[NEXT];
}
return text.join('');
}
/**
* @returns {String}
*/
get textContent() {
const text = [];
let {[NEXT]: next, [END]: end} = this;
while (next !== end) {
const nodeType = next.nodeType;
if (nodeType === TEXT_NODE || nodeType === CDATA_SECTION_NODE)
text.push(next.textContent);
next = next[NEXT];
}
return text.join('');
}
set textContent(text) {
this.replaceChildren();
if (text != null && text !== '')
this.appendChild(new Text$1(this.ownerDocument, text));
}
get innerHTML() {
return getInnerHtml(this);
}
set innerHTML(html) {
setInnerHtml(this, html);
}
get outerHTML() { return this.toString(); }
set outerHTML(html) {
const template = this.ownerDocument.createElement('');
template.innerHTML = html;
this.replaceWith(...template.childNodes);
}
// </contentRelated>
// <attributes>
get attributes() {
const attributes = new NamedNodeMap(this);
let next = this[NEXT];
while (next.nodeType === ATTRIBUTE_NODE) {
attributes.push(next);
next = next[NEXT];
}
return new Proxy(attributes, attributesHandler);
}
focus() { this.dispatchEvent(new GlobalEvent('focus')); }
getAttribute(name) {
if (name === 'class')
return this.className;
const attribute = this.getAttributeNode(name);
return attribute && (ignoreCase(this) ? attribute.value : escape(attribute.value));
}
getAttributeNode(name) {
let next = this[NEXT];
while (next.nodeType === ATTRIBUTE_NODE) {
if (next.name === name)
return next;
next = next[NEXT];
}
return null;
}
getAttributeNames() {
const attributes = new NodeList;
let next = this[NEXT];
while (next.nodeType === ATTRIBUTE_NODE) {
attributes.push(next.name);
next = next[NEXT];
}
return attributes;
}
hasAttribute(name) { return !!this.getAttributeNode(name); }
hasAttributes() { return this[NEXT].nodeType === ATTRIBUTE_NODE; }
removeAttribute(name) {
if (name === 'class' && this[CLASS_LIST])
this[CLASS_LIST].clear();
let next = this[NEXT];
while (next.nodeType === ATTRIBUTE_NODE) {
if (next.name === name) {
removeAttribute(this, next);
return;
}
next = next[NEXT];
}
}
removeAttributeNode(attribute) {
let next = this[NEXT];
while (next.nodeType === ATTRIBUTE_NODE) {
if (next === attribute) {
removeAttribute(this, next);
return;
}
next = next[NEXT];
}
}
setAttribute(name, value) {
if (name === 'class')
this.className = value;
else {
const attribute = this.getAttributeNode(name);
if (attribute)
attribute.value = value;
else
setAttribute(this, new Attr$1(this.ownerDocument, name, value));
}
}
setAttributeNode(attribute) {
const {name} = attribute;
const previously = this.getAttributeNode(name);
if (previously !== attribute) {
if (previously)
this.removeAttributeNode(previously);
const {ownerElement} = attribute;
if (ownerElement)
ownerElement.removeAttributeNode(attribute);
setAttribute(this, attribute);
}
return previously;
}
toggleAttribute(name, force) {
if (this.hasAttribute(name)) {
if (!force) {
this.removeAttribute(name);
return false;
}
return true;
}
else if (force || arguments.length === 1) {
this.setAttribute(name, '');
return true;
}
return false;
}
// </attributes>
// <ShadowDOM>
get shadowRoot() {
if (shadowRoots.has(this)) {
const {mode, shadowRoot} = shadowRoots.get(this);
if (mode === 'open')
return shadowRoot;
}
return null;
}
attachShadow(init) {
if (shadowRoots.has(this))
throw new Error('operation not supported');
// TODO: shadowRoot should be likely a specialized class that extends DocumentFragment
// but until DSD is out, I am not sure I should spend time on this.
const shadowRoot = new ShadowRoot$1(this);
shadowRoots.set(this, {
mode: init.mode,
shadowRoot
});
return shadowRoot;
}
// </ShadowDOM>
// <selectors>
matches(selectors) { return matches(this, selectors); }
closest(selectors) {
let parentElement = this;
const matches = prepareMatch(parentElement, selectors);
while (parentElement && !matches(parentElement))
parentElement = parentElement.parentElement;
return parentElement;
}
// </selectors>
// <insertAdjacent>
insertAdjacentElement(position, element) {
const {parentElement} = this;
switch (position) {
case 'beforebegin':
if (parentElement) {
parentElement.insertBefore(element, this);
break;
}
return null;
case 'afterbegin':
this.insertBefore(element, this.firstChild);
break;
case 'beforeend':
this.insertBefore(element, null);
break;
case 'afterend':
if (parentElement) {
parentElement.insertBefore(element, this.nextSibling);
break;
}
return null;
}
return element;
}
insertAdjacentHTML(position, html) {
this.insertAdjacentElement(position, htmlToFragment(this.ownerDocument, html));
}
insertAdjacentText(position, text) {
const node = this.ownerDocument.createTextNode(text);
this.insertAdjacentElement(position, node);
}
// </insertAdjacent>
cloneNode(deep = false) {
const {ownerDocument, localName} = this;
const addNext = next => {
next.parentNode = parentNode;
knownAdjacent($next, next);
$next = next;
};
const clone = create(ownerDocument, this, localName);
let parentNode = clone, $next = clone;
let {[NEXT]: next, [END]: prev} = this;
while (next !== prev && (deep || next.nodeType === ATTRIBUTE_NODE)) {
switch (next.nodeType) {
case NODE_END:
knownAdjacent($next, parentNode[END]);
$next = parentNode[END];
parentNode = parentNode.parentNode;
break;
case ELEMENT_NODE: {
const node = create(ownerDocument, next, next.localName);
addNext(node);
parentNode = node;
break;
}
case ATTRIBUTE_NODE: {
const attr = next.cloneNode(deep);
attr.ownerElement = parentNode;
addNext(attr);
break;
}
case TEXT_NODE:
case COMMENT_NODE:
case CDATA_SECTION_NODE:
addNext(next.cloneNode(deep));
break;
}
next = next[NEXT];
}
knownAdjacent($next, clone[END]);
return clone;
}
// <custom>
toString() {
const out = [];
const {[END]: end} = this;
let next = {[NEXT]: this};
let isOpened = false;
do {
next = next[NEXT];
switch (next.nodeType) {
case ATTRIBUTE_NODE: {
const attr = ' ' + next;
switch (attr) {
case ' id':
case ' class':
case ' style':
break;
default:
out.push(attr);
}
break;
}
case NODE_END: {
const start = next[START];
if (isOpened) {
if ('ownerSVGElement' in start)
out.push(' />');
else if (isVoid(start))
out.push(ignoreCase(start) ? '>' : ' />');
else
out.push(`></${start.localName}>`);
isOpened = false;
}
else
out.push(`</${start.localName}>`);
break;
}
case ELEMENT_NODE:
if (isOpened)
out.push('>');
if (next.toString !== this.toString) {
out.push(next.toString());
next = next[END];
isOpened = false;
}
else {
out.push(`<${next.localName}`);
isOpened = true;
}
break;
case TEXT_NODE:
case COMMENT_NODE:
case CDATA_SECTION_NODE:
out.push((isOpened ? '>' : '') + next);
isOpened = false;
break;
}
} while (next !== end);
return out.join('');
}
toJSON() {
const json = [];
elementAsJSON(this, json);
return json;
}
// </custom>
/* c8 ignore start */
getAttributeNS(_, name) { return this.getAttribute(name); }
getElementsByTagNameNS(_, name) { return this.getElementsByTagName(name); }
hasAttributeNS(_, name) { return this.hasAttribute(name); }
removeAttributeNS(_, name) { this.removeAttribute(name); }
setAttributeNS(_, name, value) { this.setAttribute(name, value); }
setAttributeNodeNS(attr) { return this.setAttributeNode(attr); }
/* c8 ignore stop */
};
const classNames = new WeakMap;
const handler = {
get(target, name) {
return target[name];
},
set(target, name, value) {
target[name] = value;
return true;
}
};
/**
* @implements globalThis.SVGElement
*/
let SVGElement$1 = class SVGElement extends Element$1 {
constructor(ownerDocument, localName, ownerSVGElement = null) {
super(ownerDocument, localName);
this.ownerSVGElement = ownerSVGElement;
}
get className() {
if (!classNames.has(this))
classNames.set(this, new Proxy({baseVal: '', animVal: ''}, handler));
return classNames.get(this);
}
/* c8 ignore start */
set className(value) {
const {classList} = this;
classList.clear();
classList.add(...($String(value).split(/\s+/)));
}
/* c8 ignore stop */
get namespaceURI() {
return 'http://www.w3.org/2000/svg';
}
getAttribute(name) {
return name === 'class' ?
[...this.classList].join(' ') :
super.getAttribute(name);
}
setAttribute(name, value) {
if (name === 'class')
this.className = value;
else if (name === 'style') {
const {className} = this;
className.baseVal = className.animVal = value;
}
super.setAttribute(name, value);
}
};
/* c8 ignore start */
const illegalConstructor = () => {
throw new TypeError('Illegal constructor');
};
function Attr() { illegalConstructor(); }
setPrototypeOf(Attr, Attr$1);
Attr.prototype = Attr$1.prototype;
function CDATASection() { illegalConstructor(); }
setPrototypeOf(CDATASection, CDATASection$1);
CDATASection.prototype = CDATASection$1.prototype;
function CharacterData() { illegalConstructor(); }
setPrototypeOf(CharacterData, CharacterData$1);
CharacterData.prototype = CharacterData$1.prototype;
function Comment() { illegalConstructor(); }
setPrototypeOf(Comment, Comment$2);
Comment.prototype = Comment$2.prototype;
function DocumentFragment() { illegalConstructor(); }
setPrototypeOf(DocumentFragment, DocumentFragment$1);
DocumentFragment.prototype = DocumentFragment$1.prototype;
function DocumentType() { illegalConstructor(); }
setPrototypeOf(DocumentType, DocumentType$1);
DocumentType.prototype = DocumentType$1.prototype;
function Element() { illegalConstructor(); }
setPrototypeOf(Element, Element$1);
Element.prototype = Element$1.prototype;
function Node() { illegalConstructor(); }
setPrototypeOf(Node, Node$1);
Node.prototype = Node$1.prototype;
function ShadowRoot() { illegalConstructor(); }
setPrototypeOf(ShadowRoot, ShadowRoot$1);
ShadowRoot.prototype = ShadowRoot$1.prototype;
function Text() { illegalConstructor(); }
setPrototypeOf(Text, Text$1);
Text.prototype = Text$1.prototype;
function SVGElement() { illegalConstructor(); }
setPrototypeOf(SVGElement, SVGElement$1);
SVGElement.prototype = SVGElement$1.prototype;
/* c8 ignore stop */
const Facades = {
Attr,
CDATASection,
CharacterData,
Comment,
DocumentFragment,
DocumentType,
Element,
Node,
ShadowRoot,
Text,
SVGElement
};
const Level0 = new WeakMap;
const level0 = {
get(element, name) {
return Level0.has(element) && Level0.get(element)[name] || null;
},
set(element, name, value) {
if (!Level0.has(element))
Level0.set(element, {});
const handlers = Level0.get(element);
const type = name.slice(2);
if (handlers[name])
element.removeEventListener(type, handlers[name], false);
if ((handlers[name] = value))
element.addEventListener(type, value, false);
}
};
/**
* @implements globalThis.HTMLElement
*/
class HTMLElement extends Element$1 {
static get observedAttributes() { return []; }
constructor(ownerDocument = null, localName = '') {
super(ownerDocument, localName);
const ownerLess = !ownerDocument;
let options;
if (ownerLess) {
const {constructor: Class} = this;
if (!Classes.has(Class))
throw new Error('unable to initialize this Custom Element');
({ownerDocument, localName, options} = Classes.get(Class));
}
if (ownerDocument[UPGRADE]) {
const {element, values} = ownerDocument[UPGRADE];
ownerDocument[UPGRADE] = null;
for (const [key, value] of values)
element[key] = value;
return element;
}
if (ownerLess) {
this.ownerDocument = this[END].ownerDocument = ownerDocument;
this.localName = localName;
customElements.set(this, {connected: false});
if (options.is)
this.setAttribute('is', options.is);
}
}
/* c8 ignore start */
/* TODO: what about these?
offsetHeight
offsetLeft
offsetParent
offsetTop
offsetWidth
*/
blur() { this.dispatchEvent(new GlobalEvent('blur')); }
click() {
const clickEvent = new GlobalEvent('click', {bubbles: true, cancelable: true});
clickEvent.button = 0;
this.dispatchEvent(clickEvent);
}
// Boolean getters
get accessKeyLabel() {
const {accessKey} = this;
return accessKey && `Alt+Shift+${accessKey}`;
}
get isContentEditable() { return this.hasAttribute('contenteditable'); }
// Boolean Accessors
get contentEditable() { return booleanAttribute.get(this, 'contenteditable'); }
set contentEditable(value) { booleanAttribute.set(this, 'contenteditable', value); }
get draggable() { return booleanAttribute.get(this, 'draggable'); }
set draggable(value) { booleanAttribute.set(this, 'draggable', value); }
get hidden() { return booleanAttribute.get(this, 'hidden'); }
set hidden(value) { booleanAttribute.set(this, 'hidden', value); }
get spellcheck() { return booleanAttribute.get(this, 'spellcheck'); }
set spellcheck(value) { booleanAttribute.set(this, 'spellcheck', value); }
// String Accessors
get accessKey() { return stringAttribute.get(this, 'accesskey'); }
set accessKey(value) { stringAttribute.set(this, 'accesskey', value); }
get dir() { return stringAttribute.get(this, 'dir'); }
set dir(value) { stringAttribute.set(this, 'dir', value); }
get lang() { return stringAttribute.get(this, 'lang'); }
set lang(value) { stringAttribute.set(this, 'lang', value); }
get title() { return stringAttribute.get(this, 'title'); }
set title(value) { stringAttribute.set(this, 'title', value); }
// DOM Level 0
get onabort() { return level0.get(this, 'onabort'); }
set onabort(value) { level0.set(this, 'onabort', value); }
get onblur() { return level0.get(this, 'onblur'); }
set onblur(value) { level0.set(this, 'onblur', value); }
get oncancel() { return level0.get(this, 'oncancel'); }
set oncancel(value) { level0.set(this, 'oncancel', value); }
get oncanplay() { return level0.get(this, 'oncanplay'); }
set oncanplay(value) { level0.set(this, 'oncanplay', value); }
get oncanplaythrough() { return level0.get(this, 'oncanplaythrough'); }
set oncanplaythrough(value) { level0.set(this, 'oncanplaythrough', value); }
get onchange() { return level0.get(this, 'onchange'); }
set onchange(value) { level0.set(this, 'onchange', value); }
get onclick() { return level0.get(this, 'onclick'); }
set onclick(value) { level0.set(this, 'onclick', value); }
get onclose() { return level0.get(this, 'onclose'); }
set onclose(value) { level0.set(this, 'onclose', value); }
get oncontextmenu() { return level0.get(this, 'oncontextmenu'); }
set oncontextmenu(value) { level0.set(this, 'oncontextmenu', value); }
get oncuechange() { return level0.get(this, 'oncuechange'); }
set oncuechange(value) { level0.set(this, 'oncuechange', value); }
get ondblclick() { return level0.get(this, 'ondblclick'); }
set ondblclick(value) { level0.set(this, 'ondblclick', value); }
get ondrag() { return level0.get(this, 'ondrag'); }
set ondrag(value) { level0.set(this, 'ondrag', value); }
get ondragend() { return level0.get(this, 'ondragend'); }
set ondragend(value) { level0.set(this, 'ondragend', value); }
get ondragenter() { return level0.get(this, 'ondragenter'); }
set ondragenter(value) { level0.set(this, 'ondragenter', value); }
get ondragleave() { return level0.get(this, 'ondragleave'); }
set ondragleave(value) { level0.set(this, 'ondragleave', value); }
get ondragover() { return level0.get(this, 'ondragover'); }
set ondragover(value) { level0.set(this, 'ondragover', value); }
get ondragstart() { return level0.get(this, 'ondragstart'); }
set ondragstart(value) { level0.set(this, 'ondragstart', value); }
get ondrop() { return level0.get(this, 'ondrop'); }
set ondrop(value) { level0.set(this, 'ondrop', value); }
get ondurationchange() { return level0.get(this, 'ondurationchange'); }
set ondurationchange(value) { level0.set(this, 'ondurationchange', value); }
get onemptied() { return level0.get(this, 'onemptied'); }
set onemptied(value) { level0.set(this, 'onemptied', value); }
get onended() { return level0.get(this, 'onended'); }
set onended(value) { level0.set(this, 'onended', value); }
get onerror() { return level0.get(this, 'onerror'); }
set onerror(value) { level0.set(this, 'onerror', value); }
get onfocus() { return level0.get(this, 'onfocus'); }
set onfocus(value) { level0.set(this, 'onfocus', value); }
get oninput() { return level0.get(this, 'oninput'); }
set oninput(value) { level0.set(this, 'oninput', value); }
get oninvalid() { return level0.get(this, 'oninvalid'); }
set oninvalid(value) { level0.set(this, 'oninvalid', value); }
get onkeydown() { return level0.get(this, 'onkeydown'); }
set onkeydown(value) { level0.set(this, 'onkeydown', value); }
get onkeypress() { return level0.get(this, 'onkeypress'); }
set onkeypress(value) { level0.set(this, 'onkeypress', value); }
get onkeyup() { return level0.get(this, 'onkeyup'); }
set onkeyup(value) { level0.set(this, 'onkeyup', value); }
get onload() { return level0.get(this, 'onload'); }
set onload(value) { level0.set(this, 'onload', value); }
get onloadeddata() { return level0.get(this, 'onloadeddata'); }
set onloadeddata(value) { level0.set(this, 'onloadeddata', value); }
get onloadedmetadata() { return level0.get(this, 'onloadedmetadata'); }
set onloadedmetadata(value) { level0.set(this, 'onloadedmetadata', value); }
get onloadstart() { return level0.get(this, 'onloadstart'); }
set onloadstart(value) { level0.set(this, 'onloadstart', value); }
get onmousedown() { return level0.get(this, 'onmousedown'); }
set onmousedown(value) { level0.set(this, 'onmousedown', value); }
get onmouseenter() { return level0.get(this, 'onmouseenter'); }
set onmouseenter(value) { level0.set(this, 'onmouseenter', value); }
get onmouseleave() { return level0.get(this, 'onmouseleave'); }
set onmouseleave(value) { level0.set(this, 'onmouseleave', value); }
get onmousemove() { return level0.get(this, 'onmousemove'); }
set onmousemove(value) { level0.set(this, 'onmousemove', value); }
get onmouseout() { return level0.get(this, 'onmouseout'); }
set onmouseout(value) { level0.set(this, 'onmouseout', value); }
get onmouseover() { return level0.get(this, 'onmouseover'); }
set onmouseover(value) { level0.set(this, 'onmouseover', value); }
get onmouseup() { return level0.get(this, 'onmouseup'); }
set onmouseup(value) { level0.set(this, 'onmouseup', value); }
get onmousewheel() { return level0.get(this, 'onmousewheel'); }
set onmousewheel(value) { level0.set(this, 'onmousewheel', value); }
get onpause() { return level0.get(this, 'onpause'); }
set onpause(value) { level0.set(this, 'onpause', value); }
get onplay() { return level0.get(this, 'onplay'); }
set onplay(value) { level0.set(this, 'onplay', value); }
get onplaying() { return level0.get(this, 'onplaying'); }
set onplaying(value) { level0.set(this, 'onplaying', value); }
get onprogress() { return level0.get(this, 'onprogress'); }
set onprogress(value) { level0.set(this, 'onprogress', value); }
get onratechange() { return level0.get(this, 'onratechange'); }
set onratechange(value) { level0.set(this, 'onratechange', value); }
get onreset() { return level0.get(this, 'onreset'); }
set onreset(value) { level0.set(this, 'onreset', value); }
get onresize() { return level0.get(this, 'onresize'); }
set onresize(value) { level0.set(this, 'onresize', value); }
get onscroll() { return level0.get(this, 'onscroll'); }
set onscroll(value) { level0.set(this, 'onscroll', value); }
get onseeked() { return level0.get(this, 'onseeked'); }
set onseeked(value) { level0.set(this, 'onseeked', value); }
get onseeking() { return level0.get(this, 'onseeking'); }
set onseeking(value) { level0.set(this, 'onseeking', value); }
get onselect() { return level0.get(this, 'onselect'); }
set onselect(value) { level0.set(this, 'onselect', value); }
get onshow() { return level0.get(this, 'onshow'); }
set onshow(value) { level0.set(this, 'onshow', value); }
get onstalled() { return level0.get(this, 'onstalled'); }
set onstalled(value) { level0.set(this, 'onstalled', value); }
get onsubmit() { return level0.get(this, 'onsubmit'); }
set onsubmit(value) { level0.set(this, 'onsubmit', value); }
get onsuspend() { return level0.get(this, 'onsuspend'); }
set onsuspend(value) { level0.set(this, 'onsuspend', value); }
get ontimeupdate() { return level0.get(this, 'ontimeupdate'); }
set ontimeupdate(value) { level0.set(this, 'ontimeupdate', value); }
get ontoggle() { return level0.get(this, 'ontoggle'); }
set ontoggle(value) { level0.set(this, 'ontoggle', value); }
get onvolumechange() { return level0.get(this, 'onvolumechange'); }
set onvolumechange(value) { level0.set(this, 'onvolumechange', value); }
get onwaiting() { return level0.get(this, 'onwaiting'); }
set onwaiting(value) { level0.set(this, 'onwaiting', value); }
get onauxclick() { return level0.get(this, 'onauxclick'); }
set onauxclick(value) { level0.set(this, 'onauxclick', value); }
get ongotpointercapture() { return level0.get(this, 'ongotpointercapture'); }
set ongotpointercapture(value) { level0.set(this, 'ongotpointercapture', value); }
get onlostpointercapture() { return level0.get(this, 'onlostpointercapture'); }
set onlostpointercapture(value) { level0.set(this, 'onlostpointercapture', value); }
get onpointercancel() { return level0.get(this, 'onpointercancel'); }
set onpointercancel(value) { level0.set(this, 'onpointercancel', value); }
get onpointerdown() { return level0.get(this, 'onpointerdown'); }
set onpointerdown(value) { level0.set(this, 'onpointerdown', value); }
get onpointerenter() { return level0.get(this, 'onpointerenter'); }
set onpointerenter(value) { level0.set(this, 'onpointerenter', value); }
get onpointerleave() { return level0.get(this, 'onpointerleave'); }
set onpointerleave(value) { level0.set(this, 'onpointerleave', value); }
get onpointermove() { return level0.get(this, 'onpointermove'); }
set onpointermove(value) { level0.set(this, 'onpointermove', value); }
get onpointerout() { return level0.get(this, 'onpointerout'); }
set onpointerout(value) { level0.set(this, 'onpointerout', value); }
get onpointerover() { return level0.get(this, 'onpointerover'); }
set onpointerover(value) { level0.set(this, 'onpointerover', value); }
get onpointerup() { return level0.get(this, 'onpointerup'); }
set onpointerup(value) { level0.set(this, 'onpointerup', value); }
/* c8 ignore stop */
}
const tagName$h = 'template';
/**
* @implements globalThis.HTMLTemplateElement
*/
class HTMLTemplateElement extends HTMLElement {
constructor(ownerDocument) {
super(ownerDocument, tagName$h);
const content = this.ownerDocument.createDocumentFragment();
(this[CONTENT] = content)[PRIVATE] = this;
}
get content() {
if (this.hasChildNodes() && !this[CONTENT].hasChildNodes()) {
for (const node of this.childNodes)
this[CONTENT].appendChild(node.cloneNode(true));
}
return this[CONTENT];
}
}
registerHTMLClass(tagName$h, HTMLTemplateElement);
/**
* @implements globalThis.HTMLHtmlElement
*/
class HTMLHtmlElement extends HTMLElement {
constructor(ownerDocument, localName = 'html') {
super(ownerDocument, localName);
}
}
const {toString} = HTMLElement.prototype;
class TextElement extends HTMLElement {
get innerHTML() { return this.textContent; }
set innerHTML(html) { this.textContent = html; }
toString() {
const outerHTML = toString.call(this.cloneNode());
return outerHTML.replace('><', () => `>${this.textContent}<`);
}
}
const tagName$g = 'script';
/**
* @implements globalThis.HTMLScriptElement
*/
class HTMLScriptElement extends TextElement {
constructor(ownerDocument, localName = tagName$g) {
super(ownerDocument, localName);
}
get type() {
return stringAttribute.get(this, 'type');
}
set type(value) {
stringAttribute.set(this, 'type', value);
}
get src() {
return stringAttribute.get(this, 'src');
}
set src(value) {
stringAttribute.set(this, 'src', value);
}
get defer() {
return booleanAttribute.get(this, 'defer');
}
set defer(value) {
booleanAttribute.set(this, 'defer', value);
}
get crossOrigin() {
return stringAttribute.get(this, 'crossorigin');
}
set crossOrigin(value) {
stringAttribute.set(this, 'crossorigin', value);
}
get nomodule() {
return booleanAttribute.get(this, 'nomodule');
}
set nomodule(value) {
booleanAttribute.set(this, 'nomodule', value);
}
get referrerPolicy() {
return stringAttribute.get(this, 'referrerpolicy');
}
set referrerPolicy(value) {
stringAttribute.set(this, 'referrerpolicy', value);
}
get nonce() {
return stringAttribute.get(this, 'nonce');
}
set nonce(value) {
stringAttribute.set(this, 'nonce', value);
}
get async() {
return booleanAttribute.get(this, 'async');
}
set async(value) {
booleanAttribute.set(this, 'async', value);
}
get text() { return this.textContent; }
set text(content) { this.textContent = content; }
}
registerHTMLClass(tagName$g, HTMLScriptElement);
/**
* @implements globalThis.HTMLFrameElement
*/
class HTMLFrameElement extends HTMLElement {
constructor(ownerDocument, localName = 'frame') {
super(ownerDocument, localName);
}
}
const tagName$f = 'iframe';
/**
* @implements globalThis.HTMLIFrameElement
*/
class HTMLIFrameElement extends HTMLElement {
constructor(ownerDocument, localName = tagName$f) {
super(ownerDocument, localName);
}
/* c8 ignore start */
get src() { return stringAttribute.get(this, 'src'); }
set src(value) { stringAttribute.set(this, 'src', value); }
get srcdoc() { return stringAttribute.get(this, "srcdoc"); }
set srcdoc(value) { stringAttribute.set(this, "srcdoc", value); }
get name() { return stringAttribute.get(this, "name"); }
set name(value) { stringAttribute.set(this, "name", value); }
get allow() { return stringAttribute.get(this, "allow"); }
set allow(value) { stringAttribute.set(this, "allow", value); }
get allowFullscreen() { return booleanAttribute.get(this, "allowfullscreen"); }
set allowFullscreen(value) { booleanAttribute.set(this, "allowfullscreen", value); }
get referrerPolicy() { return stringAttribute.get(this, "referrerpolicy"); }
set referrerPolicy(value) { stringAttribute.set(this, "referrerpolicy", value); }
get loading() { return stringAttribute.get(this, "loading"); }
set loading(value) { stringAttribute.set(this, "loading", value); }
/* c8 ignore stop */
}
registerHTMLClass(tagName$f, HTMLIFrameElement);
/**
* @implements globalThis.HTMLObjectElement
*/
class HTMLObjectElement extends HTMLElement {
constructor(ownerDocument, localName = 'object') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLHeadElement
*/
class HTMLHeadElement extends HTMLElement {
constructor(ownerDocument, localName = 'head') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLBodyElement
*/
class HTMLBodyElement extends HTMLElement {
constructor(ownerDocument, localName = 'body') {
super(ownerDocument, localName);
}
}
var lib = {};
var CSSStyleDeclaration = {};
var parse$1 = {};
var CSSStyleSheet = {};
var StyleSheet = {};
var hasRequiredStyleSheet;
function requireStyleSheet () {
if (hasRequiredStyleSheet) return StyleSheet;
hasRequiredStyleSheet = 1;
//.CommonJS
var CSSOM = {};
///CommonJS
/**
* @constructor
* @see http://dev.w3.org/csswg/cssom/#the-stylesheet-interface
*/
CSSOM.StyleSheet = function StyleSheet() {
this.parentStyleSheet = null;
};
//.CommonJS
StyleSheet.StyleSheet = CSSOM.StyleSheet;
///CommonJS
return StyleSheet;
}
var CSSStyleRule = {};
var CSSRule = {};
var hasRequiredCSSRule;
function requireCSSRule () {
if (hasRequiredCSSRule) return CSSRule;
hasRequiredCSSRule = 1;
//.CommonJS
var CSSOM = {};
///CommonJS
/**
* @constructor
* @see http://dev.w3.org/csswg/cssom/#the-cssrule-interface
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSRule
*/
CSSOM.CSSRule = function CSSRule() {
this.parentRule = null;
this.parentStyleSheet = null;
};
CSSOM.CSSRule.UNKNOWN_RULE = 0; // obsolete
CSSOM.CSSRule.STYLE_RULE = 1;
CSSOM.CSSRule.CHARSET_RULE = 2; // obsolete
CSSOM.CSSRule.IMPORT_RULE = 3;
CSSOM.CSSRule.MEDIA_RULE = 4;
CSSOM.CSSRule.FONT_FACE_RULE = 5;
CSSOM.CSSRule.PAGE_RULE = 6;
CSSOM.CSSRule.KEYFRAMES_RULE = 7;
CSSOM.CSSRule.KEYFRAME_RULE = 8;
CSSOM.CSSRule.MARGIN_RULE = 9;
CSSOM.CSSRule.NAMESPACE_RULE = 10;
CSSOM.CSSRule.COUNTER_STYLE_RULE = 11;
CSSOM.CSSRule.SUPPORTS_RULE = 12;
CSSOM.CSSRule.DOCUMENT_RULE = 13;
CSSOM.CSSRule.FONT_FEATURE_VALUES_RULE = 14;
CSSOM.CSSRule.VIEWPORT_RULE = 15;
CSSOM.CSSRule.REGION_STYLE_RULE = 16;
CSSOM.CSSRule.prototype = {
constructor: CSSOM.CSSRule
//FIXME
};
//.CommonJS
CSSRule.CSSRule = CSSOM.CSSRule;
///CommonJS
return CSSRule;
}
var hasRequiredCSSStyleRule;
function requireCSSStyleRule () {
if (hasRequiredCSSStyleRule) return CSSStyleRule;
hasRequiredCSSStyleRule = 1;
//.CommonJS
var CSSOM = {
CSSStyleDeclaration: requireCSSStyleDeclaration().CSSStyleDeclaration,
CSSRule: requireCSSRule().CSSRule
};
///CommonJS
/**
* @constructor
* @see http://dev.w3.org/csswg/cssom/#cssstylerule
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleRule
*/
CSSOM.CSSStyleRule = function CSSStyleRule() {
CSSOM.CSSRule.call(this);
this.selectorText = "";
this.style = new CSSOM.CSSStyleDeclaration();
this.style.parentRule = this;
};
CSSOM.CSSStyleRule.prototype = new CSSOM.CSSRule();
CSSOM.CSSStyleRule.prototype.constructor = CSSOM.CSSStyleRule;
CSSOM.CSSStyleRule.prototype.type = 1;
Object.defineProperty(CSSOM.CSSStyleRule.prototype, "cssText", {
get: function() {
var text;
if (this.selectorText) {
text = this.selectorText + " {" + this.style.cssText + "}";
} else {
text = "";
}
return text;
},
set: function(cssText) {
var rule = CSSOM.CSSStyleRule.parse(cssText);
this.style = rule.style;
this.selectorText = rule.selectorText;
}
});
/**
* NON-STANDARD
* lightweight version of parse.js.
* @param {string} ruleText
* @return CSSStyleRule
*/
CSSOM.CSSStyleRule.parse = function(ruleText) {
var i = 0;
var state = "selector";
var index;
var j = i;
var buffer = "";
var SIGNIFICANT_WHITESPACE = {
"selector": true,
"value": true
};
var styleRule = new CSSOM.CSSStyleRule();
var name, priority="";
for (var character; (character = ruleText.charAt(i)); i++) {
switch (character) {
case " ":
case "\t":
case "\r":
case "\n":
case "\f":
if (SIGNIFICANT_WHITESPACE[state]) {
// Squash 2 or more white-spaces in the row into 1
switch (ruleText.charAt(i - 1)) {
case " ":
case "\t":
case "\r":
case "\n":
case "\f":
break;
default:
buffer += " ";
break;
}
}
break;
// String
case '"':
j = i + 1;
index = ruleText.indexOf('"', j) + 1;
if (!index) {
throw '" is missing';
}
buffer += ruleText.slice(i, index);
i = index - 1;
break;
case "'":
j = i + 1;
index = ruleText.indexOf("'", j) + 1;
if (!index) {
throw "' is missing";
}
buffer += ruleText.slice(i, index);
i = index - 1;
break;
// Comment
case "/":
if (ruleText.charAt(i + 1) === "*") {
i += 2;
index = ruleText.indexOf("*/", i);
if (index === -1) {
throw new SyntaxError("Missing */");
} else {
i = index + 1;
}
} else {
buffer += character;
}
break;
case "{":
if (state === "selector") {
styleRule.selectorText = buffer.trim();
buffer = "";
state = "name";
}
break;
case ":":
if (state === "name") {
name = buffer.trim();
buffer = "";
state = "value";
} else {
buffer += character;
}
break;
case "!":
if (state === "value" && ruleText.indexOf("!important", i) === i) {
priority = "important";
i += "important".length;
} else {
buffer += character;
}
break;
case ";":
if (state === "value") {
styleRule.style.setProperty(name, buffer.trim(), priority);
priority = "";
buffer = "";
state = "name";
} else {
buffer += character;
}
break;
case "}":
if (state === "value") {
styleRule.style.setProperty(name, buffer.trim(), priority);
priority = "";
buffer = "";
} else if (state === "name") {
break;
} else {
buffer += character;
}
state = "selector";
break;
default:
buffer += character;
break;
}
}
return styleRule;
};
//.CommonJS
CSSStyleRule.CSSStyleRule = CSSOM.CSSStyleRule;
///CommonJS
return CSSStyleRule;
}
var hasRequiredCSSStyleSheet;
function requireCSSStyleSheet () {
if (hasRequiredCSSStyleSheet) return CSSStyleSheet;
hasRequiredCSSStyleSheet = 1;
//.CommonJS
var CSSOM = {
StyleSheet: requireStyleSheet().StyleSheet,
CSSStyleRule: requireCSSStyleRule().CSSStyleRule
};
///CommonJS
/**
* @constructor
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet
*/
CSSOM.CSSStyleSheet = function CSSStyleSheet() {
CSSOM.StyleSheet.call(this);
this.cssRules = [];
};
CSSOM.CSSStyleSheet.prototype = new CSSOM.StyleSheet();
CSSOM.CSSStyleSheet.prototype.constructor = CSSOM.CSSStyleSheet;
/**
* Used to insert a new rule into the style sheet. The new rule now becomes part of the cascade.
*
* sheet = new Sheet("body {margin: 0}")
* sheet.toString()
* -> "body{margin:0;}"
* sheet.insertRule("img {border: none}", 0)
* -> 0
* sheet.toString()
* -> "img{border:none;}body{margin:0;}"
*
* @param {string} rule
* @param {number} index
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet-insertRule
* @return {number} The index within the style sheet's rule collection of the newly inserted rule.
*/
CSSOM.CSSStyleSheet.prototype.insertRule = function(rule, index) {
if (index < 0 || index > this.cssRules.length) {
throw new RangeError("INDEX_SIZE_ERR");
}
var cssRule = CSSOM.parse(rule).cssRules[0];
cssRule.parentStyleSheet = this;
this.cssRules.splice(index, 0, cssRule);
return index;
};
/**
* Used to delete a rule from the style sheet.
*
* sheet = new Sheet("img{border:none} body{margin:0}")
* sheet.toString()
* -> "img{border:none;}body{margin:0;}"
* sheet.deleteRule(0)
* sheet.toString()
* -> "body{margin:0;}"
*
* @param {number} index within the style sheet's rule list of the rule to remove.
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet-deleteRule
*/
CSSOM.CSSStyleSheet.prototype.deleteRule = function(index) {
if (index < 0 || index >= this.cssRules.length) {
throw new RangeError("INDEX_SIZE_ERR");
}
this.cssRules.splice(index, 1);
};
/**
* NON-STANDARD
* @return {string} serialize stylesheet
*/
CSSOM.CSSStyleSheet.prototype.toString = function() {
var result = "";
var rules = this.cssRules;
for (var i=0; i<rules.length; i++) {
result += rules[i].cssText + "\n";
}
return result;
};
//.CommonJS
CSSStyleSheet.CSSStyleSheet = CSSOM.CSSStyleSheet;
CSSOM.parse = requireParse().parse; // Cannot be included sooner due to the mutual dependency between parse.js and CSSStyleSheet.js
///CommonJS
return CSSStyleSheet;
}
var CSSImportRule = {};
var MediaList = {};
var hasRequiredMediaList;
function requireMediaList () {
if (hasRequiredMediaList) return MediaList;
hasRequiredMediaList = 1;
//.CommonJS
var CSSOM = {};
///CommonJS
/**
* @constructor
* @see http://dev.w3.org/csswg/cssom/#the-medialist-interface
*/
CSSOM.MediaList = function MediaList(){
this.length = 0;
};
CSSOM.MediaList.prototype = {
constructor: CSSOM.MediaList,
/**
* @return {string}
*/
get mediaText() {
return Array.prototype.join.call(this, ", ");
},
/**
* @param {string} value
*/
set mediaText(value) {
var values = value.split(",");
var length = this.length = values.length;
for (var i=0; i<length; i++) {
this[i] = values[i].trim();
}
},
/**
* @param {string} medium
*/
appendMedium: function(medium) {
if (Array.prototype.indexOf.call(this, medium) === -1) {
this[this.length] = medium;
this.length++;
}
},
/**
* @param {string} medium
*/
deleteMedium: function(medium) {
var index = Array.prototype.indexOf.call(this, medium);
if (index !== -1) {
Array.prototype.splice.call(this, index, 1);
}
}
};
//.CommonJS
MediaList.MediaList = CSSOM.MediaList;
///CommonJS
return MediaList;
}
var hasRequiredCSSImportRule;
function requireCSSImportRule () {
if (hasRequiredCSSImportRule) return CSSImportRule;
hasRequiredCSSImportRule = 1;
//.CommonJS
var CSSOM = {
CSSRule: requireCSSRule().CSSRule,
CSSStyleSheet: requireCSSStyleSheet().CSSStyleSheet,
MediaList: requireMediaList().MediaList
};
///CommonJS
/**
* @constructor
* @see http://dev.w3.org/csswg/cssom/#cssimportrule
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSImportRule
*/
CSSOM.CSSImportRule = function CSSImportRule() {
CSSOM.CSSRule.call(this);
this.href = "";
this.media = new CSSOM.MediaList();
this.styleSheet = new CSSOM.CSSStyleSheet();
};
CSSOM.CSSImportRule.prototype = new CSSOM.CSSRule();
CSSOM.CSSImportRule.prototype.constructor = CSSOM.CSSImportRule;
CSSOM.CSSImportRule.prototype.type = 3;
Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
get: function() {
var mediaText = this.media.mediaText;
return "@import url(" + this.href + ")" + (mediaText ? " " + mediaText : "") + ";";
},
set: function(cssText) {
var i = 0;
/**
* @import url(partial.css) screen, handheld;
* || |
* after-import media
* |
* url
*/
var state = '';
var buffer = '';
var index;
for (var character; (character = cssText.charAt(i)); i++) {
switch (character) {
case ' ':
case '\t':
case '\r':
case '\n':
case '\f':
if (state === 'after-import') {
state = 'url';
} else {
buffer += character;
}
break;
case '@':
if (!state && cssText.indexOf('@import', i) === i) {
state = 'after-import';
i += 'import'.length;
buffer = '';
}
break;
case 'u':
if (state === 'url' && cssText.indexOf('url(', i) === i) {
index = cssText.indexOf(')', i + 1);
if (index === -1) {
throw i + ': ")" not found';
}
i += 'url('.length;
var url = cssText.slice(i, index);
if (url[0] === url[url.length - 1]) {
if (url[0] === '"' || url[0] === "'") {
url = url.slice(1, -1);
}
}
this.href = url;
i = index;
state = 'media';
}
break;
case '"':
if (state === 'url') {
index = cssText.indexOf('"', i + 1);
if (!index) {
throw i + ": '\"' not found";
}
this.href = cssText.slice(i + 1, index);
i = index;
state = 'media';
}
break;
case "'":
if (state === 'url') {
index = cssText.indexOf("'", i + 1);
if (!index) {
throw i + ': "\'" not found';
}
this.href = cssText.slice(i + 1, index);
i = index;
state = 'media';
}
break;
case ';':
if (state === 'media') {
if (buffer) {
this.media.mediaText = buffer.trim();
}
}
break;
default:
if (state === 'media') {
buffer += character;
}
break;
}
}
}
});
//.CommonJS
CSSImportRule.CSSImportRule = CSSOM.CSSImportRule;
///CommonJS
return CSSImportRule;
}
var CSSGroupingRule = {};
var hasRequiredCSSGroupingRule;
function requireCSSGroupingRule () {
if (hasRequiredCSSGroupingRule) return CSSGroupingRule;
hasRequiredCSSGroupingRule = 1;
//.CommonJS
var CSSOM = {
CSSRule: requireCSSRule().CSSRule
};
///CommonJS
/**
* @constructor
* @see https://drafts.csswg.org/cssom/#the-cssgroupingrule-interface
*/
CSSOM.CSSGroupingRule = function CSSGroupingRule() {
CSSOM.CSSRule.call(this);
this.cssRules = [];
};
CSSOM.CSSGroupingRule.prototype = new CSSOM.CSSRule();
CSSOM.CSSGroupingRule.prototype.constructor = CSSOM.CSSGroupingRule;
/**
* Used to insert a new CSS rule to a list of CSS rules.
*
* @example
* cssGroupingRule.cssText
* -> "body{margin:0;}"
* cssGroupingRule.insertRule("img{border:none;}", 1)
* -> 1
* cssGroupingRule.cssText
* -> "body{margin:0;}img{border:none;}"
*
* @param {string} rule
* @param {number} [index]
* @see https://www.w3.org/TR/cssom-1/#dom-cssgroupingrule-insertrule
* @return {number} The index within the grouping rule's collection of the newly inserted rule.
*/
CSSOM.CSSGroupingRule.prototype.insertRule = function insertRule(rule, index) {
if (index < 0 || index > this.cssRules.length) {
throw new RangeError("INDEX_SIZE_ERR");
}
var cssRule = CSSOM.parse(rule).cssRules[0];
cssRule.parentRule = this;
this.cssRules.splice(index, 0, cssRule);
return index;
};
/**
* Used to delete a rule from the grouping rule.
*
* cssGroupingRule.cssText
* -> "img{border:none;}body{margin:0;}"
* cssGroupingRule.deleteRule(0)
* cssGroupingRule.cssText
* -> "body{margin:0;}"
*
* @param {number} index within the grouping rule's rule list of the rule to remove.
* @see https://www.w3.org/TR/cssom-1/#dom-cssgroupingrule-deleterule
*/
CSSOM.CSSGroupingRule.prototype.deleteRule = function deleteRule(index) {
if (index < 0 || index >= this.cssRules.length) {
throw new RangeError("INDEX_SIZE_ERR");
}
this.cssRules.splice(index, 1)[0].parentRule = null;
};
//.CommonJS
CSSGroupingRule.CSSGroupingRule = CSSOM.CSSGroupingRule;
///CommonJS
return CSSGroupingRule;
}
var CSSMediaRule = {};
var CSSConditionRule = {};
var hasRequiredCSSConditionRule;
function requireCSSConditionRule () {
if (hasRequiredCSSConditionRule) return CSSConditionRule;
hasRequiredCSSConditionRule = 1;
//.CommonJS
var CSSOM = {
CSSRule: requireCSSRule().CSSRule,
CSSGroupingRule: requireCSSGroupingRule().CSSGroupingRule
};
///CommonJS
/**
* @constructor
* @see https://www.w3.org/TR/css-conditional-3/#the-cssconditionrule-interface
*/
CSSOM.CSSConditionRule = function CSSConditionRule() {
CSSOM.CSSGroupingRule.call(this);
this.cssRules = [];
};
CSSOM.CSSConditionRule.prototype = new CSSOM.CSSGroupingRule();
CSSOM.CSSConditionRule.prototype.constructor = CSSOM.CSSConditionRule;
CSSOM.CSSConditionRule.prototype.conditionText = '';
CSSOM.CSSConditionRule.prototype.cssText = '';
//.CommonJS
CSSConditionRule.CSSConditionRule = CSSOM.CSSConditionRule;
///CommonJS
return CSSConditionRule;
}
var hasRequiredCSSMediaRule;
function requireCSSMediaRule () {
if (hasRequiredCSSMediaRule) return CSSMediaRule;
hasRequiredCSSMediaRule = 1;
//.CommonJS
var CSSOM = {
CSSRule: requireCSSRule().CSSRule,
CSSGroupingRule: requireCSSGroupingRule().CSSGroupingRule,
CSSConditionRule: requireCSSConditionRule().CSSConditionRule,
MediaList: requireMediaList().MediaList
};
///CommonJS
/**
* @constructor
* @see http://dev.w3.org/csswg/cssom/#cssmediarule
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSMediaRule
*/
CSSOM.CSSMediaRule = function CSSMediaRule() {
CSSOM.CSSConditionRule.call(this);
this.media = new CSSOM.MediaList();
};
CSSOM.CSSMediaRule.prototype = new CSSOM.CSSConditionRule();
CSSOM.CSSMediaRule.prototype.constructor = CSSOM.CSSMediaRule;
CSSOM.CSSMediaRule.prototype.type = 4;
// https://opensource.apple.com/source/WebCore/WebCore-7611.1.21.161.3/css/CSSMediaRule.cpp
Object.defineProperties(CSSOM.CSSMediaRule.prototype, {
"conditionText": {
get: function() {
return this.media.mediaText;
},
set: function(value) {
this.media.mediaText = value;
},
configurable: true,
enumerable: true
},
"cssText": {
get: function() {
var cssTexts = [];
for (var i=0, length=this.cssRules.length; i < length; i++) {
cssTexts.push(this.cssRules[i].cssText);
}
return "@media " + this.media.mediaText + " {" + cssTexts.join("") + "}";
},
configurable: true,
enumerable: true
}
});
//.CommonJS
CSSMediaRule.CSSMediaRule = CSSOM.CSSMediaRule;
///CommonJS
return CSSMediaRule;
}
var CSSSupportsRule = {};
var hasRequiredCSSSupportsRule;
function requireCSSSupportsRule () {
if (hasRequiredCSSSupportsRule) return CSSSupportsRule;
hasRequiredCSSSupportsRule = 1;
//.CommonJS
var CSSOM = {
CSSRule: requireCSSRule().CSSRule,
CSSGroupingRule: requireCSSGroupingRule().CSSGroupingRule,
CSSConditionRule: requireCSSConditionRule().CSSConditionRule
};
///CommonJS
/**
* @constructor
* @see https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface
*/
CSSOM.CSSSupportsRule = function CSSSupportsRule() {
CSSOM.CSSConditionRule.call(this);
};
CSSOM.CSSSupportsRule.prototype = new CSSOM.CSSConditionRule();
CSSOM.CSSSupportsRule.prototype.constructor = CSSOM.CSSSupportsRule;
CSSOM.CSSSupportsRule.prototype.type = 12;
Object.defineProperty(CSSOM.CSSSupportsRule.prototype, "cssText", {
get: function() {
var cssTexts = [];
for (var i = 0, length = this.cssRules.length; i < length; i++) {
cssTexts.push(this.cssRules[i].cssText);
}
return "@supports " + this.conditionText + " {" + cssTexts.join("") + "}";
}
});
//.CommonJS
CSSSupportsRule.CSSSupportsRule = CSSOM.CSSSupportsRule;
///CommonJS
return CSSSupportsRule;
}
var CSSFontFaceRule = {};
var hasRequiredCSSFontFaceRule;
function requireCSSFontFaceRule () {
if (hasRequiredCSSFontFaceRule) return CSSFontFaceRule;
hasRequiredCSSFontFaceRule = 1;
//.CommonJS
var CSSOM = {
CSSStyleDeclaration: requireCSSStyleDeclaration().CSSStyleDeclaration,
CSSRule: requireCSSRule().CSSRule
};
///CommonJS
/**
* @constructor
* @see http://dev.w3.org/csswg/cssom/#css-font-face-rule
*/
CSSOM.CSSFontFaceRule = function CSSFontFaceRule() {
CSSOM.CSSRule.call(this);
this.style = new CSSOM.CSSStyleDeclaration();
this.style.parentRule = this;
};
CSSOM.CSSFontFaceRule.prototype = new CSSOM.CSSRule();
CSSOM.CSSFontFaceRule.prototype.constructor = CSSOM.CSSFontFaceRule;
CSSOM.CSSFontFaceRule.prototype.type = 5;
//FIXME
//CSSOM.CSSFontFaceRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
//CSSOM.CSSFontFaceRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
// http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSFontFaceRule.cpp
Object.defineProperty(CSSOM.CSSFontFaceRule.prototype, "cssText", {
get: function() {
return "@font-face {" + this.style.cssText + "}";
}
});
//.CommonJS
CSSFontFaceRule.CSSFontFaceRule = CSSOM.CSSFontFaceRule;
///CommonJS
return CSSFontFaceRule;
}
var CSSHostRule = {};
var hasRequiredCSSHostRule;
function requireCSSHostRule () {
if (hasRequiredCSSHostRule) return CSSHostRule;
hasRequiredCSSHostRule = 1;
//.CommonJS
var CSSOM = {
CSSRule: requireCSSRule().CSSRule
};
///CommonJS
/**
* @constructor
* @see http://www.w3.org/TR/shadow-dom/#host-at-rule
*/
CSSOM.CSSHostRule = function CSSHostRule() {
CSSOM.CSSRule.call(this);
this.cssRules = [];
};
CSSOM.CSSHostRule.prototype = new CSSOM.CSSRule();
CSSOM.CSSHostRule.prototype.constructor = CSSOM.CSSHostRule;
CSSOM.CSSHostRule.prototype.type = 1001;
//FIXME
//CSSOM.CSSHostRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
//CSSOM.CSSHostRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
Object.defineProperty(CSSOM.CSSHostRule.prototype, "cssText", {
get: function() {
var cssTexts = [];
for (var i=0, length=this.cssRules.length; i < length; i++) {
cssTexts.push(this.cssRules[i].cssText);
}
return "@host {" + cssTexts.join("") + "}";
}
});
//.CommonJS
CSSHostRule.CSSHostRule = CSSOM.CSSHostRule;
///CommonJS
return CSSHostRule;
}
var CSSKeyframeRule = {};
var hasRequiredCSSKeyframeRule;
function requireCSSKeyframeRule () {
if (hasRequiredCSSKeyframeRule) return CSSKeyframeRule;
hasRequiredCSSKeyframeRule = 1;
//.CommonJS
var CSSOM = {
CSSRule: requireCSSRule().CSSRule,
CSSStyleDeclaration: requireCSSStyleDeclaration().CSSStyleDeclaration
};
///CommonJS
/**
* @constructor
* @see http://www.w3.org/TR/css3-animations/#DOM-CSSKeyframeRule
*/
CSSOM.CSSKeyframeRule = function CSSKeyframeRule() {
CSSOM.CSSRule.call(this);
this.keyText = '';
this.style = new CSSOM.CSSStyleDeclaration();
this.style.parentRule = this;
};
CSSOM.CSSKeyframeRule.prototype = new CSSOM.CSSRule();
CSSOM.CSSKeyframeRule.prototype.constructor = CSSOM.CSSKeyframeRule;
CSSOM.CSSKeyframeRule.prototype.type = 8;
//FIXME
//CSSOM.CSSKeyframeRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
//CSSOM.CSSKeyframeRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
// http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSKeyframeRule.cpp
Object.defineProperty(CSSOM.CSSKeyframeRule.prototype, "cssText", {
get: function() {
return this.keyText + " {" + this.style.cssText + "} ";
}
});
//.CommonJS
CSSKeyframeRule.CSSKeyframeRule = CSSOM.CSSKeyframeRule;
///CommonJS
return CSSKeyframeRule;
}
var CSSKeyframesRule = {};
var hasRequiredCSSKeyframesRule;
function requireCSSKeyframesRule () {
if (hasRequiredCSSKeyframesRule) return CSSKeyframesRule;
hasRequiredCSSKeyframesRule = 1;
//.CommonJS
var CSSOM = {
CSSRule: requireCSSRule().CSSRule
};
///CommonJS
/**
* @constructor
* @see http://www.w3.org/TR/css3-animations/#DOM-CSSKeyframesRule
*/
CSSOM.CSSKeyframesRule = function CSSKeyframesRule() {
CSSOM.CSSRule.call(this);
this.name = '';
this.cssRules = [];
};
CSSOM.CSSKeyframesRule.prototype = new CSSOM.CSSRule();
CSSOM.CSSKeyframesRule.prototype.constructor = CSSOM.CSSKeyframesRule;
CSSOM.CSSKeyframesRule.prototype.type = 7;
//FIXME
//CSSOM.CSSKeyframesRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
//CSSOM.CSSKeyframesRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
// http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSKeyframesRule.cpp
Object.defineProperty(CSSOM.CSSKeyframesRule.prototype, "cssText", {
get: function() {
var cssTexts = [];
for (var i=0, length=this.cssRules.length; i < length; i++) {
cssTexts.push(" " + this.cssRules[i].cssText);
}
return "@" + (this._vendorPrefix || '') + "keyframes " + this.name + " { \n" + cssTexts.join("\n") + "\n}";
}
});
//.CommonJS
CSSKeyframesRule.CSSKeyframesRule = CSSOM.CSSKeyframesRule;
///CommonJS
return CSSKeyframesRule;
}
var CSSValueExpression = {};
var CSSValue = {};
var hasRequiredCSSValue;
function requireCSSValue () {
if (hasRequiredCSSValue) return CSSValue;
hasRequiredCSSValue = 1;
//.CommonJS
var CSSOM = {};
///CommonJS
/**
* @constructor
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSValue
*
* TODO: add if needed
*/
CSSOM.CSSValue = function CSSValue() {
};
CSSOM.CSSValue.prototype = {
constructor: CSSOM.CSSValue,
// @see: http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSValue
set cssText(text) {
var name = this._getConstructorName();
throw new Error('DOMException: property "cssText" of "' + name + '" is readonly and can not be replaced with "' + text + '"!');
},
get cssText() {
var name = this._getConstructorName();
throw new Error('getter "cssText" of "' + name + '" is not implemented!');
},
_getConstructorName: function() {
var s = this.constructor.toString(),
c = s.match(/function\s([^\(]+)/),
name = c[1];
return name;
}
};
//.CommonJS
CSSValue.CSSValue = CSSOM.CSSValue;
///CommonJS
return CSSValue;
}
var hasRequiredCSSValueExpression;
function requireCSSValueExpression () {
if (hasRequiredCSSValueExpression) return CSSValueExpression;
hasRequiredCSSValueExpression = 1;
//.CommonJS
var CSSOM = {
CSSValue: requireCSSValue().CSSValue
};
///CommonJS
/**
* @constructor
* @see http://msdn.microsoft.com/en-us/library/ms537634(v=vs.85).aspx
*
*/
CSSOM.CSSValueExpression = function CSSValueExpression(token, idx) {
this._token = token;
this._idx = idx;
};
CSSOM.CSSValueExpression.prototype = new CSSOM.CSSValue();
CSSOM.CSSValueExpression.prototype.constructor = CSSOM.CSSValueExpression;
/**
* parse css expression() value
*
* @return {Object}
* - error:
* or
* - idx:
* - expression:
*
* Example:
*
* .selector {
* zoom: expression(documentElement.clientWidth > 1000 ? '1000px' : 'auto');
* }
*/
CSSOM.CSSValueExpression.prototype.parse = function() {
var token = this._token,
idx = this._idx;
var character = '',
expression = '',
error = '',
info,
paren = [];
for (; ; ++idx) {
character = token.charAt(idx);
// end of token
if (character === '') {
error = 'css expression error: unfinished expression!';
break;
}
switch(character) {
case '(':
paren.push(character);
expression += character;
break;
case ')':
paren.pop(character);
expression += character;
break;
case '/':
if ((info = this._parseJSComment(token, idx))) { // comment?
if (info.error) {
error = 'css expression error: unfinished comment in expression!';
} else {
idx = info.idx;
// ignore the comment
}
} else if ((info = this._parseJSRexExp(token, idx))) { // regexp
idx = info.idx;
expression += info.text;
} else { // other
expression += character;
}
break;
case "'":
case '"':
info = this._parseJSString(token, idx, character);
if (info) { // string
idx = info.idx;
expression += info.text;
} else {
expression += character;
}
break;
default:
expression += character;
break;
}
if (error) {
break;
}
// end of expression
if (paren.length === 0) {
break;
}
}
var ret;
if (error) {
ret = {
error: error
};
} else {
ret = {
idx: idx,
expression: expression
};
}
return ret;
};
/**
*
* @return {Object|false}
* - idx:
* - text:
* or
* - error:
* or
* false
*
*/
CSSOM.CSSValueExpression.prototype._parseJSComment = function(token, idx) {
var nextChar = token.charAt(idx + 1),
text;
if (nextChar === '/' || nextChar === '*') {
var startIdx = idx,
endIdx,
commentEndChar;
if (nextChar === '/') { // line comment
commentEndChar = '\n';
} else if (nextChar === '*') { // block comment
commentEndChar = '*/';
}
endIdx = token.indexOf(commentEndChar, startIdx + 1 + 1);
if (endIdx !== -1) {
endIdx = endIdx + commentEndChar.length - 1;
text = token.substring(idx, endIdx + 1);
return {
idx: endIdx,
text: text
};
} else {
var error = 'css expression error: unfinished comment in expression!';
return {
error: error
};
}
} else {
return false;
}
};
/**
*
* @return {Object|false}
* - idx:
* - text:
* or
* false
*
*/
CSSOM.CSSValueExpression.prototype._parseJSString = function(token, idx, sep) {
var endIdx = this._findMatchedIdx(token, idx, sep),
text;
if (endIdx === -1) {
return false;
} else {
text = token.substring(idx, endIdx + sep.length);
return {
idx: endIdx,
text: text
};
}
};
/**
* parse regexp in css expression
*
* @return {Object|false}
* - idx:
* - regExp:
* or
* false
*/
/*
all legal RegExp
/a/
(/a/)
[/a/]
[12, /a/]
!/a/
+/a/
-/a/
* /a/
/ /a/
%/a/
===/a/
!==/a/
==/a/
!=/a/
>/a/
>=/a/
</a/
<=/a/
&/a/
|/a/
^/a/
~/a/
<</a/
>>/a/
>>>/a/
&&/a/
||/a/
?/a/
=/a/
,/a/
delete /a/
in /a/
instanceof /a/
new /a/
typeof /a/
void /a/
*/
CSSOM.CSSValueExpression.prototype._parseJSRexExp = function(token, idx) {
var before = token.substring(0, idx).replace(/\s+$/, ""),
legalRegx = [
/^$/,
/\($/,
/\[$/,
/\!$/,
/\+$/,
/\-$/,
/\*$/,
/\/\s+/,
/\%$/,
/\=$/,
/\>$/,
/<$/,
/\&$/,
/\|$/,
/\^$/,
/\~$/,
/\?$/,
/\,$/,
/delete$/,
/in$/,
/instanceof$/,
/new$/,
/typeof$/,
/void$/
];
var isLegal = legalRegx.some(function(reg) {
return reg.test(before);
});
if (!isLegal) {
return false;
} else {
var sep = '/';
// same logic as string
return this._parseJSString(token, idx, sep);
}
};
/**
*
* find next sep(same line) index in `token`
*
* @return {Number}
*
*/
CSSOM.CSSValueExpression.prototype._findMatchedIdx = function(token, idx, sep) {
var startIdx = idx,
endIdx;
var NOT_FOUND = -1;
while(true) {
endIdx = token.indexOf(sep, startIdx + 1);
if (endIdx === -1) { // not found
endIdx = NOT_FOUND;
break;
} else {
var text = token.substring(idx + 1, endIdx),
matched = text.match(/\\+$/);
if (!matched || matched[0] % 2 === 0) { // not escaped
break;
} else {
startIdx = endIdx;
}
}
}
// boundary must be in the same line(js sting or regexp)
var nextNewLineIdx = token.indexOf('\n', idx + 1);
if (nextNewLineIdx < endIdx) {
endIdx = NOT_FOUND;
}
return endIdx;
};
//.CommonJS
CSSValueExpression.CSSValueExpression = CSSOM.CSSValueExpression;
///CommonJS
return CSSValueExpression;
}
var CSSDocumentRule = {};
var MatcherList = {};
var hasRequiredMatcherList;
function requireMatcherList () {
if (hasRequiredMatcherList) return MatcherList;
hasRequiredMatcherList = 1;
//.CommonJS
var CSSOM = {};
///CommonJS
/**
* @constructor
* @see https://developer.mozilla.org/en/CSS/@-moz-document
*/
CSSOM.MatcherList = function MatcherList(){
this.length = 0;
};
CSSOM.MatcherList.prototype = {
constructor: CSSOM.MatcherList,
/**
* @return {string}
*/
get matcherText() {
return Array.prototype.join.call(this, ", ");
},
/**
* @param {string} value
*/
set matcherText(value) {
// just a temporary solution, actually it may be wrong by just split the value with ',', because a url can include ','.
var values = value.split(",");
var length = this.length = values.length;
for (var i=0; i<length; i++) {
this[i] = values[i].trim();
}
},
/**
* @param {string} matcher
*/
appendMatcher: function(matcher) {
if (Array.prototype.indexOf.call(this, matcher) === -1) {
this[this.length] = matcher;
this.length++;
}
},
/**
* @param {string} matcher
*/
deleteMatcher: function(matcher) {
var index = Array.prototype.indexOf.call(this, matcher);
if (index !== -1) {
Array.prototype.splice.call(this, index, 1);
}
}
};
//.CommonJS
MatcherList.MatcherList = CSSOM.MatcherList;
///CommonJS
return MatcherList;
}
var hasRequiredCSSDocumentRule;
function requireCSSDocumentRule () {
if (hasRequiredCSSDocumentRule) return CSSDocumentRule;
hasRequiredCSSDocumentRule = 1;
//.CommonJS
var CSSOM = {
CSSRule: requireCSSRule().CSSRule,
MatcherList: requireMatcherList().MatcherList
};
///CommonJS
/**
* @constructor
* @see https://developer.mozilla.org/en/CSS/@-moz-document
*/
CSSOM.CSSDocumentRule = function CSSDocumentRule() {
CSSOM.CSSRule.call(this);
this.matcher = new CSSOM.MatcherList();
this.cssRules = [];
};
CSSOM.CSSDocumentRule.prototype = new CSSOM.CSSRule();
CSSOM.CSSDocumentRule.prototype.constructor = CSSOM.CSSDocumentRule;
CSSOM.CSSDocumentRule.prototype.type = 10;
//FIXME
//CSSOM.CSSDocumentRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
//CSSOM.CSSDocumentRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
Object.defineProperty(CSSOM.CSSDocumentRule.prototype, "cssText", {
get: function() {
var cssTexts = [];
for (var i=0, length=this.cssRules.length; i < length; i++) {
cssTexts.push(this.cssRules[i].cssText);
}
return "@-moz-document " + this.matcher.matcherText + " {" + cssTexts.join("") + "}";
}
});
//.CommonJS
CSSDocumentRule.CSSDocumentRule = CSSOM.CSSDocumentRule;
///CommonJS
return CSSDocumentRule;
}
var hasRequiredParse;
function requireParse () {
if (hasRequiredParse) return parse$1;
hasRequiredParse = 1;
//.CommonJS
var CSSOM = {};
///CommonJS
/**
* @param {string} token
*/
CSSOM.parse = function parse(token) {
var i = 0;
/**
"before-selector" or
"selector" or
"atRule" or
"atBlock" or
"conditionBlock" or
"before-name" or
"name" or
"before-value" or
"value"
*/
var state = "before-selector";
var index;
var buffer = "";
var valueParenthesisDepth = 0;
var SIGNIFICANT_WHITESPACE = {
"selector": true,
"value": true,
"value-parenthesis": true,
"atRule": true,
"importRule-begin": true,
"importRule": true,
"atBlock": true,
"conditionBlock": true,
'documentRule-begin': true
};
var styleSheet = new CSSOM.CSSStyleSheet();
// @type CSSStyleSheet|CSSMediaRule|CSSSupportsRule|CSSFontFaceRule|CSSKeyframesRule|CSSDocumentRule
var currentScope = styleSheet;
// @type CSSMediaRule|CSSSupportsRule|CSSKeyframesRule|CSSDocumentRule
var parentRule;
var ancestorRules = [];
var hasAncestors = false;
var prevScope;
var name, priority="", styleRule, mediaRule, supportsRule, importRule, fontFaceRule, keyframesRule, documentRule, hostRule;
var atKeyframesRegExp = /@(-(?:\w+-)+)?keyframes/g;
var parseError = function(message) {
var lines = token.substring(0, i).split('\n');
var lineCount = lines.length;
var charCount = lines.pop().length + 1;
var error = new Error(message + ' (line ' + lineCount + ', char ' + charCount + ')');
error.line = lineCount;
/* jshint sub : true */
error['char'] = charCount;
error.styleSheet = styleSheet;
throw error;
};
for (var character; (character = token.charAt(i)); i++) {
switch (character) {
case " ":
case "\t":
case "\r":
case "\n":
case "\f":
if (SIGNIFICANT_WHITESPACE[state]) {
buffer += character;
}
break;
// String
case '"':
index = i + 1;
do {
index = token.indexOf('"', index) + 1;
if (!index) {
parseError('Unmatched "');
}
} while (token[index - 2] === '\\');
buffer += token.slice(i, index);
i = index - 1;
switch (state) {
case 'before-value':
state = 'value';
break;
case 'importRule-begin':
state = 'importRule';
break;
}
break;
case "'":
index = i + 1;
do {
index = token.indexOf("'", index) + 1;
if (!index) {
parseError("Unmatched '");
}
} while (token[index - 2] === '\\');
buffer += token.slice(i, index);
i = index - 1;
switch (state) {
case 'before-value':
state = 'value';
break;
case 'importRule-begin':
state = 'importRule';
break;
}
break;
// Comment
case "/":
if (token.charAt(i + 1) === "*") {
i += 2;
index = token.indexOf("*/", i);
if (index === -1) {
parseError("Missing */");
} else {
i = index + 1;
}
} else {
buffer += character;
}
if (state === "importRule-begin") {
buffer += " ";
state = "importRule";
}
break;
// At-rule
case "@":
if (token.indexOf("@-moz-document", i) === i) {
state = "documentRule-begin";
documentRule = new CSSOM.CSSDocumentRule();
documentRule.__starts = i;
i += "-moz-document".length;
buffer = "";
break;
} else if (token.indexOf("@media", i) === i) {
state = "atBlock";
mediaRule = new CSSOM.CSSMediaRule();
mediaRule.__starts = i;
i += "media".length;
buffer = "";
break;
} else if (token.indexOf("@supports", i) === i) {
state = "conditionBlock";
supportsRule = new CSSOM.CSSSupportsRule();
supportsRule.__starts = i;
i += "supports".length;
buffer = "";
break;
} else if (token.indexOf("@host", i) === i) {
state = "hostRule-begin";
i += "host".length;
hostRule = new CSSOM.CSSHostRule();
hostRule.__starts = i;
buffer = "";
break;
} else if (token.indexOf("@import", i) === i) {
state = "importRule-begin";
i += "import".length;
buffer += "@import";
break;
} else if (token.indexOf("@font-face", i) === i) {
state = "fontFaceRule-begin";
i += "font-face".length;
fontFaceRule = new CSSOM.CSSFontFaceRule();
fontFaceRule.__starts = i;
buffer = "";
break;
} else {
atKeyframesRegExp.lastIndex = i;
var matchKeyframes = atKeyframesRegExp.exec(token);
if (matchKeyframes && matchKeyframes.index === i) {
state = "keyframesRule-begin";
keyframesRule = new CSSOM.CSSKeyframesRule();
keyframesRule.__starts = i;
keyframesRule._vendorPrefix = matchKeyframes[1]; // Will come out as undefined if no prefix was found
i += matchKeyframes[0].length - 1;
buffer = "";
break;
} else if (state === "selector") {
state = "atRule";
}
}
buffer += character;
break;
case "{":
if (state === "selector" || state === "atRule") {
styleRule.selectorText = buffer.trim();
styleRule.style.__starts = i;
buffer = "";
state = "before-name";
} else if (state === "atBlock") {
mediaRule.media.mediaText = buffer.trim();
if (parentRule) {
ancestorRules.push(parentRule);
}
currentScope = parentRule = mediaRule;
mediaRule.parentStyleSheet = styleSheet;
buffer = "";
state = "before-selector";
} else if (state === "conditionBlock") {
supportsRule.conditionText = buffer.trim();
if (parentRule) {
ancestorRules.push(parentRule);
}
currentScope = parentRule = supportsRule;
supportsRule.parentStyleSheet = styleSheet;
buffer = "";
state = "before-selector";
} else if (state === "hostRule-begin") {
if (parentRule) {
ancestorRules.push(parentRule);
}
currentScope = parentRule = hostRule;
hostRule.parentStyleSheet = styleSheet;
buffer = "";
state = "before-selector";
} else if (state === "fontFaceRule-begin") {
if (parentRule) {
fontFaceRule.parentRule = parentRule;
}
fontFaceRule.parentStyleSheet = styleSheet;
styleRule = fontFaceRule;
buffer = "";
state = "before-name";
} else if (state === "keyframesRule-begin") {
keyframesRule.name = buffer.trim();
if (parentRule) {
ancestorRules.push(parentRule);
keyframesRule.parentRule = parentRule;
}
keyframesRule.parentStyleSheet = styleSheet;
currentScope = parentRule = keyframesRule;
buffer = "";
state = "keyframeRule-begin";
} else if (state === "keyframeRule-begin") {
styleRule = new CSSOM.CSSKeyframeRule();
styleRule.keyText = buffer.trim();
styleRule.__starts = i;
buffer = "";
state = "before-name";
} else if (state === "documentRule-begin") {
// FIXME: what if this '{' is in the url text of the match function?
documentRule.matcher.matcherText = buffer.trim();
if (parentRule) {
ancestorRules.push(parentRule);
documentRule.parentRule = parentRule;
}
currentScope = parentRule = documentRule;
documentRule.parentStyleSheet = styleSheet;
buffer = "";
state = "before-selector";
}
break;
case ":":
if (state === "name") {
name = buffer.trim();
buffer = "";
state = "before-value";
} else {
buffer += character;
}
break;
case "(":
if (state === 'value') {
// ie css expression mode
if (buffer.trim() === 'expression') {
var info = (new CSSOM.CSSValueExpression(token, i)).parse();
if (info.error) {
parseError(info.error);
} else {
buffer += info.expression;
i = info.idx;
}
} else {
state = 'value-parenthesis';
//always ensure this is reset to 1 on transition
//from value to value-parenthesis
valueParenthesisDepth = 1;
buffer += character;
}
} else if (state === 'value-parenthesis') {
valueParenthesisDepth++;
buffer += character;
} else {
buffer += character;
}
break;
case ")":
if (state === 'value-parenthesis') {
valueParenthesisDepth--;
if (valueParenthesisDepth === 0) state = 'value';
}
buffer += character;
break;
case "!":
if (state === "value" && token.indexOf("!important", i) === i) {
priority = "important";
i += "important".length;
} else {
buffer += character;
}
break;
case ";":
switch (state) {
case "value":
styleRule.style.setProperty(name, buffer.trim(), priority);
priority = "";
buffer = "";
state = "before-name";
break;
case "atRule":
buffer = "";
state = "before-selector";
break;
case "importRule":
importRule = new CSSOM.CSSImportRule();
importRule.parentStyleSheet = importRule.styleSheet.parentStyleSheet = styleSheet;
importRule.cssText = buffer + character;
styleSheet.cssRules.push(importRule);
buffer = "";
state = "before-selector";
break;
default:
buffer += character;
break;
}
break;
case "}":
switch (state) {
case "value":
styleRule.style.setProperty(name, buffer.trim(), priority);
priority = "";
/* falls through */
case "before-name":
case "name":
styleRule.__ends = i + 1;
if (parentRule) {
styleRule.parentRule = parentRule;
}
styleRule.parentStyleSheet = styleSheet;
currentScope.cssRules.push(styleRule);
buffer = "";
if (currentScope.constructor === CSSOM.CSSKeyframesRule) {
state = "keyframeRule-begin";
} else {
state = "before-selector";
}
break;
case "keyframeRule-begin":
case "before-selector":
case "selector":
// End of media/supports/document rule.
if (!parentRule) {
parseError("Unexpected }");
}
// Handle rules nested in @media or @supports
hasAncestors = ancestorRules.length > 0;
while (ancestorRules.length > 0) {
parentRule = ancestorRules.pop();
if (
parentRule.constructor.name === "CSSMediaRule"
|| parentRule.constructor.name === "CSSSupportsRule"
) {
prevScope = currentScope;
currentScope = parentRule;
currentScope.cssRules.push(prevScope);
break;
}
if (ancestorRules.length === 0) {
hasAncestors = false;
}
}
if (!hasAncestors) {
currentScope.__ends = i + 1;
styleSheet.cssRules.push(currentScope);
currentScope = styleSheet;
parentRule = null;
}
buffer = "";
state = "before-selector";
break;
}
break;
default:
switch (state) {
case "before-selector":
state = "selector";
styleRule = new CSSOM.CSSStyleRule();
styleRule.__starts = i;
break;
case "before-name":
state = "name";
break;
case "before-value":
state = "value";
break;
case "importRule-begin":
state = "importRule";
break;
}
buffer += character;
break;
}
}
return styleSheet;
};
//.CommonJS
parse$1.parse = CSSOM.parse;
// The following modules cannot be included sooner due to the mutual dependency with parse.js
CSSOM.CSSStyleSheet = requireCSSStyleSheet().CSSStyleSheet;
CSSOM.CSSStyleRule = requireCSSStyleRule().CSSStyleRule;
CSSOM.CSSImportRule = requireCSSImportRule().CSSImportRule;
CSSOM.CSSGroupingRule = requireCSSGroupingRule().CSSGroupingRule;
CSSOM.CSSMediaRule = requireCSSMediaRule().CSSMediaRule;
CSSOM.CSSConditionRule = requireCSSConditionRule().CSSConditionRule;
CSSOM.CSSSupportsRule = requireCSSSupportsRule().CSSSupportsRule;
CSSOM.CSSFontFaceRule = requireCSSFontFaceRule().CSSFontFaceRule;
CSSOM.CSSHostRule = requireCSSHostRule().CSSHostRule;
CSSOM.CSSStyleDeclaration = requireCSSStyleDeclaration().CSSStyleDeclaration;
CSSOM.CSSKeyframeRule = requireCSSKeyframeRule().CSSKeyframeRule;
CSSOM.CSSKeyframesRule = requireCSSKeyframesRule().CSSKeyframesRule;
CSSOM.CSSValueExpression = requireCSSValueExpression().CSSValueExpression;
CSSOM.CSSDocumentRule = requireCSSDocumentRule().CSSDocumentRule;
///CommonJS
return parse$1;
}
var hasRequiredCSSStyleDeclaration;
function requireCSSStyleDeclaration () {
if (hasRequiredCSSStyleDeclaration) return CSSStyleDeclaration;
hasRequiredCSSStyleDeclaration = 1;
//.CommonJS
var CSSOM = {};
///CommonJS
/**
* @constructor
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration
*/
CSSOM.CSSStyleDeclaration = function CSSStyleDeclaration(){
this.length = 0;
this.parentRule = null;
// NON-STANDARD
this._importants = {};
};
CSSOM.CSSStyleDeclaration.prototype = {
constructor: CSSOM.CSSStyleDeclaration,
/**
*
* @param {string} name
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-getPropertyValue
* @return {string} the value of the property if it has been explicitly set for this declaration block.
* Returns the empty string if the property has not been set.
*/
getPropertyValue: function(name) {
return this[name] || "";
},
/**
*
* @param {string} name
* @param {string} value
* @param {string} [priority=null] "important" or null
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-setProperty
*/
setProperty: function(name, value, priority) {
if (this[name]) {
// Property already exist. Overwrite it.
var index = Array.prototype.indexOf.call(this, name);
if (index < 0) {
this[this.length] = name;
this.length++;
}
} else {
// New property.
this[this.length] = name;
this.length++;
}
this[name] = value + "";
this._importants[name] = priority;
},
/**
*
* @param {string} name
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-removeProperty
* @return {string} the value of the property if it has been explicitly set for this declaration block.
* Returns the empty string if the property has not been set or the property name does not correspond to a known CSS property.
*/
removeProperty: function(name) {
if (!(name in this)) {
return "";
}
var index = Array.prototype.indexOf.call(this, name);
if (index < 0) {
return "";
}
var prevValue = this[name];
this[name] = "";
// That's what WebKit and Opera do
Array.prototype.splice.call(this, index, 1);
// That's what Firefox does
//this[index] = ""
return prevValue;
},
getPropertyCSSValue: function() {
//FIXME
},
/**
*
* @param {String} name
*/
getPropertyPriority: function(name) {
return this._importants[name] || "";
},
/**
* element.style.overflow = "auto"
* element.style.getPropertyShorthand("overflow-x")
* -> "overflow"
*/
getPropertyShorthand: function() {
//FIXME
},
isPropertyImplicit: function() {
//FIXME
},
// Doesn't work in IE < 9
get cssText(){
var properties = [];
for (var i=0, length=this.length; i < length; ++i) {
var name = this[i];
var value = this.getPropertyValue(name);
var priority = this.getPropertyPriority(name);
if (priority) {
priority = " !" + priority;
}
properties[i] = name + ": " + value + priority + ";";
}
return properties.join(" ");
},
set cssText(text){
var i, name;
for (i = this.length; i--;) {
name = this[i];
this[name] = "";
}
Array.prototype.splice.call(this, 0, this.length);
this._importants = {};
var dummyRule = CSSOM.parse('#bogus{' + text + '}').cssRules[0].style;
var length = dummyRule.length;
for (i = 0; i < length; ++i) {
name = dummyRule[i];
this.setProperty(dummyRule[i], dummyRule.getPropertyValue(name), dummyRule.getPropertyPriority(name));
}
}
};
//.CommonJS
CSSStyleDeclaration.CSSStyleDeclaration = CSSOM.CSSStyleDeclaration;
CSSOM.parse = requireParse().parse; // Cannot be included sooner due to the mutual dependency between parse.js and CSSStyleDeclaration.js
///CommonJS
return CSSStyleDeclaration;
}
var clone = {};
var hasRequiredClone;
function requireClone () {
if (hasRequiredClone) return clone;
hasRequiredClone = 1;
//.CommonJS
var CSSOM = {
CSSStyleSheet: requireCSSStyleSheet().CSSStyleSheet,
CSSRule: requireCSSRule().CSSRule,
CSSStyleRule: requireCSSStyleRule().CSSStyleRule,
CSSGroupingRule: requireCSSGroupingRule().CSSGroupingRule,
CSSConditionRule: requireCSSConditionRule().CSSConditionRule,
CSSMediaRule: requireCSSMediaRule().CSSMediaRule,
CSSSupportsRule: requireCSSSupportsRule().CSSSupportsRule,
CSSStyleDeclaration: requireCSSStyleDeclaration().CSSStyleDeclaration,
CSSKeyframeRule: requireCSSKeyframeRule().CSSKeyframeRule,
CSSKeyframesRule: requireCSSKeyframesRule().CSSKeyframesRule
};
///CommonJS
/**
* Produces a deep copy of stylesheet — the instance variables of stylesheet are copied recursively.
* @param {CSSStyleSheet|CSSOM.CSSStyleSheet} stylesheet
* @nosideeffects
* @return {CSSOM.CSSStyleSheet}
*/
CSSOM.clone = function clone(stylesheet) {
var cloned = new CSSOM.CSSStyleSheet();
var rules = stylesheet.cssRules;
if (!rules) {
return cloned;
}
for (var i = 0, rulesLength = rules.length; i < rulesLength; i++) {
var rule = rules[i];
var ruleClone = cloned.cssRules[i] = new rule.constructor();
var style = rule.style;
if (style) {
var styleClone = ruleClone.style = new CSSOM.CSSStyleDeclaration();
for (var j = 0, styleLength = style.length; j < styleLength; j++) {
var name = styleClone[j] = style[j];
styleClone[name] = style[name];
styleClone._importants[name] = style.getPropertyPriority(name);
}
styleClone.length = style.length;
}
if (rule.hasOwnProperty('keyText')) {
ruleClone.keyText = rule.keyText;
}
if (rule.hasOwnProperty('selectorText')) {
ruleClone.selectorText = rule.selectorText;
}
if (rule.hasOwnProperty('mediaText')) {
ruleClone.mediaText = rule.mediaText;
}
if (rule.hasOwnProperty('conditionText')) {
ruleClone.conditionText = rule.conditionText;
}
if (rule.hasOwnProperty('cssRules')) {
ruleClone.cssRules = clone(rule).cssRules;
}
}
return cloned;
};
//.CommonJS
clone.clone = CSSOM.clone;
///CommonJS
return clone;
}
var hasRequiredLib;
function requireLib () {
if (hasRequiredLib) return lib;
hasRequiredLib = 1;
lib.CSSStyleDeclaration = requireCSSStyleDeclaration().CSSStyleDeclaration;
lib.CSSRule = requireCSSRule().CSSRule;
lib.CSSGroupingRule = requireCSSGroupingRule().CSSGroupingRule;
lib.CSSConditionRule = requireCSSConditionRule().CSSConditionRule;
lib.CSSStyleRule = requireCSSStyleRule().CSSStyleRule;
lib.MediaList = requireMediaList().MediaList;
lib.CSSMediaRule = requireCSSMediaRule().CSSMediaRule;
lib.CSSSupportsRule = requireCSSSupportsRule().CSSSupportsRule;
lib.CSSImportRule = requireCSSImportRule().CSSImportRule;
lib.CSSFontFaceRule = requireCSSFontFaceRule().CSSFontFaceRule;
lib.CSSHostRule = requireCSSHostRule().CSSHostRule;
lib.StyleSheet = requireStyleSheet().StyleSheet;
lib.CSSStyleSheet = requireCSSStyleSheet().CSSStyleSheet;
lib.CSSKeyframesRule = requireCSSKeyframesRule().CSSKeyframesRule;
lib.CSSKeyframeRule = requireCSSKeyframeRule().CSSKeyframeRule;
lib.MatcherList = requireMatcherList().MatcherList;
lib.CSSDocumentRule = requireCSSDocumentRule().CSSDocumentRule;
lib.CSSValue = requireCSSValue().CSSValue;
lib.CSSValueExpression = requireCSSValueExpression().CSSValueExpression;
lib.parse = requireParse().parse;
lib.clone = requireClone().clone;
return lib;
}
var libExports = requireLib();
const tagName$e = 'style';
/**
* @implements globalThis.HTMLStyleElement
*/
class HTMLStyleElement extends TextElement {
constructor(ownerDocument, localName = tagName$e) {
super(ownerDocument, localName);
this[SHEET] = null;
}
get sheet() {
const sheet = this[SHEET];
if (sheet !== null) {
return sheet;
}
return this[SHEET] = libExports.parse(this.textContent);
}
get innerHTML() {
return super.innerHTML || '';
}
set innerHTML(value) {
super.textContent = value;
this[SHEET] = null;
}
get innerText() {
return super.innerText || '';
}
set innerText(value) {
super.textContent = value;
this[SHEET] = null;
}
get textContent() {
return super.textContent || '';
}
set textContent(value) {
super.textContent = value;
this[SHEET] = null;
}
}
registerHTMLClass(tagName$e, HTMLStyleElement);
/**
* @implements globalThis.HTMLTimeElement
*/
class HTMLTimeElement extends HTMLElement {
constructor(ownerDocument, localName = 'time') {
super(ownerDocument, localName);
}
/**
* @type {string}
*/
get dateTime() { return stringAttribute.get(this, 'datetime'); }
set dateTime(value) { stringAttribute.set(this, 'datetime', value); }
}
registerHTMLClass('time', HTMLTimeElement);
/**
* @implements globalThis.HTMLFieldSetElement
*/
class HTMLFieldSetElement extends HTMLElement {
constructor(ownerDocument, localName = 'fieldset') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLEmbedElement
*/
class HTMLEmbedElement extends HTMLElement {
constructor(ownerDocument, localName = 'embed') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLHRElement
*/
class HTMLHRElement extends HTMLElement {
constructor(ownerDocument, localName = 'hr') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLProgressElement
*/
class HTMLProgressElement extends HTMLElement {
constructor(ownerDocument, localName = 'progress') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLParagraphElement
*/
class HTMLParagraphElement extends HTMLElement {
constructor(ownerDocument, localName = 'p') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLTableElement
*/
class HTMLTableElement extends HTMLElement {
constructor(ownerDocument, localName = 'table') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLFrameSetElement
*/
class HTMLFrameSetElement extends HTMLElement {
constructor(ownerDocument, localName = 'frameset') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLLIElement
*/
class HTMLLIElement extends HTMLElement {
constructor(ownerDocument, localName = 'li') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLBaseElement
*/
class HTMLBaseElement extends HTMLElement {
constructor(ownerDocument, localName = 'base') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLDataListElement
*/
class HTMLDataListElement extends HTMLElement {
constructor(ownerDocument, localName = 'datalist') {
super(ownerDocument, localName);
}
}
const tagName$d = 'input';
/**
* @implements globalThis.HTMLInputElement
*/
class HTMLInputElement extends HTMLElement {
constructor(ownerDocument, localName = tagName$d) {
super(ownerDocument, localName);
}
/* c8 ignore start */
get autofocus() { return booleanAttribute.get(this, 'autofocus') || -1; }
set autofocus(value) { booleanAttribute.set(this, 'autofocus', value); }
get disabled() { return booleanAttribute.get(this, 'disabled'); }
set disabled(value) { booleanAttribute.set(this, 'disabled', value); }
get name() { return this.getAttribute('name'); }
set name(value) { this.setAttribute('name', value); }
get placeholder() { return this.getAttribute('placeholder'); }
set placeholder(value) { this.setAttribute('placeholder', value); }
get type() { return this.getAttribute('type'); }
set type(value) { this.setAttribute('type', value); }
get value() { return stringAttribute.get(this, 'value'); }
set value(value) { stringAttribute.set(this, 'value', value); }
/* c8 ignore stop */
}
registerHTMLClass(tagName$d, HTMLInputElement);
/**
* @implements globalThis.HTMLParamElement
*/
class HTMLParamElement extends HTMLElement {
constructor(ownerDocument, localName = 'param') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLMediaElement
*/
class HTMLMediaElement extends HTMLElement {
constructor(ownerDocument, localName = 'media') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLAudioElement
*/
class HTMLAudioElement extends HTMLElement {
constructor(ownerDocument, localName = 'audio') {
super(ownerDocument, localName);
}
}
const tagName$c = 'h1';
/**
* @implements globalThis.HTMLHeadingElement
*/
class HTMLHeadingElement extends HTMLElement {
constructor(ownerDocument, localName = tagName$c) {
super(ownerDocument, localName);
}
}
registerHTMLClass([tagName$c, 'h2', 'h3', 'h4', 'h5', 'h6'], HTMLHeadingElement);
/**
* @implements globalThis.HTMLDirectoryElement
*/
class HTMLDirectoryElement extends HTMLElement {
constructor(ownerDocument, localName = 'dir') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLQuoteElement
*/
class HTMLQuoteElement extends HTMLElement {
constructor(ownerDocument, localName = 'quote') {
super(ownerDocument, localName);
}
}
class Canvas {
constructor(width, height) {
this.width = width;
this.height = height;
}
getContext() { return null; }
toDataURL() { return ''; }
}
var Canvas$1 = {createCanvas: (width, height) => new Canvas(width, height)};
const {createCanvas} = Canvas$1;
const tagName$b = 'canvas';
/**
* @implements globalThis.HTMLCanvasElement
*/
class HTMLCanvasElement extends HTMLElement {
constructor(ownerDocument, localName = tagName$b) {
super(ownerDocument, localName);
this[IMAGE] = createCanvas(300, 150);
}
get width() {
return this[IMAGE].width;
}
set width(value) {
numericAttribute.set(this, 'width', value);
this[IMAGE].width = value;
}
get height() {
return this[IMAGE].height;
}
set height(value) {
numericAttribute.set(this, 'height', value);
this[IMAGE].height = value;
}
getContext(type) {
return this[IMAGE].getContext(type);
}
toDataURL(...args) {
return this[IMAGE].toDataURL(...args);
}
}
registerHTMLClass(tagName$b, HTMLCanvasElement);
/**
* @implements globalThis.HTMLLegendElement
*/
class HTMLLegendElement extends HTMLElement {
constructor(ownerDocument, localName = 'legend') {
super(ownerDocument, localName);
}
}
const tagName$a = 'option';
/**
* @implements globalThis.HTMLOptionElement
*/
class HTMLOptionElement extends HTMLElement {
constructor(ownerDocument, localName = tagName$a) {
super(ownerDocument, localName);
}
/* c8 ignore start */
get value() { return stringAttribute.get(this, 'value'); }
set value(value) { stringAttribute.set(this, 'value', value); }
/* c8 ignore stop */
get selected() { return booleanAttribute.get(this, 'selected'); }
set selected(value) {
const option = this.parentElement?.querySelector('option[selected]');
if (option && option !== this)
option.selected = false;
booleanAttribute.set(this, 'selected', value);
}
}
registerHTMLClass(tagName$a, HTMLOptionElement);
/**
* @implements globalThis.HTMLSpanElement
*/
class HTMLSpanElement extends HTMLElement {
constructor(ownerDocument, localName = 'span') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLMeterElement
*/
class HTMLMeterElement extends HTMLElement {
constructor(ownerDocument, localName = 'meter') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLVideoElement
*/
class HTMLVideoElement extends HTMLElement {
constructor(ownerDocument, localName = 'video') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLTableCellElement
*/
class HTMLTableCellElement extends HTMLElement {
constructor(ownerDocument, localName = 'td') {
super(ownerDocument, localName);
}
}
const tagName$9 = 'title';
/**
* @implements globalThis.HTMLTitleElement
*/
class HTMLTitleElement extends TextElement {
constructor(ownerDocument, localName = tagName$9) {
super(ownerDocument, localName);
}
}
registerHTMLClass(tagName$9, HTMLTitleElement);
/**
* @implements globalThis.HTMLOutputElement
*/
class HTMLOutputElement extends HTMLElement {
constructor(ownerDocument, localName = 'output') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLTableRowElement
*/
class HTMLTableRowElement extends HTMLElement {
constructor(ownerDocument, localName = 'tr') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLDataElement
*/
class HTMLDataElement extends HTMLElement {
constructor(ownerDocument, localName = 'data') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLMenuElement
*/
class HTMLMenuElement extends HTMLElement {
constructor(ownerDocument, localName = 'menu') {
super(ownerDocument, localName);
}
}
const tagName$8 = 'select';
/**
* @implements globalThis.HTMLSelectElement
*/
class HTMLSelectElement extends HTMLElement {
constructor(ownerDocument, localName = tagName$8) {
super(ownerDocument, localName);
}
get options() {
let children = new NodeList;
let {firstElementChild} = this;
while (firstElementChild) {
if (firstElementChild.tagName === 'OPTGROUP')
children.push(...firstElementChild.children);
else
children.push(firstElementChild);
firstElementChild = firstElementChild.nextElementSibling;
}
return children;
}
/* c8 ignore start */
get disabled() { return booleanAttribute.get(this, 'disabled'); }
set disabled(value) { booleanAttribute.set(this, 'disabled', value); }
get name() { return this.getAttribute('name'); }
set name(value) { this.setAttribute('name', value); }
/* c8 ignore stop */
get value() { return this.querySelector('option[selected]')?.value; }
}
registerHTMLClass(tagName$8, HTMLSelectElement);
/**
* @implements globalThis.HTMLBRElement
*/
class HTMLBRElement extends HTMLElement {
constructor(ownerDocument, localName = 'br') {
super(ownerDocument, localName);
}
}
const tagName$7 = 'button';
/**
* @implements globalThis.HTMLButtonElement
*/
class HTMLButtonElement extends HTMLElement {
constructor(ownerDocument, localName = tagName$7) {
super(ownerDocument, localName);
}
/* c8 ignore start */
get disabled() { return booleanAttribute.get(this, 'disabled'); }
set disabled(value) { booleanAttribute.set(this, 'disabled', value); }
get name() { return this.getAttribute('name'); }
set name(value) { this.setAttribute('name', value); }
get type() { return this.getAttribute('type'); }
set type(value) { this.setAttribute('type', value); }
/* c8 ignore stop */
}
registerHTMLClass(tagName$7, HTMLButtonElement);
/**
* @implements globalThis.HTMLMapElement
*/
class HTMLMapElement extends HTMLElement {
constructor(ownerDocument, localName = 'map') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLOptGroupElement
*/
class HTMLOptGroupElement extends HTMLElement {
constructor(ownerDocument, localName = 'optgroup') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLDListElement
*/
class HTMLDListElement extends HTMLElement {
constructor(ownerDocument, localName = 'dl') {
super(ownerDocument, localName);
}
}
const tagName$6 = 'textarea';
/**
* @implements globalThis.HTMLTextAreaElement
*/
class HTMLTextAreaElement extends TextElement {
constructor(ownerDocument, localName = tagName$6) {
super(ownerDocument, localName);
}
/* c8 ignore start */
get disabled() { return booleanAttribute.get(this, 'disabled'); }
set disabled(value) { booleanAttribute.set(this, 'disabled', value); }
get name() { return this.getAttribute('name'); }
set name(value) { this.setAttribute('name', value); }
get placeholder() { return this.getAttribute('placeholder'); }
set placeholder(value) { this.setAttribute('placeholder', value); }
get type() { return this.getAttribute('type'); }
set type(value) { this.setAttribute('type', value); }
get value() { return this.textContent; }
set value(content) { this.textContent = content; }
/* c8 ignore stop */
}
registerHTMLClass(tagName$6, HTMLTextAreaElement);
/**
* @implements globalThis.HTMLFontElement
*/
class HTMLFontElement extends HTMLElement {
constructor(ownerDocument, localName = 'font') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLDivElement
*/
class HTMLDivElement extends HTMLElement {
constructor(ownerDocument, localName = 'div') {
super(ownerDocument, localName);
}
}
const tagName$5 = 'link';
/**
* @implements globalThis.HTMLLinkElement
*/
class HTMLLinkElement extends HTMLElement {
constructor(ownerDocument, localName = tagName$5) {
super(ownerDocument, localName);
}
/* c8 ignore start */ // copy paste from img.src, already covered
get disabled() { return booleanAttribute.get(this, 'disabled'); }
set disabled(value) { booleanAttribute.set(this, 'disabled', value); }
get href() { return stringAttribute.get(this, 'href').trim(); }
set href(value) { stringAttribute.set(this, 'href', value); }
get hreflang() { return stringAttribute.get(this, 'hreflang'); }
set hreflang(value) { stringAttribute.set(this, 'hreflang', value); }
get media() { return stringAttribute.get(this, 'media'); }
set media(value) { stringAttribute.set(this, 'media', value); }
get rel() { return stringAttribute.get(this, 'rel'); }
set rel(value) { stringAttribute.set(this, 'rel', value); }
get type() { return stringAttribute.get(this, 'type'); }
set type(value) { stringAttribute.set(this, 'type', value); }
/* c8 ignore stop */
}
registerHTMLClass(tagName$5, HTMLLinkElement);
const tagName$4 = 'slot';
/**
* @implements globalThis.HTMLSlotElement
*/
class HTMLSlotElement extends HTMLElement {
constructor(ownerDocument, localName = tagName$4) {
super(ownerDocument, localName);
}
/* c8 ignore start */
get name() { return this.getAttribute('name'); }
set name(value) { this.setAttribute('name', value); }
assign() {}
assignedNodes(options) {
const isNamedSlot = !!this.name;
const hostChildNodes = this.getRootNode().host?.childNodes ?? [];
let slottables;
if (isNamedSlot) {
slottables = [...hostChildNodes].filter(node => node.slot === this.name);
} else {
slottables = [...hostChildNodes].filter(node => !node.slot);
}
if (options?.flatten) {
const result = [];
// Element and Text nodes are slottables. A slot can be a slottable.
for (let slottable of slottables) {
if (slottable.localName === 'slot') {
result.push(...slottable.assignedNodes({ flatten: true }));
} else {
result.push(slottable);
}
}
slottables = result;
}
// If no assigned nodes are found, it returns the slot's fallback content.
return slottables.length ? slottables : [...this.childNodes];
}
assignedElements(options) {
const slottables = this.assignedNodes(options).filter(n => n.nodeType === 1);
// If no assigned elements are found, it returns the slot's fallback content.
return slottables.length ? slottables : [...this.children];
}
/* c8 ignore stop */
}
registerHTMLClass(tagName$4, HTMLSlotElement);
/**
* @implements globalThis.HTMLFormElement
*/
class HTMLFormElement extends HTMLElement {
constructor(ownerDocument, localName = 'form') {
super(ownerDocument, localName);
}
}
const tagName$3 = 'img';
/**
* @implements globalThis.HTMLImageElement
*/
class HTMLImageElement extends HTMLElement {
constructor(ownerDocument, localName = tagName$3) {
super(ownerDocument, localName);
}
/* c8 ignore start */
get alt() { return stringAttribute.get(this, 'alt'); }
set alt(value) { stringAttribute.set(this, 'alt', value); }
get sizes() { return stringAttribute.get(this, 'sizes'); }
set sizes(value) { stringAttribute.set(this, 'sizes', value); }
get src() { return stringAttribute.get(this, 'src'); }
set src(value) { stringAttribute.set(this, 'src', value); }
get srcset() { return stringAttribute.get(this, 'srcset'); }
set srcset(value) { stringAttribute.set(this, 'srcset', value); }
get title() { return stringAttribute.get(this, 'title'); }
set title(value) { stringAttribute.set(this, 'title', value); }
get width() { return numericAttribute.get(this, 'width'); }
set width(value) { numericAttribute.set(this, 'width', value); }
get height() { return numericAttribute.get(this, 'height'); }
set height(value) { numericAttribute.set(this, 'height', value); }
/* c8 ignore stop */
}
registerHTMLClass(tagName$3, HTMLImageElement);
/**
* @implements globalThis.HTMLPreElement
*/
class HTMLPreElement extends HTMLElement {
constructor(ownerDocument, localName = 'pre') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLUListElement
*/
class HTMLUListElement extends HTMLElement {
constructor(ownerDocument, localName = 'ul') {
super(ownerDocument, localName);
}
}
const tagName$2 = 'meta';
/**
* @implements globalThis.HTMLMetaElement
*/
class HTMLMetaElement extends HTMLElement {
constructor(ownerDocument, localName =tagName$2) {
super(ownerDocument, localName);
}
/* c8 ignore start */
get name() { return stringAttribute.get(this, 'name'); }
set name(value) { stringAttribute.set(this, 'name', value); }
get httpEquiv() { return stringAttribute.get(this, 'http-equiv'); }
set httpEquiv(value) { stringAttribute.set(this, 'http-equiv', value); }
get content() { return stringAttribute.get(this, 'content'); }
set content(value) { stringAttribute.set(this, 'content', value); }
get charset() { return stringAttribute.get(this, 'charset'); }
set charset(value) { stringAttribute.set(this, 'charset', value); }
get media() { return stringAttribute.get(this, 'media'); }
set media(value) { stringAttribute.set(this, 'media', value); }
/* c8 ignore stop */
}
registerHTMLClass(tagName$2, HTMLMetaElement);
/**
* @implements globalThis.HTMLPictureElement
*/
class HTMLPictureElement extends HTMLElement {
constructor(ownerDocument, localName = 'picture') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLAreaElement
*/
class HTMLAreaElement extends HTMLElement {
constructor(ownerDocument, localName = 'area') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLOListElement
*/
class HTMLOListElement extends HTMLElement {
constructor(ownerDocument, localName = 'ol') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLTableCaptionElement
*/
class HTMLTableCaptionElement extends HTMLElement {
constructor(ownerDocument, localName = 'caption') {
super(ownerDocument, localName);
}
}
const tagName$1 = 'a';
/**
* @implements globalThis.HTMLAnchorElement
*/
class HTMLAnchorElement extends HTMLElement {
constructor(ownerDocument, localName = tagName$1) {
super(ownerDocument, localName);
}
/* c8 ignore start */ // copy paste from img.src, already covered
get href() { return encodeURI(decodeURI(stringAttribute.get(this, 'href'))).trim(); }
set href(value) { stringAttribute.set(this, 'href', decodeURI(value)); }
get download() { return encodeURI(decodeURI(stringAttribute.get(this, 'download'))); }
set download(value) { stringAttribute.set(this, 'download', decodeURI(value)); }
get target() { return stringAttribute.get(this, 'target'); }
set target(value) { stringAttribute.set(this, 'target', value); }
get type() { return stringAttribute.get(this, 'type'); }
set type(value) { stringAttribute.set(this, 'type', value); }
get rel() { return stringAttribute.get(this, 'rel'); }
set rel(value) { stringAttribute.set(this, 'rel', value); }
/* c8 ignore stop */
}
registerHTMLClass(tagName$1, HTMLAnchorElement);
/**
* @implements globalThis.HTMLLabelElement
*/
class HTMLLabelElement extends HTMLElement {
constructor(ownerDocument, localName = 'label') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLUnknownElement
*/
class HTMLUnknownElement extends HTMLElement {
constructor(ownerDocument, localName = 'unknown') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLModElement
*/
class HTMLModElement extends HTMLElement {
constructor(ownerDocument, localName = 'mod') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLDetailsElement
*/
class HTMLDetailsElement extends HTMLElement {
constructor(ownerDocument, localName = 'details') {
super(ownerDocument, localName);
}
}
const tagName = 'source';
/**
* @implements globalThis.HTMLSourceElement
*/
class HTMLSourceElement extends HTMLElement {
constructor(ownerDocument, localName = tagName) {
super(ownerDocument, localName);
}
/* c8 ignore start */
get src() { return stringAttribute.get(this, 'src'); }
set src(value) { stringAttribute.set(this, 'src', value); }
get srcset() { return stringAttribute.get(this, 'srcset'); }
set srcset(value) { stringAttribute.set(this, 'srcset', value); }
get sizes() { return stringAttribute.get(this, 'sizes'); }
set sizes(value) { stringAttribute.set(this, 'sizes', value); }
get type() { return stringAttribute.get(this, 'type'); }
set type(value) { stringAttribute.set(this, 'type', value); }
/* c8 ignore stop */
}
registerHTMLClass(tagName, HTMLSourceElement);
/**
* @implements globalThis.HTMLTrackElement
*/
class HTMLTrackElement extends HTMLElement {
constructor(ownerDocument, localName = 'track') {
super(ownerDocument, localName);
}
}
/**
* @implements globalThis.HTMLMarqueeElement
*/
class HTMLMarqueeElement extends HTMLElement {
constructor(ownerDocument, localName = 'marquee') {
super(ownerDocument, localName);
}
}
const HTMLClasses = {
HTMLElement,
HTMLTemplateElement,
HTMLHtmlElement,
HTMLScriptElement,
HTMLFrameElement,
HTMLIFrameElement,
HTMLObjectElement,
HTMLHeadElement,
HTMLBodyElement,
HTMLStyleElement,
HTMLTimeElement,
HTMLFieldSetElement,
HTMLEmbedElement,
HTMLHRElement,
HTMLProgressElement,
HTMLParagraphElement,
HTMLTableElement,
HTMLFrameSetElement,
HTMLLIElement,
HTMLBaseElement,
HTMLDataListElement,
HTMLInputElement,
HTMLParamElement,
HTMLMediaElement,
HTMLAudioElement,
HTMLHeadingElement,
HTMLDirectoryElement,
HTMLQuoteElement,
HTMLCanvasElement,
HTMLLegendElement,
HTMLOptionElement,
HTMLSpanElement,
HTMLMeterElement,
HTMLVideoElement,
HTMLTableCellElement,
HTMLTitleElement,
HTMLOutputElement,
HTMLTableRowElement,
HTMLDataElement,
HTMLMenuElement,
HTMLSelectElement,
HTMLBRElement,
HTMLButtonElement,
HTMLMapElement,
HTMLOptGroupElement,
HTMLDListElement,
HTMLTextAreaElement,
HTMLFontElement,
HTMLDivElement,
HTMLLinkElement,
HTMLSlotElement,
HTMLFormElement,
HTMLImageElement,
HTMLPreElement,
HTMLUListElement,
HTMLMetaElement,
HTMLPictureElement,
HTMLAreaElement,
HTMLOListElement,
HTMLTableCaptionElement,
HTMLAnchorElement,
HTMLLabelElement,
HTMLUnknownElement,
HTMLModElement,
HTMLDetailsElement,
HTMLSourceElement,
HTMLTrackElement,
HTMLMarqueeElement
};
// TODO: ensure all these are text only
// /^(?:plaintext|script|style|textarea|title|xmp)$/i
const voidElements = {test: () => true};
const Mime = {
'text/html': {
docType: '<!DOCTYPE html>',
ignoreCase: true,
voidElements: /^(?:area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr)$/i
},
'image/svg+xml': {
docType: '<?xml version="1.0" encoding="utf-8"?>',
ignoreCase: false,
voidElements
},
'text/xml': {
docType: '<?xml version="1.0" encoding="utf-8"?>',
ignoreCase: false,
voidElements
},
'application/xml': {
docType: '<?xml version="1.0" encoding="utf-8"?>',
ignoreCase: false,
voidElements
},
'application/xhtml+xml': {
docType: '<?xml version="1.0" encoding="utf-8"?>',
ignoreCase: false,
voidElements
}
};
// https://dom.spec.whatwg.org/#interface-customevent
/**
* @implements globalThis.CustomEvent
*/
class CustomEvent extends GlobalEvent {
constructor(type, eventInitDict = {}) {
super(type, eventInitDict);
this.detail = eventInitDict.detail;
}
}
/* c8 ignore stop */
// https://dom.spec.whatwg.org/#interface-customevent
/**
* @implements globalThis.InputEvent
*/
class InputEvent extends GlobalEvent {
constructor(type, inputEventInit = {}) {
super(type, inputEventInit);
this.inputType = inputEventInit.inputType;
this.data = inputEventInit.data;
this.dataTransfer = inputEventInit.dataTransfer;
this.isComposing = inputEventInit.isComposing || false;
this.ranges = inputEventInit.ranges;
}
}
/* c8 ignore stop */
const ImageClass = ownerDocument =>
/**
* @implements globalThis.Image
*/
class Image extends HTMLImageElement {
constructor(width, height) {
super(ownerDocument);
switch (arguments.length) {
case 1:
this.height = width;
this.width = width;
break;
case 2:
this.height = height;
this.width = width;
break;
}
}
};
// https://dom.spec.whatwg.org/#concept-live-range
const deleteContents = ({[START]: start, [END]: end}, fragment = null) => {
setAdjacent(start[PREV], end[NEXT]);
do {
const after = getEnd(start);
const next = after === end ? after : after[NEXT];
if (fragment)
fragment.insertBefore(start, fragment[END]);
else
start.remove();
start = next;
} while (start !== end);
};
/**
* @implements globalThis.Range
*/
class Range {
constructor() {
this[START] = null;
this[END] = null;
this.commonAncestorContainer = null;
}
/* TODO: this is more complicated than it looks
setStart(node, offset) {
this[START] = node.childNodes[offset];
}
setEnd(node, offset) {
this[END] = getEnd(node.childNodes[offset]);
}
//*/
insertNode(newNode) {
this[END].parentNode.insertBefore(newNode, this[START]);
}
selectNode(node) {
this[START] = node;
this[END] = getEnd(node);
}
// TODO: SVG elements should then create contextual fragments
// that return SVG nodes
selectNodeContents(node) {
this.selectNode(node);
this.commonAncestorContainer = node;
}
surroundContents(parentNode) {
parentNode.replaceChildren(this.extractContents());
}
setStartBefore(node) {
this[START] = node;
}
setStartAfter(node) {
this[START] = node.nextSibling;
}
setEndBefore(node) {
this[END] = getEnd(node.previousSibling);
}
setEndAfter(node) {
this[END] = getEnd(node);
}
cloneContents() {
let {[START]: start, [END]: end} = this;
const fragment = start.ownerDocument.createDocumentFragment();
while (start !== end) {
fragment.insertBefore(start.cloneNode(true), fragment[END]);
start = getEnd(start);
if (start !== end)
start = start[NEXT];
}
return fragment;
}
deleteContents() {
deleteContents(this);
}
extractContents() {
const fragment = this[START].ownerDocument.createDocumentFragment();
deleteContents(this, fragment);
return fragment;
}
createContextualFragment(html) {
const { commonAncestorContainer: doc } = this;
const isSVG = 'ownerSVGElement' in doc;
const document = isSVG ? doc.ownerDocument : doc;
let content = htmlToFragment(document, html);
if (isSVG) {
const childNodes = [...content.childNodes];
content = document.createDocumentFragment();
Object.setPrototypeOf(content, SVGElement$1.prototype);
content.ownerSVGElement = document;
for (const child of childNodes) {
Object.setPrototypeOf(child, SVGElement$1.prototype);
child.ownerSVGElement = document;
content.appendChild(child);
}
}
else
this.selectNode(content);
return content;
}
cloneRange() {
const range = new Range;
range[START] = this[START];
range[END] = this[END];
return range;
}
}
const isOK = ({nodeType}, mask) => {
switch (nodeType) {
case ELEMENT_NODE:
return mask & SHOW_ELEMENT;
case TEXT_NODE:
return mask & SHOW_TEXT;
case COMMENT_NODE:
return mask & SHOW_COMMENT;
case CDATA_SECTION_NODE:
return mask & SHOW_CDATA_SECTION;
}
return 0;
};
/**
* @implements globalThis.TreeWalker
*/
class TreeWalker {
constructor(root, whatToShow = SHOW_ALL) {
this.root = root;
this.currentNode = root;
this.whatToShow = whatToShow;
let {[NEXT]: next, [END]: end} = root;
if (root.nodeType === DOCUMENT_NODE) {
const {documentElement} = root;
next = documentElement;
end = documentElement[END];
}
const nodes = [];
while (next && next !== end) {
if (isOK(next, whatToShow))
nodes.push(next);
next = next[NEXT];
}
this[PRIVATE] = {i: 0, nodes};
}
nextNode() {
const $ = this[PRIVATE];
this.currentNode = $.i < $.nodes.length ? $.nodes[$.i++] : null;
return this.currentNode;
}
}
const query = (method, ownerDocument, selectors) => {
let {[NEXT]: next, [END]: end} = ownerDocument;
return method.call({ownerDocument, [NEXT]: next, [END]: end}, selectors);
};
const globalExports = assign(
{},
Facades,
HTMLClasses,
{
CustomEvent,
Event: GlobalEvent,
EventTarget: DOMEventTarget,
InputEvent,
NamedNodeMap,
NodeList
}
);
const window = new WeakMap;
/**
* @implements globalThis.Document
*/
let Document$1 = class Document extends NonElementParentNode {
constructor(type) {
super(null, '#document', DOCUMENT_NODE);
this[CUSTOM_ELEMENTS] = {active: false, registry: null};
this[MUTATION_OBSERVER] = {active: false, class: null};
this[MIME] = Mime[type];
/** @type {DocumentType} */
this[DOCTYPE] = null;
this[DOM_PARSER] = null;
this[GLOBALS] = null;
this[IMAGE] = null;
this[UPGRADE] = null;
}
/**
* @type {globalThis.Document['defaultView']}
*/
get defaultView() {
if (!window.has(this))
window.set(this, new Proxy(globalThis, {
set: (target, name, value) => {
switch (name) {
case 'addEventListener':
case 'removeEventListener':
case 'dispatchEvent':
this[EVENT_TARGET][name] = value;
break;
default:
target[name] = value;
break;
}
return true;
},
get: (globalThis, name) => {
switch (name) {
case 'addEventListener':
case 'removeEventListener':
case 'dispatchEvent':
if (!this[EVENT_TARGET]) {
const et = this[EVENT_TARGET] = new DOMEventTarget;
et.dispatchEvent = et.dispatchEvent.bind(et);
et.addEventListener = et.addEventListener.bind(et);
et.removeEventListener = et.removeEventListener.bind(et);
}
return this[EVENT_TARGET][name];
case 'document':
return this;
/* c8 ignore start */
case 'navigator':
return {
userAgent: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36'
};
/* c8 ignore stop */
case 'window':
return window.get(this);
case 'customElements':
if (!this[CUSTOM_ELEMENTS].registry)
this[CUSTOM_ELEMENTS] = new CustomElementRegistry(this);
return this[CUSTOM_ELEMENTS];
case 'performance':
return globalThis.performance;
case 'DOMParser':
return this[DOM_PARSER];
case 'Image':
if (!this[IMAGE])
this[IMAGE] = ImageClass(this);
return this[IMAGE];
case 'MutationObserver':
if (!this[MUTATION_OBSERVER].class)
this[MUTATION_OBSERVER] = new MutationObserverClass(this);
return this[MUTATION_OBSERVER].class;
}
return (this[GLOBALS] && this[GLOBALS][name]) ||
globalExports[name] ||
globalThis[name];
}
}));
return window.get(this);
}
get doctype() {
const docType = this[DOCTYPE];
if (docType)
return docType;
const {firstChild} = this;
if (firstChild && firstChild.nodeType === DOCUMENT_TYPE_NODE)
return (this[DOCTYPE] = firstChild);
return null;
}
set doctype(value) {
if (/^([a-z:]+)(\s+system|\s+public(\s+"([^"]+)")?)?(\s+"([^"]+)")?/i.test(value)) {
const {$1: name, $4: publicId, $6: systemId} = RegExp;
this[DOCTYPE] = new DocumentType$1(this, name, publicId, systemId);
knownSiblings(this, this[DOCTYPE], this[NEXT]);
}
}
get documentElement() {
return this.firstElementChild;
}
get isConnected() { return true; }
/**
* @protected
*/
_getParent() {
return this[EVENT_TARGET];
}
createAttribute(name) { return new Attr$1(this, name); }
createCDATASection(data) { return new CDATASection$1(this, data); }
createComment(textContent) { return new Comment$2(this, textContent); }
createDocumentFragment() { return new DocumentFragment$1(this); }
createDocumentType(name, publicId, systemId) { return new DocumentType$1(this, name, publicId, systemId); }
createElement(localName) { return new Element$1(this, localName); }
createRange() {
const range = new Range;
range.commonAncestorContainer = this;
return range;
}
createTextNode(textContent) { return new Text$1(this, textContent); }
createTreeWalker(root, whatToShow = -1) { return new TreeWalker(root, whatToShow); }
createNodeIterator(root, whatToShow = -1) { return this.createTreeWalker(root, whatToShow); }
createEvent(name) {
const event = create$1(name === 'Event' ? new GlobalEvent('') : new CustomEvent(''));
event.initEvent = event.initCustomEvent = (
type,
canBubble = false,
cancelable = false,
detail
) => {
event.bubbles = !!canBubble;
defineProperties(event, {
type: {value: type},
canBubble: {value: canBubble},
cancelable: {value: cancelable},
detail: {value: detail}
});
};
return event;
}
cloneNode(deep = false) {
const {
constructor,
[CUSTOM_ELEMENTS]: customElements,
[DOCTYPE]: doctype
} = this;
const document = new constructor();
document[CUSTOM_ELEMENTS] = customElements;
if (deep) {
const end = document[END];
const {childNodes} = this;
for (let {length} = childNodes, i = 0; i < length; i++)
document.insertBefore(childNodes[i].cloneNode(true), end);
if (doctype)
document[DOCTYPE] = childNodes[0];
}
return document;
}
importNode(externalNode) {
// important: keep the signature length as *one*
// or it would behave like old IE or Edge with polyfills
const deep = 1 < arguments.length && !!arguments[1];
const node = externalNode.cloneNode(deep);
const {[CUSTOM_ELEMENTS]: customElements} = this;
const {active} = customElements;
const upgrade = element => {
const {ownerDocument, nodeType} = element;
element.ownerDocument = this;
if (active && ownerDocument !== this && nodeType === ELEMENT_NODE)
customElements.upgrade(element);
};
upgrade(node);
if (deep) {
switch (node.nodeType) {
case ELEMENT_NODE:
case DOCUMENT_FRAGMENT_NODE: {
let {[NEXT]: next, [END]: end} = node;
while (next !== end) {
if (next.nodeType === ELEMENT_NODE)
upgrade(next);
next = next[NEXT];
}
break;
}
}
}
return node;
}
toString() { return this.childNodes.join(''); }
querySelector(selectors) {
return query(super.querySelector, this, selectors);
}
querySelectorAll(selectors) {
return query(super.querySelectorAll, this, selectors);
}
/* c8 ignore start */
getElementsByTagNameNS(_, name) {
return this.getElementsByTagName(name);
}
createAttributeNS(_, name) {
return this.createAttribute(name);
}
createElementNS(nsp, localName, options) {
return nsp === SVG_NAMESPACE ?
new SVGElement$1(this, localName, null) :
this.createElement(localName, options);
}
/* c8 ignore stop */
};
setPrototypeOf(
globalExports.Document = function Document() {
illegalConstructor();
},
Document$1
).prototype = Document$1.prototype;
const createHTMLElement$1 = (ownerDocument, builtin, localName, options) => {
if (!builtin && htmlClasses.has(localName)) {
const Class = htmlClasses.get(localName);
return new Class(ownerDocument, localName);
}
const {[CUSTOM_ELEMENTS]: {active, registry}} = ownerDocument;
if (active) {
const ce = builtin ? options.is : localName;
if (registry.has(ce)) {
const {Class} = registry.get(ce);
const element = new Class(ownerDocument, localName);
customElements.set(element, {connected: false});
return element;
}
}
return new HTMLElement(ownerDocument, localName);
};
/**
* @implements globalThis.HTMLDocument
*/
class HTMLDocument extends Document$1 {
constructor() { super('text/html'); }
get all() {
const nodeList = new NodeList;
let {[NEXT]: next, [END]: end} = this;
while (next !== end) {
switch (next.nodeType) {
case ELEMENT_NODE:
nodeList.push(next);
break;
}
next = next[NEXT];
}
return nodeList;
}
/**
* @type HTMLHeadElement
*/
get head() {
const {documentElement} = this;
let {firstElementChild} = documentElement;
if (!firstElementChild || firstElementChild.tagName !== 'HEAD') {
firstElementChild = this.createElement('head');
documentElement.prepend(firstElementChild);
}
return firstElementChild;
}
/**
* @type HTMLBodyElement
*/
get body() {
const {head} = this;
let {nextElementSibling} = head;
if (!nextElementSibling || nextElementSibling.tagName !== 'BODY') {
nextElementSibling = this.createElement('body');
head.after(nextElementSibling);
}
return nextElementSibling;
}
/**
* @type HTMLTitleElement
*/
get title() {
const {head} = this;
return head.getElementsByTagName('title').at(0)?.textContent || '';
}
set title(textContent) {
const {head} = this;
let title = head.getElementsByTagName('title').at(0);
if (title)
title.textContent = textContent;
else {
head.insertBefore(
this.createElement('title'),
head.firstChild
).textContent = textContent;
}
}
createElement(localName, options) {
const builtin = !!(options && options.is);
const element = createHTMLElement$1(this, builtin, localName, options);
if (builtin)
element.setAttribute('is', options.is);
return element;
}
}
/**
* @implements globalThis.Document
*/
class SVGDocument extends Document$1 {
constructor() { super('image/svg+xml'); }
toString() {
return this[MIME].docType + super.toString();
}
}
/**
* @implements globalThis.XMLDocument
*/
class XMLDocument extends Document$1 {
constructor() { super('text/xml'); }
toString() {
return this[MIME].docType + super.toString();
}
}
/**
* @implements globalThis.DOMParser
*/
class DOMParser {
/** @typedef {{ "text/html": HTMLDocument, "image/svg+xml": SVGDocument, "text/xml": XMLDocument }} MimeToDoc */
/**
* @template {keyof MimeToDoc} MIME
* @param {string} markupLanguage
* @param {MIME} mimeType
* @returns {MimeToDoc[MIME]}
*/
parseFromString(markupLanguage, mimeType, globals = null) {
let isHTML = false, document;
if (mimeType === 'text/html') {
isHTML = true;
document = new HTMLDocument;
}
else if (mimeType === 'image/svg+xml')
document = new SVGDocument;
else
document = new XMLDocument;
document[DOM_PARSER] = DOMParser;
if (globals)
document[GLOBALS] = globals;
if (isHTML && markupLanguage === '...')
markupLanguage = '<!doctype html><html><head></head><body></body></html>';
return markupLanguage ?
parseFromString(document, isHTML, markupLanguage) :
document;
}
}
const {parse} = JSON;
const append = (parentNode, node, end) => {
node.parentNode = parentNode;
knownSiblings(end[PREV], node, end);
};
const createHTMLElement = (ownerDocument, localName) => {
if (htmlClasses.has(localName)) {
const Class = htmlClasses.get(localName);
return new Class(ownerDocument, localName);
}
return new HTMLElement(ownerDocument, localName);
};
/**
* @typedef {number|string} jsdonValue - either a node type or its content
*/
/**
* Given a stringified, or arrayfied DOM element, returns an HTMLDocument
* that represent the content of such string, or array.
* @param {string|jsdonValue[]} value
* @returns {HTMLDocument}
*/
const parseJSON = value => {
const array = typeof value === 'string' ? parse(value) : value;
const {length} = array;
const document = new HTMLDocument;
let parentNode = document, end = parentNode[END], svg = false, i = 0;
while (i < length) {
let nodeType = array[i++];
switch (nodeType) {
case ELEMENT_NODE: {
const localName = array[i++];
const isSVG = svg || localName === 'svg' || localName === 'SVG';
const element = isSVG ?
new SVGElement$1(document, localName, parentNode.ownerSVGElement || null) :
createHTMLElement(document, localName);
knownBoundaries(end[PREV], element, end);
element.parentNode = parentNode;
parentNode = element;
end = parentNode[END];
svg = isSVG;
break;
}
case ATTRIBUTE_NODE: {
const name = array[i++];
const value = typeof array[i] === 'string' ? array[i++] : '';
const attr = new Attr$1(document, name, value);
attr.ownerElement = parentNode;
knownSiblings(end[PREV], attr, end);
break;
}
case TEXT_NODE:
append(parentNode, new Text$1(document, array[i++]), end);
break;
case COMMENT_NODE:
append(parentNode, new Comment$2(document, array[i++]), end);
break;
case CDATA_SECTION_NODE:
append(parentNode, new CDATASection$1(document, array[i++]), end);
break;
case DOCUMENT_TYPE_NODE: {
const args = [document];
while (typeof array[i] === 'string')
args.push(array[i++]);
if (args.length === 3 && /\.dtd$/i.test(args[2]))
args.splice(2, 0, '');
append(parentNode, new DocumentType$1(...args), end);
break;
}
case DOCUMENT_FRAGMENT_NODE:
parentNode = document.createDocumentFragment();
end = parentNode[END];
/* eslint no-fallthrough:0 */
case DOCUMENT_NODE:
break;
default:
do {
nodeType -= NODE_END;
if (svg && !parentNode.ownerSVGElement)
svg = false;
parentNode = parentNode.parentNode || parentNode;
} while (nodeType < 0);
end = parentNode[END];
break;
}
}
switch (i && array[0]) {
case ELEMENT_NODE:
return document.firstElementChild;
case DOCUMENT_FRAGMENT_NODE:
return parentNode;
}
return document;
};
/**
*
* @param {Document|Element} node the Document or Element to serialize
* @returns {jsdonValue[]} the linear jsdon serialized array
*/
const toJSON = node => node.toJSON();
class NodeFilter {
static get SHOW_ALL() { return SHOW_ALL; }
static get SHOW_ELEMENT() { return SHOW_ELEMENT; }
static get SHOW_COMMENT() { return SHOW_COMMENT; }
static get SHOW_CDATA_SECTION() { return SHOW_CDATA_SECTION; }
static get SHOW_TEXT() { return SHOW_TEXT; }
}
const parseHTML = (html, globals = null) => (new DOMParser).parseFromString(
html, 'text/html', globals
).defaultView;
function Document() {
illegalConstructor();
}
setPrototypeOf(Document, Document$1).prototype = Document$1.prototype;
globalThis.__linkedom = {Attr: Attr, CDATASection: CDATASection, CharacterData: CharacterData, Comment: Comment, CustomEvent: CustomEvent, DOMParser: DOMParser, Document: Document, DocumentFragment: DocumentFragment, DocumentType: DocumentType, Element: Element, Event: GlobalEvent, EventTarget: DOMEventTarget, Facades: Facades, HTMLAnchorElement: HTMLAnchorElement, HTMLAreaElement: HTMLAreaElement, HTMLAudioElement: HTMLAudioElement, HTMLBRElement: HTMLBRElement, HTMLBaseElement: HTMLBaseElement, HTMLBodyElement: HTMLBodyElement, HTMLButtonElement: HTMLButtonElement, HTMLCanvasElement: HTMLCanvasElement, HTMLClasses: HTMLClasses, HTMLDListElement: HTMLDListElement, HTMLDataElement: HTMLDataElement, HTMLDataListElement: HTMLDataListElement, HTMLDetailsElement: HTMLDetailsElement, HTMLDirectoryElement: HTMLDirectoryElement, HTMLDivElement: HTMLDivElement, HTMLElement: HTMLElement, HTMLEmbedElement: HTMLEmbedElement, HTMLFieldSetElement: HTMLFieldSetElement, HTMLFontElement: HTMLFontElement, HTMLFormElement: HTMLFormElement, HTMLFrameElement: HTMLFrameElement, HTMLFrameSetElement: HTMLFrameSetElement, HTMLHRElement: HTMLHRElement, HTMLHeadElement: HTMLHeadElement, HTMLHeadingElement: HTMLHeadingElement, HTMLHtmlElement: HTMLHtmlElement, HTMLIFrameElement: HTMLIFrameElement, HTMLImageElement: HTMLImageElement, HTMLInputElement: HTMLInputElement, HTMLLIElement: HTMLLIElement, HTMLLabelElement: HTMLLabelElement, HTMLLegendElement: HTMLLegendElement, HTMLLinkElement: HTMLLinkElement, HTMLMapElement: HTMLMapElement, HTMLMarqueeElement: HTMLMarqueeElement, HTMLMediaElement: HTMLMediaElement, HTMLMenuElement: HTMLMenuElement, HTMLMetaElement: HTMLMetaElement, HTMLMeterElement: HTMLMeterElement, HTMLModElement: HTMLModElement, HTMLOListElement: HTMLOListElement, HTMLObjectElement: HTMLObjectElement, HTMLOptGroupElement: HTMLOptGroupElement, HTMLOptionElement: HTMLOptionElement, HTMLOutputElement: HTMLOutputElement, HTMLParagraphElement: HTMLParagraphElement, HTMLParamElement: HTMLParamElement, HTMLPictureElement: HTMLPictureElement, HTMLPreElement: HTMLPreElement, HTMLProgressElement: HTMLProgressElement, HTMLQuoteElement: HTMLQuoteElement, HTMLScriptElement: HTMLScriptElement, HTMLSelectElement: HTMLSelectElement, HTMLSlotElement: HTMLSlotElement, HTMLSourceElement: HTMLSourceElement, HTMLSpanElement: HTMLSpanElement, HTMLStyleElement: HTMLStyleElement, HTMLTableCaptionElement: HTMLTableCaptionElement, HTMLTableCellElement: HTMLTableCellElement, HTMLTableElement: HTMLTableElement, HTMLTableRowElement: HTMLTableRowElement, HTMLTemplateElement: HTMLTemplateElement, HTMLTextAreaElement: HTMLTextAreaElement, HTMLTimeElement: HTMLTimeElement, HTMLTitleElement: HTMLTitleElement, HTMLTrackElement: HTMLTrackElement, HTMLUListElement: HTMLUListElement, HTMLUnknownElement: HTMLUnknownElement, HTMLVideoElement: HTMLVideoElement, InputEvent: InputEvent, Node: Node, NodeFilter: NodeFilter, NodeList: NodeList, SVGElement: SVGElement, ShadowRoot: ShadowRoot, Text: Text, illegalConstructor: illegalConstructor, parseHTML: parseHTML, parseJSON: parseJSON, toJSON: toJSON};
})();