Tim van der Lippe | 706ec96 | 2021-06-04 13:24:42 +0100 | [diff] [blame^] | 1 | "use strict"; |
| 2 | var __spreadArrays = (this && this.__spreadArrays) || function () { |
| 3 | for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; |
| 4 | for (var r = Array(s), k = 0, i = 0; i < il; i++) |
| 5 | for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) |
| 6 | r[k] = a[j]; |
| 7 | return r; |
| 8 | }; |
| 9 | Object.defineProperty(exports, "__esModule", { value: true }); |
| 10 | exports.isTraversal = void 0; |
| 11 | var reName = /^[^\\#]?(?:\\(?:[\da-f]{1,6}\s?|.)|[\w\-\u00b0-\uFFFF])+/; |
| 12 | var reEscape = /\\([\da-f]{1,6}\s?|(\s)|.)/gi; |
| 13 | // Modified version of https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L87 |
| 14 | var reAttr = /^\s*(?:(\*|[-\w]*)\|)?((?:\\.|[\w\u00b0-\uFFFF-])+)\s*(?:(\S?)=\s*(?:(['"])((?:[^\\]|\\[^])*?)\4|(#?(?:\\.|[\w\u00b0-\uFFFF-])*)|)|)\s*([iI])?\]/; |
| 15 | var actionTypes = { |
| 16 | undefined: "exists", |
| 17 | "": "equals", |
| 18 | "~": "element", |
| 19 | "^": "start", |
| 20 | $: "end", |
| 21 | "*": "any", |
| 22 | "!": "not", |
| 23 | "|": "hyphen", |
| 24 | }; |
| 25 | var Traversals = { |
| 26 | ">": "child", |
| 27 | "<": "parent", |
| 28 | "~": "sibling", |
| 29 | "+": "adjacent", |
| 30 | }; |
| 31 | var attribSelectors = { |
| 32 | "#": ["id", "equals"], |
| 33 | ".": ["class", "element"], |
| 34 | }; |
| 35 | // Pseudos, whose data property is parsed as well. |
| 36 | var unpackPseudos = new Set([ |
| 37 | "has", |
| 38 | "not", |
| 39 | "matches", |
| 40 | "is", |
| 41 | "host", |
| 42 | "host-context", |
| 43 | ]); |
| 44 | var traversalNames = new Set(__spreadArrays([ |
| 45 | "descendant" |
| 46 | ], Object.keys(Traversals).map(function (k) { return Traversals[k]; }))); |
| 47 | /** |
| 48 | * Checks whether a specific selector is a traversal. |
| 49 | * This is useful eg. in swapping the order of elements that |
| 50 | * are not traversals. |
| 51 | * |
| 52 | * @param selector Selector to check. |
| 53 | */ |
| 54 | function isTraversal(selector) { |
| 55 | return traversalNames.has(selector.type); |
| 56 | } |
| 57 | exports.isTraversal = isTraversal; |
| 58 | var stripQuotesFromPseudos = new Set(["contains", "icontains"]); |
| 59 | var quotes = new Set(['"', "'"]); |
| 60 | // Unescape function taken from https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L152 |
| 61 | function funescape(_, escaped, escapedWhitespace) { |
| 62 | var high = parseInt(escaped, 16) - 0x10000; |
| 63 | // NaN means non-codepoint |
| 64 | return high !== high || escapedWhitespace |
| 65 | ? escaped |
| 66 | : high < 0 |
| 67 | ? // BMP codepoint |
| 68 | String.fromCharCode(high + 0x10000) |
| 69 | : // Supplemental Plane codepoint (surrogate pair) |
| 70 | String.fromCharCode((high >> 10) | 0xd800, (high & 0x3ff) | 0xdc00); |
| 71 | } |
| 72 | function unescapeCSS(str) { |
| 73 | return str.replace(reEscape, funescape); |
| 74 | } |
| 75 | function isWhitespace(c) { |
| 76 | return c === " " || c === "\n" || c === "\t" || c === "\f" || c === "\r"; |
| 77 | } |
| 78 | /** |
| 79 | * Parses `selector`, optionally with the passed `options`. |
| 80 | * |
| 81 | * @param selector Selector to parse. |
| 82 | * @param options Options for parsing. |
| 83 | * @returns Returns a two-dimensional array. |
| 84 | * The first dimension represents selectors separated by commas (eg. `sub1, sub2`), |
| 85 | * the second contains the relevant tokens for that selector. |
| 86 | */ |
| 87 | function parse(selector, options) { |
| 88 | var subselects = []; |
| 89 | var endIndex = parseSelector(subselects, "" + selector, options, 0); |
| 90 | if (endIndex < selector.length) { |
| 91 | throw new Error("Unmatched selector: " + selector.slice(endIndex)); |
| 92 | } |
| 93 | return subselects; |
| 94 | } |
| 95 | exports.default = parse; |
| 96 | function parseSelector(subselects, selector, options, selectorIndex) { |
| 97 | var _a, _b; |
| 98 | if (options === void 0) { options = {}; } |
| 99 | var tokens = []; |
| 100 | var sawWS = false; |
| 101 | function getName(offset) { |
| 102 | var match = selector.slice(selectorIndex + offset).match(reName); |
| 103 | if (!match) { |
| 104 | throw new Error("Expected name, found " + selector.slice(selectorIndex)); |
| 105 | } |
| 106 | var name = match[0]; |
| 107 | selectorIndex += offset + name.length; |
| 108 | return unescapeCSS(name); |
| 109 | } |
| 110 | function stripWhitespace(offset) { |
| 111 | while (isWhitespace(selector.charAt(selectorIndex + offset))) |
| 112 | offset++; |
| 113 | selectorIndex += offset; |
| 114 | } |
| 115 | function isEscaped(pos) { |
| 116 | var slashCount = 0; |
| 117 | while (selector.charAt(--pos) === "\\") |
| 118 | slashCount++; |
| 119 | return (slashCount & 1) === 1; |
| 120 | } |
| 121 | function ensureNotTraversal() { |
| 122 | if (tokens.length > 0 && isTraversal(tokens[tokens.length - 1])) { |
| 123 | throw new Error("Did not expect successive traversals."); |
| 124 | } |
| 125 | } |
| 126 | stripWhitespace(0); |
| 127 | while (selector !== "") { |
| 128 | var firstChar = selector.charAt(selectorIndex); |
| 129 | if (isWhitespace(firstChar)) { |
| 130 | sawWS = true; |
| 131 | stripWhitespace(1); |
| 132 | } |
| 133 | else if (firstChar in Traversals) { |
| 134 | ensureNotTraversal(); |
| 135 | tokens.push({ type: Traversals[firstChar] }); |
| 136 | sawWS = false; |
| 137 | stripWhitespace(1); |
| 138 | } |
| 139 | else if (firstChar === ",") { |
| 140 | if (tokens.length === 0) { |
| 141 | throw new Error("Empty sub-selector"); |
| 142 | } |
| 143 | subselects.push(tokens); |
| 144 | tokens = []; |
| 145 | sawWS = false; |
| 146 | stripWhitespace(1); |
| 147 | } |
| 148 | else { |
| 149 | if (sawWS) { |
| 150 | ensureNotTraversal(); |
| 151 | tokens.push({ type: "descendant" }); |
| 152 | sawWS = false; |
| 153 | } |
| 154 | if (firstChar in attribSelectors) { |
| 155 | var _c = attribSelectors[firstChar], name_1 = _c[0], action = _c[1]; |
| 156 | tokens.push({ |
| 157 | type: "attribute", |
| 158 | name: name_1, |
| 159 | action: action, |
| 160 | value: getName(1), |
| 161 | ignoreCase: false, |
| 162 | namespace: null, |
| 163 | }); |
| 164 | } |
| 165 | else if (firstChar === "[") { |
| 166 | var attributeMatch = selector |
| 167 | .slice(selectorIndex + 1) |
| 168 | .match(reAttr); |
| 169 | if (!attributeMatch) { |
| 170 | throw new Error("Malformed attribute selector: " + selector.slice(selectorIndex)); |
| 171 | } |
| 172 | var completeSelector = attributeMatch[0], _d = attributeMatch[1], namespace = _d === void 0 ? null : _d, baseName = attributeMatch[2], actionType = attributeMatch[3], _e = attributeMatch[5], quotedValue = _e === void 0 ? "" : _e, _f = attributeMatch[6], value = _f === void 0 ? quotedValue : _f, ignoreCase = attributeMatch[7]; |
| 173 | selectorIndex += completeSelector.length + 1; |
| 174 | var name_2 = unescapeCSS(baseName); |
| 175 | if ((_a = options.lowerCaseAttributeNames) !== null && _a !== void 0 ? _a : !options.xmlMode) { |
| 176 | name_2 = name_2.toLowerCase(); |
| 177 | } |
| 178 | tokens.push({ |
| 179 | type: "attribute", |
| 180 | name: name_2, |
| 181 | action: actionTypes[actionType], |
| 182 | value: unescapeCSS(value), |
| 183 | namespace: namespace, |
| 184 | ignoreCase: !!ignoreCase, |
| 185 | }); |
| 186 | } |
| 187 | else if (firstChar === ":") { |
| 188 | if (selector.charAt(selectorIndex + 1) === ":") { |
| 189 | tokens.push({ |
| 190 | type: "pseudo-element", |
| 191 | name: getName(2).toLowerCase(), |
| 192 | }); |
| 193 | continue; |
| 194 | } |
| 195 | var name_3 = getName(1).toLowerCase(); |
| 196 | var data = null; |
| 197 | if (selector.charAt(selectorIndex) === "(") { |
| 198 | if (unpackPseudos.has(name_3)) { |
| 199 | if (quotes.has(selector.charAt(selectorIndex + 1))) { |
| 200 | throw new Error("Pseudo-selector " + name_3 + " cannot be quoted"); |
| 201 | } |
| 202 | data = []; |
| 203 | selectorIndex = parseSelector(data, selector, options, selectorIndex + 1); |
| 204 | if (selector.charAt(selectorIndex) !== ")") { |
| 205 | throw new Error("Missing closing parenthesis in :" + name_3 + " (" + selector + ")"); |
| 206 | } |
| 207 | selectorIndex += 1; |
| 208 | } |
| 209 | else { |
| 210 | selectorIndex += 1; |
| 211 | var start = selectorIndex; |
| 212 | var counter = 1; |
| 213 | for (; counter > 0 && selectorIndex < selector.length; selectorIndex++) { |
| 214 | if (selector.charAt(selectorIndex) === "(" && |
| 215 | !isEscaped(selectorIndex)) { |
| 216 | counter++; |
| 217 | } |
| 218 | else if (selector.charAt(selectorIndex) === ")" && |
| 219 | !isEscaped(selectorIndex)) { |
| 220 | counter--; |
| 221 | } |
| 222 | } |
| 223 | if (counter) { |
| 224 | throw new Error("Parenthesis not matched"); |
| 225 | } |
| 226 | data = selector.slice(start, selectorIndex - 1); |
| 227 | if (stripQuotesFromPseudos.has(name_3)) { |
| 228 | var quot = data.charAt(0); |
| 229 | if (quot === data.slice(-1) && quotes.has(quot)) { |
| 230 | data = data.slice(1, -1); |
| 231 | } |
| 232 | data = unescapeCSS(data); |
| 233 | } |
| 234 | } |
| 235 | } |
| 236 | tokens.push({ type: "pseudo", name: name_3, data: data }); |
| 237 | } |
| 238 | else { |
| 239 | var namespace = null; |
| 240 | var name_4 = void 0; |
| 241 | if (firstChar === "*") { |
| 242 | selectorIndex += 1; |
| 243 | name_4 = "*"; |
| 244 | } |
| 245 | else if (reName.test(selector.slice(selectorIndex))) { |
| 246 | name_4 = getName(0); |
| 247 | } |
| 248 | else { |
| 249 | /* |
| 250 | * We have finished parsing the selector. |
| 251 | * Remove descendant tokens at the end if they exist, |
| 252 | * and return the last index, so that parsing can be |
| 253 | * picked up from here. |
| 254 | */ |
| 255 | if (tokens.length && |
| 256 | tokens[tokens.length - 1].type === "descendant") { |
| 257 | tokens.pop(); |
| 258 | } |
| 259 | addToken(subselects, tokens); |
| 260 | return selectorIndex; |
| 261 | } |
| 262 | if (selector.charAt(selectorIndex) === "|") { |
| 263 | namespace = name_4; |
| 264 | if (selector.charAt(selectorIndex + 1) === "*") { |
| 265 | name_4 = "*"; |
| 266 | selectorIndex += 2; |
| 267 | } |
| 268 | else { |
| 269 | name_4 = getName(1); |
| 270 | } |
| 271 | } |
| 272 | if (name_4 === "*") { |
| 273 | tokens.push({ type: "universal", namespace: namespace }); |
| 274 | } |
| 275 | else { |
| 276 | if ((_b = options.lowerCaseTags) !== null && _b !== void 0 ? _b : !options.xmlMode) { |
| 277 | name_4 = name_4.toLowerCase(); |
| 278 | } |
| 279 | tokens.push({ type: "tag", name: name_4, namespace: namespace }); |
| 280 | } |
| 281 | } |
| 282 | } |
| 283 | } |
| 284 | addToken(subselects, tokens); |
| 285 | return selectorIndex; |
| 286 | } |
| 287 | function addToken(subselects, tokens) { |
| 288 | if (subselects.length > 0 && tokens.length === 0) { |
| 289 | throw new Error("Empty sub-selector"); |
| 290 | } |
| 291 | subselects.push(tokens); |
| 292 | } |