@@ -101,6 +101,8 @@ function rewriteSelector(
101101) {
102102 let node : selectorParser . Node | null = null
103103 let shouldInject = ! deep
104+ let hasNestedDeep = false
105+ let splitForNestedDeep = false
104106 // find the last child node to insert attribute selector
105107 selector . each ( n => {
106108 // DEPRECATED ">>>" and "/deep/" combinator
@@ -119,6 +121,64 @@ function rewriteSelector(
119121
120122 if ( n . type === 'pseudo' ) {
121123 const { value } = n
124+ if ( isDeepContainerPseudo ( n ) ) {
125+ const hasDeepSelectors = n . nodes . some ( selector =>
126+ selector . some ( isDeepSelector ) ,
127+ )
128+ if ( hasDeepSelectors ) {
129+ const hasScopeAnchor = ! ! node
130+ const hasMixedSelectors = n . nodes . some (
131+ selector => ! selector . some ( isDeepSelector ) ,
132+ )
133+ const hasTrailingNodes = selector . index ( n ) < selector . length - 1
134+ if (
135+ canSplitDeepContainerPseudo ( n ) &&
136+ ! deep &&
137+ ! hasScopeAnchor &&
138+ hasMixedSelectors &&
139+ hasTrailingNodes
140+ ) {
141+ splitSelectorForNestedDeep (
142+ id ,
143+ rule ,
144+ selector ,
145+ selectorRoot ,
146+ n ,
147+ deep ,
148+ slotted ,
149+ )
150+ splitForNestedDeep = true
151+ return false
152+ }
153+
154+ if (
155+ value === ':not' &&
156+ ! deep &&
157+ ! hasScopeAnchor &&
158+ hasMixedSelectors &&
159+ hasTrailingNodes
160+ ) {
161+ return
162+ }
163+
164+ n . nodes . forEach ( selector =>
165+ rewriteSelector (
166+ id ,
167+ rule ,
168+ selector ,
169+ selectorRoot ,
170+ deep || hasScopeAnchor ,
171+ slotted ,
172+ ) ,
173+ )
174+ if ( ! hasScopeAnchor ) {
175+ node = n
176+ shouldInject = false
177+ }
178+ hasNestedDeep = true
179+ }
180+ }
181+
122182 // deep: inject [id] attribute at the node before the ::v-deep
123183 // combinator.
124184 if ( value === ':deep' || value === '::v-deep' ) {
@@ -219,15 +279,20 @@ function rewriteSelector(
219279 }
220280
221281 if (
222- ( n . type !== 'pseudo' && n . type !== 'combinator' ) ||
223- ( n . type === 'pseudo' &&
224- ( n . value === ':is' || n . value === ':where' ) &&
225- ! node )
282+ ! hasNestedDeep &&
283+ ( ( n . type !== 'pseudo' && n . type !== 'combinator' ) ||
284+ ( n . type === 'pseudo' &&
285+ ( n . value === ':is' || n . value === ':where' ) &&
286+ ! node ) )
226287 ) {
227288 node = n
228289 }
229290 } )
230291
292+ if ( splitForNestedDeep ) {
293+ return
294+ }
295+
231296 if ( rule . nodes . some ( node => node . type === 'rule' ) ) {
232297 const deep = ( rule as any ) . __deep
233298 if ( ! deep ) {
@@ -240,7 +305,7 @@ function rewriteSelector(
240305 shouldInject = deep
241306 }
242307
243- if ( node ) {
308+ if ( node && ! hasNestedDeep ) {
244309 const { type, value } = node as selectorParser . Node
245310 if ( type === 'pseudo' && ( value === ':is' || value === ':where' ) ) {
246311 ; ( node as selectorParser . Pseudo ) . nodes . forEach ( value =>
@@ -279,6 +344,67 @@ function isSpaceCombinator(node: selectorParser.Node) {
279344 return node . type === 'combinator' && / ^ \s + $ / . test ( node . value )
280345}
281346
347+ function isDeepSelector ( node : selectorParser . Node ) : boolean {
348+ if (
349+ node . type === 'pseudo' &&
350+ ( node . value === ':deep' || node . value === '::v-deep' )
351+ ) {
352+ return true
353+ }
354+
355+ return ! ! (
356+ node as selectorParser . Node & { nodes ?: selectorParser . Node [ ] }
357+ ) . nodes ?. some ( child => isDeepSelector ( child ) )
358+ }
359+
360+ function isDeepContainerPseudo (
361+ node : selectorParser . Node ,
362+ ) : node is selectorParser . Pseudo {
363+ return (
364+ node . type === 'pseudo' &&
365+ ( node . value === ':is' ||
366+ node . value === ':where' ||
367+ node . value === ':has' ||
368+ node . value === ':not' )
369+ )
370+ }
371+
372+ function canSplitDeepContainerPseudo ( node : selectorParser . Pseudo ) : boolean {
373+ return (
374+ node . value === ':is' || node . value === ':where' || node . value === ':has'
375+ )
376+ }
377+
378+ function splitSelectorForNestedDeep (
379+ id : string ,
380+ rule : Rule ,
381+ selector : selectorParser . Selector ,
382+ selectorRoot : selectorParser . Root ,
383+ pseudo : selectorParser . Pseudo ,
384+ deep : boolean ,
385+ slotted : boolean ,
386+ ) {
387+ const pseudoIndex = selector . index ( pseudo )
388+ const selectors = pseudo . nodes . map ( ( branch , index ) => {
389+ const branchSelector = selector . clone ( )
390+ if ( branchSelector . first ) {
391+ branchSelector . first . spaces . before =
392+ index === 0 ? selector . first . spaces . before : ' '
393+ }
394+ const branchPseudo = branchSelector . at ( pseudoIndex ) as selectorParser . Pseudo
395+ const branchClone = branch . clone ( )
396+ if ( branchClone . first ) {
397+ branchClone . first . spaces . before = ''
398+ }
399+ branchPseudo . removeAll ( )
400+ branchPseudo . append ( branchClone )
401+ rewriteSelector ( id , rule , branchSelector , selectorRoot , deep , slotted )
402+ return branchSelector
403+ } )
404+
405+ selector . replaceWith ( ...selectors )
406+ }
407+
282408function extractAndWrapNodes ( parentNode : Rule | AtRule ) {
283409 if ( ! parentNode . nodes ) return
284410 const nodes = parentNode . nodes . filter (
0 commit comments