You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
122 lines
2.7 KiB
JavaScript
122 lines
2.7 KiB
JavaScript
'use strict';
|
|
const CSSselect = require('css-select');
|
|
|
|
const {ELEMENT_NODE, TEXT_NODE} = require('./constants.js');
|
|
const {ignoreCase} = require('./utils.js');
|
|
|
|
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) => CSSselect.compile(
|
|
selectors,
|
|
{
|
|
context: selectors.includes(':scope') ? element : void 0,
|
|
xmlMode: !ignoreCase(element),
|
|
adapter
|
|
}
|
|
);
|
|
exports.prepareMatch = prepareMatch;
|
|
|
|
const matches = (element, selectors) => CSSselect.is(
|
|
element,
|
|
selectors,
|
|
{
|
|
strict: true,
|
|
context: selectors.includes(':scope') ? element : void 0,
|
|
xmlMode: !ignoreCase(element),
|
|
adapter
|
|
}
|
|
);
|
|
exports.matches = matches;
|