import boolbase from "boolbase"; /** * 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; function escapeRegex(value) { return value.replace(reChars, "\\$&"); } /** * Attributes that are case-insensitive in HTML. * * @private * @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 */ export const attributeRules = { equals(next, data, options) { const { adapter } = options; const { name } = data; let { value } = data; if (shouldIgnoreCase(data, options)) { value = value.toLowerCase(); return (elem) => { const attr = adapter.getAttributeValue(elem, name); return (attr != null && attr.length === value.length && attr.toLowerCase() === value && next(elem)); }; } return (elem) => adapter.getAttributeValue(elem, name) === value && next(elem); }, hyphen(next, data, options) { const { adapter } = options; const { name } = data; let { value } = data; const len = value.length; if (shouldIgnoreCase(data, options)) { value = value.toLowerCase(); return function hyphenIC(elem) { const 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) { const attr = adapter.getAttributeValue(elem, name); return (attr != null && (attr.length === len || attr.charAt(len) === "-") && attr.substr(0, len) === value && next(elem)); }; }, element(next, data, options) { const { adapter } = options; const { name, value } = data; if (/\s/.test(value)) { return boolbase.falseFunc; } const regex = new RegExp(`(?:^|\\s)${escapeRegex(value)}(?:$|\\s)`, shouldIgnoreCase(data, options) ? "i" : ""); return function element(elem) { const attr = adapter.getAttributeValue(elem, name); return (attr != null && attr.length >= value.length && regex.test(attr) && next(elem)); }; }, exists(next, { name }, { adapter }) { return (elem) => adapter.hasAttrib(elem, name) && next(elem); }, start(next, data, options) { const { adapter } = options; const { name } = data; let { value } = data; const len = value.length; if (len === 0) { return boolbase.falseFunc; } if (shouldIgnoreCase(data, options)) { value = value.toLowerCase(); return (elem) => { const attr = adapter.getAttributeValue(elem, name); return (attr != null && attr.length >= len && attr.substr(0, len).toLowerCase() === value && next(elem)); }; } return (elem) => { var _a; return !!((_a = adapter.getAttributeValue(elem, name)) === null || _a === void 0 ? void 0 : _a.startsWith(value)) && next(elem); }; }, end(next, data, options) { const { adapter } = options; const { name } = data; let { value } = data; const len = -value.length; if (len === 0) { return boolbase.falseFunc; } if (shouldIgnoreCase(data, options)) { value = value.toLowerCase(); return (elem) => { var _a; return ((_a = adapter .getAttributeValue(elem, name)) === null || _a === void 0 ? void 0 : _a.substr(len).toLowerCase()) === value && next(elem); }; } return (elem) => { var _a; return !!((_a = adapter.getAttributeValue(elem, name)) === null || _a === void 0 ? void 0 : _a.endsWith(value)) && next(elem); }; }, any(next, data, options) { const { adapter } = options; const { name, value } = data; if (value === "") { return boolbase.falseFunc; } if (shouldIgnoreCase(data, options)) { const regex = new RegExp(escapeRegex(value), "i"); return function anyIC(elem) { const attr = adapter.getAttributeValue(elem, name); return (attr != null && attr.length >= value.length && regex.test(attr) && next(elem)); }; } return (elem) => { var _a; return !!((_a = adapter.getAttributeValue(elem, name)) === null || _a === void 0 ? void 0 : _a.includes(value)) && next(elem); }; }, not(next, data, options) { const { adapter } = options; const { name } = data; let { value } = data; if (value === "") { return (elem) => !!adapter.getAttributeValue(elem, name) && next(elem); } else if (shouldIgnoreCase(data, options)) { value = value.toLowerCase(); return (elem) => { const attr = adapter.getAttributeValue(elem, name); return ((attr == null || attr.length !== value.length || attr.toLowerCase() !== value) && next(elem)); }; } return (elem) => adapter.getAttributeValue(elem, name) !== value && next(elem); }, }; //# sourceMappingURL=attributes.js.map