Skip to content

Commit f51177d

Browse files
committed
add :nth-child
1 parent 2cb9c21 commit f51177d

File tree

6 files changed

+65
-9
lines changed

6 files changed

+65
-9
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ That's it!
6161
- [x] Ends with: `[value$="suffix"]`
6262
- [ ] Structural pseudo-classes: `paragraph:first-of-type`
6363
- [x] `:root`
64-
- [ ] `:nth-child(2n+1)`
64+
- [x] `:nth-child(2n+1)`
6565
- [ ] `:nth-last-child(2n+1)`
6666
- [ ] `:nth-of-type(2n+1)`
6767
- [ ] `:nth-last-of-type(2n+1)`

lib/match-node.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ module.exports = matchNode;
44

55

66
// Match node against a simple selector.
7-
function matchNode (rule, node, parent) {
7+
function matchNode (rule, node, nodeIndex, parent) {
88
return matchType(rule, node) &&
99
matchAttrs(rule, node) &&
10-
matchPseudos(rule, node, parent);
10+
matchPseudos(rule, node, nodeIndex, parent);
1111
}
1212

1313

@@ -58,14 +58,17 @@ function matchAttrs (rule, node) {
5858
}
5959

6060

61-
function matchPseudos (rule, node, parent) {
61+
function matchPseudos (rule, node, nodeIndex, parent) {
6262
return !rule.pseudos || rule.pseudos.every(function (pseudo) {
6363
switch (pseudo.name) {
6464
case 'root':
6565
return parent == null;
6666

67+
case 'nth-child':
68+
return pseudo.value(nodeIndex);
69+
6770
case 'not':
68-
return !matchNode(pseudo.value.rule, node, parent);
71+
return !matchNode(pseudo.value.rule, node, nodeIndex, parent);
6972

7073
default:
7174
throw Error('Undefined pseudo-class: ' + pseudo.name);

lib/select.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ select.rule = function (rule, ast) {
4141
}
4242

4343
function match (rule, node, nodeIndex, parent) {
44-
if (matchNode(rule, node, parent)) {
44+
if (matchNode(rule, node, nodeIndex, parent)) {
4545
if (rule.rule) {
4646
search(rule.rule, node, nodeIndex, parent);
4747
}

lib/selector.js

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,49 @@
11
'use strict';
22

3-
var Parser = require('css-selector-parser').CssSelectorParser;
3+
var Parser = require('css-selector-parser').CssSelectorParser,
4+
nthCheck = require('nth-check');
45

56

67
module.exports = function parseSelector (selector) {
78
var parser = new Parser;
89
parser.registerNestingOperators('>', '+', '~');
910
parser.registerAttrEqualityMods('^', '*', '$');
1011
parser.registerSelectorPseudos('not');
11-
return parser.parse(selector);
12+
return compileNthChecks(parser.parse(selector));
1213
};
14+
15+
16+
function compileNthChecks (ast) {
17+
if (ast == null) {
18+
return ast;
19+
}
20+
21+
switch (ast.type) {
22+
case 'selectors':
23+
ast.selectors.forEach(compileNthChecks);
24+
break;
25+
26+
case 'ruleSet':
27+
compileNthChecks(ast.rule);
28+
break;
29+
30+
case 'rule':
31+
if (ast.pseudos) {
32+
ast.pseudos.forEach(function (pseudo) {
33+
if (pseudo.name == 'nth-child') {
34+
pseudo.value = nthCheck(pseudo.value);
35+
pseudo.valueType = 'function';
36+
}
37+
});
38+
}
39+
if (ast.rule) {
40+
compileNthChecks(ast.rule);
41+
}
42+
break;
43+
44+
default:
45+
throw Error('Undefined AST node: ' + ast.type);
46+
}
47+
48+
return ast;
49+
}

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
],
4242
"dependencies": {
4343
"css-selector-parser": "^1.1.0",
44-
"debug": "^2.2.0"
44+
"debug": "^2.2.0",
45+
"nth-check": "^1.0.1"
4546
},
4647
"devDependencies": {
4748
"tape": "^4.2.0"

test/select.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,21 @@ test('structural pseudo-classes', function (t) {
139139
t.end();
140140
});
141141

142+
t.test(':nth-child', function (t) {
143+
t.deepEqual(select(ast, ':root:nth-child(0)'), []);
144+
t.deepEqual(select(ast, ':root:nth-child(n)'), [ast]);
145+
t.deepEqual(select(ast, 'root > list:nth-child(2n+5)'),
146+
select(ast, 'root > list'));
147+
t.deepEqual(select(ast, 'heading:nth-child(even)'), [
148+
path(ast, [1]),
149+
path(ast, [7])
150+
]);
151+
t.deepEqual(select(ast, ':nth-child(3n+2)[type=inlineCode]')
152+
.map(function (node) { return node.value }),
153+
['integer', 'proin', 'tan']);
154+
t.end();
155+
});
156+
142157
t.end();
143158
});
144159

0 commit comments

Comments
 (0)