(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/BjAAFleR4cIRzkIWlsN2E6ZHIAAOA12CjdciJlZW4AOGFjAHkARWRjAHkAXGRwAGYAAOA12FzdYwByAADgNdjA3IALQUJFSGFiY2RlZmdoamxtbm9wcnN0dXYAXhxtHHEcdRx5HN8cBx0dHTwd3B3tHfEdAR4EHh0eLB5FHrwewx7hHgkfPR9LH4ABYXJ0AGQcZxxpHHIA8gBvB/IAxQLhIWlsAKAbKeEhcnIAoA4pZ6BmIgCgiyphAHIAAKBiKWMJjRwAAJAcAACVHAAAAAAAAAAAAACZHJwcAACmHKgcrRwAANIc9SF0ZTph7SJwdHl2AKC0KXIAYQDuAFoG4iFkYbtjZwAAoegnZGyhHKMcAKCRKeUAiwYAoIUqdQBvADuAqwCrQHIAgKOQIWJmaGxwc3QAuhy/HMIcxBzHHMoczhxmoOQhcwAAoB8pcwAAoB0p6wCyGnAAAKCrIWwAAKA5KWkAbQAAoHMpbAAAoKIhAKGrKmFl1hzaHGkAbAAAoBkpc6CtKgDgrSoA/oABYWJyAOUc6RztHHIAcgAAoAwpcgBrAACgcicAAWFr8Rz4HGMAAAFla/Yc9xx7YFtgAAFlc/wc/hwAoIspbAAAAWR1Ax0FHQCgjykAoI0pAAJhZXV5Dh0RHRodHB3yIW9uPmEAAWRpFR0YHWkAbAA8YewAowbiAPccO2QAAmNxcnMkHScdLB05HWEAAKA2KXUAbwDyoBwgqhEAAWR1MB00HeghYXIAoGcpcyJoYXIAAKBLKWgAAKCyIQCiZCJmZ3FzRB1FB5Qdnh10AIACYWhscnQATh1WHWUdbB2NHXIicm93AHSgkCFhAOkAzxxhI3Jwb29uAAABZHVeHWId7yF3bgCgvSFwAACgvCHlJGZ0YXJyb3dzAKDHIWkiZ2h0AIABYWhzAHUdex2DHXIicm93APOglCGdBmEAcgBwAG8AbwBuAPMAzgtxAHUAaQBnAGEAcgByAG8A9wBlGugkcmVldGltZXMAoMsi8aFkIk0HAACaHWwAYQBuAPQAXgcAon0qY2Rnc6YdqR2xHbcdYwAAoKgqbwB0AG+gfypyoIEqAKCDKmXg2iIA/nMAAKCTKoACYWRlZ3MAwB3GHcod1h3ZHXAAcAByAG8A+ACmHG8AdAAAoNYicQAAAWdxzx3SHXQA8gBGB2cAdADyAHQcdADyAFMHaQDtAGMHgAFpbHIA4h3mHeod8yFodACgfClvAG8A8gDKBgDgNdgp3UWgdiIAoJEqYQH1Hf4dcgAAAWR1YB35HWygvCEAoGopbABrAACghCVjAHkAWWQAomoiYWNodAweDx4VHhkecgDyAGsdbwByAG4AZQDyAGAW4SFyZACgaylyAGkAAKD6JQABaW8hHiQe5CFvdEBh9SFzdGGgsCPjIWhlAKCwIwACRWFlczMeNR48HkEeAKBoInAAcKCJKvIhb3gAoIkqcaCHKvGghyo0HmkAbQAAoOYiAARhYm5vcHR3elIeXB5fHoUelh6mHqsetB4AAW5yVh5ZHmcAAKDsJ3IAAKD9IXIA6wCwBmcAgAFsbXIAZh52Hnse5SFmdAABYXKIB2weaQBnAGgAdABhAHIAcgBvAPcAkwfhInBzdG8AoPwnaQBnAGgAdABhAHIAcgBvAPcAmgdwI2Fycm93AAABbHKNHpEeZQBmAPQAxhxpImdodAAAoKwhgAFhZmwAnB6fHqIecgAAoIUpAOA12F3ddQBzAACgLSppIm1lcwAAoDQqYQGvHrMecwB0AACgFyLhAIoOZaHKJbkeRhLuIWdlAKDKJWEAcgBsoCgAdAAAoJMpgAJhY2htdADMHs8e1R7bHt0ecgDyAJ0GbwByAG4AZQDyANYWYQByAGSgyyEAoG0pAKAOIHIAaQAAoL8iAANhY2hpcXTrHu8e1QfzHv0eBh/xIXVvAKA5IHIAAOA12MHcbQDloXIi+h4AAPweAKCNKgCgjyoAAWJ19xwBH28AcqAYIACgGiDyIW9rQmEAhDwAO2NkaGlscXJCBhcfxh0gHyQfKB8sHzEfAAFjaRsfHR8AoKYqcgAAoHkqcgBlAOUAkx3tIWVzAKDJIuEhcnIAoHYpdSJlc3QAAKB7KgABUGk1HzkfYQByAACglillocMlAgdfEnIAAAFkdUIfRx9zImhhcgAAoEop6CFhcgCgZikAAWVuTx9WH3IjdG5lcXEAAOBoIgD+xQBUHwAHRGFjZGVmaGlsbm9wc3VuH3Ifoh+rH68ftx+7H74f5h/uH/MfBwj/HwsgxCFvdACgOiIAAmNscHJ5H30fiR+eH3IAO4CvAK9AAAFldIEfgx8AoEImZaAgJ3MAZQAAoCAnc6CmIXQAbwCAoaYhZGx1AJQfmB+cH28AdwDuAHkDZQBmAPQA6gbwAOkO6yFlcgCgriUAAW95ph+qH+0hbWEAoCkqPGThIXNoAKAUIOElc3VyZWRhbmdsZQCgISJyAADgNdgq3W8AAKAnIYABY2RuAMQfyR/bH3IAbwA7gLUAtUBhoiMi0B8AANMf1x9zAPQAKxFpAHIAAKDwKm8AdAA7gLcAt0B1AHMA4qESIh4TAADjH3WgOCIAoCoqYwHqH+0fcAAAoNsq8gB+GnAAbAB1APMACAgAAWRw9x/7H+UhbHMAoKciZgAA4DXYXt0AAWN0AyAHIHIAAOA12MLc8CFvcwCgPiJsobwDECAVIPQiaW1hcACguCJhAPAAEyAADEdMUlZhYmNkZWZnaGlqbG1vcHJzdHV2dzwgRyBmIG0geSCqILgg2iDeIBEhFSEyIUMhTSFQIZwhnyHSIQAiIyKLIrEivyIUIwABZ3RAIEMgAODZIjgD9uBrItIgBwmAAWVsdABNIF8gYiBmAHQAAAFhclMgWCByInJvdwAAoM0h6SRnaHRhcnJvdwCgziEA4NgiOAP24Goi0iBfCekkZ2h0YXJyb3cAoM8hAAFEZHEgdSDhIXNoAKCvIuEhc2gAoK4igAJiY25wdACCIIYgiSCNIKIgbABhAACgByL1IXRlRGFnAADgICLSIACiSSJFaW9wlSCYIJwgniAA4HAqOANkAADgSyI4A3MASWFyAG8A+AAyCnUAcgBhoG4mbADzoG4mmwjzAa8gAACzIHAAO4CgAKBAbQBwAOXgTiI4AyoJgAJhZW91eQDBIMogzSDWINkg8AHGIAAAyCAAoEMqbwBuAEhh5CFpbEZhbgBnAGSgRyJvAHQAAOBtKjgDcAAAoEIqPWThIXNoAKATIACjYCJBYWRxc3jpIO0g+SD+IAIhDCFyAHIAAKDXIXIAAAFocvIg9SBrAACgJClvoJch9wAGD28AdAAA4FAiOAN1AGkA9gC7CAABZWkGIQohYQByAACgKCntAN8I6SFzdPOgBCLlCHIAAOA12CvdAAJFZXN0/wgcISshLiHxoXEiIiEAABMJ8aFxIgAJAAAnIWwAYQBuAPQAEwlpAO0AGQlyoG8iAKBvIoABQWFwADghOyE/IXIA8gBeIHIAcgAAoK4hYQByAACg8ipzogsiSiEAAAAAxwtkoPwiAKD6ImMAeQBaZIADQUVhZGVzdABcIV8hYiFmIWkhkyGWIXIA8gBXIADgZiI4A3IAcgAAoJohcgAAoCUggKFwImZxcwBwIYQhjiF0AAABYXJ1IXohcgByAG8A9wBlIWkAZwBoAHQAYQByAHIAbwD3AD4h8aFwImAhAACKIWwAYQBuAPQAZwlz4H0qOAMAoG4iaQDtAG0JcqBuImkA5aDqIkUJaQDkADoKAAFwdKMhpyFmAADgNdhf3YCBrAA7aW4AriGvIcchrEBuAIChCSJFZHYAtyG6Ib8hAOD5IjgDbwB0AADg9SI4A+EB1gjEIcYhAKD3IgCg9iJpAHagDCLhAagJzyHRIQCg/iIAoP0igAFhb3IA2CHsIfEhcgCAoSYiYXN0AOAh5SHpIWwAbABlAOwAywhsAADg/SrlIADgAiI4A2wiaW50AACgFCrjoYAi9yEAAPohdQDlAJsJY+CvKjgDZaCAIvEAkwkAAkFhaXQHIgoiFyIeInIA8gBsIHIAcgAAoZshY3cRIhQiAOAzKTgDAOCdITgDZyRodGFycm93AACgmyFyAGkA5aDrIr4JgANjaGltcHF1AC8iPCJHIpwhTSJQIloigKGBImNlcgA2Iv0JOSJ1AOUABgoA4DXYw9zvIXJ0bQKdIQAAAABEImEAcgDhAOEhbQBloEEi8aBEIiYKYQDyAMsIcwB1AAABYnBWIlgi5QDUCeUA3wmAAWJjcABgInMieCKAoYQiRWVzAGci7glqIgDgxSo4A2UAdABl4IIi0iBxAPGgiCJoImMAZaCBIvEA/gmAoYUiRWVzAH8iFgqCIgDgxio4A2UAdABl4IMi0iBxAPGgiSKAIgACZ2lscpIilCKaIpwi7AAMCWwAZABlADuA8QDxQOcAWwlpI2FuZ2xlAAABbHKkIqoi5SFmdGWg6iLxAEUJaSJnaHQAZaDrIvEAvgltoL0DAKEjAGVzuCK8InIAbwAAoBYhcAAAoAcggARESGFkZ2lscnMAziLSItYi2iLeIugi7SICIw8j4SFzaACgrSLhIXJyAKAEKXAAAOBNItIg4SFzaACgrCIAAWV04iLlIgDgZSLSIADgPgDSIG4iZmluAACg3imAAUFldADzIvci+iJyAHIAAKACKQDgZCLSIHLgPADSIGkAZQAA4LQi0iAAAUF0BiMKI3IAcgAAoAMp8iFpZQDgtSLSIGkAbQAA4Dwi0iCAAUFhbgAaIx4jKiNyAHIAAKDWIXIAAAFociMjJiNrAACgIylvoJYh9wD/DuUhYXIAoCcpUxJqFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVCMAAF4jaSN/I4IjjSOeI8AUAAAAAKYjwCMAANoj3yMAAO8jHiQvJD8kRCQAAWNzVyNsFHUAdABlADuA8wDzQAABaXlhI2cjcgBjoJoiO4D0APRAPmSAAmFiaW9zAHEjdCN3I3EBeiNzAOgAdhTsIWFjUWF2AACgOCrvIWxkAKC8KewhaWdTYQABY3KFI4kjaQByAACgvykA4DXYLN1vA5QjAAAAAJYjAACcI24A22JhAHYAZQA7gPIA8kAAoMEpAAFibaEjjAphAHIAAKC1KQACYWNpdKwjryO6I70jcgDyAFkUAAFpcrMjtiNyAACgvinvIXNzAKC7KW4A5QDZCgCgwCmAAWFlaQDFI8gjyyNjAHIATWFnAGEAyWOAAWNkbgDRI9Qj1iPyIW9uv2MAoLYpdQDzAHgBcABmAADgNdhg3YABYWVsAOQj5yPrI3IAAKC3KXIAcAAAoLkpdQDzAHwBAKMoImFkaW9zdvkj/CMPJBMkFiQbJHIA8gBeFIChXSplZm0AAyQJJAwkcgBvoDQhZgAAoDQhO4CqAKpAO4C6ALpA5yFvZgCgtiJyAACgVipsIm9wZQAAoFcqAKBbKoABY2xvACMkJSQrJPIACCRhAHMAaAA7gPgA+EBsAACgmCJpAGwBMyQ4JGQAZQA7gPUA9UBlAHMAYaCXInMAAKA2Km0AbAA7gPYA9kDiIWFyAKA9I+EKXiQAAHokAAB8JJQkAACYJKkkAAAAALUkEQsAAPAkAAAAAAQleiUAAIMlcgCAoSUiYXN0AGUkbyQBCwCBtgA7bGokayS2QGwAZQDsABgDaQJ1JAAAAAB4JG0AAKDzKgCg/Sp5AD9kcgCAAmNpbXB0AIUkiCSLJJkSjyRuAHQAJWBvAGQALmBpAGwAAKAwIOUhbmsAoDEgcgAA4DXYLd2AAWltbwCdJKAkpCR2oMYD1WNtAGEA9AD+B24AZQAAoA4m9KHAA64kAAC0JGMjaGZvcmsAAKDUItZjAAFhdbgkxCRuAAABY2u9JMIkawBooA8hAKAOIfYAaRpzAACkKwBhYmNkZW1zdNMkIRPXJNsk4STjJOck6yTjIWlyAKAjKmkAcgAAoCIqAAFvdYsW3yQAoCUqAKByKm4AO4CxALFAaQBtAACgJip3AG8AAKAnKoABaXB1APUk+iT+JO4idGludACgFSpmAADgNdhh3W4AZAA7gKMAo0CApHoiRWFjZWlub3N1ABMlFSUYJRslTCVRJVklSSV1JQCgsypwAACgtyp1AOUAPwtjoK8qgKJ6ImFjZW5zACclLSU0JTYlSSVwAHAAcgBvAPgAFyV1AHIAbAB5AGUA8QA/C/EAOAuAAWFlcwA8JUElRSXwInByb3gAoLkqcQBxAACgtSppAG0AAKDoImkA7QBEC20AZQDzoDIgIguAAUVhcwBDJVclRSXwAEAlgAFkZnAATwtfJXElgAFhbHMAZSVpJW0l7CFhcgCgLiPpIW5lAKASI/UhcmYAoBMjdKAdIu8AWQvyIWVsAKCwIgABY2l9JYElcgAA4DXYxdzIY24iY3NwAACgCCAAA2Zpb3BzdZElKxuVJZolnyWkJXIAAOA12C7dcABmAADgNdhi3XIiaW1lAACgVyBjAHIAAOA12MbcgAFhZW8AqiW6JcAldAAAAWVpryW2JXIAbgBpAG8AbgDzABkFbgB0AACgFipzAHQAZaA/APEACRj0AG0LgApBQkhhYmNkZWZoaWxtbm9wcnN0dXgA4yXyJfYl+iVpJpAmpia9JtUm5ib4JlonaCdxJ3UnnietJ7EnyCfiJ+cngAFhcnQA6SXsJe4lcgDyAJkM8gD6AuEhaWwAoBwpYQByAPIA3BVhAHIAAKBkKYADY2RlbnFydAAGJhAmEyYYJiYmKyZaJgABZXUKJg0mAOA9IjEDdABlAFVhaQDjACAN7SJwdHl2AKCzKWcAgKHpJ2RlbAAgJiImJCYAoJIpAKClKeUA9wt1AG8AO4C7ALtAcgAApZIhYWJjZmhscHN0dz0mQCZFJkcmSiZMJk4mUSZVJlgmcAAAoHUpZqDlIXMAAKAgKQCgMylzAACgHinrALka8ACVHmwAAKBFKWkAbQAAoHQpbAAAoKMhAKCdIQABYWleJmImaQBsAACgGilvAG6gNiJhAGwA8wB2C4ABYWJyAG8mciZ2JnIA8gAvEnIAawAAoHMnAAFha3omgSZjAAABZWt/JoAmfWBdYAABZXOFJocmAKCMKWwAAAFkdYwmjiYAoI4pAKCQKQACYWV1eZcmmiajJqUm8iFvbllhAAFkaZ4moSZpAGwAV2HsAA8M4gCAJkBkAAJjbHFzrSawJrUmuiZhAACgNylkImhhcgAAoGkpdQBvAPKgHSCjAWgAAKCzIYABYWNnAMMm0iaUC2wAgKEcIWlwcwDLJs4migxuAOUAoAxhAHIA9ADaC3QAAKCtJYABaWxyANsm3ybjJvMhaHQAoH0pbwBvAPIANgwA4DXYL90AAWFv6ib1JnIAAAFkde8m8SYAoMEhbKDAIQCgbCl2oMED8WOAAWducwD+Jk4nUCdoAHQAAANhaGxyc3QKJxInISc1Jz0nRydyInJvdwB0oJIhYQDpAFYmYSNycG9vbgAAAWR1GiceJ28AdwDuAPAmcAAAoMAh5SFmdAABYWgnJy0ncgByAG8AdwDzAAkMYQByAHAAbwBvAG4A8wATBGklZ2h0YXJyb3dzAACgySFxAHUAaQBnAGEAcgByAG8A9wBZJugkcmVldGltZXMAoMwiZwDaYmkAbgBnAGQAbwB0AHMAZQDxABwYgAFhaG0AYCdjJ2YncgDyAAkMYQDyABMEAKAPIG8idXN0AGGgsSPjIWhlAKCxI+0haWQAoO4qAAJhYnB0fCeGJ4knmScAAW5ygCeDJ2cAAKDtJ3IAAKD+IXIA6wAcDIABYWZsAI8nkieVJ3IAAKCGKQDgNdhj3XUAcwAAoC4qaSJtZXMAAKA1KgABYXCiJ6gncgBnoCkAdAAAoJQp7yJsaW50AKASKmEAcgDyADwnAAJhY2hxuCe8J6EMwCfxIXVvAKA6IHIAAOA12MfcAAFidYAmxCdvAPKgGSCoAYABaGlyAM4n0ifWJ3IAZQDlAE0n7SFlcwCgyiJpAIChuSVlZmwAXAxjEt4n9CFyaQCgzinsInVoYXIAoGgpAKAeIWENBSgJKA0oSyhVKIYoAACLKLAoAAAAAOMo5ygAABApJCkxKW0pcSmHKaYpAACYKgAAAACxKmMidXRlAFthcQB1AO8ABR+ApHsiRWFjZWlucHN5ABwoHignKCooLygyKEEoRihJKACgtCrwASMoAAAlKACguCpvAG4AYWF1AOUAgw1koLAqaQBsAF9hcgBjAF1hgAFFYXMAOCg6KD0oAKC2KnAAAKC6KmkAbQAAoOki7yJsaW50AKATKmkA7QCIDUFkbwB0AGKixSKRFgAAAABTKACgZiqAA0FhY21zdHgAYChkKG8ocyh1KHkogihyAHIAAKDYIXIAAAFocmkoayjrAJAab6CYIfcAzAd0ADuApwCnQGkAO2D3IWFyAKApKW0AAAFpbn4ozQBuAHUA8wDOAHQAAKA2J3IA7+A12DDdIxkAAmFjb3mRKJUonSisKHIAcAAAoG8mAAFoeZkonChjAHkASWRIZHIAdABtAqUoAAAAAKgoaQDkAFsPYQByAGEA7ABsJDuArQCtQAABZ22zKLsobQBhAAChwwNmdroouijCY4CjPCJkZWdsbnByAMgozCjPKNMo1yjaKN4obwB0AACgairxoEMiCw5FoJ4qAKCgKkWgnSoAoJ8qZQAAoEYi7CF1cwCgJCrhIXJyAKByKWEAcgDyAPwMAAJhZWl07Sj8KAEpCCkAAWxz8Sj4KGwAcwBlAHQAbQDpAH8oaABwAACgMyrwImFyc2wAoOQpAAFkbFoPBSllAACgIyNloKoqc6CsKgDgrCoA/oABZmxwABUpGCkfKfQhY3lMZGKgLwBhoMQpcgAAoD8jZgAA4DXYZN1hAAABZHIoKRcDZQBzAHWgYCZpAHQAAKBgJoABY3N1ADYpRilhKQABYXU6KUApcABzoJMiAOCTIgD+cABzoJQiAOCUIgD+dQAAAWJwSylWKQChjyJlcz4NUCllAHQAZaCPIvEAPw0AoZAiZXNIDVspZQB0AGWgkCLxAEkNAKGhJWFmZilbBHIAZQFrKVwEAKChJWEAcgDyAAMNAAJjZW10dyl7KX8pgilyAADgNdjI3HQAbQDuAM4AaQDsAAYpYQByAOYAVw0AAWFyiimOKXIA5qAGJhESAAFhbpIpoylpImdodAAAAWVwmSmgKXAAcwBpAGwAbwDuANkXaADpAKAkcwCvYIACYmNtbnAArin8KY4NJSooKgCkgiJFZGVtbnByc7wpvinCKcgpzCnUKdgp3CkAoMUqbwB0AACgvSpkoIYibwB0AACgwyr1IWx0AKDBKgABRWXQKdIpAKDLKgCgiiLsIXVzAKC/KuEhcnIAoHkpgAFlaXUA4inxKfQpdAAAoYIiZW7oKewpcQDxoIYivSllAHEA8aCKItEpbQAAoMcqAAFicPgp+ikAoNUqAKDTKmMAgKJ7ImFjZW5zAAcqDSoUKhYqRihwAHAAcgBvAPgAIyh1AHIAbAB5AGUA8QCDDfEAfA2AAWFlcwAcKiIqPShwAHAAcgBvAPgAPChxAPEAOShnAACgaiYApoMiMTIzRWRlaGxtbnBzPCo/KkIqRSpHKlIqWCpjKmcqaypzKncqO4C5ALlAO4CyALJAO4CzALNAAKDGKgABb3NLKk4qdAAAoL4qdQBiAACg2CpkoIcibwB0AACgxCpzAAABb3VdKmAqbAAAoMknYgAAoNcq4SFycgCgeyn1IWx0AKDCKgABRWVvKnEqAKDMKgCgiyLsIXVzAKDAKoABZWl1AH0qjCqPKnQAAKGDImVugyqHKnEA8aCHIkYqZQBxAPGgiyJwKm0AAKDIKgABYnCTKpUqAKDUKgCg1iqAAUFhbgCdKqEqrCpyAHIAAKDZIXIAAAFocqYqqCrrAJUab6CZIfcAxQf3IWFyAKAqKWwAaQBnADuA3wDfQOELzyrZKtwq6SrsKvEqAAD1KjQrAAAAAAAAAAAAAEwrbCsAAHErvSsAAAAAAADRK3IC1CoAAAAA2CrnIWV0AKAWI8RjcgDrAOUKgAFhZXkA4SrkKucq8iFvbmVh5CFpbGNhQmRvAPQAIg5sInJlYwAAoBUjcgAA4DXYMd0AAmVpa2/7KhIrKCsuK/IBACsAAAkrZQAAATRm6g0EK28AcgDlAOsNYQBzorgDECsAAAAAEit5AG0A0WMAAWNuFislK2sAAAFhcxsrIStwAHAAcgBvAPgAFw5pAG0AAKA8InMA8AD9DQABYXMsKyEr8AAXDnIAbgA7gP4A/kDsATgrOyswG2QA5QBnAmUAcwCAgdcAO2JkAEMrRCtJK9dAYaCgInIAAKAxKgCgMCqAAWVwcwBRK1MraSvhAAkh4qKkIlsrXysAAAAAYytvAHQAAKA2I2kAcgAAoPEqb+A12GXdcgBrAACg2irhAHgociJpbWUAAKA0IIABYWlwAHYreSu3K2QA5QC+DYADYWRlbXBzdACFK6MrmiunK6wrsCuzK24iZ2xlAACitSVkbHFykCuUK5ornCvvIXduAKC/JeUhZnRloMMl8QACBwCgXCJpImdodABloLkl8QBdDG8AdAAAoOwlaSJudXMAAKA6KuwhdXMAoDkqYgAAoM0p6SFtZQCgOyrlInppdW0AoOIjgAFjaHQAwivKK80rAAFyecYrySsA4DXYydxGZGMAeQBbZPIhb2tnYQABaW/UK9creAD0ANERaCJlYWQAAAFsct4r5ytlAGYAdABhAHIAcgBvAPcAXQbpJGdodGFycm93AKCgIQAJQUhhYmNkZmdobG1vcHJzdHV3CiwNLBEsHSwnLDEsQCxLLFIsYix6LIQsjyzLLOgs7Sz/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]), // ` 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 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': ' ', '&': '&', '<': '<', '>': '>' }; 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, '"'); 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, """], [38, "&"], [39, "'"], [60, "<"], [62, ">"], ]); // 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. `ü`) 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, """], [38, "&"], [160, " "], ])); /** * 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, "&"], [60, "<"], [62, ">"], [160, " "], ])); /** * 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, """); } /** * 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}; })();