cssauron
Advanced tools
Comparing version 0.2.1 to 1.0.0
89
index.js
@@ -14,3 +14,3 @@ module.exports = language | ||
opts[key] = Function( | ||
'return function(node, attr) { return node.'+opts[key]+' }' | ||
'return function(node, attr) { return node.' + opts[key] + ' }' | ||
) | ||
@@ -29,2 +29,3 @@ opts[key] = opts[key]() | ||
var stream = tokenizer() | ||
, default_subj = true | ||
, selectors = [[]] | ||
@@ -45,5 +46,7 @@ , traversal | ||
.on('data', group) | ||
.end(selector) | ||
.end(selector) | ||
function group(token) { | ||
var crnt | ||
if(token.type === 'comma') { | ||
@@ -62,15 +65,31 @@ selectors.unshift(bits = []) | ||
(bits[0] = bits[0] || check()).bits.push( | ||
bits[0] = bits[0] || check() | ||
crnt = bits[0] | ||
if(token.type === '!') { | ||
crnt.subject = | ||
selectors[0].subject = true | ||
return | ||
} | ||
crnt.push( | ||
token.type === 'attr' ? attr(token) : | ||
token.type === ':' || token.type === '::' ? pseudo(token) : | ||
token.type === '*' ? Boolean : matches(token.type, token.data) | ||
token.type === '*' ? Boolean : | ||
matches(token.type, token.data) | ||
) | ||
} | ||
return function(node) { | ||
return selector_fn | ||
function selector_fn(node, as_boolean) { | ||
var current | ||
, length | ||
, orig | ||
, subj | ||
, set | ||
orig = node | ||
set = [] | ||
@@ -82,5 +101,6 @@ for(var i = 0, len = selectors.length; i < len; ++i) { | ||
node = orig | ||
subj = [] | ||
for(var j = 0; j < length; j += 2) { | ||
node = current(node, bits[j]) | ||
node = current(node, bits[j], subj) | ||
@@ -95,7 +115,29 @@ if(!node) { | ||
if(j >= length) { | ||
return true | ||
if(as_boolean) { | ||
return true | ||
} | ||
add(!bits.subject ? [orig] : subj) | ||
} | ||
} | ||
return false | ||
if(as_boolean) { | ||
return false | ||
} | ||
return !set.length ? false : | ||
set.length === 1 ? set[0] : | ||
set | ||
function add(items) { | ||
var next | ||
while(items.length) { | ||
next = items.shift() | ||
if(set.indexOf(next) === -1) { | ||
set.push(next) | ||
} | ||
} | ||
} | ||
} | ||
@@ -105,2 +147,3 @@ | ||
_check.bits = [] | ||
_check.subject = false | ||
_check.push = function(token) { | ||
@@ -112,3 +155,3 @@ _check.bits.push(token) | ||
function _check(node) { | ||
function _check(node, subj) { | ||
for(var i = 0, len = _check.bits.length; i < len; ++i) { | ||
@@ -120,2 +163,6 @@ if(!_check.bits[i](node)) { | ||
if(_check.subject) { | ||
subj.push(node) | ||
} | ||
return true | ||
@@ -142,6 +189,6 @@ } | ||
function any_parents(node, next) { | ||
do { | ||
function any_parents(node, next, subj) { | ||
do { | ||
node = options.parent(node) | ||
} while(node && !next(node)) | ||
} while(node && !next(node, subj)) | ||
@@ -151,9 +198,9 @@ return node | ||
function direct_parent(node, next) { | ||
function direct_parent(node, next, subj) { | ||
node = options.parent(node) | ||
return node && next(node) ? node : null | ||
return node && next(node, subj) ? node : null | ||
} | ||
function direct_sibling(node, next) { | ||
function direct_sibling(node, next, subj) { | ||
var parent = options.parent(node) | ||
@@ -173,3 +220,3 @@ , idx = 0 | ||
return children[idx - 1] && next(children[idx - 1]) ? | ||
return children[idx - 1] && next(children[idx - 1], subj) ? | ||
children[idx - 1] : | ||
@@ -179,3 +226,3 @@ null | ||
function any_sibling(node, next) { | ||
function any_sibling(node, next, subj) { | ||
var parent = options.parent(node) | ||
@@ -191,3 +238,3 @@ , children | ||
if(next(children[i])) { | ||
if(next(children[i], subj)) { | ||
return children[i] | ||
@@ -206,4 +253,4 @@ } | ||
function entry(node, next) { | ||
return next(node) ? node : null | ||
function entry(node, next, subj) { | ||
return next(node, subj) ? node : null | ||
} | ||
@@ -246,3 +293,3 @@ | ||
if(cmp.length == 1) { | ||
if(cmp.length === 1) { | ||
return attr == rhs | ||
@@ -249,0 +296,0 @@ } |
{ | ||
"name": "cssauron", | ||
"version": "0.2.1", | ||
"version": "1.0.0", | ||
"description": "create matching selectors from css for your very own nested object hierarchy", | ||
@@ -26,3 +26,6 @@ "main": "index.js", | ||
"through": "X.X.X" | ||
}, | ||
"devDependencies": { | ||
"tape": "~2.0.0" | ||
} | ||
} |
@@ -51,6 +51,29 @@ # cssauron | ||
### match(node) -> true or false | ||
### match(node) -> false | node | [subjects, ...] | ||
Returns true or false depending on whether the provided node matches the selector. | ||
Returns false if the provided node matches the selector. Returns truthy if the provided | ||
node *does* match. Exact return value is determined by the selector, based on | ||
the [CSS4 subject selector spec](http://dev.w3.org/csswg/selectors4/#subject): if only | ||
a single node is matched, only that node is returned. If multiple subjects are matched, | ||
a deduplicated array of those subjects are returned. | ||
For example, given the following HTML (and `cssauron-html`): | ||
```html | ||
<div id="gary-busey"> | ||
<p> | ||
<span class="jake-busey"> | ||
</span> | ||
</p> | ||
</div> | ||
``` | ||
Checking the following selectors against the `span.jake-busey` element yields: | ||
`#gary-busey`: `false`, no match. | ||
`#gary-busey *`: `span.jake-busey`, a single match. | ||
`!#gary-busey *`: `div#gary-busey`, a single match using the `!` subject selector. | ||
`#gary-busey *, p span`: `span.jake-busey`, a single match, though both selectors match. | ||
`#gary-busey !* !*, !p > !span`: `[p, span.jake-busey]`, two matches. | ||
## Supported pseudoclasses | ||
@@ -57,0 +80,0 @@ |
@@ -1,27 +0,20 @@ | ||
var assert = require('assert') | ||
, cssauron = require('../index') | ||
var cssauron = require('../index') | ||
, test = require('tape') | ||
, language | ||
var tests = [ | ||
test_select_single // all of the selectors by themselves | ||
, test_select_multiple // all of the combinators | ||
] | ||
language = cssauron({ | ||
id: 'id' | ||
, class: 'class' | ||
, tag: 'tag' | ||
, attr: 'attr[attr]' | ||
, parent: 'parent' | ||
, children: 'children' | ||
, contents: 'contents || ""' | ||
}) | ||
start() | ||
test('select single', test_select_single) | ||
test('select multiple', test_select_multiple) | ||
test('select subject', test_select_subject) | ||
function setup() { | ||
language = cssauron({ | ||
id: 'id' | ||
, class: 'class' | ||
, tag: 'tag' | ||
, attr: 'attr[attr]' | ||
, parent: 'parent' | ||
, children: 'children' | ||
, contents: 'contents || ""' | ||
}) | ||
} | ||
// integration tests because reasons. | ||
function test_select_single() { | ||
function test_select_single(assert) { | ||
var data = {id: 'one-id', class: 'one-class', tag: 'one-tag', attr:{first: 'test', second:'gary busey', third:'richard-m-nixon'}, parent:null, children:[]} | ||
@@ -35,5 +28,6 @@ | ||
assert.ok(!language('two-tag')(data)) | ||
assert.end() | ||
} | ||
function test_select_multiple() { | ||
function test_select_multiple(assert) { | ||
var data = {id: 'one-id', class: 'one-class', tag: 'one-tag', attr:{first: 'test', second:'gary busey', third:'richard-m-nixon'}, parent:null, children:[]} | ||
@@ -56,4 +50,10 @@ , data2 = {id: 'two-id', class: 'two-class', tag: 'two-tag', attr:{first: 'test', second:'gary busey', third:'richard-m-nixon'}, parent:null, children:[]} | ||
assert.ok(language('#root-id > #parent-id > #one-id')(data)) | ||
assert.ok(language('#parent-id > #one-id,\n#root-id > #parent-id > #one-id')(data)) | ||
assert.ok(language('#ok,\n #parent-id > #one-id,\n#root-id > #parent-id > #one-id')(data)) | ||
assert.ok( | ||
language('#parent-id > #one-id,\n#root-id > #parent-id > #one-id')(data) | ||
) | ||
assert.ok( | ||
language( | ||
'#ok,\n #parent-id > #one-id,\n#root-id > #parent-id > #one-id' | ||
)(data) | ||
) | ||
assert.ok(language('.one-class + .two-class')(data2)) | ||
@@ -86,71 +86,71 @@ assert.ok(!language('.one-class + #one-id')(data)) | ||
assert.ok(language(':contains(world)')(data2)) | ||
assert.ok( | ||
language(':root > :any(thing-tag, parent-tag, #asdf) > #one-id')(data) | ||
) | ||
assert.end() | ||
} | ||
// utils | ||
function test_select_subject(assert) { | ||
var data = {id: 'one-id', class: 'one-class', tag: 'one-tag', attr:{first: 'test', second:'gary busey', third:'richard-m-nixon'}, parent:null, children:[]} | ||
, data2 = {id: 'two-id', class: 'two-class', tag: 'two-tag', attr:{first: 'test', second:'gary busey', third:'richard-m-nixon'}, parent:null, children:[]} | ||
, data3 = {id: 'three-id', class: 'three-class', tag: 'three-tag', attr:{first: 'test', second:'gary busey', third:'richard-m-nixon'}, parent:null, children:[]} | ||
, parent = {id: 'parent-id', class: 'parent-class', tag: 'parent-tag', attr:{first: 'test', second:'gary busey', third:'richard-m-nixon'}, parent:null, children:[data, data2, data3]} | ||
, root = {id: 'root-id', class: 'root-class', tag: 'root-tag', attr:{first: 'test', second:'gary busey', third:'richard-m-nixon'}, parent:null, children:[parent]} | ||
, res | ||
function out(what) { | ||
process.stdout.write(what) | ||
} | ||
data.parent = parent | ||
data2.parent = parent | ||
data3.parent = parent | ||
data2.contents = 'hello world' | ||
parent.parent = root | ||
// test runner | ||
assert.equal( | ||
language(':root > :any(thing-tag, parent-tag, #asdf) > #one-id')(data) | ||
, data | ||
) | ||
function start() { | ||
Function.prototype.before = function(fn) { | ||
var self = this | ||
return function ret() { | ||
var args = [].slice.call(arguments) | ||
fn.call(ret, args) | ||
assert.equal( | ||
language(':root > !parent-tag > #one-id')(data) | ||
, parent | ||
) | ||
return self.apply(this, args) | ||
} | ||
} | ||
res = language( | ||
':root > !:any(thing-tag, parent-tag, #asdf) > !#one-id' | ||
)(data) | ||
if(typeof window !== 'undefined') { | ||
out = function(s) { | ||
out.buf = (out.buf || '') + s | ||
if(!!~s.indexOf('\n')) { | ||
console.log(out.buf) | ||
out.buf = '' | ||
} | ||
} | ||
} | ||
run() | ||
} | ||
assert.equal( | ||
res[0] | ||
, data | ||
) | ||
function run() { | ||
if(!tests.length) | ||
return out('\n') | ||
assert.equal( | ||
res[1] | ||
, parent | ||
) | ||
var test = tests.shift() | ||
, now = Date.now() | ||
// one of these has a subject, one doesn't | ||
res = language( | ||
':root > parent-tag > #one-id, !#root-id *' | ||
)(data) | ||
setup() | ||
assert.equal( | ||
res[0] | ||
, root | ||
) | ||
out(test.name+' - ') | ||
test.length ? test(done) : (test(), done()) | ||
assert.equal( | ||
res[1] | ||
, data | ||
) | ||
function done() { | ||
out(''+(Date.now() - now)+'ms\n') | ||
run() | ||
} | ||
} | ||
// no duplicates, no matter how many valid selections. | ||
// both sides select `data`. | ||
res = language( | ||
':root > parent-tag > #one-id, #root-id !*' | ||
)(data) | ||
function pathed(path, value) { | ||
var root = {} | ||
, obj = root | ||
, bits = path.split('.') | ||
assert.equal(res, data) | ||
while(bits.length > 1) { | ||
(obj = obj[bits.shift()] = {}) | ||
} | ||
obj[bits.shift()] = value | ||
return root | ||
assert.end() | ||
} | ||
@@ -17,2 +17,3 @@ module.exports = tokenize | ||
, ATTR = 'attr' | ||
, SUBJECT = '!' | ||
, TAG = 'tag' | ||
@@ -45,3 +46,3 @@ , STAR = '*' | ||
switch(state) { | ||
case READY: state_ready(); break | ||
case READY: state_ready(); break | ||
case ANY_CHILD: state_any_child(); break | ||
@@ -56,3 +57,3 @@ case OPERATION: state_op(); break | ||
case ID: | ||
case TAG: | ||
case TAG: | ||
case CLASS: state_gather(); break | ||
@@ -81,6 +82,7 @@ } | ||
case '[' === c: state = ATTR_START; break | ||
case '!' === c: subject(); break | ||
case '*' === c: star(); break | ||
case ',' === c: comma(); break | ||
case /[>\+~]/.test(c): state = OPERATION; break | ||
case /\s/.test(c): state = ANY_CHILD; break | ||
case /\s/.test(c): state = ANY_CHILD; break | ||
case /[\w\d\-_]/.test(c): state = TAG; --idx; break | ||
@@ -90,2 +92,9 @@ } | ||
function subject() { | ||
state = SUBJECT | ||
gathered = ['!'] | ||
stream.queue(token()) | ||
state = READY | ||
} | ||
function star() { | ||
@@ -109,3 +118,3 @@ state = STAR | ||
} | ||
// chomp down the following whitespace. | ||
@@ -116,3 +125,3 @@ if(/\s/.test(c)) { | ||
stream.queue(token()) | ||
stream.queue(token()) | ||
state = READY | ||
@@ -119,0 +128,0 @@ --idx |
Uses eval
Supply chain riskPackage uses eval() which is a dangerous function. This prevents the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses eval() which is a dangerous function. This prevents the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
21330
658
0
98
1