@@ -186,68 +186,75 @@ function makeExtractUtilityRules(css, lookupTree, config) {
186
186
}
187
187
}
188
188
189
+ function findParent ( rule , predicate ) {
190
+ let parent = rule . parent
191
+ while ( parent ) {
192
+ if ( predicate ( parent ) ) {
193
+ return parent
194
+ }
195
+
196
+ parent = parent . parent
197
+ }
198
+
199
+ throw new Error ( 'No parent could be found' )
200
+ }
201
+
189
202
function processApplyAtRules ( css , lookupTree , config ) {
190
203
const extractUtilityRules = makeExtractUtilityRules ( css , lookupTree , config )
191
204
192
205
do {
193
- css . walkRules ( rule => {
194
- const applyRules = [ ]
206
+ css . walkAtRules ( 'apply' , applyRule => {
207
+ const parent = applyRule . parent // Direct parent
208
+ const nearestParentRule = findParent ( applyRule , r => r . type === 'rule' )
209
+ const currentUtilityNames = extractUtilityNames ( nearestParentRule . selector )
210
+
211
+ const [
212
+ importantEntries ,
213
+ applyUtilityNames ,
214
+ important = importantEntries . length > 0 ,
215
+ ] = _ . partition ( applyRule . params . split ( / [ \s \t \n ] + / g) , n => n === '!important' )
216
+
217
+ if ( _ . intersection ( applyUtilityNames , currentUtilityNames ) . length > 0 ) {
218
+ const currentUtilityName = _ . intersection ( applyUtilityNames , currentUtilityNames ) [ 0 ]
219
+ throw parent . error (
220
+ `You cannot \`@apply\` the \`${ currentUtilityName } \` utility here because it creates a circular dependency.`
221
+ )
222
+ }
195
223
196
- // Only walk direct children to avoid issues with nesting plugins
197
- rule . each ( child => {
198
- if ( child . type === 'atrule' && child . name === 'apply' ) {
199
- applyRules . unshift ( child )
200
- }
201
- } )
224
+ // Extract any post-apply declarations and re-insert them after apply rules
225
+ const afterRule = parent . clone ( { raws : { } } )
226
+ afterRule . nodes = afterRule . nodes . slice ( parent . index ( applyRule ) + 1 )
227
+ parent . nodes = parent . nodes . slice ( 0 , parent . index ( applyRule ) + 1 )
202
228
203
- applyRules . forEach ( applyRule => {
204
- const [
205
- importantEntries ,
206
- applyUtilityNames ,
207
- important = importantEntries . length > 0 ,
208
- ] = _ . partition ( applyRule . params . split ( / [ \s \t \n ] + / g) , n => n === '!important' )
229
+ // Sort applys to match CSS source order
230
+ const applys = extractUtilityRules ( applyUtilityNames , applyRule )
209
231
210
- const currentUtilityNames = extractUtilityNames ( rule . selector )
232
+ // Get new rules with the utility portion of the selector replaced with the new selector
233
+ const rulesToInsert = [ ]
211
234
212
- if ( _ . intersection ( applyUtilityNames , currentUtilityNames ) . length > 0 ) {
213
- const currentUtilityName = _ . intersection ( applyUtilityNames , currentUtilityNames ) [ 0 ]
214
- throw rule . error (
215
- `You cannot \`@apply\` the \`${ currentUtilityName } \` utility here because it creates a circular dependency.`
216
- )
217
- }
235
+ applys . forEach (
236
+ nearestParentRule === parent
237
+ ? util => rulesToInsert . push ( generateRulesFromApply ( util , parent . selectors ) )
238
+ : util => util . rule . nodes . forEach ( n => afterRule . append ( n . clone ( ) ) )
239
+ )
218
240
219
- // Extract any post-apply declarations and re-insert them after apply rules
220
- const afterRule = rule . clone ( { raws : { } } )
221
- afterRule . nodes = afterRule . nodes . slice ( rule . index ( applyRule ) + 1 )
222
- rule . nodes = rule . nodes . slice ( 0 , rule . index ( applyRule ) + 1 )
223
-
224
- // Sort applys to match CSS source order
225
- const applys = extractUtilityRules ( applyUtilityNames , applyRule )
226
-
227
- // Get new rules with the utility portion of the selector replaced with the new selector
228
- const rulesToInsert = [
229
- ...applys . map ( applyUtility => {
230
- return generateRulesFromApply ( applyUtility , rule . selectors )
231
- } ) ,
232
- afterRule ,
233
- ]
234
-
235
- const { nodes } = _ . tap ( postcss . root ( { nodes : rulesToInsert } ) , root =>
236
- root . walkDecls ( d => {
237
- d . important = important
238
- } )
239
- )
241
+ rulesToInsert . push ( afterRule )
240
242
241
- const mergedRules = mergeAdjacentRules ( rule , nodes )
243
+ const { nodes } = _ . tap ( postcss . root ( { nodes : rulesToInsert } ) , root =>
244
+ root . walkDecls ( d => {
245
+ d . important = important
246
+ } )
247
+ )
242
248
243
- applyRule . remove ( )
244
- rule . after ( mergedRules )
245
- } )
249
+ const mergedRules = mergeAdjacentRules ( nearestParentRule , nodes )
250
+
251
+ applyRule . remove ( )
252
+ parent . after ( mergedRules )
246
253
247
254
// If the base rule has nothing in it (all applys were pseudo or responsive variants),
248
255
// remove the rule fuggit.
249
- if ( rule . nodes . length === 0 ) {
250
- rule . remove ( )
256
+ if ( parent . nodes . length === 0 ) {
257
+ parent . remove ( )
251
258
}
252
259
} )
253
260
0 commit comments