1
- import type { AtRule , PluginCreator , Rule } from 'postcss'
1
+ import {
2
+ type AtRule ,
3
+ type Container ,
4
+ type Document ,
5
+ type PluginCreator ,
6
+ Rule ,
7
+ } from 'postcss'
2
8
import selectorParser from 'postcss-selector-parser'
3
9
import { warn } from '../warn'
4
10
@@ -71,21 +77,32 @@ function processRule(id: string, rule: Rule) {
71
77
return
72
78
}
73
79
processedRules . add ( rule )
80
+ let deep = false
81
+ let parent : Document | Container | undefined = rule . parent
82
+ while ( parent && parent . type !== 'root' ) {
83
+ if ( ( parent as any ) . __deep ) {
84
+ deep = true
85
+ break
86
+ }
87
+ parent = parent . parent
88
+ }
74
89
rule . selector = selectorParser ( selectorRoot => {
75
90
selectorRoot . each ( selector => {
76
- rewriteSelector ( id , selector , selectorRoot )
91
+ rewriteSelector ( id , rule , selector , selectorRoot , deep )
77
92
} )
78
93
} ) . processSync ( rule . selector )
79
94
}
80
95
81
96
function rewriteSelector (
82
97
id : string ,
98
+ rule : Rule ,
83
99
selector : selectorParser . Selector ,
84
100
selectorRoot : selectorParser . Root ,
101
+ deep : boolean ,
85
102
slotted = false ,
86
103
) {
87
104
let node : selectorParser . Node | null = null
88
- let shouldInject = true
105
+ let shouldInject = ! deep
89
106
// find the last child node to insert attribute selector
90
107
selector . each ( n => {
91
108
// DEPRECATED ">>>" and "/deep/" combinator
@@ -107,6 +124,7 @@ function rewriteSelector(
107
124
// deep: inject [id] attribute at the node before the ::v-deep
108
125
// combinator.
109
126
if ( value === ':deep' || value === '::v-deep' ) {
127
+ ; ( rule as any ) . __deep = true
110
128
if ( n . nodes . length ) {
111
129
// .foo ::v-deep(.bar) -> .foo[xxxxxxx] .bar
112
130
// replace the current node with ::v-deep's inner selector
@@ -147,7 +165,14 @@ function rewriteSelector(
147
165
// instead.
148
166
// ::v-slotted(.foo) -> .foo[xxxxxxx-s]
149
167
if ( value === ':slotted' || value === '::v-slotted' ) {
150
- rewriteSelector ( id , n . nodes [ 0 ] , selectorRoot , true /* slotted */ )
168
+ rewriteSelector (
169
+ id ,
170
+ rule ,
171
+ n . nodes [ 0 ] ,
172
+ selectorRoot ,
173
+ deep ,
174
+ true /* slotted */ ,
175
+ )
151
176
let last : selectorParser . Selector [ 'nodes' ] [ 0 ] = n
152
177
n . nodes [ 0 ] . each ( ss => {
153
178
selector . insertAfter ( last , ss )
@@ -206,11 +231,27 @@ function rewriteSelector(
206
231
}
207
232
} )
208
233
234
+ if ( rule . nodes . some ( node => node . type === 'rule' ) ) {
235
+ const deep = ( rule as any ) . __deep
236
+ const decls = rule . nodes . filter ( node => node . type === 'decl' )
237
+ if ( ! deep && decls . length ) {
238
+ for ( const decl of decls ) {
239
+ rule . removeChild ( decl )
240
+ }
241
+ const hostRule = new Rule ( {
242
+ nodes : decls ,
243
+ selector : '&' ,
244
+ } )
245
+ rule . prepend ( hostRule )
246
+ }
247
+ shouldInject = deep
248
+ }
249
+
209
250
if ( node ) {
210
251
const { type, value } = node as selectorParser . Node
211
252
if ( type === 'pseudo' && ( value === ':is' || value === ':where' ) ) {
212
253
; ( node as selectorParser . Pseudo ) . nodes . forEach ( value =>
213
- rewriteSelector ( id , value , selectorRoot , slotted ) ,
254
+ rewriteSelector ( id , rule , value , selectorRoot , deep , slotted ) ,
214
255
)
215
256
shouldInject = false
216
257
}
0 commit comments