85 lines
2.0 KiB
JavaScript
85 lines
2.0 KiB
JavaScript
/*
|
|
compiles a selector to an executable function
|
|
*/
|
|
|
|
module.exports = compile;
|
|
module.exports.compileUnsafe = compileUnsafe;
|
|
|
|
var parse = require("CSSwhat"),
|
|
DomUtils = require("domutils"),
|
|
isTag = DomUtils.isTag,
|
|
Rules = require("./general.js"),
|
|
sortRules = require("./sort.js"),
|
|
BaseFuncs = require("./basefunctions.js"),
|
|
trueFunc = BaseFuncs.trueFunc,
|
|
falseFunc = BaseFuncs.falseFunc;
|
|
|
|
function compile(selector, options){
|
|
var next = compileUnsafe(selector, options);
|
|
|
|
return function base(elem){
|
|
return isTag(elem) && next(elem);
|
|
};
|
|
}
|
|
|
|
function compileUnsafe(selector, options){
|
|
return parse(selector, options)
|
|
.map(compileRules)
|
|
.reduce(reduceRules, falseFunc);
|
|
}
|
|
|
|
function compileRules(arr){
|
|
if(arr.length === 0) return falseFunc;
|
|
return sortRules(arr).reduce(function(func, rule){
|
|
if(func === falseFunc) return func;
|
|
return Rules[rule.type](func, rule);
|
|
}, trueFunc);
|
|
}
|
|
|
|
function reduceRules(a, b){
|
|
if(b === falseFunc || a === trueFunc){
|
|
return a;
|
|
}
|
|
if(a === falseFunc || b === trueFunc){
|
|
return b;
|
|
}
|
|
|
|
return function combine(elem){
|
|
return a(elem) || b(elem);
|
|
};
|
|
}
|
|
|
|
//:not and :has have to compile selectors
|
|
//doing this in lib/pseudos.js would lead to circular dependencies,
|
|
//so we add them here
|
|
|
|
var Pseudos = require("./pseudos.js"),
|
|
filters = Pseudos.filters,
|
|
isParent = Pseudos.pseudos.parent,
|
|
existsOne = DomUtils.existsOne,
|
|
getChildren = DomUtils.getChildren;
|
|
|
|
filters.not = function(next, select){
|
|
var func = compileUnsafe(select);
|
|
|
|
if(func === falseFunc) return next;
|
|
if(func === trueFunc) return falseFunc;
|
|
|
|
return function(elem){
|
|
return !func(elem) && next(elem);
|
|
};
|
|
};
|
|
|
|
filters.has = function(next, selector){
|
|
var func = compile(selector);
|
|
|
|
if(func === falseFunc) return falseFunc;
|
|
if(func === trueFunc) return function(elem){
|
|
return isParent(elem) && next(elem);
|
|
};
|
|
|
|
return function has(elem){
|
|
return next(elem) && existsOne(func, getChildren(elem));
|
|
};
|
|
};
|