@@ -53,12 +53,12 @@ function interpolateAmpInSelector(nodes, parent) {
5353 */
5454function mergeSelectors ( parent , child ) {
5555 let merged = [ ]
56- parent . selectors . forEach ( sel => {
56+ for ( let sel of parent . selectors ) {
5757 let parentNode = parse ( sel , parent )
5858
59- child . selectors . forEach ( selector => {
59+ for ( let selector of child . selectors ) {
6060 if ( ! selector ) {
61- return
61+ continue
6262 }
6363 let node = parse ( selector , child )
6464 let replaced = interpolateAmpInSelector ( node , parentNode )
@@ -67,22 +67,43 @@ function mergeSelectors(parent, child) {
6767 node . prepend ( parentNode . clone ( { } ) )
6868 }
6969 merged . push ( node . toString ( ) )
70- } )
71- } )
70+ }
71+ }
7272 return merged
7373}
7474
7575/**
76- * Move a child and its preceeding comment(s) to after "after"
76+ * Move a child and its preceding comment(s) to after "after"
77+ * ! It is necessary to clarify the comment
7778 */
7879function breakOut ( child , after ) {
79- let prev = child . prev ( )
80- after . after ( child )
81- while ( prev && prev . type === 'comment' ) {
82- let nextPrev = prev . prev ( )
83- after . after ( prev )
84- prev = nextPrev
80+ let changeParent = true
81+
82+ for ( let node of after . nodes ) {
83+ if ( ! node . nodes ) continue
84+
85+ let prevNode = node . prev ( )
86+ if ( prevNode ?. type !== 'comment' ) continue
87+
88+ let parentRule = after . toString ( )
89+
90+ /* Checking that the comment "describes" the rule following. Like this:
91+ /* comment about the rule below /*
92+ .rule {}
93+ */
94+ let regexp = new RegExp ( `${ prevNode . toString ( ) } *\n *${ node . toString ( ) } ` )
95+
96+ if ( parentRule . match ( regexp ) ) {
97+ changeParent = false
98+ after . after ( node ) . after ( prevNode )
99+ }
100+ }
101+
102+ // It is necessary if the above child has never been moved
103+ if ( changeParent ) {
104+ after . after ( child )
85105 }
106+
86107 return child
87108}
88109
@@ -104,14 +125,12 @@ function createFnAtruleChilds(bubble) {
104125 children . push ( child )
105126 }
106127 } )
107- if ( bubbling ) {
108- if ( children . length ) {
109- let clone = rule . clone ( { nodes : [ ] } )
110- for ( let child of children ) {
111- clone . append ( child )
112- }
113- atrule . prepend ( clone )
128+ if ( bubbling && children . length ) {
129+ let clone = rule . clone ( { nodes : [ ] } )
130+ for ( let child of children ) {
131+ clone . append ( child )
114132 }
133+ atrule . prepend ( clone )
115134 }
116135 }
117136}
@@ -125,16 +144,23 @@ function pickDeclarations(selector, declarations, after) {
125144 after . after ( parent )
126145 return parent
127146}
147+ function pickAndClearDeclarations ( ruleSelector , declarations , after , clear = true ) {
148+ if ( ! declarations . length ) return [ after , declarations ]
128149
129- function atruleNames ( defaults , custom ) {
130- let list = { }
131- for ( let name of defaults ) {
132- list [ name ] = true
150+ after = pickDeclarations ( ruleSelector , declarations , after )
151+
152+ if ( clear ) {
153+ declarations = [ ]
133154 }
134- if ( custom ) {
135- for ( let name of custom ) {
136- list [ name . replace ( / ^ @ / , '' ) ] = true
137- }
155+
156+ return [ after , declarations ]
157+ }
158+
159+ function atruleNames ( defaults , custom = '' ) {
160+ let names = defaults . concat ( custom )
161+ let list = { }
162+ for ( let name of names ) {
163+ list [ name . replace ( / ^ @ / , '' ) ] = true
138164 }
139165 return list
140166}
@@ -297,10 +323,10 @@ module.exports = (opts = {}) => {
297323 postcssPlugin : 'postcss-nested' ,
298324
299325 RootExit ( root ) {
300- if ( root [ hasRootRule ] ) {
301- root . walkAtRules ( rootRuleName , unwrapRootRule )
302- root [ hasRootRule ] = false
303- }
326+ if ( ! root [ hasRootRule ] ) return
327+
328+ root . walkAtRules ( rootRuleName , unwrapRootRule )
329+ root [ hasRootRule ] = false
304330 } ,
305331
306332 Rule ( rule ) {
@@ -310,46 +336,48 @@ module.exports = (opts = {}) => {
310336 let declarations = [ ]
311337
312338 rule . each ( child => {
313- if ( child . type === 'rule' ) {
314- if ( declarations . length ) {
315- after = pickDeclarations ( rule . selector , declarations , after )
316- declarations = [ ]
317- }
318-
319- copyDeclarations = true
320- unwrapped = true
321- child . selectors = mergeSelectors ( rule , child )
322- after = breakOut ( child , after )
323- } else if ( child . type === 'atrule' ) {
324- if ( declarations . length ) {
325- after = pickDeclarations ( rule . selector , declarations , after )
326- declarations = [ ]
327- }
328- if ( child . name === rootRuleName ) {
329- unwrapped = true
330- atruleChilds ( rule , child , true , child [ rootRuleMergeSel ] )
331- after = breakOut ( child , after )
332- } else if ( bubble [ child . name ] ) {
333- copyDeclarations = true
334- unwrapped = true
335- atruleChilds ( rule , child , true )
336- after = breakOut ( child , after )
337- } else if ( unwrap [ child . name ] ) {
339+ switch ( child . type ) {
340+ case 'rule' :
341+ [ after , declarations ] = pickAndClearDeclarations ( rule . selector , declarations , after )
342+
338343 copyDeclarations = true
339344 unwrapped = true
340- atruleChilds ( rule , child , false )
345+ child . selectors = mergeSelectors ( rule , child )
341346 after = breakOut ( child , after )
342- } else if ( copyDeclarations ) {
343- declarations . push ( child )
344- }
345- } else if ( child . type === 'decl' && copyDeclarations ) {
346- declarations . push ( child )
347+
348+ break
349+ case 'atrule' :
350+ [ after , declarations ] = pickAndClearDeclarations ( rule . selector , declarations , after )
351+
352+ if ( child . name === rootRuleName ) {
353+ unwrapped = true
354+ atruleChilds ( rule , child , true , child [ rootRuleMergeSel ] )
355+ after = breakOut ( child , after )
356+ } else if ( bubble [ child . name ] ) {
357+ copyDeclarations = true
358+ unwrapped = true
359+ atruleChilds ( rule , child , true )
360+ after = breakOut ( child , after )
361+ } else if ( unwrap [ child . name ] ) {
362+ copyDeclarations = true
363+ unwrapped = true
364+ atruleChilds ( rule , child , false )
365+ after = breakOut ( child , after )
366+ } else if ( copyDeclarations ) {
367+ declarations . push ( child )
368+ }
369+
370+ break
371+ case 'decl' :
372+ if ( copyDeclarations ) {
373+ declarations . push ( child )
374+ }
375+
376+ break
347377 }
348378 } )
349379
350- if ( declarations . length ) {
351- after = pickDeclarations ( rule . selector , declarations , after )
352- }
380+ pickAndClearDeclarations ( rule . selector , declarations , after , false )
353381
354382 if ( unwrapped && preserveEmpty !== true ) {
355383 rule . raws . semicolon = true
0 commit comments