Skip to content

Commit ac72f50

Browse files
committed
Add opts.preserve (still need to tackle 'computed') and opts.preserveInjectedVariables support
1 parent 79c05ff commit ac72f50

8 files changed

+68
-30
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# v1.0.0 - *upcoming*
2+
3+
- Complete rewrite of the codebase using `postcss-node-scope-utility`
4+
- Order is preserved instead of reversed, https://github.com/MadLittleMods/postcss-css-variables/issues/30
5+
- Fix variable only used from last pseudo-element, https://github.com/MadLittleMods/postcss-css-variables/issues/46
6+
- Variables supplied by `opts.variables` now live a single `:root` rule and don't leave empty `:root` around
7+
18

29
# v0.9.0 - 2018-6-26
310

index.js

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,16 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
5757
// Map of variable names to a list of declarations
5858
let map = {};
5959

60+
6061
// Add the js defined variables `opts.variables` to the map
61-
Object.keys(opts.variables).forEach(function(prevVariableMap, variableKey) {
62+
// ---------------------------------------------------------
63+
// ---------------------------------------------------------
64+
const rootNode = postcss.rule({ selector: ':root' });
65+
if(opts.variables && Object.keys(opts.variables).length > 0 && opts.preserve && opts.preserveInjectedVariables) {
66+
css.prepend(rootNode);
67+
}
68+
69+
Object.keys(opts.variables).forEach(function(variableKey) {
6270
const variableEntry = opts.variables[variableKey];
6371
// Automatically prefix any variable with `--` (CSS custom property syntax) if it doesn't have it already
6472
const variableName = variableKey.slice(0, 2) === '--' ? variableKey : '--' + variableKey;
@@ -70,14 +78,19 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
7078
name: variableName,
7179
value: variableValue,
7280
isImportant,
73-
selectorBranches: [':root']
81+
selectorBranches: generateSelectorBranchesFromPostcssNode(rootNode)
7482
});
83+
84+
if(opts.preserve && opts.preserveInjectedVariables) {
85+
const variableDecl = postcss.decl({ prop: variableName, value: variableValue });
86+
rootNode.append(variableDecl);
87+
}
7588
});
7689

7790

7891

7992

