Skip to content
This repository was archived by the owner on Jun 6, 2022. It is now read-only.

Commit a980515

Browse files
thecrypticacejonathantneal
authored andcommitted
Ensure escaped colons do not break selector transformations
* Add failing tests * Use a regex for pseudo selectors searches The regex is set up to ensure that escaped colons are not considered when looking for :not. This slows down selector transformation by about 25% * Cache generated regular expressions This provides a pretty decent speedup. Overall selector matching is now slight slower by about 6% instead of 25%.
1 parent 0508237 commit a980515

File tree

2 files changed

+35
-1
lines changed

2 files changed

+35
-1
lines changed

src/index.js

+23-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import list from "postcss/lib/list"
44
import balancedMatch from "balanced-match"
55

66
function explodeSelector(pseudoClass, selector) {
7-
const position = selector.indexOf(pseudoClass)
7+
const position = locatePseudoClass(selector, pseudoClass)
88
if (selector && position > -1) {
99
const pre = selector.slice(0, position)
1010
const matches = balancedMatch("(", ")", selector.slice(position))
@@ -23,6 +23,28 @@ function explodeSelector(pseudoClass, selector) {
2323
return selector
2424
}
2525

26+
const patternCache = {}
27+
28+
function locatePseudoClass(selector, pseudoClass) {
29+
patternCache[pseudoClass] = patternCache[pseudoClass]
30+
|| new RegExp(`([^\\\\]|^)${pseudoClass}`)
31+
32+
// The regex is used to ensure that selectors with
33+
// escaped colons in them are treated properly
34+
// Ex: .foo\:not-bar is a valid CSS selector
35+
// But it is not a reference to a pseudo selector
36+
const pattern = patternCache[pseudoClass]
37+
const position = selector.search(pattern)
38+
39+
if (position === -1) {
40+
return -1
41+
}
42+
43+
// The offset returned by the regex may be off by one because
44+
// of it including the negated character match in the position
45+
return position + selector.slice(position).indexOf(pseudoClass)
46+
}
47+
2648
function explodeSelectors(pseudoClass) {
2749
return () => {
2850
return (css) => {

test/index.js

+12
Original file line numberDiff line numberDiff line change
@@ -77,5 +77,17 @@ tape("postcss-selector-not", t => {
7777
"should work with something after :not()"
7878
)
7979

80+
t.equal(
81+
transform(".foo\\:not-italic {}"),
82+
".foo\\:not-italic {}",
83+
"should not replace selectors with escaped colons followed by not"
84+
)
85+
86+
t.equal(
87+
transform(".foo\\:not-italic:not(:hover, :focus) {}"),
88+
".foo\\:not-italic:not(:hover):not(:focus) {}",
89+
"should replace pseudo selectors without touching escaped colons"
90+
)
91+
8092
t.end()
8193
})

0 commit comments

Comments
 (0)