Skip to content

Commit d231094

Browse files
committed
improve splitting by comma and replacing &
1 parent 5538466 commit d231094

File tree

4 files changed

+104
-23
lines changed

4 files changed

+104
-23
lines changed

index.js

+23-20
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ module.exports = function resolveNestedSelector(selector, node) {
66
if (parent.type !== 'rule' && !parentIsNestAtRule) return resolveNestedSelector(selector, parent);
77

88
var parentSelectors = (parentIsNestAtRule)
9-
? list(parent.params)
9+
? split(parent.params, ',', false).map((x) => x.trim())
1010
: parent.selectors;
1111

1212
var resolvedSelectors = parentSelectors.reduce(function(result, parentSelector) {
1313
if (selector.indexOf('&') !== -1) {
1414
var newlyResolvedSelectors = resolveNestedSelector(parentSelector, parent).map(function(resolvedParentSelector) {
15-
return selector.replace(/&/g, resolvedParentSelector);
15+
return split(selector, '&', true).join(resolvedParentSelector);
1616
});
1717
return result.concat(newlyResolvedSelectors);
1818
}
@@ -24,17 +24,20 @@ module.exports = function resolveNestedSelector(selector, node) {
2424
return resolvedSelectors;
2525
}
2626

27-
// https://github.com/postcss/postcss/blob/main/lib/list.js#L1
28-
// We should not have `postcss` as a direct dependency so, we inline the same code here.
29-
function list(string) {
30-
let array = []
31-
let current = ''
32-
let split = false
27+
function split(string, separator, splitFunctions) {
28+
var blockPairs = {
29+
'(': ')',
30+
'[': ']',
31+
'{': '}'
32+
}
33+
var array = []
34+
var current = ''
35+
var split = false
3336

34-
let func = 0
35-
let inQuote = false
36-
let prevQuote = ''
37-
let escape = false
37+
var blockClose = []
38+
var inQuote = false
39+
var prevQuote = ''
40+
var escape = false
3841

3942
for (let letter of string) {
4043
if (escape) {
@@ -48,23 +51,23 @@ function list(string) {
4851
} else if (letter === '"' || letter === "'") {
4952
inQuote = true
5053
prevQuote = letter
51-
} else if (letter === '(') {
52-
func += 1
53-
} else if (letter === ')') {
54-
if (func > 0) func -= 1
55-
} else if (func === 0) {
56-
if (letter === ',') split = true
54+
} else if (letter === '(' || letter === '[' || letter === '{') {
55+
blockClose.push(blockPairs[letter])
56+
} else if (letter === blockClose[blockClose.length - 1]) {
57+
blockClose.pop()
58+
} else if (blockClose.length === 0 || (splitFunctions && blockClose.every((x) => x === ')'))) {
59+
if (letter === separator) split = true
5760
}
5861

5962
if (split) {
60-
if (current !== '') array.push(current.trim())
63+
array.push(current)
6164
current = ''
6265
split = false
6366
} else {
6467
current += letter
6568
}
6669
}
6770

68-
if (current !== '') array.push(current.trim())
71+
array.push(current)
6972
return array
7073
}

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "postcss-resolve-nested-selector",
3-
"version": "0.1.3",
3+
"version": "0.1.4",
44
"description": "Resolve a nested selector in a PostCSS AST",
55
"main": "index.js",
66
"scripts": {

test/api.test.mjs

+78
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,48 @@ test(async t => {
8888
);
8989
});
9090

91+
test(async t => {
92+
const code = `.a {
93+
@nest [a=,] & {
94+
& .c {
95+
color: red;
96+
}
97+
}
98+
}`;
99+
assert.deepEqual(
100+
await util.resolveChosenSelector(code, '& .c'),
101+
['[a=,] .a .c'],
102+
);
103+
});
104+
105+
test(async t => {
106+
const code = `.a {
107+
@nest a \\, & {
108+
& .c {
109+
color: red;
110+
}
111+
}
112+
}`;
113+
assert.deepEqual(
114+
await util.resolveChosenSelector(code, '& .c'),
115+
['a \\, .a .c'],
116+
);
117+
});
118+
119+
test(async t => {
120+
const code = `.a {
121+
@nest [a=","] & {
122+
& .c {
123+
color: red;
124+
}
125+
}
126+
}`;
127+
assert.deepEqual(
128+
await util.resolveChosenSelector(code, '& .c'),
129+
['[a=","] .a .c'],
130+
);
131+
});
132+
91133
test(async t => {
92134
const code = `.a {
93135
@nest .b & , & .c , & .d & {
@@ -105,3 +147,39 @@ test(async t => {
105147
],
106148
);
107149
});
150+
151+
test(async t => {
152+
const code = `.a {
153+
.b [c="&"] & {}
154+
}`;
155+
assert.deepEqual(
156+
await util.resolveChosenSelector(code, '.b [c="&"] &'),
157+
[
158+
'.b [c="&"] .a'
159+
],
160+
);
161+
});
162+
163+
test(async t => {
164+
const code = `.a {
165+
.b [c=&] & {}
166+
}`;
167+
assert.deepEqual(
168+
await util.resolveChosenSelector(code, '.b [c=&] &'),
169+
[
170+
'.b [c=&] .a'
171+
],
172+
);
173+
});
174+
175+
test(async t => {
176+
const code = `.a {
177+
.b \\& + & {
178+
& .c {}
179+
}
180+
}`;
181+
assert.deepEqual(
182+
await util.resolveChosenSelector(code, '& .c'),
183+
['.b \\& + .a .c'],
184+
);
185+
});

0 commit comments

Comments
 (0)