diff --git a/README.md b/README.md index 85f2185..1f16ac3 100644 --- a/README.md +++ b/README.md @@ -375,6 +375,12 @@ Keeps your at-rules like media queries in the order to defined them. Ideally, this would be defaulted to `true` and it will be in the next major version. All of the tests expecations need to be updated and probably just drop support for `preserveAtRulesOrder: false` +### `preserveUndefinedVariables` (default: `false`) + +Whether to preserve the undefined variables in final output. + +Setting this option to `true` leaves any undefined variables as is in output CSS. + # Quick Reference/Notes - This plugin was spawned out of a [discussion on the `cssnext` repo](https://github.com/cssnext/cssnext/issues/99). diff --git a/index.js b/index.js index 4174270..453ec68 100644 --- a/index.js +++ b/index.js @@ -60,7 +60,9 @@ var defaults = { preserveInjectedVariables: true, // Will write media queries in the same order as in the original file. // Currently defaulted to false for legacy behavior. We can update to `true` in a major version - preserveAtRulesOrder: false + preserveAtRulesOrder: false, + // Preserve undefined variables as is in final output. + preserveUndefinedVariables: false }; module.exports = (options = {}) => { @@ -158,7 +160,7 @@ module.exports = (options = {}) => { eachCssVariableDeclaration(css, function(decl) { var declParentRule = decl.parent; - var valueResults = logResolveValueResult(resolveValue(decl, map)); + var valueResults = logResolveValueResult(resolveValue(decl, map, opts.preserveUndefinedVariables)); // 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 @@ -263,6 +265,7 @@ module.exports = (options = {}) => { map, opts.preserve, opts.preserveAtRulesOrder, + opts.preserveUndefinedVariables, logResolveValueResult ); } diff --git a/lib/resolve-decl.js b/lib/resolve-decl.js index e469849..cf17b2e 100644 --- a/lib/resolve-decl.js +++ b/lib/resolve-decl.js @@ -71,7 +71,7 @@ function eachMapItemDependencyOfDecl(variablesUsedList, map, decl, cb) { // Resolve the decl with the computed value // Also add in any media queries that change the value as necessary -function resolveDecl(decl, map, /*optional*/shouldPreserve, /*optional*/preserveAtRulesOrder, /*optional*/logResolveValueResult) { +function resolveDecl(decl, map, /*optional*/shouldPreserve, /*optional*/preserveAtRulesOrder, /*optional*/preserveUndefinedVariables, /*optional*/logResolveValueResult) { shouldPreserve = (typeof shouldPreserve === "function" ? shouldPreserve(decl) : shouldPreserve) || false; preserveAtRulesOrder = preserveAtRulesOrder || false; @@ -88,7 +88,7 @@ function resolveDecl(decl, map, /*optional*/shouldPreserve, /*optional*/preserve // Grab the balue for this declarations //console.log('resolveDecl 1'); - var valueResults = _logResolveValueResult(resolveValue(decl, map)); + var valueResults = _logResolveValueResult(resolveValue(decl, map, preserveUndefinedVariables)); // Resolve the cascade dependencies @@ -112,7 +112,7 @@ function resolveDecl(decl, map, /*optional*/shouldPreserve, /*optional*/preserve } // No mangle resolve - declClone.value = _logResolveValueResult(resolveValue(mimicDecl, map, true)).value; + declClone.value = _logResolveValueResult(resolveValue(mimicDecl, map, preserveUndefinedVariables, true)).value; if(mapItem.isUnderAtRule) { // Create the clean atRule for which we place the declaration under diff --git a/lib/resolve-value.js b/lib/resolve-value.js index 60b6789..2048370 100644 --- a/lib/resolve-value.js +++ b/lib/resolve-value.js @@ -61,7 +61,7 @@ function balancedVar(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, /*optional*/ignorePseudoScope, /*internal debugging*/_debugIsInternal) { +var resolveValue = function(decl, map, /*optional*/preserveUndefinedVariables, /*optional*/ignorePseudoScope, /*internal debugging*/_debugIsInternal) { var debugIndent = _debugIsInternal ? '\t' : ''; var matchingVarDecl = undefined; @@ -136,7 +136,7 @@ var resolveValue = function(decl, map, /*optional*/ignorePseudoScope, /*internal var fallbackValue = fallback; if(fallback) { var fallbackDecl = decl.clone({ parent: decl.parent, value: fallback }); - fallbackValue = resolveValue(fallbackDecl, map, false, /*internal*/true).value; + fallbackValue = resolveValue(fallbackDecl, map, preserveUndefinedVariables, false, /*internal*/true).value; } return fallbackValue; @@ -153,7 +153,7 @@ var resolveValue = function(decl, map, /*optional*/ignorePseudoScope, /*internal return ancestor === nodeToSpliceParentOnto; }); - replaceValue = resolveValue(matchingMimicDecl, map, false, /*internal*/true).value; + replaceValue = resolveValue(matchingMimicDecl, map, preserveUndefinedVariables, false, /*internal*/true).value; } isResultantValueUndefined = replaceValue === undefined; @@ -167,7 +167,9 @@ var resolveValue = function(decl, map, /*optional*/ignorePseudoScope, /*internal return { // The resolved value - value: !isResultantValueUndefined ? resultantValue : undefined, + value: isResultantValueUndefined ? + (preserveUndefinedVariables ? decl.value : undefined) : + resultantValue, // Array of variable names used in resolving this value variablesUsed: variablesUsedInValue, // Any warnings generated from parsing this value