Skip to content
This repository was archived by the owner on Apr 30, 2021. It is now read-only.

Commit d433388

Browse files
committed
Some refactors, add export variables functionality
1 parent 8eb32cf commit d433388

File tree

5 files changed

+170
-127
lines changed

5 files changed

+170
-127
lines changed

index.js

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ var shallowCloneNode = require("./lib/shallow-clone-node");
1313
var resolveValue = require("./lib/resolve-value");
1414
var resolveDecl = require("./lib/resolve-decl");
1515

16+
const fs = require('fs');
17+
1618
// A custom property is any property whose name starts with two dashes (U+002D HYPHEN-MINUS)
1719
// `--foo`
1820
// See: http://dev.w3.org/csswg/css-variables/#custom-property
@@ -61,12 +63,18 @@ var defaults = {
6163
preserveInjectedVariables: true,
6264
// Will write media queries in the same order as in the original file.
6365
// Currently defaulted to false for legacy behavior. We can update to `true` in a major version
64-
preserveAtRulesOrder: false
66+
preserveAtRulesOrder: false,
67+
// Export all var statement usages to a file.
68+
exportVarUsagesTo: null,
6569
};
6670

6771
module.exports = postcss.plugin("postcss-css-variables", function(options) {
6872
var opts = extend({}, defaults, options);
6973

74+
if ( !['object'].includes( typeof opts.exportVarUsagesTo ) ) {
75+
throw new Error('`exportVarUsagesTo` must be a valid location.')
76+
}
77+
7078
// Work with opts here
7179

7280
return function(css, result) {
@@ -217,26 +225,29 @@ module.exports = postcss.plugin("postcss-css-variables", function(options) {
217225
if (rule.nodes === undefined) return;
218226

219227
var doesRuleUseVariables = rule.nodes.some(function(node) {
220-
if (node.type === "decl") {
221-
var decl = node;
222-
// If it uses variables
223-
// and is not a variable declarations that we may be preserving from earlier
224-
if (
225-
resolveValue.RE_VAR_FUNC.test(decl.value) &&
226-
!RE_VAR_PROP.test(decl.prop)
227-
) {
228-
return true;
229-
}
230-
}
231-
232-
return false;
228+
// If it uses variables
229+
// and is not a variable declarations that we may be preserving from earlier
230+
return node.type === "decl"
231+
&& resolveValue.RE_VAR_FUNC.test( node.value )
232+
&& !RE_VAR_PROP.test( node.prop )
233233
});
234234

235235
if (doesRuleUseVariables) {
236236
rulesThatHaveDeclarationsWithVariablesList.push(rule);
237237
}
238238
});
239239

240+
const allVars = {}
241+
242+
const shouldExport = () => !!opts.exportVarUsagesTo
243+
244+
const collectVar = !shouldExport() ? null : ( cssVar ) => {
245+
if ( !allVars[ cssVar.name ] ) {
246+
allVars[ cssVar.name ] = { usages: []};
247+
}
248+
allVars[ cssVar.name ].usages.push(cssVar.usage);
249+
}
250+
240251
rulesThatHaveDeclarationsWithVariablesList.forEach(function(rule) {
241252
var rulesToWorkOn = [].concat(rule);
242253
// Split out the rule into each comma separated selector piece
@@ -256,16 +267,20 @@ module.exports = postcss.plugin("postcss-css-variables", function(options) {
256267
// Resolve the declarations
257268
rulesToWorkOn.forEach(function(ruleToWorkOn) {
258269
ruleToWorkOn.nodes.slice(0).forEach(function(node) {
259-
if (node.type === "decl") {
260-
var decl = node;
261-
resolveDecl(
262-
decl,
263-
map,
264-
opts.preserve,
265-
opts.preserveAtRulesOrder,
266-
logResolveValueResult
267-
);
270+
if ( node.type !== "decl" ) {
271+
return;
268272
}
273+
let preserveAtRulesOrder;
274+
resolveDecl(
275+
node,
276+
map,
277+
{
278+
shouldPreserve: opts.preserve,
279+
preserveAtRulesOrder: opts.preserveAtRulesOrder,
280+
logResolveValueResult,
281+
collectVar,
282+
},
283+
);
269284
});
270285
});
271286
});
@@ -279,6 +294,19 @@ module.exports = postcss.plugin("postcss-css-variables", function(options) {
279294
injectedDecl.remove();
280295
});
281296

297+
// Merge variables with the ones that are already in the passed object.
298+
if ( opts.exportVarUsagesTo && allVars ) {
299+
Object.keys( allVars ).forEach( varName => {
300+
if ( 'undefined' === typeof opts.exportVarUsagesTo[ varName ] ) {
301+
opts.exportVarUsagesTo[ varName ] = {
302+
name: varName,
303+
usages: [],
304+
};
305+
}
306+
opts.exportVarUsagesTo[ varName ].usages.push( ...allVars[ varName ].usages );
307+
} );
308+
}
309+
282310
//console.log('map', map);
283311

284312
/* * /

lib/balanced-var.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const balanced = require( 'balanced-match' );
2+
3+
// Check for balanced `var(` and `)` pairs inside `value`, and return the 3 fragments:
4+
// `body` (inside), `pre` (before), `post` (after) of the found wrapper
5+
function balancedVar(value) {
6+
var match = balanced('(', ')', value)
7+
if ( !match ) {
8+
return;
9+
}
10+
if ( /(?:^|[^\w-])var$/.test( match.pre ) ) {
11+
// Remove the var from the end of pre
12+
return {
13+
pre: match.pre.slice( 0, -3 ),
14+
body: match.body,
15+
post: match.post
16+
};
17+
}
18+
// Check inside body
19+
const bodyMatch = balancedVar( match.body );
20+
if ( bodyMatch ) {
21+
// Reconstruct pre and post
22+
return {
23+
pre: match.pre + '(' + bodyMatch.pre,
24+
body: bodyMatch.body,
25+
post: bodyMatch.post + ')' + match.post
26+
};
27+
}
28+
// Check inside post
29+
var postMatch = balancedVar( match.post );
30+
31+
if ( postMatch ) {
32+
// Reconstruct pre
33+
return {
34+
pre: match.pre + '(' + match.body + ')' + postMatch.pre,
35+
body: postMatch.body,
36+
post: postMatch.post
37+
};
38+
}
39+
40+
41+
}
42+
43+
module.exports = balancedVar;

lib/resolve-decl.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,19 @@ function eachMapItemDependencyOfDecl(variablesUsedList, map, decl, cb) {
6767
}
6868

6969

70-
71-
7270
// Resolve the decl with the computed value
7371
// Also add in any media queries that change the value as necessary
74-
function resolveDecl(decl, map, /*optional*/shouldPreserve, /*optional*/preserveAtRulesOrder, /*optional*/logResolveValueResult) {
75-
shouldPreserve = (typeof shouldPreserve === "function" ? shouldPreserve(decl) : shouldPreserve) || false;
72+
function resolveDecl(
73+
decl,
74+
map,
75+
{
76+
shouldPreserve = false,
77+
preserveAtRulesOrder,
78+
logResolveValueResult,
79+
collectVar,
80+
}
81+
) {
82+
shouldPreserve = typeof shouldPreserve === "function" ? shouldPreserve( decl ) : shouldPreserve;
7683
preserveAtRulesOrder = preserveAtRulesOrder || false;
7784

7885
// Make it chainable
@@ -88,8 +95,7 @@ function resolveDecl(decl, map, /*optional*/shouldPreserve, /*optional*/preserve
8895

8996
// Grab the balue for this declarations
9097
//console.log('resolveDecl 1');
91-
var valueResults = _logResolveValueResult(resolveValue(decl, map));
92-
98+
var valueResults = _logResolveValueResult(resolveValue(decl, map, {collectVar}));
9399

94100
// Resolve the cascade dependencies
95101
// Now find any at-rule declarations that need to be added below each rule
@@ -112,7 +118,7 @@ function resolveDecl(decl, map, /*optional*/shouldPreserve, /*optional*/preserve
112118
}
113119

114120
// No mangle resolve
115-
declClone.value = _logResolveValueResult(resolveValue(mimicDecl, map, true)).value;
121+
declClone.value = _logResolveValueResult(resolveValue(mimicDecl, map, {ignorePseudoScope: true})).value;
116122

117123
if(mapItem.isUnderAtRule) {
118124
// Create the clean atRule for which we place the declaration under

0 commit comments

Comments
 (0)