"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = parse; var reName = /^[^\\]?(?:\\(?:[\da-f]{1,6}\s?|.)|[\w\-\u00b0-\uFFFF])+/; var reEscape = /\\([\da-f]{1,6}\s?|(\s)|.)/gi; // Modified version of https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L87 var reAttr = /^\s*((?:\\.|[\w\u00b0-\uFFFF-])+)\s*(?:(\S?)=\s*(?:(['"])((?:[^\\]|\\[^])*?)\3|(#?(?:\\.|[\w\u00b0-\uFFFF-])*)|)|)\s*(i)?\]/; var actionTypes = { undefined: "exists", "": "equals", "~": "element", "^": "start", $: "end", "*": "any", "!": "not", "|": "hyphen", }; var Traversals = { ">": "child", "<": "parent", "~": "sibling", "+": "adjacent", }; var attribSelectors = { "#": ["id", "equals"], ".": ["class", "element"], }; // Pseudos, whose data property is parsed as well. var unpackPseudos = new Set([ "has", "not", "matches", "is", "host", "host-context", ]); var stripQuotesFromPseudos = new Set(["contains", "icontains"]); var quotes = new Set(['"', "'"]); // Unescape function taken from https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L152 function funescape(_, escaped, escapedWhitespace) { var high = parseInt(escaped, 16) - 0x10000; // NaN means non-codepoint return high !== high || escapedWhitespace ? escaped : high < 0 ? // BMP codepoint String.fromCharCode(high + 0x10000) : // Supplemental Plane codepoint (surrogate pair) String.fromCharCode((high >> 10) | 0xd800, (high & 0x3ff) | 0xdc00); } function unescapeCSS(str) { return str.replace(reEscape, funescape); } function isWhitespace(c) { return c === " " || c === "\n" || c === "\t" || c === "\f" || c === "\r"; } function parse(selector, options) { var subselects = []; selector = parseSelector(subselects, "" + selector, options); if (selector !== "") { throw new Error("Unmatched selector: " + selector); } return subselects; } function parseSelector(subselects, selector, options) { var _a, _b; if (options === void 0) { options = {}; } var tokens = []; var sawWS = false; function getName() { var match = selector.match(reName); if (!match) { throw new Error("Expected name, found " + selector); } var sub = match[0]; selector = selector.substr(sub.length); return unescapeCSS(sub); } function stripWhitespace(start) { while (isWhitespace(selector.charAt(start))) start++; selector = selector.substr(start); } function isEscaped(pos) { var slashCount = 0; while (selector.charAt(--pos) === "\\") slashCount++; return (slashCount & 1) === 1; } stripWhitespace(0); while (selector !== "") { var firstChar = selector.charAt(0); if (isWhitespace(firstChar)) { sawWS = true; stripWhitespace(1); } else if (firstChar in Traversals) { tokens.push({ type: Traversals[firstChar] }); sawWS = false; stripWhitespace(1); } else if (firstChar === ",") { if (tokens.length === 0) { throw new Error("Empty sub-selector"); } subselects.push(tokens); tokens = []; sawWS = false; stripWhitespace(1); } else { if (sawWS) { if (tokens.length > 0) { tokens.push({ type: "descendant" }); } sawWS = false; } if (firstChar === "*") { selector = selector.substr(1); tokens.push({ type: "universal" }); } else if (firstChar in attribSelectors) { var _c = attribSelectors[firstChar], name_1 = _c[0], action = _c[1]; selector = selector.substr(1); tokens.push({ type: "attribute", name: name_1, action: action, value: getName(), ignoreCase: false, }); } else if (firstChar === "[") { selector = selector.substr(1); var attributeMatch = selector.match(reAttr); if (!attributeMatch) { throw new Error("Malformed attribute selector: " + selector); } var completeSelector = attributeMatch[0], baseName = attributeMatch[1], actionType = attributeMatch[2], _d = attributeMatch[4], quotedValue = _d === void 0 ? "" : _d, _e = attributeMatch[5], value = _e === void 0 ? quotedValue : _e, ignoreCase = attributeMatch[6]; selector = selector.substr(completeSelector.length); var name_2 = unescapeCSS(baseName); if ((_a = options.lowerCaseAttributeNames) !== null && _a !== void 0 ? _a : !options.xmlMode) { name_2 = name_2.toLowerCase(); } tokens.push({ type: "attribute", name: name_2, action: actionTypes[actionType], value: unescapeCSS(value), ignoreCase: !!ignoreCase, }); } else if (firstChar === ":") { if (selector.charAt(1) === ":") { selector = selector.substr(2); tokens.push({ type: "pseudo-element", name: getName().toLowerCase(), }); continue; } selector = selector.substr(1); var name_3 = getName().toLowerCase(); var data = null; if (selector.startsWith("(")) { if (unpackPseudos.has(name_3)) { var quot = selector.charAt(1); var quoted = quotes.has(quot); selector = selector.substr(quoted ? 2 : 1); data = []; selector = parseSelector(data, selector, options); if (quoted) { if (!selector.startsWith(quot)) { throw new Error("Unmatched quotes in :" + name_3); } else { selector = selector.substr(1); } } if (!selector.startsWith(")")) { throw new Error("Missing closing parenthesis in :" + name_3 + " (" + selector + ")"); } selector = selector.substr(1); } else { var pos = 1; var counter = 1; for (; counter > 0 && pos < selector.length; pos++) { if (selector.charAt(pos) === "(" && !isEscaped(pos)) { counter++; } else if (selector.charAt(pos) === ")" && !isEscaped(pos)) { counter--; } } if (counter) { throw new Error("Parenthesis not matched"); } data = selector.substr(1, pos - 2); selector = selector.substr(pos); if (stripQuotesFromPseudos.has(name_3)) { var quot = data.charAt(0); if (quot === data.slice(-1) && quotes.has(quot)) { data = data.slice(1, -1); } data = unescapeCSS(data); } } } tokens.push({ type: "pseudo", name: name_3, data: data }); } else if (reName.test(selector)) { var name_4 = getName(); if ((_b = options.lowerCaseTags) !== null && _b !== void 0 ? _b : !options.xmlMode) { name_4 = name_4.toLowerCase(); } tokens.push({ type: "tag", name: name_4 }); } else { if (tokens.length && tokens[tokens.length - 1].type === "descendant") { tokens.pop(); } addToken(subselects, tokens); return selector; } } } addToken(subselects, tokens); return selector; } function addToken(subselects, tokens) { if (subselects.length > 0 && tokens.length === 0) { throw new Error("Empty sub-selector"); } subselects.push(tokens); }