Skip to content

Commit 3ea5e3a

Browse files
committed
add :root
1 parent d788c58 commit 3ea5e3a

File tree

3 files changed

+40
-7
lines changed

3 files changed

+40
-7
lines changed

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,19 @@ That's it!
5959
- [x] Begins with: `[value^="prefix"]`
6060
- [x] Containment: `[value*="substr"]`
6161
- [x] Ends with: `[value$="suffix"]`
62+
- [ ] Structural pseudo-classes: `paragraph:first-of-type`
63+
- [x] `:root`
64+
- [ ] `:nth-child(2n+1)`
65+
- [ ] `:nth-last-child(2n+1)`
66+
- [ ] `:nth-of-type(2n+1)`
67+
- [ ] `:nth-last-of-type(2n+1)`
68+
- [ ] `:first-child`
69+
- [ ] `:last-child`
70+
- [ ] `:first-of-type`
71+
- [ ] `:last-of-type`
72+
- [ ] `:only-child`
73+
- [ ] `:only-of-type`
74+
- [ ] `:empty`
6275
- [x] Negation pseudo-class: `*:not(paragraph)`
6376

6477
## API

lib/select.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ select.ruleSet = function (selector, ast) {
1717
};
1818

1919

20-
select.rule = function (selector, ast) {
20+
select.rule = function (selector, ast, parentNode) {
2121
var result = [];
2222

2323
switch (selector.nestingOperator) {
2424
case null:
2525
case undefined:
2626
case '>':
27-
walk(ast);
27+
walk(ast, parentNode);
2828
break;
2929

3030
case '+':
@@ -46,23 +46,23 @@ select.rule = function (selector, ast) {
4646
return result;
4747

4848
function walk (node, parent) {
49-
if (matches(selector, node)) {
49+
if (matches(selector, node, parent == null)) {
5050
if (!selector.rule) {
5151
append(result, [node]);
5252
}
5353
else if (!selector.rule.nestingOperator ||
5454
selector.rule.nestingOperator == '>') {
5555
if (node.children) {
5656
node.children.forEach(function (childNode) {
57-
append(result, select.rule(selector.rule, childNode));
57+
append(result, select.rule(selector.rule, childNode, node));
5858
});
5959
}
6060
}
6161
else {
6262
if (parent) {
6363
append(result, select.rule(selector.rule, {
6464
children: parent.children.slice(parent.children.indexOf(node) + 1)
65-
}));
65+
}, parent));
6666
}
6767
}
6868
}
@@ -77,7 +77,7 @@ select.rule = function (selector, ast) {
7777

7878

7979
// True if node matches head of selector rule.
80-
function matches (rule, node) {
80+
function matches (rule, node, isRoot) {
8181
var match = true;
8282

8383
// Match type.
@@ -127,6 +127,9 @@ function matches (rule, node) {
127127
// Match pseudo classes.
128128
match = match && (rule.pseudos || []).every(function (pseudo) {
129129
switch (pseudo.name) {
130+
case 'root':
131+
return isRoot;
132+
130133
case 'not':
131134
return !matches(pseudo.value.rule, node);
132135

test/test.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ test('edge cases', function (t) {
1616

1717
test('type selector', function (t) {
1818
t.equal(select(ast, 'root').length, 1);
19-
t.equal(select(ast, 'root')[0], ast);
19+
t.deepEqual(select(ast, 'root'), [ast]);
2020
t.equal(select(ast, 'text').length, 39);
2121
t.equal(select(ast, 'text')[1], ast.children[1].children[0]);
2222
t.equal(select(ast, 'tableRow').length, 2);
@@ -127,6 +127,23 @@ test('attribute selectors', function (t) {
127127
});
128128

129129

130+
test('structural pseudo-classes', function (t) {
131+
t.test(':root', function (t) {
132+
t.deepEqual(select(ast, ':root'), [ast]);
133+
t.deepEqual(select(ast, ':root:root'), [ast]);
134+
t.deepEqual(select(ast, '* :root'), []);
135+
t.deepEqual(select(ast, 'text:not(:root)'), select(ast, 'text'));
136+
t.deepEqual(select(ast, ':root > list'), [
137+
path(ast, [4]),
138+
path(ast, [6])
139+
]);
140+
t.end();
141+
});
142+
143+
t.end();
144+
});
145+
146+
130147
test('negation pseudo-class', function (t) {
131148
t.deepEqual(select(ast, 'list:not([nonexistent])'), select(ast, 'list'));
132149
t.deepEqual(select(ast, 'list:not([start=null])'),

0 commit comments

Comments
 (0)