UNPKG

node-scrapy

Version:

Simple, lightweight and expressive web scraping with Node.js

1,744 lines (1,459 loc) 98.9 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('domutils')) : typeof define === 'function' && define.amd ? define(['domutils'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.scrapy = factory(global.DomUtils)); }(this, (function (DomUtils) { 'use strict'; function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var DomUtils__default = /*#__PURE__*/_interopDefaultLegacy(DomUtils); var boolbase = { trueFunc: function trueFunc() { return true; }, falseFunc: function falseFunc() { return false; } }; var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; function createCommonjsModule(fn, basedir, module) { return module = { path: basedir, exports: {}, require: function (path, base) { return commonjsRequire(path, (base === undefined || base === null) ? module.path : base); } }, fn(module, module.exports), module.exports; } function commonjsRequire () { throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs'); } var parse_1 = createCommonjsModule(function (module, exports) { 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"]); 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 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 _a = attribSelectors[firstChar], name_1 = _a[0], action = _a[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 data = selector.match(reAttr); if (!data) { throw new Error("Malformed attribute selector: " + selector); } selector = selector.substr(data[0].length); var name_2 = unescapeCSS(data[1]); if (!options || ("lowerCaseAttributeNames" in options ? options.lowerCaseAttributeNames : !options.xmlMode)) { name_2 = name_2.toLowerCase(); } tokens.push({ type: "attribute", name: name_2, action: actionTypes[data[2]], value: unescapeCSS(data[4] || data[5] || ""), ignoreCase: !!data[6] }); } 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.charAt(0) === "(") { 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.charAt(0) !== quot) { throw new Error("Unmatched quotes in :" + name_3); } else { selector = selector.substr(1); } } if (selector.charAt(0) !== ")") { 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 (!options || ("lowerCaseTags" in options ? options.lowerCaseTags : !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); } }); var stringify_1 = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); var actionTypes = { equals: "", element: "~", start: "^", end: "$", any: "*", not: "!", hyphen: "|" }; function stringify(token) { return token.map(stringifySubselector).join(", "); } exports.default = stringify; function stringifySubselector(token) { return token.map(stringifyToken).join(""); } function stringifyToken(token) { switch (token.type) { // Simple types case "child": return " > "; case "parent": return " < "; case "sibling": return " ~ "; case "adjacent": return " + "; case "descendant": return " "; case "universal": return "*"; case "tag": return escapeName(token.name); case "pseudo-element": return "::" + escapeName(token.name); case "pseudo": if (token.data === null) return ":" + escapeName(token.name); if (typeof token.data === "string") { return ":" + escapeName(token.name) + "(" + token.data + ")"; } return ":" + escapeName(token.name) + "(" + stringify(token.data) + ")"; case "attribute": if (token.action === "exists") { return "[" + escapeName(token.name) + "]"; } if (token.name === "id" && token.action === "equals" && !token.ignoreCase) { return "#" + escapeName(token.value); } if (token.name === "class" && token.action === "element" && !token.ignoreCase) { return "." + escapeName(token.value); } return "[" + escapeName(token.name) + actionTypes[token.action] + "='" + escapeName(token.value) + "'" + (token.ignoreCase ? "i" : "") + "]"; default: throw new Error("Unknown type"); } } function escapeName(str) { //TODO return str; } }); var lib = createCommonjsModule(function (module, exports) { var __createBinding = commonjsGlobal && commonjsGlobal.__createBinding || (Object.create ? function (o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function () { return m[k]; } }); } : function (o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; }); var __exportStar = commonjsGlobal && commonjsGlobal.__exportStar || function (m, exports) { for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", { value: true }); __exportStar(parse_1, exports); var parse_1$1 = parse_1; Object.defineProperty(exports, "parse", { enumerable: true, get: function () { return parse_1$1.default; } }); Object.defineProperty(exports, "stringify", { enumerable: true, get: function () { return stringify_1.default; } }); }); var universal = 50; var tag = 30; var attribute = 1; var pseudo = 0; var descendant = -1; var child = -1; var parent = -1; var sibling = -1; var adjacent = -1; var procedure = { universal: universal, tag: tag, attribute: attribute, pseudo: pseudo, descendant: descendant, child: child, parent: parent, sibling: sibling, adjacent: adjacent }; var sort = sortByProcedure; /* sort the parts of the passed selector, as there is potential for optimization (some types of selectors are faster than others) */ var attributes = { __proto__: null, exists: 10, equals: 8, not: 7, start: 6, end: 6, any: 5, hyphen: 4, element: 4 }; function sortByProcedure(arr) { var procs = arr.map(getProcedure); for (var i = 1; i < arr.length; i++) { var procNew = procs[i]; if (procNew < 0) continue; for (var j = i - 1; j >= 0 && procNew < procs[j]; j--) { var token = arr[j + 1]; arr[j + 1] = arr[j]; arr[j] = token; procs[j + 1] = procs[j]; procs[j] = procNew; } } } function getProcedure(token) { var proc = procedure[token.type]; if (proc === procedure.attribute) { proc = attributes[token.action]; if (proc === attributes.equals && token.name === "id") { //prefer ID selectors (eg. #ID) proc = 9; } if (token.ignoreCase) { //ignoreCase adds some overhead, prefer "normal" token //this is a binary operation, to ensure it's still an int proc >>= 1; } } else if (proc === procedure.pseudo) { if (!token.data) { proc = 3; } else if (token.name === "has" || token.name === "contains") { proc = 0; //expensive in any case } else if (token.name === "matches" || token.name === "not") { proc = 0; for (var i = 0; i < token.data.length; i++) { //TODO better handling of complex selectors if (token.data[i].length !== 1) continue; var cur = getProcedure(token.data[i][0]); //avoid executing :has or :contains if (cur === 0) { proc = 0; break; } if (cur > proc) proc = cur; } if (token.data.length > 1 && proc > 0) proc -= 1; } else { proc = 1; } } return proc; } var falseFunc = boolbase.falseFunc; //https://github.com/slevithan/XRegExp/blob/master/src/xregexp.js#L469 var reChars = /[-[\]{}()*+?.,\\^$|#\s]/g; /* attribute selectors */ var attributeRules = { __proto__: null, equals: function (next, data, options) { var name = data.name; var value = data.value; var adapter = options.adapter; if (data.ignoreCase) { value = value.toLowerCase(); return function equalsIC(elem) { var attr = adapter.getAttributeValue(elem, name); return attr != null && attr.toLowerCase() === value && next(elem); }; } return function equals(elem) { return adapter.getAttributeValue(elem, name) === value && next(elem); }; }, hyphen: function (next, data, options) { var name = data.name; var value = data.value; var len = value.length; var adapter = options.adapter; if (data.ignoreCase) { value = value.toLowerCase(); return function hyphenIC(elem) { var attr = adapter.getAttributeValue(elem, name); return attr != null && (attr.length === len || attr.charAt(len) === "-") && attr.substr(0, len).toLowerCase() === value && next(elem); }; } return function hyphen(elem) { var attr = adapter.getAttributeValue(elem, name); return attr != null && attr.substr(0, len) === value && (attr.length === len || attr.charAt(len) === "-") && next(elem); }; }, element: function (next, data, options) { var name = data.name; var value = data.value; var adapter = options.adapter; if (/\s/.test(value)) { return falseFunc; } value = value.replace(reChars, "\\$&"); var pattern = "(?:^|\\s)" + value + "(?:$|\\s)", flags = data.ignoreCase ? "i" : "", regex = new RegExp(pattern, flags); return function element(elem) { var attr = adapter.getAttributeValue(elem, name); return attr != null && regex.test(attr) && next(elem); }; }, exists: function (next, data, options) { var name = data.name; var adapter = options.adapter; return function exists(elem) { return adapter.hasAttrib(elem, name) && next(elem); }; }, start: function (next, data, options) { var name = data.name; var value = data.value; var len = value.length; var adapter = options.adapter; if (len === 0) { return falseFunc; } if (data.ignoreCase) { value = value.toLowerCase(); return function startIC(elem) { var attr = adapter.getAttributeValue(elem, name); return attr != null && attr.substr(0, len).toLowerCase() === value && next(elem); }; } return function start(elem) { var attr = adapter.getAttributeValue(elem, name); return attr != null && attr.substr(0, len) === value && next(elem); }; }, end: function (next, data, options) { var name = data.name; var value = data.value; var len = -value.length; var adapter = options.adapter; if (len === 0) { return falseFunc; } if (data.ignoreCase) { value = value.toLowerCase(); return function endIC(elem) { var attr = adapter.getAttributeValue(elem, name); return attr != null && attr.substr(len).toLowerCase() === value && next(elem); }; } return function end(elem) { var attr = adapter.getAttributeValue(elem, name); return attr != null && attr.substr(len) === value && next(elem); }; }, any: function (next, data, options) { var name = data.name; var value = data.value; var adapter = options.adapter; if (value === "") { return falseFunc; } if (data.ignoreCase) { var regex = new RegExp(value.replace(reChars, "\\$&"), "i"); return function anyIC(elem) { var attr = adapter.getAttributeValue(elem, name); return attr != null && regex.test(attr) && next(elem); }; } return function any(elem) { var attr = adapter.getAttributeValue(elem, name); return attr != null && attr.indexOf(value) >= 0 && next(elem); }; }, not: function (next, data, options) { var name = data.name; var value = data.value; var adapter = options.adapter; if (value === "") { return function notEmpty(elem) { return !!adapter.getAttributeValue(elem, name) && next(elem); }; } else if (data.ignoreCase) { value = value.toLowerCase(); return function notIC(elem) { var attr = adapter.getAttributeValue(elem, name); return attr != null && attr.toLowerCase() !== value && next(elem); }; } return function not(elem) { return adapter.getAttributeValue(elem, name) !== value && next(elem); }; } }; var attributes$1 = { compile: function (next, data, options) { if (options && options.strict && (data.ignoreCase || data.action === "not")) { throw new Error("Unsupported attribute selector"); } return attributeRules[data.action](next, data, options); }, rules: attributeRules }; var parse_1$1 = parse; //following http://www.w3.org/TR/css3-selectors/#nth-child-pseudo //[ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]? var re_nthElement = /^([+\-]?\d*n)?\s*(?:([+\-]?)\s*(\d+))?$/; /* parses a nth-check formula, returns an array of two numbers */ function parse(formula) { formula = formula.trim().toLowerCase(); if (formula === "even") { return [2, 0]; } else if (formula === "odd") { return [2, 1]; } else { var parsed = formula.match(re_nthElement); if (!parsed) { throw new SyntaxError("n-th rule couldn't be parsed ('" + formula + "')"); } var a; if (parsed[1]) { a = parseInt(parsed[1], 10); if (isNaN(a)) { if (parsed[1].charAt(0) === "-") a = -1;else a = 1; } } else a = 0; return [a, parsed[3] ? parseInt((parsed[2] || "") + parsed[3], 10) : 0]; } } var compile_1 = compile; var trueFunc = boolbase.trueFunc, falseFunc$1 = boolbase.falseFunc; /* returns a function that checks if an elements index matches the given rule highly optimized to return the fastest solution */ function compile(parsed) { var a = parsed[0], b = parsed[1] - 1; //when b <= 0, a*n won't be possible for any matches when a < 0 //besides, the specification says that no element is matched when a and b are 0 if (b < 0 && a <= 0) return falseFunc$1; //when a is in the range -1..1, it matches any element (so only b is checked) if (a === -1) return function (pos) { return pos <= b; }; if (a === 0) return function (pos) { return pos === b; }; //when b <= 0 and a === 1, they match any element if (a === 1) return b < 0 ? trueFunc : function (pos) { return pos >= b; }; //when a > 0, modulo can be used to check if there is a match var bMod = b % a; if (bMod < 0) bMod += a; if (a > 1) { return function (pos) { return pos >= b && pos % a === bMod; }; } a *= -1; //make `a` positive return function (pos) { return pos <= b && pos % a === bMod; }; } var nthCheck = function nthCheck(formula) { return compile_1(parse_1$1(formula)); }; var parse_1$2 = parse_1$1; var compile_1$1 = compile_1; nthCheck.parse = parse_1$2; nthCheck.compile = compile_1$1; /* pseudo selectors --- they are available in two forms: * filters called when the selector is compiled and return a function that needs to return next() * pseudos get called on execution they need to return a boolean */ var trueFunc$1 = boolbase.trueFunc; var falseFunc$2 = boolbase.falseFunc; var checkAttrib = attributes$1.rules.equals; function getAttribFunc(name, value) { var data = { name: name, value: value }; return function attribFunc(next, rule, options) { return checkAttrib(next, data, options); }; } function getChildFunc(next, adapter) { return function (elem) { return !!adapter.getParent(elem) && next(elem); }; } var filters = { contains: function (next, text, options) { var adapter = options.adapter; return function contains(elem) { return next(elem) && adapter.getText(elem).indexOf(text) >= 0; }; }, icontains: function (next, text, options) { var itext = text.toLowerCase(); var adapter = options.adapter; return function icontains(elem) { return next(elem) && adapter.getText(elem).toLowerCase().indexOf(itext) >= 0; }; }, //location specific methods "nth-child": function (next, rule, options) { var func = nthCheck(rule); var adapter = options.adapter; if (func === falseFunc$2) return func; if (func === trueFunc$1) return getChildFunc(next, adapter); return function nthChild(elem) { var siblings = adapter.getSiblings(elem); for (var i = 0, pos = 0; i < siblings.length; i++) { if (adapter.isTag(siblings[i])) { if (siblings[i] === elem) break;else pos++; } } return func(pos) && next(elem); }; }, "nth-last-child": function (next, rule, options) { var func = nthCheck(rule); var adapter = options.adapter; if (func === falseFunc$2) return func; if (func === trueFunc$1) return getChildFunc(next, adapter); return function nthLastChild(elem) { var siblings = adapter.getSiblings(elem); for (var pos = 0, i = siblings.length - 1; i >= 0; i--) { if (adapter.isTag(siblings[i])) { if (siblings[i] === elem) break;else pos++; } } return func(pos) && next(elem); }; }, "nth-of-type": function (next, rule, options) { var func = nthCheck(rule); var adapter = options.adapter; if (func === falseFunc$2) return func; if (func === trueFunc$1) return getChildFunc(next, adapter); return function nthOfType(elem) { var siblings = adapter.getSiblings(elem); for (var pos = 0, i = 0; i < siblings.length; i++) { if (adapter.isTag(siblings[i])) { if (siblings[i] === elem) break; if (adapter.getName(siblings[i]) === adapter.getName(elem)) pos++; } } return func(pos) && next(elem); }; }, "nth-last-of-type": function (next, rule, options) { var func = nthCheck(rule); var adapter = options.adapter; if (func === falseFunc$2) return func; if (func === trueFunc$1) return getChildFunc(next, adapter); return function nthLastOfType(elem) { var siblings = adapter.getSiblings(elem); for (var pos = 0, i = siblings.length - 1; i >= 0; i--) { if (adapter.isTag(siblings[i])) { if (siblings[i] === elem) break; if (adapter.getName(siblings[i]) === adapter.getName(elem)) pos++; } } return func(pos) && next(elem); }; }, //TODO determine the actual root element root: function (next, rule, options) { var adapter = options.adapter; return function (elem) { return !adapter.getParent(elem) && next(elem); }; }, scope: function (next, rule, options, context) { var adapter = options.adapter; if (!context || context.length === 0) { //equivalent to :root return filters.root(next, rule, options); } function equals(a, b) { if (typeof adapter.equals === "function") return adapter.equals(a, b); return a === b; } if (context.length === 1) { //NOTE: can't be unpacked, as :has uses this for side-effects return function (elem) { return equals(context[0], elem) && next(elem); }; } return function (elem) { return context.indexOf(elem) >= 0 && next(elem); }; }, //jQuery extensions (others follow as pseudos) checkbox: getAttribFunc("type", "checkbox"), file: getAttribFunc("type", "file"), password: getAttribFunc("type", "password"), radio: getAttribFunc("type", "radio"), reset: getAttribFunc("type", "reset"), image: getAttribFunc("type", "image"), submit: getAttribFunc("type", "submit"), //dynamic state pseudos. These depend on optional Adapter methods. hover: function (next, rule, options) { var adapter = options.adapter; if (typeof adapter.isHovered === 'function') { return function hover(elem) { return next(elem) && adapter.isHovered(elem); }; } return falseFunc$2; }, visited: function (next, rule, options) { var adapter = options.adapter; if (typeof adapter.isVisited === 'function') { return function visited(elem) { return next(elem) && adapter.isVisited(elem); }; } return falseFunc$2; }, active: function (next, rule, options) { var adapter = options.adapter; if (typeof adapter.isActive === 'function') { return function active(elem) { return next(elem) && adapter.isActive(elem); }; } return falseFunc$2; } }; //helper methods function getFirstElement(elems, adapter) { for (var i = 0; elems && i < elems.length; i++) { if (adapter.isTag(elems[i])) return elems[i]; } } //while filters are precompiled, pseudos get called when they are needed var pseudos = { empty: function (elem, adapter) { return !adapter.getChildren(elem).some(function (elem) { return adapter.isTag(elem) || elem.type === "text"; }); }, "first-child": function (elem, adapter) { return getFirstElement(adapter.getSiblings(elem), adapter) === elem; }, "last-child": function (elem, adapter) { var siblings = adapter.getSiblings(elem); for (var i = siblings.length - 1; i >= 0; i--) { if (siblings[i] === elem) return true; if (adapter.isTag(siblings[i])) break; } return false; }, "first-of-type": function (elem, adapter) { var siblings = adapter.getSiblings(elem); for (var i = 0; i < siblings.length; i++) { if (adapter.isTag(siblings[i])) { if (siblings[i] === elem) return true; if (adapter.getName(siblings[i]) === adapter.getName(elem)) break; } } return false; }, "last-of-type": function (elem, adapter) { var siblings = adapter.getSiblings(elem); for (var i = siblings.length - 1; i >= 0; i--) { if (adapter.isTag(siblings[i])) { if (siblings[i] === elem) return true; if (adapter.getName(siblings[i]) === adapter.getName(elem)) break; } } return false; }, "only-of-type": function (elem, adapter) { var siblings = adapter.getSiblings(elem); for (var i = 0, j = siblings.length; i < j; i++) { if (adapter.isTag(siblings[i])) { if (siblings[i] === elem) continue; if (adapter.getName(siblings[i]) === adapter.getName(elem)) { return false; } } } return true; }, "only-child": function (elem, adapter) { var siblings = adapter.getSiblings(elem); for (var i = 0; i < siblings.length; i++) { if (adapter.isTag(siblings[i]) && siblings[i] !== elem) return false; } return true; }, //:matches(a, area, link)[href] link: function (elem, adapter) { return adapter.hasAttrib(elem, "href"); }, //TODO: :any-link once the name is finalized (as an alias of :link) //forms //to consider: :target //:matches([selected], select:not([multiple]):not(> option[selected]) > option:first-of-type) selected: function (elem, adapter) { if (adapter.hasAttrib(elem, "selected")) return true;else if (adapter.getName(elem) !== "option") return false; //the first <option> in a <select> is also selected var parent = adapter.getParent(elem); if (!parent || adapter.getName(parent) !== "select" || adapter.hasAttrib(parent, "multiple")) { return false; } var siblings = adapter.getChildren(parent); var sawElem = false; for (var i = 0; i < siblings.length; i++) { if (adapter.isTag(siblings[i])) { if (siblings[i] === elem) { sawElem = true; } else if (!sawElem) { return false; } else if (adapter.hasAttrib(siblings[i], "selected")) { return false; } } } return sawElem; }, //https://html.spec.whatwg.org/multipage/scripting.html#disabled-elements //:matches( // :matches(button, input, select, textarea, menuitem, optgroup, option)[disabled], // optgroup[disabled] > option), // fieldset[disabled] * //TODO not child of first <legend> //) disabled: function (elem, adapter) { return adapter.hasAttrib(elem, "disabled"); }, enabled: function (elem, adapter) { return !adapter.hasAttrib(elem, "disabled"); }, //:matches(:matches(:radio, :checkbox)[checked], :selected) (TODO menuitem) checked: function (elem, adapter) { return adapter.hasAttrib(elem, "checked") || pseudos.selected(elem, adapter); }, //:matches(input, select, textarea)[required] required: function (elem, adapter) { return adapter.hasAttrib(elem, "required"); }, //:matches(input, select, textarea):not([required]) optional: function (elem, adapter) { return !adapter.hasAttrib(elem, "required"); }, //jQuery extensions //:not(:empty) parent: function (elem, adapter) { return !pseudos.empty(elem, adapter); }, //:matches(h1, h2, h3, h4, h5, h6) header: namePseudo(["h1", "h2", "h3", "h4", "h5", "h6"]), //:matches(button, input[type=button]) button: function (elem, adapter) { var name = adapter.getName(elem); return name === "button" || name === "input" && adapter.getAttributeValue(elem, "type") === "button"; }, //:matches(input, textarea, select, button) input: namePseudo(["input", "textarea", "select", "button"]), //input:matches(:not([type!='']), [type='text' i]) text: function (elem, adapter) { var attr; return adapter.getName(elem) === "input" && (!(attr = adapter.getAttributeValue(elem, "type")) || attr.toLowerCase() === "text"); } }; function namePseudo(names) { if (typeof Set !== "undefined") { // eslint-disable-next-line no-undef var nameSet = new Set(names); return function (elem, adapter) { return nameSet.has(adapter.getName(elem)); }; } return function (elem, adapter) { return names.indexOf(adapter.getName(elem)) >= 0; }; } function verifyArgs(func, name, subselect) { if (subselect === null) { if (func.length > 2 && name !== "scope") { throw new Error("pseudo-selector :" + name + " requires an argument"); } } else { if (func.length === 2) { throw new Error("pseudo-selector :" + name + " doesn't have any arguments"); } } } //FIXME this feels hacky var re_CSS3 = /^(?:(?:nth|last|first|only)-(?:child|of-type)|root|empty|(?:en|dis)abled|checked|not)$/; var pseudos_1 = { compile: function (next, data, options, context) { var name = data.name; var subselect = data.data; var adapter = options.adapter; if (options && options.strict && !re_CSS3.test(name)) { throw new Error(":" + name + " isn't part of CSS3"); } if (typeof filters[name] === "function") { return filters[name](next, subselect, options, context); } else if (typeof pseudos[name] === "function") { var func = pseudos[name]; verifyArgs(func, name, subselect); if (func === falseFunc$2) { return func; } if (next === trueFunc$1) { return function pseudoRoot(elem) { return func(elem, adapter, subselect); }; } return function pseudoArgs(elem) { return func(elem, adapter, subselect) && next(elem); }; } else { throw new Error("unmatched pseudo-class :" + name); } }, filters: filters, pseudos: pseudos }; /* all available rules */ var general = { __proto__: null, attribute: attributes$1.compile, pseudo: pseudos_1.compile, //tags tag: function (next, data, options) { var name = data.name; var adapter = options.adapter; return function tag(elem) { return adapter.getName(elem) === name && next(elem); }; }, //traversal descendant: function (next, data, options) { // eslint-disable-next-line no-undef var isFalseCache = typeof WeakSet !== "undefined" ? new WeakSet() : null; var adapter = options.adapter; return function descendant(elem) { var found = false; while (!found && (elem = adapter.getParent(elem))) { if (!isFalseCache || !isFalseCache.has(elem)) { found = next(elem); if (!found && isFalseCache) { isFalseCache.add(elem); } } } return found; }; }, _flexibleDescendant: function (next, data, options) { var adapter = options.adapter; // Include element itself, only used while querying an array return function descendant(elem) { var found = next(elem); while (!found && (elem = adapter.getParent(elem))) { found = next(elem); } return found; }; }, parent: function (next, data, options) { if (options && options.strict) { throw new Error("Parent selector isn't part of CSS3"); } var adapter = options.adapter; return function parent(elem) { return adapter.getChildren(elem).some(test); }; function test(elem) { return adapter.isTag(elem) && next(elem); } }, child: function (next, data, options) { var adapter = options.adapter; return function child(elem) { var parent = adapter.getParent(elem); return !!parent && next(parent); }; }, sibling: function (next, data, options) { var adapter = options.adapter; return function sibling(elem) { var siblings = adapter.getSiblings(elem); for (var i = 0; i < siblings.length; i++) { if (adapter.isTag(siblings[i])) { if (siblings[i] === elem) break; if (next(siblings[i])) return true; } } return false; }; }, adjacent: function (next, data, options) { var adapter = options.adapter; return function adjacent(elem) { var siblings = adapter.getSiblings(elem), lastElement; for (var i = 0; i < siblings.length; i++) { if (adapter.isTag(siblings[i])) { if (siblings[i] === elem) break; lastElement = siblings[i]; } } return !!lastElement && next(lastElement); }; }, universal: function (next) { return next; } }; /* compiles a selector to an executable function */ var compile_1$2 = compile$1; var parse$1 = lib.parse; var trueFunc$2 = boolbase.trueFunc; var falseFunc$3 = boolbase.falseFunc; var filters$1 = pseudos_1.filters; function compile$1(selector, options, context) { var next = compileUnsafe(selector, options, context); return wrap(next, options); } function wrap(next, options) { var adapter = options.adapter; return function base(elem) { return adapter.isTag(elem) && next(elem); }; } function compileUnsafe(selector, options, context) { var token = parse$1(selector, options); return compileToken(token, options, context); } function includesScopePseudo(t) { return t.type === "pseudo" && (t.name === "scope" || Array.isArray(t.data) && t.data.some(function (data) { return data.some(includesScopePseudo); })); } var DESCENDANT_TOKEN = { type: "descendant" }; var FLEXIBLE_DESCENDANT_TOKEN = { type: "_flexibleDescendant" }; var SCOPE_TOKEN = { type: "pseudo", name: "scope" }; var PLACEHOLDER_ELEMENT = {}; //CSS 4 Spec (Draft): 3.3.1. Absolutizing a Scope-relative Selector //http://www.w3.org/TR/selectors4/#absolutizing function absolutize(token, options, context) { var adapter = options.adapter; //TODO better check if context is document var hasContext = !!context && !!context.length && context.every(function (e) { return e === PLACEHOLDER_ELEMENT || !!adapter.getParent(e); }); token.forEach(function (t) { if (t.length > 0 && isTraversal(t[0]) && t[0].type !== "descendant") ; else if (hasContext && !(Array.isArray(t) ? t.some(includesScopePseudo) : includesScopePseudo(t))) { t.unshift(DESCENDANT_TOKEN); } else { return; } t.unshift(SCOPE_TOKEN); }); } function compileToken(token, options, context) { token = token.filter(function (t) { return t.length > 0; }); token.forEach(sort); var isArrayContext = Array.isArray(context); context = options && options.context || context; if (context && !isArrayContext) context = [context]; absolutize(token, options, context); var shouldTestNextSiblings = false; var query = token.map(function (rules) { if (rules[0] && rules[1] && rules[0].name === "scope") { var ruleType = rules[1].type; if (isArrayContext && ruleType === "descendant") { rules[1] = FLEXIBLE_DESCENDANT_TOKEN; } else if (ruleType === "adjacent" || ruleType === "sibling") { shouldTestNextSiblings = true; } } return compileRules(rules, options, context); }).reduce(reduceRules, falseFunc$3); query.shouldTestNextSiblings = shouldTestNextSiblings; return query; } function isTraversal(t) { return procedure[t.type] < 0; } function compileRules(rules, options, context) { return rules.reduce(function (func, rule) { if (func === falseFunc$3) return func; if (!(rule.type in general)) { throw new Error("Rule type " + rule.type + " is not supported by css-select"); } return general[rule.type](func, rule, options, context); }, options && options.rootFunc || trueFunc$2); } function reduceRules(a, b) { if (b === falseFunc$3 || a === trueFunc$2) { return a; } if (a === falseFunc$3 || b === trueFunc$2) { return b; } return function combine(elem) { return a(elem) || b(elem); }; } function containsTraversal(t) { return t.some(isTraversal); } //:not, :has and :matches have to compile selectors //doing this in lib/pseudos.js would lead to circular dependencies, //so we add them here filters$1.not = function (next, token, options, context) { var opts = { xmlMode: !!(options && options.xmlMode), strict: !!(options && options.strict), adapter: options.adapter }; if (opts.strict) { if (token.length > 1 || token.some(containsTraversal)) { throw new Error("complex selectors in :not aren't allowed in strict mode"); } } var func = compileToken(token, opts, context); if (func === falseFunc$3) return next; if (func === trueFunc$2) return falseFunc$3; return function not(elem) { return !func(elem) && next(elem); }; }; filters$1.has = function (next, token, options) { var adapter = options.adapter; var opts = { xmlMode: !!(options && options.xmlMode), strict: !!(options && options.strict), adapter: adapter }; //FIXME: Uses an array as a pointer to the current element (side effects) var context = token.some(containsTraversal) ? [PLACEHOLDER_ELEMENT] : null; var func = compileToken(token, opts, context); if (func === falseFunc$3) return falseFunc$3; if (func === trueFunc$2) { return function hasChild(elem) { return adapter.getChildren(elem).some(adapter.isTag) && next(elem); }; } func = wrap(func, options); if (context) { return function has(elem) { return next(elem) && (context[0] = elem, adapter.existsOne(func, adapter.getChildren(elem))); }; } return function has(elem) { return next(elem) && adapter.existsOne(func, adapter.getChildren(elem)); }; }; filters$1.matches = function (next, token, options, context) { var opts = { xmlMode: !!(options && options.xmlMode), strict: !!(options && options.strict), rootFunc: next, adapter: options.adapter }; return compileToken(token, opts, context); }; compile$1.compileToken = compileToken; compile$1.compileUnsafe = compileUnsafe; compile$1.Pseudos = pseudos_1; var cssSelect = CSSselect; var falseFunc$4 = boolbase.falseFunc; function wrapCompile(func) { return function addAdapter(selector, options, context) { options = options || {}; options.adapter = options.adapter || DomUtils__default['default']; return func(selector, options, context); }; } var compile$2 = wrapCompile(compile_1$2); var compileUnsafe$1 = wrapCompile(compile_1$2.compileUnsafe); function getSelectorFunc(searchFunc) { return function select(query, elems, options) { options = options || {}; options.adapter = options.adapter || DomUtils__default['default']; if (typeof query !== "function") { query = compileUnsafe$1(query, options, elems); } if (query.shouldTestNextSiblings) { elems = appendNextSiblings(options && options.context || elems, options.adapter); } if (!Array.isArray(elems)) elems = options.adapter.getChildren(elems);else elems = options.adapter.removeSubsets(elems); return searchFunc(query, elems, options); }; } function getNextSiblings(elem, adapter) { var siblings = adapter.getSiblings(elem); if (!Array.isArray(siblings)) return []; siblings = siblings.slice(0); while (siblings.shift() !== elem); return siblings; } function appendNextSiblings(elems, adapter) { // Order matters because jQuery seems to check the children before the siblings if (!Array.isArray(elems)) elems = [elems]; var newElems = elems.slice(0); for (var i = 0, len = elems.length; i < len; i++) { var nextSiblings = getNextSiblings(newElems[i], adapter); newElems.push.apply(newElems, nextSiblings); } return newElems; } var selectAll = getSelectorFunc(function selectAll(query, elems, options) { return query === falseFunc$4 || !elems || elems.length === 0 ? [] : options.adapter.findAll(query, elems); }); var selectOne = getSelectorFunc(function selectOne(query, elems, options) { return query === falseFunc$4 || !elems || elems.length === 0 ? null : options.adapter.findOne(query, elems); }); function is(elem, query, options) { options = options || {}; options.adapter = options.adapter || DomUtils__default['default']; return (typeof query === "function" ? query : compile$2(query, options))(elem); } /* the exported interface */ function CSSselect(query, elems, options) { return selectAll(query, elems, options); } CSSselect.compile = compile$2; CSSselect.filters = compile_1$2.Pseudos.filters; CSSselect.pseudos = compile_1$2.Pseudos.pseudos; CSSselect.selectAll = selectAll; CSSselect.selectOne = selectOne; CSSselect.is = is; //legacy methods (might be removed) CSSselect.parse = compile$2; CSSselect.iterate = selectAll; //hooks CSSselect._compileUnsafe = compileUnsafe$1; CSSselect._compileToken = compile_1$2.compileToken; const EMPTY_OBJECT = {}; function isTag(elem) { return elem.nodeType === 1; } function getChildren(elem) { return elem.childNodes ? Array.prototype.slice.call(elem.childNodes, 0) : []; } function getParent(elem) { return elem.parentNode; } function removeSubsets(nodes) { var idx = nodes.length, node, ancestor, replace; // Check if each node (or one of its ancestors) is already contained in the // array. while (--idx > -1) { node = ancestor = nodes[idx]; // Temporarily remove the node under consideration nodes[idx] = null; replace = true; while (ancestor) { if (nodes.indexOf(ancestor) > -1) { replace = false; nodes.splice(idx, 1); break; } ancestor = getParent(ancestor); } // If the node has been found to be unique, re-insert it. if (replace) { nodes[idx] = node; } } return nodes; } var adapter = { isTag: isTag, existsOne: function (test, elems) { return elems.some(function (elem) { return isTag(elem) ? test(elem) || adapter.existsOne(test, getChildren(elem)) : false; }); }, getSiblings: function (elem) { var parent = getParent(elem); return parent ? getChildren(parent) : [elem]; }, getChildren: getChildren, getParent: getParent, getAttributeValue: function (elem, name) { if (elem.attributes && name in elem.attributes) { var attr = elem.attributes[name]; return typeof attr === "string" ? attr : attr.value; } else if (name === "class" && elem.classList) { return Array.from(elem.classList).join(" "); } }, hasAttrib: function (elem, name) { return name in (elem.attributes || EMPTY_OBJECT); }, removeSubsets: removeSubsets, getName: function (elem) { return (elem.tagName || "").toLowerCase(); }, findOne: function findOne(test, arr) { var elem = null; for (var i = 0, l = arr.length; i < l && !elem; i++) { if (test(arr[i])) { elem = arr[i]; } else { var childs = getChildren(arr[i]); if (childs && childs.length > 0) { elem = findOne(test, childs); } } } return elem; }, findAll: function findAll(test, elems) { var result = []; for (var i = 0, j = elems.length; i < j; i++) { if (!isTag(elems[i])) continue; if (test(elems[i])) result.push(elems[i]); var childs = getChildren(elems[i]); if (childs) result = result.concat(findAll(test, childs)); } return result; }, getText: function getText(elem) { if (Array.isArray(elem)) return elem.map(getText).join(""); if (isTag(elem)) return getText(getChildren(elem)); if (elem.nodeType === 3) return elem.nodeValue; return ""; } }; var cssSelectBrowserAdapter = adapter; function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function (obj) { return typeof obj; }; } else { _typeof = function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymb