postcss-css-variables
Advanced tools
Comparing version
# v0.3.5 - 2015-5-12 | ||
- Big refactor of code to reduce cyclomatic complexity. Still needs work though. | ||
- Fix variable referencing another variable resolution when being changed by at-rule in non-root rule | ||
# v0.3.4 - 2015-5-12 | ||
- Fix variable referencing another variable resolution when being changed by at-rule | ||
# v0.3.3 - 2015-5-11 | ||
@@ -7,3 +16,2 @@ | ||
# v0.3.1 - 2015-5-5 | ||
@@ -18,3 +26,2 @@ | ||
# v0.2.2 - 2015-5-1 | ||
@@ -21,0 +28,0 @@ |
543
index.js
// PostCSS CSS Variables (postcss-css-variables) | ||
// v0.3.3 | ||
// v0.3.5 | ||
// | ||
@@ -11,4 +11,11 @@ // https://github.com/MadLittleMods/postcss-css-variables | ||
var extend = require('extend'); | ||
var escapeStringRegexp = require('escape-string-regexp'); | ||
var cloneSpliceParentOntoNodeWhen = require('./lib/clone-splice-parent-onto-node-when'); | ||
var findNodeAncestorWithSelector = require('./lib/find-node-ancestor-with-selector'); | ||
var resolveValue = require('./lib/resolve-value'); | ||
var isNodeUnderScope = require('./lib/is-node-under-scope'); | ||
var generateScopeList = require('./lib/generate-scope-list'); | ||
var gatherVariableDependencies = require('./lib/gather-variable-dependencies'); | ||
// A custom property is any property whose name starts with two dashes (U+002D HYPHEN-MINUS) | ||
@@ -18,301 +25,60 @@ // `--foo` | ||
var RE_VAR_PROP = (/(--(.+))/); | ||
// matches `name[, fallback]`, captures "name" and "fallback" | ||
// var() = var( <custom-property-name> [, <any-value> ]? ) | ||
// See: http://dev.w3.org/csswg/css-variables/#funcdef-var | ||
var RE_VAR_FUNC = (/var\((--[^,\s]+?)(?:\s*,\s*(.+))?\)/); | ||
// Unit Tests: https://regex101.com/r/oP0fM9/13 | ||
// | ||
// It is a shame the regex has to be this long. Maybe a CSS selector parser would be better. | ||
// We could almost use `/\b\s(?![><+~][\s]+?)/` to split the selector but this doesn't work with attribute selectors | ||
var RE_SELECTOR_DESCENDANT_SPLIT = (/(.*?(?:(?:\[[^\]]+\]|(?![><+~\s]).)+)(?:(?:(?:\s(?!>>))|(?:\t(?!>>))|(?:\s?>>\s?))(?!\s+))(?![><+~][\s]+?))/); | ||
// Splice on a parent scope onto a node | ||
// And return a detached clone | ||
function cloneSpliceParentOntoNodeWhen(node, parent, /*optional*/whenCb) { | ||
whenCb = whenCb || function() { | ||
return true; | ||
}; | ||
var cloneList = []; | ||
// Gather node ancestors and clone along the way | ||
var current = node; | ||
var isWhenNow = false; | ||
while(current && !isWhenNow) { | ||
if(current.type === 'decl') { | ||
cloneList.push(current.clone()); | ||
function eachCssVariableDeclaration(css, cb) { | ||
// Loop through all of the declarations and grab the variables and put them in the map | ||
css.eachDecl(function(decl, index) { | ||
// If declaration is a variable | ||
if(RE_VAR_PROP.test(decl.prop)) { | ||
cb(decl); | ||
} | ||
else { | ||
cloneList.push(current.clone().removeAll()); | ||
} | ||
isWhenNow = whenCb(current); | ||
current = current.parent; | ||
} | ||
// Gather parent ancestors all the way up and clone along the way | ||
var cloneParentList = []; | ||
var currentParent = parent; | ||
while(currentParent) { | ||
cloneParentList.push(currentParent.clone().removeAll()); | ||
currentParent = currentParent.parent; | ||
} | ||
// Assign parents to our parent clones | ||
cloneParentList.forEach(function(parentClone, index, cloneParentList) { | ||
// Keep assigning parents detached until the very end | ||
if(index+1 < cloneParentList.length) { | ||
parentClone.parent = cloneParentList[index+1]; | ||
} | ||
}); | ||
// Assign parents to our node clones | ||
cloneList.forEach(function(clone, index, cloneList) { | ||
// Keep assigning parents detached until the very end | ||
if(index+1 < cloneList.length) { | ||
clone.parent = cloneList[index+1]; | ||
// Then splice on the new parent scope | ||
} else { | ||
// Set the highest parent ancestor to back to where we should splice in | ||
cloneParentList.slice(-1)[0].parent = current; | ||
// Set the node clone to the lowest parent ancestor | ||
clone.parent = cloneParentList[0]; | ||
} | ||
}); | ||
return cloneList[0]; | ||
} | ||
// Find a node starting from the given node that matches | ||
function findNodeAncestorWithSelector(selector, node) { | ||
var matchingNode; | ||
function eachMapItemUnderAtRuleUsedByVariable(variablesUsedList, map, decl, cb) { | ||
// Now find any at-rule declarations that pertains to each rule | ||
// Loop through the variables used | ||
variablesUsedList.forEach(function(variableUsedName) { | ||
var currentNode = node; | ||
var stillFindingNode = true; | ||
// Keep going until we run out of parents to search | ||
// or we found the node | ||
while(currentNode.parent && !matchingNode) { | ||
// A trick to get the selector split up. Generate a scope list on a clone(clean parent) | ||
var currentNodeScopeList = generateScopeList(currentNode.clone(), true); | ||
currentNodeScopeList.some(function(scopePieces) { | ||
return scopePieces.some(function(scopePiece) { | ||
if(scopePiece === selector) { | ||
matchingNode = currentNode; | ||
return true; | ||
} | ||
return false; | ||
}); | ||
}); | ||
currentNode = currentNode.parent; | ||
} | ||
return matchingNode; | ||
} | ||
function generateDescendantPieces(selector) { | ||
return selector.split(RE_SELECTOR_DESCENDANT_SPLIT) | ||
.filter(function(piece) { | ||
if(piece.length > 0) { | ||
return true; | ||
} | ||
return false; | ||
}) | ||
.map(function(piece) { | ||
// Trim whitespace which would be a normal descendant selector | ||
// and trim off the CSS4 descendant `>>` into a normal descendant selector | ||
return piece.trim().replace(/\s*?>>\s*?/, function(match) { | ||
return ''; | ||
}); | ||
}); | ||
} | ||
function generateScopeList(node, /*optional*/includeSelf) { | ||
includeSelf = includeSelf || false; | ||
var selectorScopeList = [ | ||
// Start off with one branch | ||
[] | ||
]; | ||
var currentNodeParent = includeSelf ? node : node.parent; | ||
while(currentNodeParent) { | ||
// `currentNodeParent.selectors` is a list of each comma separated piece of the selector | ||
var scopePieces = (currentNodeParent.selectors || []).map(function(selectorPiece) { | ||
return { | ||
value: selectorPiece, | ||
type: 'selector' | ||
}; | ||
}); | ||
// If it is a at-rule, then we need to construct the proper piece | ||
if(currentNodeParent.type === 'atrule') { | ||
scopePieces = [].concat(currentNodeParent.params).map(function(param, index) { | ||
return { | ||
value: '@' + currentNodeParent.name + ' ' + param, | ||
type: 'atrule' | ||
}; | ||
}); | ||
} | ||
// Branch each current scope for each comma separated selector | ||
// Otherwise just keep the [1] branch going | ||
var branches = (scopePieces.length > 0 ? scopePieces : [1]).map(function() { | ||
return selectorScopeList.map(function(scopePieces) { | ||
return scopePieces.slice(0); | ||
}); | ||
}); | ||
scopePieces.forEach(function(scopeObject, index) { | ||
// Update each selector string with the new piece | ||
branches[index] = branches[index].map(function(scopeStringPieces) { | ||
var descendantPieces = [scopeObject.value]; | ||
// Split at any descendant combinators to properly make the scope list | ||
if(scopeObject.type === 'selector') { | ||
descendantPieces = generateDescendantPieces(scopeObject.value); | ||
} | ||
// Add to the front of the array | ||
scopeStringPieces.unshift.apply(scopeStringPieces, descendantPieces); | ||
// Find anything in the map that corresponds to that variable | ||
gatherVariableDependencies(variablesUsedList, map).deps.forEach(function(mapItem) { | ||
if(mapItem.isUnderAtRule) { | ||
return scopeStringPieces; | ||
}); | ||
}); | ||
// Get the inner-most selector of the at-rule scope variable declaration we are matching | ||
// 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 | ||
var varDeclScopeList = generateScopeList(mapItem.parent, true); | ||
var innerMostAtRuleSelector = varDeclScopeList[0].slice(-1)[0]; | ||
var nodeToSpliceParentOnto = findNodeAncestorWithSelector(innerMostAtRuleSelector, decl.parent); | ||
// Start from a new list so we can | ||
// Flatten out the branches a bit and and merge back into the list | ||
selectorScopeList = []; | ||
branches.forEach(function(branch) { | ||
selectorScopeList = selectorScopeList.concat(branch); | ||
}); | ||
// Splice on where the selector starts matching the selector inside at-rule | ||
// See: `test/fixtures/cascade-on-nested-rules.css` | ||
var varDeclAtRule = mapItem.parent.parent; | ||
var mimicDecl = cloneSpliceParentOntoNodeWhen(decl, varDeclAtRule, function(ancestor) { | ||
return ancestor === nodeToSpliceParentOnto; | ||
}); | ||
currentNodeParent = currentNodeParent.parent; | ||
} | ||
return selectorScopeList; | ||
} | ||
//console.log('amd og', generateScopeList(decl.parent, true)); | ||
//console.log('amd', generateScopeList(mimicDecl.parent, true)); | ||
//console.log(generateScopeList(mapItem.parent, true)); | ||
//console.log('amd isNodeUnderScope', isNodeUnderScope(mimicDecl.parent, mapItem.parent), mapItem.decl.value); | ||
function isUnderScope(nodeScopeList, scopeNodeScopeList) { | ||
var matchesScope = scopeNodeScopeList.some(function(scopeNodeScopePieces) { | ||
return nodeScopeList.some(function(nodeScopePieces) { | ||
var currentPieceOffset; | ||
var wasEveryPieceFound = scopeNodeScopePieces.every(function(scopePiece) { | ||
var pieceOffset = currentPieceOffset || 0; | ||
// Start from the previous index and make sure we can find it | ||
//var foundIndex = nodeScopePieces.indexOf(scopePiece, pieceOffset); | ||
var foundIndex = -1; | ||
var piecesWeCanMatch = nodeScopePieces.slice(pieceOffset); | ||
piecesWeCanMatch.some(function(nodeScopePiece, index) { | ||
// Find the scope piece at the end of the node selector | ||
// Last-occurence | ||
if(new RegExp(escapeStringRegexp(scopePiece) + '$').test(nodeScopePiece)) { | ||
foundIndex = pieceOffset + index; | ||
// Escape | ||
return true; | ||
} | ||
return false; | ||
}); | ||
// If it is a star or root, then it is valid no matter what | ||
// We might consider adding `html` and `body` to this list as well | ||
if(foundIndex < 0 && (scopePiece === '*' || scopePiece === ':root')) { | ||
foundIndex = pieceOffset + 1; | ||
// If it is under the proper scope, | ||
// we need to check because we are iterating over all map entries that are `isUnderAtRule` | ||
// Then lets create the new rules | ||
if(isNodeUnderScope(mimicDecl.parent, mapItem.parent)) { | ||
cb(mimicDecl, mapItem); | ||
} | ||
var isFurther = foundIndex > pieceOffset || (foundIndex >= 0 && currentPieceOffset === undefined); | ||
currentPieceOffset = foundIndex; | ||
return isFurther; | ||
}); | ||
return wasEveryPieceFound; | ||
} | ||
}); | ||
}); | ||
return matchesScope; | ||
} | ||
function isNodeUnderNode(node, scopeNode) { | ||
var nodeScopeList = generateScopeList(node, true); | ||
var scopeNodeScopeList = generateScopeList(scopeNode, true); | ||
return isUnderScope(nodeScopeList, scopeNodeScopeList); | ||
} | ||
// Pass in a value string to parse/resolve and a map of available values | ||
// and we can figure out the final value | ||
// | ||
// Note: We do not modify the declaration | ||
// Note: Resolving a declaration value without any `var(...)` does not harm the final value. | ||
// This means, feel free to run everything through this function | ||
var resolveValue = function(decl, map) { | ||
var resultantValue = decl.value; | ||
var variablesUsedInValue = []; | ||
var warnings = []; | ||
// Resolve any var(...) substitutons | ||
var isResultantValueUndefined = false; | ||
resultantValue = resultantValue.replace(new RegExp(RE_VAR_FUNC.source, 'g'), function(match, variableName, fallback) { | ||
variablesUsedInValue.push(variableName); | ||
// Loop through the list of declarations for that value and find the one that best matches | ||
// By best match, we mean, the variable actually applies. Criteria: | ||
// - At the root | ||
// - Defined in the same rule | ||
// - The latest defined `!important` if any | ||
var matchingVarDeclMapItem; | ||
(map[variableName] || []).forEach(function(varDeclMapItem) { | ||
// Make sure the variable declaration came from the right spot | ||
// And if the current matching variable is already important, a new one to replace it has to be important | ||
var isRoot = varDeclMapItem.parent.type === 'root' || varDeclMapItem.parent.selectors[0] === ':root'; | ||
//console.log(generateScopeList(decl.parent, true)); | ||
//console.log(generateScopeList(varDeclMapItem.parent, true)); | ||
//console.log('isNodeUnderNode', isNodeUnderNode(decl.parent, varDeclMapItem.parent), varDeclMapItem.value); | ||
if( | ||
isNodeUnderNode(decl.parent, varDeclMapItem.parent) && | ||
// And if the currently matched declaration is `!important`, it will take another `!important` to override it | ||
(!(matchingVarDeclMapItem || {}).isImportant || varDeclMapItem.isImportant) | ||
) { | ||
matchingVarDeclMapItem = varDeclMapItem; | ||
} | ||
}); | ||
var replaceValue = (matchingVarDeclMapItem || {}).value || fallback; | ||
isResultantValueUndefined = replaceValue === undefined; | ||
if(isResultantValueUndefined) { | ||
warnings.push(["variable '" + variableName + "' is undefined and used without a fallback", { node: decl }]); | ||
} | ||
return replaceValue; | ||
}); | ||
return { | ||
// The resolved value | ||
value: !isResultantValueUndefined ? resultantValue : undefined, | ||
// Array of variable names used in resolving this value | ||
variablesUsed: variablesUsedInValue, | ||
// Any warnings generated from parsing this value | ||
warnings: warnings | ||
}; | ||
}; | ||
module.exports = postcss.plugin('postcss-css-variables', function(options) { | ||
@@ -352,32 +118,38 @@ var defaults = { | ||
map, | ||
Object.keys(opts.variables) | ||
.reduce(function(prevVariableMap, variableName) { | ||
var variableValue = opts.variables[variableName]; | ||
// Automatically prefix any variable with `--` (CSS custom property syntax) if it doesn't have it already | ||
variableName = variableName.slice(0, 2) === '--' ? variableName : '--' + variableName; | ||
Object.keys(opts.variables).reduce(function(prevVariableMap, variableName) { | ||
var variableEntry = opts.variables[variableName]; | ||
// Automatically prefix any variable with `--` (CSS custom property syntax) if it doesn't have it already | ||
variableName = variableName.slice(0, 2) === '--' ? variableName : '--' + variableName; | ||
var variableValue = (variableEntry || {}).value || variableEntry; | ||
var isImportant = (variableEntry || {}).isImportant || false; | ||
// If they didn't pass a object, lets construct one | ||
if(typeof variableValue !== 'object') { | ||
variableValue = { | ||
value: variableValue, | ||
isImportant: false, | ||
parent: css.root(), | ||
isUnderAtRule: false | ||
}; | ||
} | ||
// Add a root node to the AST | ||
var variableRootRule = postcss.rule({ selector: ':root' }); | ||
css.root().prepend(variableRootRule); | ||
// Add the variable decl to the root node | ||
var varDecl = postcss.decl({ | ||
prop: variableName, | ||
value: variableValue | ||
}); | ||
varDecl.moveTo(variableRootRule); | ||
prevVariableMap[variableName] = (prevVariableMap[variableName] || []).concat(extend({ | ||
value: undefined, | ||
isImportant: false, | ||
parent: css.root(), | ||
isUnderAtRule: false | ||
}, variableValue)); | ||
// Add the entry to the map | ||
prevVariableMap[variableName] = (prevVariableMap[variableName] || []).concat({ | ||
decl: varDecl, | ||
prop: variableName, | ||
calculatedInPlaceValue: variableValue, | ||
isImportant: isImportant, | ||
variablesUsed: [], | ||
parent: variableRootRule, | ||
isUnderAtRule: false | ||
}); | ||
return prevVariableMap; | ||
}, {}) | ||
return prevVariableMap; | ||
}, {}) | ||
); | ||
// Chainable helper function to log any messages (warnings) | ||
function logResolveValueResult(valueResult) { | ||
var logResolveValueResult = function(valueResult) { | ||
// Log any warnings that might of popped up | ||
@@ -392,3 +164,3 @@ var warningList = [].concat(valueResult.warnings); | ||
return valueResult; | ||
} | ||
}; | ||
@@ -399,57 +171,44 @@ | ||
// --------------------------------------------------------- | ||
var addedRules = []; | ||
css.eachRule(function(rule) { | ||
// We don't want infinite recursion possibly, so don't iterate over the rules we add inside | ||
var shouldNotIterateOverThisRule = addedRules.some(function(addedRule) { | ||
return addedRule === rule; | ||
}); | ||
if(shouldNotIterateOverThisRule) { | ||
return; | ||
} | ||
eachCssVariableDeclaration(css, function(decl) { | ||
var declParentRule = decl.parent; | ||
var valueResults = logResolveValueResult(resolveValue(decl, map)); | ||
// Split out each selector piece into its own declaration for easier logic down the road | ||
decl.parent.selectors.forEach(function(selector) { | ||
// Create a detached clone | ||
var splitOutRule = decl.parent.clone().removeAll(); | ||
splitOutRule.selector = selector; | ||
splitOutRule.parent = decl.parent.parent; | ||
var numberOfStartingChildren = rule.nodes.length; | ||
var declClone = decl.clone(); | ||
declClone.moveTo(splitOutRule); | ||
// Loop through all of the declarations and grab the variables and put them in the map | ||
rule.eachDecl(function(decl, index) { | ||
var prop = decl.prop; | ||
// If declaration is a variable | ||
if(RE_VAR_PROP.test(prop)) { | ||
var resolvedValue = logResolveValueResult(resolveValue(decl, map)).value; | ||
if(resolvedValue !== undefined) { | ||
// Split out each selector piece into its own declaration for easier logic down the road | ||
decl.parent.selectors.forEach(function(selector, index) { | ||
// Create a detached clone | ||
var splitOutRule = rule.clone(); | ||
rule.selector = selector; | ||
splitOutRule.parent = rule.parent; | ||
map[prop] = (map[prop] || []).concat({ | ||
prop: prop, | ||
value: resolvedValue, | ||
isImportant: decl.important || false, | ||
// variables inside root or at-rules (eg. @media, @support) | ||
parent: splitOutRule, | ||
isUnderAtRule: splitOutRule.parent.type === 'atrule' | ||
}); | ||
}); | ||
} | ||
// Remove the variable declaration because they are pretty much useless after we resolve them | ||
if(!opts.preserve) { | ||
decl.removeSelf(); | ||
} | ||
// Or we can also just show the computed value used for that variable | ||
else if(opts.preserve === 'computed') { | ||
decl.value = resolvedValue; | ||
} | ||
// Otherwise just keep them as var declarations | ||
} | ||
map[prop] = (map[prop] || []).concat({ | ||
decl: declClone, | ||
prop: prop, | ||
calculatedInPlaceValue: valueResults.value, | ||
isImportant: decl.important || false, | ||
variablesUsed: valueResults.variablesUsed, | ||
parent: splitOutRule, | ||
// variables inside root or at-rules (eg. @media, @support) | ||
isUnderAtRule: splitOutRule.parent.type === 'atrule' | ||
}); | ||
}); | ||
// We don't want to mess up their code if they wrote a empty rule | ||
// We add to the clean up list if we removed some variable declarations to make it become empty | ||
if(numberOfStartingChildren > 0 && rule.nodes.length <= 0) { | ||
nodesToRemoveAtEnd.push(rule); | ||
// Remove the variable declaration because they are pretty much useless after we resolve them | ||
if(!opts.preserve) { | ||
decl.removeSelf(); | ||
} | ||
// Or we can also just show the computed value used for that variable | ||
else if(opts.preserve === 'computed') { | ||
decl.value = valueResults.value; | ||
} | ||
// Otherwise just keep them as var declarations | ||
//else {} | ||
// We add to the clean up list if we removed some variable declarations to make it become an empty rule | ||
if(declParentRule.nodes.length <= 0) { | ||
nodesToRemoveAtEnd.push(declParentRule); | ||
} | ||
}); | ||
@@ -459,3 +218,2 @@ | ||
// Resolve variables everywhere | ||
@@ -474,69 +232,37 @@ // --------------------------------------------------------- | ||
// Resolve the cascade | ||
// Now find any at-rule declarations that need to be added below each rule | ||
// Loop through the variables used | ||
valueResults.variablesUsed.forEach(function(variableUsedName) { | ||
// Find anything in the map that corresponds to that variable | ||
(map[variableUsedName] || []).forEach(function(varDeclMapItem) { | ||
if(varDeclMapItem.isUnderAtRule) { | ||
eachMapItemUnderAtRuleUsedByVariable(valueResults.variablesUsed, map, decl, function(mimicDecl, mapItem) { | ||
// Create the clean atRule for which we place the declaration under | ||
var atRuleNode = mapItem.parent.parent.clone().removeAll(); | ||
// Get the inner-most selector of the at-rule scope variable declaration we are matching | ||
// Because the inner-most selector will be the same for each branch, we can look in any of them | ||
var varDeclScopeList = generateScopeList(varDeclMapItem.parent, true); | ||
var selector = varDeclScopeList[0].slice(-1)[0]; | ||
var ruleClone = decl.parent.clone().removeAll(); | ||
var declClone = decl.clone(); | ||
declClone.value = logResolveValueResult(resolveValue(mimicDecl, map)).value; | ||
var currentNodeToSpliceParentOnto = findNodeAncestorWithSelector(selector, decl.parent); | ||
// Add the declaration to our new rule | ||
ruleClone.append(declClone); | ||
// Add the rule to the atRule | ||
atRuleNode.append(ruleClone); | ||
var varDeclAtRule = varDeclMapItem.parent.parent; | ||
var mimicDecl = cloneSpliceParentOntoNodeWhen(decl, varDeclAtRule, function(ancestor) { | ||
return ancestor === currentNodeToSpliceParentOnto; | ||
}); | ||
// Since that atRuleNode can be nested in other atRules, we need to make the appropriate structure | ||
var parentAtRuleNode = atRuleNode; | ||
var currentAtRuleNode = mapItem.parent.parent; | ||
while(currentAtRuleNode.parent.type === 'atrule') { | ||
// Create a new clean clone of that at rule to nest under | ||
var newParentAtRuleNode = currentAtRuleNode.parent.clone().removeAll(); | ||
// Append the old parent | ||
newParentAtRuleNode.append(parentAtRuleNode); | ||
// Then set the new one as the current for next iteration | ||
parentAtRuleNode = newParentAtRuleNode; | ||
//console.log('amd og', generateScopeList(decl.parent, true)); | ||
//console.log('amd', generateScopeList(mimicDecl.parent, true)); | ||
//console.log(generateScopeList(varDeclMapItem.parent, true)); | ||
//console.log('amd isNodeUnderNode', isNodeUnderNode(mimicDecl.parent, varDeclMapItem.parent), varDeclMapItem.value); | ||
currentAtRuleNode = currentAtRuleNode.parent; | ||
} | ||
// If it is under the proper scope | ||
// Then lets create the new rules | ||
if(isNodeUnderNode(mimicDecl.parent, varDeclMapItem.parent)) { | ||
// Create the clean atRule for which we place the declaration under | ||
var atRuleNode = varDeclMapItem.parent.parent.clone().removeAll(); | ||
var ruleClone = decl.parent.clone().removeAll(); | ||
var declClone = decl.clone(); | ||
declClone.value = logResolveValueResult(resolveValue(mimicDecl, map)).value; | ||
// Add the declaration to our new rule | ||
ruleClone.append(declClone); | ||
// Add the rule to the atRule | ||
atRuleNode.append(ruleClone); | ||
// Since that atRuleNode can be nested in other atRules, we need to make the appropriate structure | ||
var parentAtRuleNode = atRuleNode; | ||
var currentAtRuleNode = varDeclMapItem.parent.parent; | ||
while(currentAtRuleNode.parent.type === 'atrule') { | ||
// Create a new clean clone of that at rule to nest under | ||
var newParentAtRuleNode = currentAtRuleNode.parent.clone().removeAll(); | ||
// Append the old parent | ||
newParentAtRuleNode.append(parentAtRuleNode); | ||
// Then set the new one as the current for next iteration | ||
parentAtRuleNode = newParentAtRuleNode; | ||
currentAtRuleNode = currentAtRuleNode.parent; | ||
} | ||
createNodeCallbackList.push(function() { | ||
// Put the atRuleStructure after the declaration's rule | ||
decl.parent.parent.insertAfter(decl.parent, parentAtRuleNode); | ||
}); | ||
} | ||
} | ||
createNodeCallbackList.push(function() { | ||
// Put the atRuleStructure after the declaration's rule | ||
decl.parent.parent.insertAfter(decl.parent, parentAtRuleNode); | ||
}); | ||
@@ -590,2 +316,3 @@ }); | ||
catch(e) { | ||
//console.log('e', e.message); | ||
console.log('e', e.message, e.stack); | ||
@@ -592,0 +319,0 @@ } |
{ | ||
"name": "postcss-css-variables", | ||
"version": "0.3.3", | ||
"version": "0.3.5", | ||
"description": "PostCSS plugin to transform CSS Custom Properties(CSS variables) syntax into a static representation", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -11,3 +11,3 @@ [](http://badge.fury.io/js/postcss-css-variables) [](https://travis-ci.org/MadLittleMods/postcss-css-variables) | ||
## Latest Version: v0.3.3 | ||
## Latest Version: v0.3.5 | ||
### [Changelog](https://github.com/MadLittleMods/postcss-css-variables/blob/master/CHANGELOG.md) | ||
@@ -14,0 +14,0 @@ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
38743
22.76%15
150%584
24.26%1
Infinity%