Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

css-select

Package Overview
Dependencies
Maintainers
2
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

css-select - npm Package Compare versions

Comparing version 1.3.0-rc0 to 2.0.0

index.d.ts

56

index.js

@@ -5,19 +5,32 @@ "use strict";

var DomUtils = require("domutils"),
falseFunc = require("boolbase").falseFunc,
compileFactory = require("./lib/compile.js"),
defaultCompile = compileFactory(DomUtils);
var DomUtils = require("domutils");
var falseFunc = require("boolbase").falseFunc;
var compileRaw = require("./lib/compile.js");
function adapterCompile(adapter){
return adapter === DomUtils ? defaultCompile : compileFactory(adapter);
function wrapCompile(func){
return function addAdapter(selector, options, context){
options = options || {};
options.adapter = options.adapter || DomUtils;
return func(selector, options, context);
};
}
var compile = wrapCompile(compileRaw);
var compileUnsafe = wrapCompile(compileRaw.compileUnsafe);
function getSelectorFunc(searchFunc){
return function select(query, elems, options){
options = options || {}
options = options || {};
options.adapter = options.adapter || DomUtils;
var compile = adapterCompile(options.adapter);
if(typeof query !== "function") query = compile.compileUnsafe(query, options, elems);
if(query.shouldTestNextSiblings) elems = appendNextSiblings((options && options.context) || elems, options.adapter);
if(typeof query !== "function"){
query = compileUnsafe(query, options, elems);
}
if(query.shouldTestNextSiblings){
elems = appendNextSiblings(
(options && options.context) || elems,
options.adapter
);
}
if(!Array.isArray(elems)) elems = options.adapter.getChildren(elems);

@@ -50,13 +63,16 @@ else elems = options.adapter.removeSubsets(elems);

var selectAll = getSelectorFunc(function selectAll(query, elems, options){
return (query === falseFunc || !elems || elems.length === 0) ? [] : options.adapter.findAll(query, elems);
return query === falseFunc || !elems || elems.length === 0
? []
: options.adapter.findAll(query, elems);
});
var selectOne = getSelectorFunc(function selectOne(query, elems, options){
return (query === falseFunc || !elems || elems.length === 0) ? null : options.adapter.findOne(query, elems);
return query === falseFunc || !elems || elems.length === 0
? null
: options.adapter.findOne(query, elems);
});
function is(elem, query, options){
options = options || {}
options = options || {};
options.adapter = options.adapter || DomUtils;
var compile = adapterCompile(options.adapter);
return (typeof query === "function" ? query : compile(query, options))(elem);

@@ -72,5 +88,5 @@ }

CSSselect.compile = defaultCompile;
CSSselect.filters = defaultCompile.Pseudos.filters;
CSSselect.pseudos = defaultCompile.Pseudos.pseudos;
CSSselect.compile = compile;
CSSselect.filters = compileRaw.Pseudos.filters;
CSSselect.pseudos = compileRaw.Pseudos.pseudos;

@@ -83,7 +99,7 @@ CSSselect.selectAll = selectAll;

//legacy methods (might be removed)
CSSselect.parse = defaultCompile;
CSSselect.parse = compile;
CSSselect.iterate = selectAll;
//hooks
CSSselect._compileUnsafe = defaultCompile.compileUnsafe;
CSSselect._compileToken = defaultCompile.compileToken;
CSSselect._compileUnsafe = compileUnsafe;
CSSselect._compileToken = compileRaw.compileToken;

@@ -6,177 +6,196 @@ var falseFunc = require("boolbase").falseFunc;

function factory(adapter){
/*
attribute selectors
*/
var attributeRules = {
__proto__: null,
equals: function(next, data){
var name = data.name,
value = data.value;
/*
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();
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);
return function equalsIC(elem){
var attr = adapter.getAttributeValue(elem, name);
return attr != null && attr.toLowerCase() === value && next(elem);
};
},
hyphen: function(next, data){
var name = data.name,
value = data.value,
len = value.length;
}
if(data.ignoreCase){
value = value.toLowerCase();
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;
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);
};
}
if(data.ignoreCase){
value = value.toLowerCase();
return function hyphen(elem){
return function hyphenIC(elem){
var attr = adapter.getAttributeValue(elem, name);
return attr != null &&
attr.substr(0, len) === value &&
(attr.length === len || attr.charAt(len) === "-") &&
next(elem);
return (
attr != null &&
(attr.length === len || attr.charAt(len) === "-") &&
attr.substr(0, len).toLowerCase() === value &&
next(elem)
);
};
},
element: function(next, data){
var name = data.name,
value = data.value;
}
if(/\s/.test(value)){
return falseFunc;
}
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;
value = value.replace(reChars, "\\$&");
if(/\s/.test(value)){
return falseFunc;
}
var pattern = "(?:^|\\s)" + value + "(?:$|\\s)",
flags = data.ignoreCase ? "i" : "",
regex = new RegExp(pattern, flags);
value = value.replace(reChars, "\\$&");
return function element(elem){
var attr = adapter.getAttributeValue(elem, name);
return attr != null && regex.test(attr) && next(elem);
};
},
exists: function(next, data){
var name = data.name;
return function exists(elem){
return adapter.hasAttrib(elem, name) && next(elem);
};
},
start: function(next, data){
var name = data.name,
value = data.value,
len = value.length;
var pattern = "(?:^|\\s)" + value + "(?:$|\\s)",
flags = data.ignoreCase ? "i" : "",
regex = new RegExp(pattern, flags);
if(len === 0){
return falseFunc;
}
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;
if(data.ignoreCase){
value = value.toLowerCase();
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;
return function startIC(elem){
var attr = adapter.getAttributeValue(elem, name);
return attr != null && attr.substr(0, len).toLowerCase() === value && next(elem);
};
}
if(len === 0){
return falseFunc;
}
return function start(elem){
if(data.ignoreCase){
value = value.toLowerCase();
return function startIC(elem){
var attr = adapter.getAttributeValue(elem, name);
return attr != null && attr.substr(0, len) === value && next(elem);
return (
attr != null &&
attr.substr(0, len).toLowerCase() === value &&
next(elem)
);
};
},
end: function(next, data){
var name = data.name,
value = data.value,
len = -value.length;
}
if(len === 0){
return falseFunc;
}
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(data.ignoreCase){
value = value.toLowerCase();
if(len === 0){
return falseFunc;
}
return function endIC(elem){
var attr = adapter.getAttributeValue(elem, name);
return attr != null && attr.substr(len).toLowerCase() === value && next(elem);
};
}
if(data.ignoreCase){
value = value.toLowerCase();
return function end(elem){
return function endIC(elem){
var attr = adapter.getAttributeValue(elem, name);
return attr != null && attr.substr(len) === value && next(elem);
return (
attr != null && attr.substr(len).toLowerCase() === value && next(elem)
);
};
},
any: function(next, data){
var name = data.name,
value = data.value;
}
if(value === ""){
return falseFunc;
}
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(data.ignoreCase){
var regex = new RegExp(value.replace(reChars, "\\$&"), "i");
if(value === ""){
return falseFunc;
}
return function anyIC(elem){
var attr = adapter.getAttributeValue(elem, name);
return attr != null && regex.test(attr) && next(elem);
};
}
if(data.ignoreCase){
var regex = new RegExp(value.replace(reChars, "\\$&"), "i");
return function any(elem){
return function anyIC(elem){
var attr = adapter.getAttributeValue(elem, name);
return attr != null && attr.indexOf(value) >= 0 && next(elem);
return attr != null && regex.test(attr) && next(elem);
};
},
not: function(next, data){
var name = data.name,
value = data.value;
}
if(value === ""){
return function notEmpty(elem){
return !!adapter.getAttributeValue(elem, name) && next(elem);
};
} else if(data.ignoreCase){
value = value.toLowerCase();
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;
return function notIC(elem){
var attr = adapter.getAttributeValue(elem, name);
return attr != null && attr.toLowerCase() !== value && next(elem);
};
}
if(value === ""){
return function notEmpty(elem){
return !!adapter.getAttributeValue(elem, name) && next(elem);
};
} else if(data.ignoreCase){
value = value.toLowerCase();
return function not(elem){
return adapter.getAttributeValue(elem, name) !== value && next(elem);
return function notIC(elem){
var attr = adapter.getAttributeValue(elem, name);
return attr != null && attr.toLowerCase() !== value && next(elem);
};
}
};
return {
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);
},
rules: attributeRules
};
}
return function not(elem){
return adapter.getAttributeValue(elem, name) !== value && next(elem);
};
}
};
module.exports = factory;
module.exports = {
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
};

@@ -5,204 +5,224 @@ /*

module.exports = compileFactory;
module.exports = compile;
var parse = require("css-what"),
BaseFuncs = require("boolbase"),
sortRules = require("./sort.js"),
procedure = require("./procedure.json"),
rulesFactory = require("./general.js"),
pseudosFactory = require("./pseudos.js"),
trueFunc = BaseFuncs.trueFunc,
falseFunc = BaseFuncs.falseFunc;
var parse = require("css-what");
var BaseFuncs = require("boolbase");
var sortRules = require("./sort.js");
var procedure = require("./procedure.json");
var Rules = require("./general.js");
var Pseudos = require("./pseudos.js");
var trueFunc = BaseFuncs.trueFunc;
var falseFunc = BaseFuncs.falseFunc;
function compileFactory(adapter){
var Pseudos = pseudosFactory(adapter),
filters = Pseudos.filters,
Rules = rulesFactory(adapter, Pseudos);
var filters = Pseudos.filters;
function compile(selector, options, context){
var next = compileUnsafe(selector, options, context);
return wrap(next);
}
function compile(selector, options, context){
var next = compileUnsafe(selector, options, context);
return wrap(next, options);
}
function wrap(next){
return function base(elem){
return adapter.isTag(elem) && next(elem);
};
}
function wrap(next, options){
var adapter = options.adapter;
function compileUnsafe(selector, options, context){
var token = parse(selector, options);
return compileToken(token, options, context);
}
return function base(elem){
return adapter.isTag(elem) && next(elem);
};
}
function includesScopePseudo(t){
return t.type === "pseudo" && (
t.name === "scope" || (
Array.isArray(t.data) &&
function compileUnsafe(selector, options, context){
var token = parse(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"},
FLEXIBLE_DESCENDANT_TOKEN = {type: "_flexibleDescendant"},
SCOPE_TOKEN = {type: "pseudo", name: "scope"},
PLACEHOLDER_ELEMENT = {};
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, context){
//TODO better check if context is document
var hasContext = !!context && !!context.length && context.every(function(e){
//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"){
//don't return in else branch
} else if(hasContext && !includesScopePseudo(t)){
t.unshift(DESCENDANT_TOKEN);
} else {
return;
}
token.forEach(function(t){
if(t.length > 0 && isTraversal(t[0]) && t[0].type !== "descendant"){
//don't return in else branch
} else if(hasContext && !includesScopePseudo(t)){
t.unshift(DESCENDANT_TOKEN);
} else {
return;
}
t.unshift(SCOPE_TOKEN);
});
}
t.unshift(SCOPE_TOKEN);
});
}
function compileToken(token, options, context){
token = token.filter(function(t){
return t.length > 0;
});
function compileToken(token, options, context){
token = token.filter(function(t){ return t.length > 0; });
token.forEach(sortRules);
token.forEach(sortRules);
var isArrayContext = Array.isArray(context);
var isArrayContext = Array.isArray(context);
context = (options && options.context) || context;
context = (options && options.context) || context;
if(context && !isArrayContext) context = [context];
if(context && !isArrayContext) context = [context];
absolutize(token, options, context);
absolutize(token, context);
var shouldTestNextSiblings = false;
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;
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);
}
return compileRules(rules, options, context);
})
.reduce(reduceRules, falseFunc);
query.shouldTestNextSiblings = shouldTestNextSiblings;
query.shouldTestNextSiblings = shouldTestNextSiblings;
return query;
}
return query;
}
function isTraversal(t){
return procedure[t.type] < 0;
}
function isTraversal(t){
return procedure[t.type] < 0;
}
function compileRules(rules, options, context){
return rules.reduce(function(func, rule){
if(func === falseFunc) return func;
return Rules[rule.type](func, rule, options, context);
}, options && options.rootFunc || trueFunc);
}
function compileRules(rules, options, context){
return rules.reduce(function(func, rule){
if(func === falseFunc) return func;
function reduceRules(a, b){
if(b === falseFunc || a === trueFunc){
return a;
if(!(rule.type in Rules)){
throw new Error(
"Rule type " + rule.type + " is not supported by css-select"
);
}
if(a === falseFunc || b === trueFunc){
return b;
}
return function combine(elem){
return a(elem) || b(elem);
};
}
return Rules[rule.type](func, rule, options, context);
}, (options && options.rootFunc) || trueFunc);
}
function containsTraversal(t){
return t.some(isTraversal);
function reduceRules(a, b){
if(b === falseFunc || a === trueFunc){
return a;
}
if(a === falseFunc || b === trueFunc){
return b;
}
//: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.not = function(next, token, options, context){
var opts = {
xmlMode: !!(options && options.xmlMode),
strict: !!(options && options.strict)
};
return function combine(elem){
return a(elem) || b(elem);
};
}
if(opts.strict){
if(token.length > 1 || token.some(containsTraversal)){
throw new Error("complex selectors in :not aren't allowed in strict mode");
}
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.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);
var func = compileToken(token, opts, context);
if(func === falseFunc) return next;
if(func === trueFunc) return falseFunc;
if(func === falseFunc) return next;
if(func === trueFunc) return falseFunc;
return function(elem){
return !func(elem) && next(elem);
};
return function not(elem){
return !func(elem) && next(elem);
};
};
filters.has = function(next, token, options){
var opts = {
xmlMode: !!(options && options.xmlMode),
strict: !!(options && options.strict)
};
filters.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;
//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);
var func = compileToken(token, opts, context);
if(func === falseFunc) return falseFunc;
if(func === trueFunc){
return function(elem){
return adapter.getChildren(elem).some(adapter.isTag) && next(elem);
};
}
if(func === falseFunc) return falseFunc;
if(func === trueFunc){
return function hasChild(elem){
return adapter.getChildren(elem).some(adapter.isTag) && next(elem);
};
}
func = wrap(func);
func = wrap(func, options);
if(context){
return function has(elem){
return next(elem) && (
(context[0] = elem), adapter.existsOne(func, adapter.getChildren(elem))
);
};
}
if(context){
return function has(elem){
return next(elem) && adapter.existsOne(func, adapter.getChildren(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.matches = function(next, token, options, context){
var opts = {
xmlMode: !!(options && options.xmlMode),
strict: !!(options && options.strict),
rootFunc: next
};
return compileToken(token, opts, context);
filters.matches = function(next, token, options, context){
var opts = {
xmlMode: !!(options && options.xmlMode),
strict: !!(options && options.strict),
rootFunc: next,
adapter: options.adapter
};
compile.compileToken = compileToken;
compile.compileUnsafe = compileUnsafe;
compile.Pseudos = Pseudos;
return compileToken(token, opts, context);
};
return compile;
}
compile.compileToken = compileToken;
compile.compileUnsafe = compileUnsafe;
compile.Pseudos = Pseudos;

@@ -1,99 +0,117 @@

var attributeFactory = require("./attributes.js");
var attributes = require("./attributes.js");
var Pseudos = require("./pseudos");
function generalFactory(adapter, Pseudos){
/*
all available rules
*/
return {
__proto__: null,
/*
all available rules
*/
module.exports = {
__proto__: null,
attribute: attributeFactory(adapter).compile,
pseudo: Pseudos.compile,
attribute: attributes.compile,
pseudo: Pseudos.compile,
//tags
tag: function(next, data){
var name = data.name;
return function tag(elem){
return adapter.getName(elem) === name && next(elem);
};
},
//tags
tag: function(next, data, options){
var name = data.name;
var adapter = options.adapter;
//traversal
descendant: function(next){
return function descendant(elem){
return function tag(elem){
return adapter.getName(elem) === name && next(elem);
};
},
var found = false;
//traversal
descendant: function(next, data, options){
// eslint-disable-next-line no-undef
var isFalseCache = typeof WeakSet !== "undefined" ? new WeakSet() : null;
var adapter = options.adapter;
while(!found && (elem = adapter.getParent(elem))){
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){
// Include element itself, only used while querying an array
return function descendant(elem){
return found;
};
},
_flexibleDescendant: function(next, data, options){
var adapter = options.adapter;
var found = next(elem);
// 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);
}
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");
return found;
};
},
parent: function(next, data, options){
if(options && options.strict){
throw new Error("Parent selector isn't part of CSS3");
}
return function parent(elem){
return adapter.getChildren(elem).some(test);
};
var adapter = options.adapter;
function test(elem){
return adapter.isTag(elem) && next(elem);
}
},
child: function(next){
return function child(elem){
var parent = adapter.getParent(elem);
return !!parent && next(parent);
};
},
sibling: function(next){
return function sibling(elem){
var siblings = adapter.getSiblings(elem);
return function parent(elem){
return adapter.getChildren(elem).some(test);
};
for(var i = 0; i < siblings.length; i++){
if(adapter.isTag(siblings[i])){
if(siblings[i] === elem) break;
if(next(siblings[i])) return true;
}
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){
return function adjacent(elem){
var siblings = adapter.getSiblings(elem),
lastElement;
return false;
};
},
adjacent: function(next, data, options){
var adapter = options.adapter;
for(var i = 0; i < siblings.length; i++){
if(adapter.isTag(siblings[i])){
if(siblings[i] === elem) break;
lastElement = siblings[i];
}
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;
}
};
}
module.exports = generalFactory;
return !!lastElement && next(lastElement);
};
},
universal: function(next){
return next;
}
};
{
"universal": 50,
"tag": 30,
"attribute": 1,
"pseudo": 0,
"descendant": -1,
"child": -1,
"parent": -1,
"sibling": -1,
"adjacent": -1
"universal": 50,
"tag": 30,
"attribute": 1,
"pseudo": 0,
"descendant": -1,
"child": -1,
"parent": -1,
"sibling": -1,
"adjacent": -1
}

@@ -14,345 +14,362 @@ /*

var getNCheck = require("nth-check"),
BaseFuncs = require("boolbase"),
attributesFactory = require("./attributes.js"),
trueFunc = BaseFuncs.trueFunc,
falseFunc = BaseFuncs.falseFunc;
var getNCheck = require("nth-check");
var BaseFuncs = require("boolbase");
var attributes = require("./attributes.js");
var trueFunc = BaseFuncs.trueFunc;
var falseFunc = BaseFuncs.falseFunc;
function filtersFactory(adapter){
var attributes = attributesFactory(adapter),
checkAttrib = attributes.rules.equals;
var checkAttrib = attributes.rules.equals;
//helper methods
function equals(a, b){
if(typeof adapter.equals === "function") return adapter.equals(a, b);
function getAttribFunc(name, value){
var data = { name: name, value: value };
return function attribFunc(next, rule, options){
return checkAttrib(next, data, options);
};
}
return a === b;
}
function getChildFunc(next, adapter){
return function(elem){
return !!adapter.getParent(elem) && next(elem);
};
}
function getAttribFunc(name, value){
var data = {name: name, value: value};
return function attribFunc(next){
return checkAttrib(next, data);
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;
function getChildFunc(next){
return function(elem){
return !!adapter.getParent(elem) && next(elem);
return function icontains(elem){
return (
next(elem) &&
adapter
.getText(elem)
.toLowerCase()
.indexOf(itext) >= 0
);
};
}
},
var filters = {
contains: function(next, text){
return function contains(elem){
return next(elem) && adapter.getText(elem).indexOf(text) >= 0;
};
},
icontains: function(next, text){
var itext = text.toLowerCase();
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 = getNCheck(rule);
var adapter = options.adapter;
//location specific methods
"nth-child": function(next, rule){
var func = getNCheck(rule);
if(func === falseFunc) return func;
if(func === trueFunc) return getChildFunc(next, adapter);
if(func === falseFunc) return func;
if(func === trueFunc) return getChildFunc(next);
return function nthChild(elem){
var siblings = adapter.getSiblings(elem);
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++;
}
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){
var func = getNCheck(rule);
return func(pos) && next(elem);
};
},
"nth-last-child": function(next, rule, options){
var func = getNCheck(rule);
var adapter = options.adapter;
if(func === falseFunc) return func;
if(func === trueFunc) return getChildFunc(next);
if(func === falseFunc) return func;
if(func === trueFunc) return getChildFunc(next, adapter);
return function nthLastChild(elem){
var siblings = adapter.getSiblings(elem);
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++;
}
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){
var func = getNCheck(rule);
return func(pos) && next(elem);
};
},
"nth-of-type": function(next, rule, options){
var func = getNCheck(rule);
var adapter = options.adapter;
if(func === falseFunc) return func;
if(func === trueFunc) return getChildFunc(next);
if(func === falseFunc) return func;
if(func === trueFunc) return getChildFunc(next, adapter);
return function nthOfType(elem){
var siblings = adapter.getSiblings(elem);
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++;
}
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){
var func = getNCheck(rule);
return func(pos) && next(elem);
};
},
"nth-last-of-type": function(next, rule, options){
var func = getNCheck(rule);
var adapter = options.adapter;
if(func === falseFunc) return func;
if(func === trueFunc) return getChildFunc(next);
if(func === falseFunc) return func;
if(func === trueFunc) return getChildFunc(next, adapter);
return function nthLastOfType(elem){
var siblings = adapter.getSiblings(elem);
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++;
}
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);
};
},
return func(pos) && next(elem);
};
},
//TODO determine the actual root element
root: function(next){
return function(elem){
return !adapter.getParent(elem) && next(elem);
};
},
//TODO determine the actual root element
root: function(next, rule, options){
var adapter = options.adapter;
scope: function(next, rule, options, context){
if(!context || context.length === 0){
//equivalent to :root
return filters.root(next);
}
return function(elem){
return !adapter.getParent(elem) && next(elem);
};
},
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);
};
}
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 context.indexOf(elem) >= 0 && next(elem);
return equals(context[0], elem) && 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")
};
return filters;
}
return function(elem){
return context.indexOf(elem) >= 0 && next(elem);
};
},
function pseudosFactory(adapter){
//helper methods
function getFirstElement(elems){
for(var i = 0; elems && i < elems.length; i++){
if(adapter.isTag(elems[i])) return elems[i];
}
//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")
};
//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){
return !adapter.getChildren(elem).some(function(elem){
return adapter.isTag(elem) || elem.type === "text";
});
},
//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){
return getFirstElement(adapter.getSiblings(elem)) === elem;
},
"last-child": function(elem){
var siblings = adapter.getSiblings(elem);
"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;
}
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){
var siblings = adapter.getSiblings(elem);
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;
}
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){
var siblings = adapter.getSiblings(elem);
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;
}
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){
var siblings = adapter.getSiblings(elem);
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;
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){
var siblings = adapter.getSiblings(elem);
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;
}
for(var i = 0; i < siblings.length; i++){
if(adapter.isTag(siblings[i]) && siblings[i] !== elem) return false;
}
return true;
},
return true;
},
//:matches(a, area, link)[href]
link: function(elem){
return adapter.hasAttrib(elem, "href");
},
visited: falseFunc, //seems to be a valid implementation
//TODO: :any-link once the name is finalized (as an alias of :link)
//:matches(a, area, link)[href]
link: function(elem, adapter){
return adapter.hasAttrib(elem, "href");
},
visited: falseFunc, //Valid implementation
//TODO: :any-link once the name is finalized (as an alias of :link)
//forms
//to consider: :target
//forms
//to consider: :target
//:matches([selected], select:not([multiple]):not(> option[selected]) > option:first-of-type)
selected: function(elem){
if(adapter.hasAttrib(elem, "selected")) return true;
else if(adapter.getName(elem) !== "option") return false;
//: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);
//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;
if(
!parent ||
adapter.getName(parent) !== "select" ||
adapter.hasAttrib(parent, "multiple")
){
return false;
}
var siblings = adapter.getChildren(parent),
sawElem = 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;
}
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){
return adapter.hasAttrib(elem, "disabled");
},
enabled: function(elem){
return !adapter.hasAttrib(elem, "disabled");
},
//:matches(:matches(:radio, :checkbox)[checked], :selected) (TODO menuitem)
checked: function(elem){
return adapter.hasAttrib(elem, "checked") || pseudos.selected(elem);
},
//:matches(input, select, textarea)[required]
required: function(elem){
return adapter.hasAttrib(elem, "required");
},
//:matches(input, select, textarea):not([required])
optional: function(elem){
return !adapter.hasAttrib(elem, "required");
},
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
//jQuery extensions
//:not(:empty)
parent: function(elem){
return !pseudos.empty(elem);
},
//:matches(h1, h2, h3, h4, h5, h6)
header: function(elem){
var name = adapter.getName(elem);
return name === "h1" ||
name === "h2" ||
name === "h3" ||
name === "h4" ||
name === "h5" ||
name === "h6";
},
//: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){
var name = adapter.getName(elem);
return name === "button" ||
name === "input" &&
adapter.getAttributeValue(elem, "type") === "button";
},
//:matches(input, textarea, select, button)
input: function(elem){
var name = adapter.getName(elem);
return name === "input" ||
name === "textarea" ||
name === "select" ||
name === "button";
},
//input:matches(:not([type!='']), [type='text' i])
text: function(elem){
var attr;
return adapter.getName(elem) === "input" && (
!(attr = adapter.getAttributeValue(elem, "type")) ||
attr.toLowerCase() === "text"
);
}
//: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;
};
return pseudos;
}

@@ -362,8 +379,10 @@

if(subselect === null){
if(func.length > 1 && name !== "scope"){
if(func.length > 2 && name !== "scope"){
throw new Error("pseudo-selector :" + name + " requires an argument");
}
} else {
if(func.length === 1){
throw new Error("pseudo-selector :" + name + " doesn't have any arguments");
if(func.length === 2){
throw new Error(
"pseudo-selector :" + name + " doesn't have any arguments"
);
}

@@ -376,36 +395,37 @@ }

function factory(adapter){
var pseudos = pseudosFactory(adapter);
var filters = filtersFactory(adapter);
module.exports = {
compile: function(next, data, options, context){
var name = data.name;
var subselect = data.data;
var adapter = options.adapter;
return {
compile: function(next, data, options, context){
var name = data.name,
subselect = data.data;
if(options && options.strict && !re_CSS3.test(name)){
throw new Error(":" + name + " isn't part of CSS3");
}
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){
return func;
}
if(typeof filters[name] === "function"){
verifyArgs(filters[name], name, subselect);
return filters[name](next, subselect, options, context);
} else if(typeof pseudos[name] === "function"){
var func = pseudos[name];
verifyArgs(func, name, subselect);
if(next === trueFunc) return func;
return function pseudoArgs(elem){
return func(elem, subselect) && next(elem);
if(next === trueFunc){
return function pseudoRoot(elem){
return func(elem, adapter, subselect);
};
} else {
throw new Error("unmatched pseudo-class :" + name);
}
},
filters: filters,
pseudos: pseudos
};
}
module.exports = factory;
return function pseudoArgs(elem){
return func(elem, adapter, subselect) && next(elem);
};
} else {
throw new Error("unmatched pseudo-class :" + name);
}
},
filters: filters,
pseudos: pseudos
};
{
"name": "css-select",
"version": "1.3.0-rc0",
"version": "2.0.0",
"description": "a CSS selector compiler/engine",

@@ -17,2 +17,3 @@ "author": "Felix Boehm <me@feedic.com>",

"index.js",
"index.d.ts",
"lib"

@@ -23,14 +24,14 @@ ],

"css-what": "2.1",
"domutils": "1.5.1",
"domutils": "^1.7.0",
"nth-check": "^1.0.1"
},
"devDependencies": {
"cheerio-soupselect": "*",
"coveralls": "*",
"eslint": "^3.0.0",
"expect.js": "*",
"htmlparser2": "*",
"istanbul": "*",
"mocha": "*",
"mocha-lcov-reporter": "*"
"cheerio-soupselect": "^0.1.1",
"coveralls": "^3.0.0",
"eslint": "^4.18.2",
"expect.js": "^0.3.1",
"htmlparser2": "^3.9.2",
"istanbul": "^0.4.5",
"mocha": "^5.0.4",
"mocha-lcov-reporter": "^1.3.0"
},

@@ -43,3 +44,4 @@ "scripts": {

},
"license": "BSD-like"
"license": "BSD-like",
"types": "index.d.ts"
}

@@ -60,5 +60,7 @@ # css-select [![NPM version](http://img.shields.io/npm/v/css-select.svg)](https://npmjs.org/package/css-select) [![Build Status](https://travis-ci.org/fb55/css-select.svg?branch=master)](http://travis-ci.org/fb55/css-select) [![Downloads](https://img.shields.io/npm/dm/css-select.svg)](https://npmjs.org/package/css-select) [![Coverage](https://coveralls.io/repos/fb55/css-select/badge.svg?branch=master)](https://coveralls.io/r/fb55/css-select)

```js
var CSSselect = require("css-select");
const CSSselect = require("css-select");
```
__Note:__ css-select throws errors when invalid selectors are passed to it, contrary to the behavior in browsers, which swallow them. This is done to aid with writing css selectors, but can be unexpected when processing arbitrary strings.
#### `CSSselect(query, elems, options)`

@@ -65,0 +67,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc