Skip to content

Commit 24fea07

Browse files
committed
Code to start with
1 parent 358060e commit 24fea07

File tree

8 files changed

+486
-1
lines changed

8 files changed

+486
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

README.md

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,56 @@
11
# postcss-resolve-nested-selector
2-
Resolve a nested selector in a PostCSS AST
2+
3+
Resolve a nested selector in a PostCSS AST.
4+
5+
## API
6+
7+
`resolveNestedSelector(selector, node)`
8+
9+
Returns an array of selectors resolved from `selector`.
10+
11+
For example, given this JS:
12+
13+
```js
14+
var resolvedNestedSelector = require('postcss-resolve-nested-selector');
15+
postcssRoot.eachRule(function(rule) {
16+
var resolvedSelectors = rule.selectors.map(function(selector) {
17+
return resolvedNestedSelector(selector, rule);
18+
});
19+
});
20+
```
21+
22+
And the following CSS:
23+
24+
```css
25+
.foo {
26+
.bar {
27+
color: pink;
28+
}
29+
}
30+
```
31+
32+
This should log:
33+
34+
```
35+
['.foo']
36+
['.foo .bar']
37+
```
38+
39+
Or with this CSS:
40+
41+
```css
42+
.foo {
43+
.bar &,
44+
a {
45+
color: pink;
46+
}
47+
}
48+
```
49+
50+
This should log:
51+
52+
```
53+
['.foo']
54+
['.bar .foo']
55+
['.foo a']
56+
```

index.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module.exports = function resolveNestedSelector(selector, node) {
2+
var parent = node.parent;
3+
if (parent.type === 'root') return [selector];
4+
if (parent.type !== 'rule') return resolveNestedSelector(selector, parent);
5+
6+
var resolvedSelectors = parent.selectors.reduce(function(result, parentSelector) {
7+
if (selector.indexOf('&') !== -1) {
8+
var newlyResolvedSelectors = resolveNestedSelector(parentSelector, parent).map(function(resolvedParentSelector) {
9+
return selector.replace(/&/g, resolvedParentSelector);
10+
});
11+
return result.concat(newlyResolvedSelectors);
12+
}
13+
14+
var combinedSelector = [ parentSelector, selector ].join(' ');
15+
return result.concat(resolveNestedSelector(combinedSelector, parent));
16+
}, []);
17+
18+
return resolvedSelectors;
19+
}

package.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "postcss-resolve-nested-selector",
3+
"version": "0.1.0",
4+
"description": "Resolve a nested selector in a PostCSS AST",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "ava test/*-test.js"
8+
},
9+
"author": "David Clark",
10+
"license": "MIT",
11+
"files": [
12+
"index.js"
13+
],
14+
"devDependencies": {
15+
"ava": "0.12.0",
16+
"postcss": "5.0.16",
17+
"postcss-nested": "1.0.0",
18+
"postcss-nesting": "2.2.0",
19+
"tape": "4.4.0"
20+
}
21+
}

