1
1
// PostCSS CSS Variables (postcss-css-variables)
2
- // v0.3.5
2
+ // v0.3.6
3
3
//
4
4
// https://github.com/MadLittleMods/postcss-css-variables
5
5
9
9
var postcss = require ( 'postcss' ) ;
10
10
var extend = require ( 'extend' ) ;
11
11
12
- var cloneSpliceParentOntoNodeWhen = require ( './lib/clone-splice-parent-onto-node-when' ) ;
13
- var findNodeAncestorWithSelector = require ( './lib/find-node-ancestor-with-selector' ) ;
14
12
var resolveValue = require ( './lib/resolve-value' ) ;
15
- var isNodeUnderScope = require ( './lib/is-node-under-scope' ) ;
16
- var generateScopeList = require ( './lib/generate-scope-list' ) ;
17
- var gatherVariableDependencies = require ( './lib/gather-variable-dependencies' ) ;
13
+ var resolveDecl = require ( './lib/resolve-decl' ) ;
18
14
19
15
20
16
// A custom property is any property whose name starts with two dashes (U+002D HYPHEN-MINUS)
@@ -36,49 +32,22 @@ function eachCssVariableDeclaration(css, cb) {
36
32
}
37
33
38
34
39
- function eachMapItemUnderAtRuleUsedByVariable ( variablesUsedList , map , decl , cb ) {
40
- // Now find any at-rule declarations that pertains to each rule
41
- // Loop through the variables used
42
- variablesUsedList . forEach ( function ( variableUsedName ) {
43
-
44
- // Find anything in the map that corresponds to that variable
45
- gatherVariableDependencies ( variablesUsedList , map ) . deps . forEach ( function ( mapItem ) {
46
- if ( mapItem . isUnderAtRule ) {
47
-
48
- // Get the inner-most selector of the at-rule scope variable declaration we are matching
49
- // Because the inner-most selector will be the same for each branch, we can look at the first one [0] or any of the others
50
- var varDeclScopeList = generateScopeList ( mapItem . parent , true ) ;
51
- var innerMostAtRuleSelector = varDeclScopeList [ 0 ] . slice ( - 1 ) [ 0 ] ;
52
- var nodeToSpliceParentOnto = findNodeAncestorWithSelector ( innerMostAtRuleSelector , decl . parent ) ;
53
-
54
- // Splice on where the selector starts matching the selector inside at-rule
55
- // See: `test/fixtures/cascade-on-nested-rules.css`
56
- var varDeclAtRule = mapItem . parent . parent ;
57
- var mimicDecl = cloneSpliceParentOntoNodeWhen ( decl , varDeclAtRule , function ( ancestor ) {
58
- return ancestor === nodeToSpliceParentOnto ;
59
- } ) ;
60
-
61
35
62
- //console.log('amd og', generateScopeList(decl.parent, true));
63
- //console.log('amd', generateScopeList(mimicDecl.parent, true));
64
- //console.log(generateScopeList(mapItem.parent, true));
65
- //console.log('amd isNodeUnderScope', isNodeUnderScope(mimicDecl.parent, mapItem.parent), mapItem.decl.value);
36
+ function cleanUpNode ( currentNodeToRemove ) {
37
+ // If we removed all of the declarations in the rule(making it empty), then just remove it
38
+ var currentNodeToPossiblyCleanUp = currentNodeToRemove ;
39
+ while ( currentNodeToPossiblyCleanUp && currentNodeToPossiblyCleanUp . nodes . length <= 0 ) {
40
+ var nodeToRemove = currentNodeToPossiblyCleanUp ;
41
+ // Get a reference to it before we remove and lose reference to the child after removing it
42
+ currentNodeToPossiblyCleanUp = currentNodeToPossiblyCleanUp . parent ;
66
43
67
- // If it is under the proper scope,
68
- // we need to check because we are iterating over all map entries that are `isUnderAtRule`
69
- // Then lets create the new rules
70
- if ( isNodeUnderScope ( mimicDecl . parent , mapItem . parent ) ) {
71
- cb ( mimicDecl , mapItem ) ;
72
- }
73
- }
74
- } ) ;
75
- } ) ;
44
+ nodeToRemove . removeSelf ( ) ;
45
+ }
76
46
}
77
47
78
48
79
49
80
50
81
-
82
51
module . exports = postcss . plugin ( 'postcss-css-variables' , function ( options ) {
83
52
var defaults = {
84
53
// Allows you to preserve custom properties & var() usage in output.
@@ -100,9 +69,6 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
100
69
try {
101
70
/* */
102
71
103
- // List of nodes to add at the end
104
- // We use this so we don't add to the tree as we are processing it (infinite loop)
105
- var createNodeCallbackList = [ ] ;
106
72
// List of nodes that if empty, will be removed
107
73
// We use this because we don't want to modify the AST when we still need to reference these later on
108
74
var nodesToRemoveAtEnd = [ ] ;
@@ -203,102 +169,76 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
203
169
//else {}
204
170
205
171
// We add to the clean up list if we removed some variable declarations to make it become an empty rule
172
+ // We clean up later on because we don't want to modify the AST when we still need to reference these later on
206
173
if ( declParentRule . nodes . length <= 0 ) {
207
174
nodesToRemoveAtEnd . push ( declParentRule ) ;
208
175
}
209
176
} ) ;
210
177
211
178
212
179
180
+
181
+
213
182
// Resolve variables everywhere
214
183
// ---------------------------------------------------------
215
184
// ---------------------------------------------------------
216
- css . eachDecl ( function ( decl ) {
217
- // Ignore any variable declarations that we may be preserving from earlier
218
- // Don't worry, they are already processed
219
- // If not a variable decalaraton... then resolve
220
- if ( ! RE_VAR_PROP . test ( decl . prop ) ) {
221
-
222
-
223
- // Grab the balue for this declarations
224
- var valueResults = logResolveValueResult ( resolveValue ( decl , map ) ) ;
225
-
226
185
227
- // Resolve the cascade
228
- // Now find any at-rule declarations that need to be added below each rule
229
- eachMapItemUnderAtRuleUsedByVariable ( valueResults . variablesUsed , map , decl , function ( mimicDecl , mapItem ) {
230
- // Create the clean atRule for which we place the declaration under
231
- var atRuleNode = mapItem . parent . parent . clone ( ) . removeAll ( ) ;
232
-
233
- var ruleClone = decl . parent . clone ( ) . removeAll ( ) ;
234
- var declClone = decl . clone ( ) ;
235
- declClone . value = logResolveValueResult ( resolveValue ( mimicDecl , map ) ) . value ;
186
+ // Collect all the rules that have declarations that use variables
187
+ var rulesThatHaveDeclarationsWithVariablesList = [ ] ;
188
+ css . eachRule ( function ( rule ) {
189
+ var doesRuleUseVariables = rule . nodes . some ( function ( node ) {
190
+ if ( node . type == 'decl' ) {
191
+ var decl = node ;
192
+ // If it uses variables
193
+ // and is not a variable declarations that we may be preserving from earlier
194
+ if ( resolveValue . RE_VAR_FUNC . test ( decl . value ) && ! RE_VAR_PROP . test ( decl . prop ) ) {
195
+ return true ;
196
+ }
197
+ }
236
198
237
- // Add the declaration to our new rule
238
- ruleClone . append ( declClone ) ;
239
- // Add the rule to the atRule
240
- atRuleNode . append ( ruleClone ) ;
199
+ return false ;
200
+ } ) ;
241
201
202
+ if ( doesRuleUseVariables ) {
203
+ rulesThatHaveDeclarationsWithVariablesList . push ( rule ) ;
204
+ }
205
+ } ) ;
242
206
243
- // Since that atRuleNode can be nested in other atRules, we need to make the appropriate structure
244
- var parentAtRuleNode = atRuleNode ;
245
- var currentAtRuleNode = mapItem . parent . parent ;
246
- while ( currentAtRuleNode . parent . type === 'atrule' ) {
247
- // Create a new clean clone of that at rule to nest under
248
- var newParentAtRuleNode = currentAtRuleNode . parent . clone ( ) . removeAll ( ) ;
207
+ rulesThatHaveDeclarationsWithVariablesList . forEach ( function ( rule ) {
208
+ var rulesToWorkOn = [ ] . concat ( rule ) ;
209
+ // Split out the rule into each comma separated selector piece
210
+ // We only need to split if is actually comma separted(selectors > 1)
211
+ if ( rule . selectors . length > 1 ) {
212
+ // Reverse the selectors so that we can cloneAfter in the same comma separated order
213
+ rulesToWorkOn = rule . selectors . reverse ( ) . map ( function ( selector ) {
214
+ var ruleClone = rule . cloneAfter ( ) ;
215
+ ruleClone . selector = selector ;
216
+
217
+ return ruleClone ;
218
+ } ) ;
249
219
250
- // Append the old parent
251
- newParentAtRuleNode . append ( parentAtRuleNode ) ;
252
- // Then set the new one as the current for next iteration
253
- parentAtRuleNode = newParentAtRuleNode ;
220
+ rule . removeSelf ( ) ;
221
+ }
254
222
255
- currentAtRuleNode = currentAtRuleNode . parent ;
223
+ // Resolve the declarations
224
+ rulesToWorkOn . forEach ( function ( ruleToWorkOn ) {
225
+ ruleToWorkOn . nodes . slice ( 0 ) . forEach ( function ( node ) {
226
+ if ( node . type == 'decl' ) {
227
+ var decl = node ;
228
+ resolveDecl ( decl , map ) ;
256
229
}
257
-
258
- createNodeCallbackList . push ( function ( ) {
259
- // Put the atRuleStructure after the declaration's rule
260
- decl . parent . parent . insertAfter ( decl . parent , parentAtRuleNode ) ;
261
- } ) ;
262
230
} ) ;
231
+ } ) ;
263
232
264
-
265
- // If we are preserving var(...) usage and the value changed meaning it had some
266
- if ( opts . preserve === true && decl . value !== valueResults . value ) {
267
- createNodeCallbackList . push ( function ( ) {
268
- decl . cloneAfter ( ) ;
269
-
270
- // Set the new value after we are done dealing with at-rule stuff
271
- decl . value = valueResults . value ;
272
- } ) ;
273
- }
274
- else {
275
- // Set the new value after we are done dealing with at-rule stuff
276
- decl . value = valueResults . value ;
277
- }
278
-
279
- }
280
233
} ) ;
281
234
235
+
282
236
283
237
284
- // Add some nodes that we need to add
285
- // We use this so we don't add to the tree as we are processing it (infinite loop)
286
- createNodeCallbackList . forEach ( function ( cb ) {
287
- cb ( ) ;
288
- } ) ;
289
238
290
239
// Clean up any nodes we don't want anymore
291
- nodesToRemoveAtEnd . forEach ( function ( currentChildToRemove ) {
292
- // If we removed all of the declarations in the rule(making it empty), then just remove it
293
- var currentNodeToPossiblyCleanUp = currentChildToRemove ;
294
- while ( currentNodeToPossiblyCleanUp && currentNodeToPossiblyCleanUp . nodes . length <= 0 ) {
295
- var nodeToRemove = currentNodeToPossiblyCleanUp ;
296
- // Get a reference to it before we remove and lose reference to the child after removing it
297
- currentNodeToPossiblyCleanUp = currentNodeToPossiblyCleanUp . parent ;
298
-
299
- nodeToRemove . removeSelf ( ) ;
300
- }
301
- } ) ;
240
+ // We clean up at the end because we don't want to modify the AST when we still need to reference these later on
241
+ nodesToRemoveAtEnd . forEach ( cleanUpNode ) ;
302
242
303
243
304
244
//console.log('map', map);
0 commit comments