11const postcss = require ( 'postcss' )
2+ const Selector = require ( 'postcss-selector-parser' )
23
34module . exports = postcss . plugin ( 'postcss-prefix' , postcssPrefix )
45
@@ -7,11 +8,58 @@ function postcssPrefix (prefix, options) {
78
89 return function ( root ) {
910 root . walkRules ( function ( rule ) {
10- rule . selectors = rule . selectors . map ( function ( selector ) {
11- if ( rule . selector . indexOf ( ':root' ) === 0 ) return selector
12- return prefix + selector
13- } )
14- rule . selector = rule . selectors . join ( ', ' )
11+ const selector = Selector (
12+ transformSelectors
13+ ) . process ( rule . selector ) . result
14+
15+ rule . selector = selector
16+ } )
17+ }
18+
19+ function transformSelectors ( selectors ) {
20+ selectors . eachInside ( function ( selector ) {
21+ if (
22+ // if parent is not selector and
23+ selector . parent . type !== 'selector' ||
24+ // if not first node in container
25+ selector . parent . nodes [ 0 ] !== selector
26+ ) return
27+
28+ const prefixNode = getPrefixNode ( prefix )
29+
30+ if ( selector . type === 'pseudo' ) {
31+ switch ( selector . value ) {
32+ case ':root' :
33+ return
34+ case ':host' :
35+ const replacement = Selector . selector ( )
36+ replacement . nodes = [ prefixNode ] . concat ( selector . clone ( ) . nodes )
37+ selector . replaceWith ( replacement )
38+ return
39+ }
40+ }
41+
42+ // prefix
43+ //
44+ // start by prepending a space combinator
45+ selector . parent . prepend ( Selector . combinator ( { value : ' ' } ) )
46+ // then prepend the prefix node, preserving spacing
47+ prefixNode . spaces . before = selector . spaces . before
48+ selector . spaces . before = ''
49+ selector . parent . prepend ( prefixNode )
1550 } )
1651 }
52+
53+ }
54+
55+ function getPrefixNode ( prefix ) {
56+ const sigil = prefix [ 0 ]
57+ const value = prefix . slice ( 1 )
58+
59+ switch ( sigil ) {
60+ case '#' :
61+ return Selector . id ( { value } )
62+ case '.' :
63+ return Selector . className ( { value } )
64+ }
1765}
0 commit comments