test/postcss-nested-test.js

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
import test from 'ava';
2+
import util from './util';
3+
4+
// tests copied from https://github.com/postcss/postcss-nested
5+
6+
test('postcss-nested unwraps rule inside rule', async t => {
7+
const code = 'a { a: 1 } a { a: 1; b { b: 2; c { c: 3 } } }';
8+
t.same(
9+
await util.postcssNestedResolve(code),
10+
await util.expected(code),
11+
);
12+
t.same(
13+
await util.expected(code),
14+
['a', 'a', 'a b', 'a b c'],
15+
);
16+
});
17+
18+
test('postcss-nested cleans rules after unwrap', async t => {
19+
const code = 'a { b .one {} b .two {} }';
20+
t.same(
21+
await util.postcssNestedResolve(code),
22+
await util.expected(code),
23+
);
24+
t.same(
25+
await util.expected(code),
26+
['a b .one', 'a b .two'],
27+
);
28+
});
29+
30+
test('postcss-nested replaces ampersand', async t => {
31+
const code = 'a { body &:hover b {} }';
32+
t.same(
33+
await util.postcssNestedResolve(code),
34+
await util.expected(code),
35+
);
36+
t.same(
37+
await util.expected(code),
38+
['body a:hover b'],
39+
);
40+
});
41+
42+
test('postcss-nested replaces ampersands', async t => {
43+
const code = 'a { &:hover, &:active {} }';
44+
t.same(
45+
await util.postcssNestedResolve(code),
46+
await util.expected(code),
47+
);
48+
t.same(
49+
await util.expected(code),
50+
['a:active', 'a:hover'],
51+
);
52+
});
53+
54+
test('postcss-nested replaces ampersand in string', async t => {
55+
const code = '.block { &_elem {} }';
56+
t.same(
57+
await util.postcssNestedResolve(code),
58+
await util.expected(code),
59+
);
60+
t.same(
61+
await util.expected(code),
62+
['.block_elem'],
63+
);
64+
});
65+
66+
test('postcss-nested unwrap rules inside at-rules', async t => {
67+
const code = '@media (max-width: 500px) { a { b {} } }';
68+
t.same(
69+
await util.postcssNestedResolve(code),
70+
await util.expected(code),
71+
);
72+
t.same(
73+
await util.expected(code),
74+
['a b'],
75+
);
76+
});
77+
78+
test('postcss-nested unwraps at-rule', async t => {
79+
const code = 'a { b { @media screen { width: auto } } }';
80+
t.same(
81+
await util.postcssNestedResolve(code),
82+
await util.expected(code),
83+
);
84+
t.same(
85+
await util.expected(code),
86+
['a b'],
87+
);
88+
});
89+
90+
test('postcss-nested unwraps at-rule with rules', async t => {
91+
const code = 'a { @media screen { b { color: black } } }';
92+
t.same(
93+
await util.postcssNestedResolve(code),
94+
await util.expected(code),
95+
);
96+
t.same(
97+
await util.expected(code),
98+
['a b'],
99+
);
100+
});
101+
102+
test('postcss-nested unwraps at-rules', async t => {
103+
const code = 'a { a: 1 } a { @media screen { @supports (a: 1) { a: 1 } } }';
104+
t.same(
105+
await util.postcssNestedResolve(code),
106+
await util.expected(code),
107+
);
108+
t.same(
109+
await util.expected(code),
110+
['a', 'a'],
111+
);
112+
});
113+
114+
test('postcss-nested processes comma', async t => {
115+
const code = '.one, .two { a {} }';
116+
t.same(
117+
await util.postcssNestedResolve(code),
118+
await util.expected(code),
119+
);
120+
t.same(
121+
await util.expected(code),
122+
['.one a', '.two a'],
123+
);
124+
});
125+
126+
test('postcss-nested processes comma with ampersand', async t => {
127+
const code = '.one, .two { &:hover {} }';
128+
t.same(
129+
await util.postcssNestedResolve(code),
130+
await util.expected(code),
131+
);
132+
t.same(
133+
await util.expected(code),
134+
['.one:hover', '.two:hover'],
135+
);
136+
});
137+
138+
test('postcss-nested processes comma inside', async t => {
139+
const code = 'a, b { .one, .two {} }';
140+
t.same(
141+
await util.postcssNestedResolve(code),
142+
await util.expected(code),
143+
);
144+
t.same(
145+
await util.expected(code),
146+
['a .one', 'a .two', 'b .one', 'b .two'],
147+
);
148+
});
149+
150+
test('postcss-nested moves comment with rule', async t => {
151+
const code = 'a {\n /*B*/\n b {}\n}';
152+
t.same(
153+
await util.postcssNestedResolve(code),
154+
await util.expected(code),
155+
);
156+
t.same(
157+
await util.expected(code),
158+
['a b'],
159+
);
160+
});
161+
162+
test('postcss-nested moves comment with at-rule', async t => {
163+
const code = 'a {\n /*B*/\n @media {\n one: 1\n }\n}';
164+
t.same(
165+
await util.postcssNestedResolve(code),
166+
await util.expected(code),
167+
);
168+
t.same(
169+
await util.expected(code),
170+
['a'],
171+
);
172+
});
173+
174+
test('postcss-nested moves comment with declaration', async t => {
175+
const code = 'a {\n @media {\n /*B*/\n one: 1\n }\n}';
176+
t.same(
177+
await util.postcssNestedResolve(code),
178+
await util.expected(code),
179+
);
180+
t.same(
181+
await util.expected(code),
182+
['a'],
183+
);
184+
});

0 commit comments

Comments
 (0)