blob: b2e4277148988b98aee75eb26e69aff5f163340e [file] [log] [blame]
var attributes = require("./attributes.js");
var Pseudos = require("./pseudos");
/*
all available rules
*/
module.exports = {
__proto__: null,
attribute: attributes.compile,
pseudo: Pseudos.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;
}
};