11// PostCSS CSS Variables (postcss-css-variables)
2- // v0.3.5
2+ // v0.3.6
33//
44// https://github.com/MadLittleMods/postcss-css-variables
55
99var postcss = require ( 'postcss' ) ;
1010var extend = require ( 'extend' ) ;
1111
12- var cloneSpliceParentOntoNodeWhen = require ( './lib/clone-splice-parent-onto-node-when' ) ;
13- var findNodeAncestorWithSelector = require ( './lib/find-node-ancestor-with-selector' ) ;
1412var 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' ) ;
1814
1915
2016// A custom property is any property whose name starts with two dashes (U+002D HYPHEN-MINUS)
@@ -36,49 +32,22 @@ function eachCssVariableDeclaration(css, cb) {
3632}
3733
3834
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-
6135
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 ;
6643
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+ }
7646}
7747
7848
7949
8050
81-
8251module . exports = postcss . plugin ( 'postcss-css-variables' , function ( options ) {
8352 var defaults = {
8453 // Allows you to preserve custom properties & var() usage in output.
@@ -100,9 +69,6 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
10069 try {
10170 /* */
10271
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 = [ ] ;
10672 // List of nodes that if empty, will be removed
10773 // We use this because we don't want to modify the AST when we still need to reference these later on
10874 var nodesToRemoveAtEnd = [ ] ;
@@ -203,102 +169,76 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
203169 //else {}
204170
205171 // 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
206173 if ( declParentRule . nodes . length <= 0 ) {
207174 nodesToRemoveAtEnd . push ( declParentRule ) ;
208175 }
209176 } ) ;
210177
211178
212179
180+
181+
213182 // Resolve variables everywhere
214183 // ---------------------------------------------------------
215184 // ---------------------------------------------------------
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-
226185
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+ }
236198
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+ } ) ;
241201
202+ if ( doesRuleUseVariables ) {
203+ rulesThatHaveDeclarationsWithVariablesList . push ( rule ) ;
204+ }
205+ } ) ;
242206
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+ } ) ;
249219
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+ }
254222
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 ) ;
256229 }
257-
258- createNodeCallbackList . push ( function ( ) {
259- // Put the atRuleStructure after the declaration's rule
260- decl . parent . parent . insertAfter ( decl . parent , parentAtRuleNode ) ;
261- } ) ;
262230 } ) ;
231+ } ) ;
263232
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- }
280233 } ) ;
281234
235+
282236
283237
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- } ) ;
289238
290239 // 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 ) ;
302242
303243
304244 //console.log('map', map);
0 commit comments