80-
// Collect all of the variables defined
93+
// Collect all of the variables defined `--foo: #f00;`
8194
// ---------------------------------------------------------
8295
// ---------------------------------------------------------
8396
eachCssVariableDeclaration(css, function(variableDecl) {
@@ -105,8 +118,8 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
105118
// .foo { --color: #f00; color: var(--color); }
106119
// .foo:hover { --color: #0f0; };
107120
// After:
108-
// .foo { color: #f00; }
109-
// .foo:hover { color: #0f0; }
121+
// .foo { --color: #f00; color: var(--color); }
122+
// .foo:hover { --color: #0f0; color: var(--color); }
110123
// --------------------------------
111124
css.walkDecls(function(usageDecl) {
112125
// Avoid duplicating the usage decl on itself
@@ -120,8 +133,10 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
120133
return usageSelectorBranches.some((usageSelectorBranch) => {
121134
// In this case, we look whether the usage is under the scope of the definition
122135
const isUnderScope = isSelectorBranchUnderScope(usageSelectorBranch, variableSelectorBranch);
136+
//const isUnderScope = isSelectorBranchUnderScope(variableSelectorBranch, usageSelectorBranch, { ignoreConditionals: true });
123137

124138
debug(`Should expand usage? isUnderScope=${isUnderScope}`, usageSelectorBranch.selector.toString(), '|', variableSelectorBranch.selector.toString())
139+
//debug(`Should expand usage? isUnderScope=${isUnderScope}`, variableSelectorBranch.selector.toString(), '|', usageSelectorBranch.selector.toString())
125140

126141
if(isUnderScope) {
127142
usageDecl.value.replace(new RegExp(RE_VAR_FUNC.source, 'g'), (match, matchedVariableName) => {
@@ -137,7 +152,6 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
137152
});
138153

139154

140-
141155
// Remove the variable declaration because they are pretty much useless after we resolve them
142156
if(!opts.preserve) {
143157
variableDecl.remove();
@@ -146,6 +160,8 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
146160
else if(opts.preserve === 'computed') {
147161
// TODO: put computed value here
148162
}
163+
// Otherwise just leave them alone
164+
// else {}
149165

150166
// Clean up the rule that declared them if it doesn't have anything left after we potentially remove the variable decl
151167
if(variableDeclParentRule.nodes.length <= 0) {
@@ -160,15 +176,25 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
160176
debug('---------------------------------');
161177

162178

163-
// Resolve variables everywhere
179+
180+
181+
// Resolve variable values
182+
// ---------------------------------------------------------
183+
// ---------------------------------------------------------
184+
// TODO
185+
186+
187+
188+
189+
// Resolve variable usage everywhere `var(--foo)`
164190
// ---------------------------------------------------------
165191
// ---------------------------------------------------------
166192
css.walkDecls(function(decl) {
167193
// Avoid any variable decls, `--foo: var(--bar);`, that may have been preserved
168194
if(!RE_VAR_PROP.test(decl.prop)) {
169195
const selectorBranches = generateSelectorBranchesFromPostcssNode(decl.parent);
170196

171-
decl.value = decl.value.replace(new RegExp(RE_VAR_FUNC.source, 'g'), (match, variableName, fallback) => {
197+
const newDeclValue = decl.value.replace(new RegExp(RE_VAR_FUNC.source, 'g'), (match, variableName, fallback) => {
172198
debug('usage', variableName);
173199
const variableEntries = map[variableName] || [];
174200

@@ -204,11 +230,30 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
204230
result.warn(['variable ' + variableName + ' is undefined and used without a fallback', { node: decl }]);
205231
}
206232

233+
// We use 'undefined' value as a string to avoid making other plugins down the line unhappy, see #22
207234
return resultantValue || 'undefined';
208235
});
236+
237+
238+
if(newDeclValue !== decl.value) {
239+
let potentialClone = decl;
240+
if(opts.preserve === true) {
241+
potentialClone = decl.cloneBefore();
242+
}
243+
244+
// We `cloneBefore` and put the value on the clone so that
245+
// `walkDecl` doesn't try to iterate on the new decl
246+
potentialClone.value = newDeclValue;
247+
}
248+
209249
}
210250
});
211251

212252

253+
254+
debug('postcss-css-variables completed -');
255+
debug(css.toString());
256+
debug('---------------------------------');
257+
213258
};
214259
});

test/fixtures/cascade-on-nested-rules.expected.css

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,13 @@
66
}
77

88
@media (max-width: 800px) {
9-
109
.box-bar {
1110
width: 300px;
1211
}
1312
}
1413
}
1514

1615
@media (max-width: 800px) {
17-
1816
.box-foo {
1917
width: 300px;
2018
}

test/fixtures/js-defined-preserve-injected.expected.css

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
:root {
2-
}
3-
:root {
4-
}
5-
:root {
6-
}
7-
81
.box1 {
92
width: 75px;
103
width: var(--js-defined1);

test/fixtures/js-defined-preserve.expected.css

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
:root {
2-
--js-defined-no-prefix: #ff0000;
3-
}
4-
:root {
5-
--js-defined2: 80px;
6-
}
71
:root {
82
--js-defined1: 75px;
3+
--js-defined2: 80px;
4+
--js-defined-no-prefix: #ff0000;
95
}
106

117
.box1 {

test/fixtures/media-query.expected.css

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
}
44

55
@media (max-width: 1000px) {
6-
76
.box {
87
width: 200px;
98
}
10-
}
9+
}

test/fixtures/pseudo-multi.expected.css

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
color: pink;
33
}
44

5-
.bar:active {
6-
color: blue;
5+
.bar:focus {
6+
color: green;
77
}
88

99
.bar:hover {
1010
color: red;
1111
}
1212

13-
.bar:focus {
14-
color: green;
13+
.bar:active {
14+
color: blue;
1515
}

test/test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ var testPlugin = function(filePath, expectedFilePath, options) {
5454
});
5555
})
5656
.then(({ actualResult, expectedResult }) => {
57-
expect(actualResult.css.replace(/\r?\n/g, '')).to.equal(expectedResult.css.replace(/\r?\n/g, ''));
57+
expect(actualResult.css.replace(/(\r?\n)|\s/g, '')).to.equal(expectedResult.css.replace(/(\r?\n)|\s/g, ''));
5858
});
5959
};
6060

0 commit comments

Comments
 (0)