Skip to content

Commit d216e21

Browse files
committed
Add last piece combinator chain var resolution
v0.3.3
1 parent 126f58c commit d216e21

File tree

10 files changed

+155
-60
lines changed

10 files changed

+155
-60
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11

2+
# v0.3.3 - 2015-5-11
3+
4+
- Add support for last piece of combinator chain in selector resolution matching.
5+
- `.foo + .bar` can match variables declared in `.bar`
6+
7+
28
# v0.3.1 - 2015-5-5
39

410
- Large overhaul of code to make it more robust on proper scope resolution.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ CSS variables or CSS Custom Properties limited subset polyfill/shim.
88

99
We strive for the most complete transformation but we/no plugin can achieve true complete parity according to the [speficification](http://dev.w3.org/csswg/css-variables/) because of the DOM cascade unknowns.
1010

11-
## Latest Version: v0.3.1
11+
## Latest Version: v0.3.3
1212
### [Changelog](https://github.com/MadLittleMods/postcss-css-variables/blob/master/CHANGELOG.md)
1313

1414
### Install

index.js

Lines changed: 52 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// PostCSS CSS Variables (postcss-css-variables)
2-
// v0.3.1
2+
// v0.3.3
33
//
44
// https://github.com/MadLittleMods/postcss-css-variables
55

@@ -8,6 +8,7 @@
88

99
var postcss = require('postcss');
1010
var extend = require('extend');
11+
var escapeStringRegexp = require('escape-string-regexp');
1112

1213
// A custom property is any property whose name starts with two dashes (U+002D HYPHEN-MINUS)
1314
// `--foo`
@@ -117,6 +118,23 @@ function findNodeAncestorWithSelector(selector, node) {
117118
}
118119

119120

121+
function generateDescendantPieces(selector) {
122+
return selector.split(RE_SELECTOR_DESCENDANT_SPLIT)
123+
.filter(function(piece) {
124+
if(piece.length > 0) {
125+
return true;
126+
}
127+
return false;
128+
})
129+
.map(function(piece) {
130+
// Trim whitespace which would be a normal descendant selector
131+
// and trim off the CSS4 descendant `>>` into a normal descendant selector
132+
return piece.trim().replace(/\s*?>>\s*?/, function(match) {
133+
return '';
134+
});
135+
});
136+
}
137+
120138
function generateScopeList(node, /*optional*/includeSelf) {
121139
includeSelf = includeSelf || false;
122140

@@ -160,20 +178,7 @@ function generateScopeList(node, /*optional*/includeSelf) {
160178
var descendantPieces = [scopeObject.value];
161179
// Split at any descendant combinators to properly make the scope list
162180
if(scopeObject.type === 'selector') {
163-
descendantPieces = scopeObject.value.split(RE_SELECTOR_DESCENDANT_SPLIT)
164-
.filter(function(piece) {
165-
if(piece.length > 0) {
166-
return true;
167-
}
168-
return false;
169-
})
170-
.map(function(piece) {
171-
// Trim whitespace which would be a normal descendant selector
172-
// and trim off the CSS4 descendant `>>` into a normal descendant selector
173-
return piece.trim().replace(/\s*?>>\s*?/, function(match) {
174-
return '';
175-
});
176-
});
181+
descendantPieces = generateDescendantPieces(scopeObject.value);
177182
}
178183

179184
// Add to the front of the array
@@ -183,6 +188,8 @@ function generateScopeList(node, /*optional*/includeSelf) {
183188
});
184189
});
185190

191+
// Start from a new list so we can
192+
// Flatten out the branches a bit and and merge back into the list
186193
selectorScopeList = [];
187194
branches.forEach(function(branch) {
188195
selectorScopeList = selectorScopeList.concat(branch);
@@ -194,18 +201,27 @@ function generateScopeList(node, /*optional*/includeSelf) {
194201
return selectorScopeList;
195202
}
196203

197-
function isUnderScope(node, scopeNode) {
198-
199-
var nodeScopeList = generateScopeList(node, true);
200-
var scopeNodeList = generateScopeList(scopeNode, true);
201-
202-
var matchesScope = scopeNodeList.some(function(scopeNodeScopePieces) {
204+
function isUnderScope(nodeScopeList, scopeNodeScopeList) {
205+
var matchesScope = scopeNodeScopeList.some(function(scopeNodeScopePieces) {
203206
return nodeScopeList.some(function(nodeScopePieces) {
204207
var currentPieceOffset;
205208
var wasEveryPieceFound = scopeNodeScopePieces.every(function(scopePiece) {
206209
var pieceOffset = currentPieceOffset || 0;
207210
// Start from the previous index and make sure we can find it
208-
var foundIndex = nodeScopePieces.indexOf(scopePiece, pieceOffset);
211+
//var foundIndex = nodeScopePieces.indexOf(scopePiece, pieceOffset);
212+
213+
var foundIndex = -1;
214+
var piecesWeCanMatch = nodeScopePieces.slice(pieceOffset);
215+
piecesWeCanMatch.some(function(nodeScopePiece, index) {
216+
// Find the scope piece at the end of the node selector
217+
// Last-occurence
218+
if(new RegExp(escapeStringRegexp(scopePiece) + '$').test(nodeScopePiece)) {
219+
foundIndex = pieceOffset + index;
220+
// Escape
221+
return true;
222+
}
223+
return false;
224+
});
209225
// If it is a star or root, then it is valid no matter what
210226
// We might consider adding `html` and `body` to this list as well
211227
if(foundIndex < 0 && (scopePiece === '*' || scopePiece === ':root')) {
@@ -225,6 +241,14 @@ function isUnderScope(node, scopeNode) {
225241
return matchesScope;
226242
}
227243

244+
function isNodeUnderNode(node, scopeNode) {
245+
246+
var nodeScopeList = generateScopeList(node, true);
247+
var scopeNodeScopeList = generateScopeList(scopeNode, true);
248+
249+
return isUnderScope(nodeScopeList, scopeNodeScopeList);
250+
}
251+
228252

229253
// Pass in a value string to parse/resolve and a map of available values
230254
// and we can figure out the final value
@@ -254,13 +278,11 @@ var resolveValue = function(decl, map) {
254278
// And if the current matching variable is already important, a new one to replace it has to be important
255279
var isRoot = varDeclMapItem.parent.type === 'root' || varDeclMapItem.parent.selectors[0] === ':root';
256280

257-
var mimicDeclParent = decl.parent;
258-
259-
//console.log(generateScopeList(mimicDeclParent, true));
281+
//console.log(generateScopeList(decl.parent, true));
260282
//console.log(generateScopeList(varDeclMapItem.parent, true));
261-
//console.log('isunderscope', isUnderScope(mimicDeclParent, varDeclMapItem.parent), varDeclMapItem.value);
283+
//console.log('isNodeUnderNode', isNodeUnderNode(decl.parent, varDeclMapItem.parent), varDeclMapItem.value);
262284
if(
263-
isUnderScope(mimicDeclParent, varDeclMapItem.parent) &&
285+
isNodeUnderNode(decl.parent, varDeclMapItem.parent) &&
264286
// And if the currently matched declaration is `!important`, it will take another `!important` to override it
265287
(!(matchingVarDeclMapItem || {}).isImportant || varDeclMapItem.isImportant)
266288
) {
@@ -469,12 +491,12 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
469491
//console.log('amd og', generateScopeList(decl.parent, true));
470492
//console.log('amd', generateScopeList(mimicDecl.parent, true));
471493
//console.log(generateScopeList(varDeclMapItem.parent, true));
472-
//console.log('amd isunderscope', isUnderScope(mimicDecl.parent, varDeclMapItem.parent), varDeclMapItem.value);
494+
//console.log('amd isNodeUnderNode', isNodeUnderNode(mimicDecl.parent, varDeclMapItem.parent), varDeclMapItem.value);
473495

474496

475497
// If it is under the proper scope
476498
// Then lets create the new rules
477-
if(isUnderScope(mimicDecl.parent, varDeclMapItem.parent)) {
499+
if(isNodeUnderNode(mimicDecl.parent, varDeclMapItem.parent)) {
478500
// Create the clean atRule for which we place the declaration under
479501
var atRuleNode = varDeclMapItem.parent.parent.clone().removeAll();
480502

@@ -553,7 +575,7 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
553575
});
554576

555577

556-
//console.log(map);
578+
//console.log('map', map);
557579

558580
/* * /
559581
}

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "postcss-css-variables",
3-
"version": "0.3.1",
3+
"version": "0.3.3",
44
"description": "PostCSS plugin to transform CSS Custom Properties(CSS variables) syntax into a static representation",
55
"keywords": [
66
"postcss",
@@ -14,6 +14,7 @@
1414
"url": "https://github.com/MadLittleMods/postcss-css-variables.git"
1515
},
1616
"dependencies": {
17+
"escape-string-regexp": "^1.0.3",
1718
"extend": "^2.0.1",
1819
"postcss": "^4.1.5"
1920
},

playground/build.js

Lines changed: 63 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10038,6 +10038,22 @@ System.register("npm:extend@2.0.1/index", [], true, function(require, exports, m
1003810038
return module.exports;
1003910039
});
1004010040

10041+
System.register("npm:escape-string-regexp@1.0.3/index", [], true, function(require, exports, module) {
10042+
var global = System.global,
10043+
__define = global.define;
10044+
global.define = undefined;
10045+
'use strict';
10046+
var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
10047+
module.exports = function(str) {
10048+
if (typeof str !== 'string') {
10049+
throw new TypeError('Expected a string');
10050+
}
10051+
return str.replace(matchOperatorsRe, '\\$&');
10052+
};
10053+
global.define = __define;
10054+
return module.exports;
10055+
});
10056+
1004110057
System.register("npm:babel-runtime@5.2.6/helpers/define-property", ["npm:babel-runtime@5.2.6/core-js/object/define-property"], true, function(require, exports, module) {
1004210058
var global = System.global,
1004310059
__define = global.define;
@@ -14854,6 +14870,15 @@ System.register("npm:extend@2.0.1", ["npm:extend@2.0.1/index"], true, function(r
1485414870
return module.exports;
1485514871
});
1485614872

14873+
System.register("npm:escape-string-regexp@1.0.3", ["npm:escape-string-regexp@1.0.3/index"], true, function(require, exports, module) {
14874+
var global = System.global,
14875+
__define = global.define;
14876+
global.define = undefined;
14877+
module.exports = require("npm:escape-string-regexp@1.0.3/index");
14878+
global.define = __define;
14879+
return module.exports;
14880+
});
14881+
1485714882
System.register("npm:babel-runtime@5.2.6/core-js/object/keys", ["npm:core-js@0.9.6/library/fn/object/keys"], true, function(require, exports, module) {
1485814883
var global = System.global,
1485914884
__define = global.define;
@@ -19119,13 +19144,14 @@ System.register("npm:postcss@4.1.9/lib/previous-map", ["npm:js-base64@2.1.8", "n
1911919144
return module.exports;
1912019145
});
1912119146

19122-
System.register("npm:postcss-css-variables@0.3.1/index", ["npm:postcss@4.1.9", "npm:extend@2.0.1", "github:jspm/nodelibs-process@0.1.1"], true, function(require, exports, module) {
19147+
System.register("npm:postcss-css-variables@0.3.3/index", ["npm:postcss@4.1.9", "npm:extend@2.0.1", "npm:escape-string-regexp@1.0.3", "github:jspm/nodelibs-process@0.1.1"], true, function(require, exports, module) {
1912319148
var global = System.global,
1912419149
__define = global.define;
1912519150
global.define = undefined;
1912619151
(function(process) {
1912719152
var postcss = require("npm:postcss@4.1.9");
1912819153
var extend = require("npm:extend@2.0.1");
19154+
var escapeStringRegexp = require("npm:escape-string-regexp@1.0.3");
1912919155
var RE_VAR_PROP = (/(--(.+))/);
1913019156
var RE_VAR_FUNC = (/var\((--[^,\s]+?)(?:\s*,\s*(.+))?\)/);
1913119157
var RE_SELECTOR_DESCENDANT_SPLIT = (/(.*?(?:(?:\[[^\]]+\]|(?![><+~\s]).)+)(?:(?:(?:\s(?!>>))|(?:\t(?!>>))|(?:\s?>>\s?))(?!\s+))(?![><+~][\s]+?))/);
@@ -19185,6 +19211,18 @@ System.register("npm:postcss-css-variables@0.3.1/index", ["npm:postcss@4.1.9", "
1918519211
}
1918619212
return matchingNode;
1918719213
}
19214+
function generateDescendantPieces(selector) {
19215+
return selector.split(RE_SELECTOR_DESCENDANT_SPLIT).filter(function(piece) {
19216+
if (piece.length > 0) {
19217+
return true;
19218+
}
19219+
return false;
19220+
}).map(function(piece) {
19221+
return piece.trim().replace(/\s*?>>\s*?/, function(match) {
19222+
return '';
19223+
});
19224+
});
19225+
}
1918819226
function generateScopeList(node, includeSelf) {
1918919227
includeSelf = includeSelf || false;
1919019228
var selectorScopeList = [[]];
@@ -19213,16 +19251,7 @@ System.register("npm:postcss-css-variables@0.3.1/index", ["npm:postcss@4.1.9", "
1921319251
branches[index] = branches[index].map(function(scopeStringPieces) {
1921419252
var descendantPieces = [scopeObject.value];
1921519253
if (scopeObject.type === 'selector') {
19216-
descendantPieces = scopeObject.value.split(RE_SELECTOR_DESCENDANT_SPLIT).filter(function(piece) {
19217-
if (piece.length > 0) {
19218-
return true;
19219-
}
19220-
return false;
19221-
}).map(function(piece) {
19222-
return piece.trim().replace(/\s*?>>\s*?/, function(match) {
19223-
return '';
19224-
});
19225-
});
19254+
descendantPieces = generateDescendantPieces(scopeObject.value);
1922619255
}
1922719256
scopeStringPieces.unshift.apply(scopeStringPieces, descendantPieces);
1922819257
return scopeStringPieces;
@@ -19236,15 +19265,21 @@ System.register("npm:postcss-css-variables@0.3.1/index", ["npm:postcss@4.1.9", "
1923619265
}
1923719266
return selectorScopeList;
1923819267
}
19239-
function isUnderScope(node, scopeNode) {
19240-
var nodeScopeList = generateScopeList(node, true);
19241-
var scopeNodeList = generateScopeList(scopeNode, true);
19242-
var matchesScope = scopeNodeList.some(function(scopeNodeScopePieces) {
19268+
function isUnderScope(nodeScopeList, scopeNodeScopeList) {
19269+
var matchesScope = scopeNodeScopeList.some(function(scopeNodeScopePieces) {
1924319270
return nodeScopeList.some(function(nodeScopePieces) {
1924419271
var currentPieceOffset;
1924519272
var wasEveryPieceFound = scopeNodeScopePieces.every(function(scopePiece) {
1924619273
var pieceOffset = currentPieceOffset || 0;
19247-
var foundIndex = nodeScopePieces.indexOf(scopePiece, pieceOffset);
19274+
var foundIndex = -1;
19275+
var piecesWeCanMatch = nodeScopePieces.slice(pieceOffset);
19276+
piecesWeCanMatch.some(function(nodeScopePiece, index) {
19277+
if (new RegExp(escapeStringRegexp(scopePiece) + '$').test(nodeScopePiece)) {
19278+
foundIndex = pieceOffset + index;
19279+
return true;
19280+
}
19281+
return false;
19282+
});
1924819283
if (foundIndex < 0 && (scopePiece === '*' || scopePiece === ':root')) {
1924919284
foundIndex = pieceOffset + 1;
1925019285
}
@@ -19257,6 +19292,11 @@ System.register("npm:postcss-css-variables@0.3.1/index", ["npm:postcss@4.1.9", "
1925719292
});
1925819293
return matchesScope;
1925919294
}
19295+
function isNodeUnderNode(node, scopeNode) {
19296+
var nodeScopeList = generateScopeList(node, true);
19297+
var scopeNodeScopeList = generateScopeList(scopeNode, true);
19298+
return isUnderScope(nodeScopeList, scopeNodeScopeList);
19299+
}
1926019300
var resolveValue = function(decl, map) {
1926119301
var resultantValue = decl.value;
1926219302
var variablesUsedInValue = [];
@@ -19267,8 +19307,7 @@ System.register("npm:postcss-css-variables@0.3.1/index", ["npm:postcss@4.1.9", "
1926719307
var matchingVarDeclMapItem;
1926819308
(map[variableName] || []).forEach(function(varDeclMapItem) {
1926919309
var isRoot = varDeclMapItem.parent.type === 'root' || varDeclMapItem.parent.selectors[0] === ':root';
19270-
var mimicDeclParent = decl.parent;
19271-
if (isUnderScope(mimicDeclParent, varDeclMapItem.parent) && (!(matchingVarDeclMapItem || {}).isImportant || varDeclMapItem.isImportant)) {
19310+
if (isNodeUnderNode(decl.parent, varDeclMapItem.parent) && (!(matchingVarDeclMapItem || {}).isImportant || varDeclMapItem.isImportant)) {
1927219311
matchingVarDeclMapItem = varDeclMapItem;
1927319312
}
1927419313
});
@@ -19373,7 +19412,7 @@ System.register("npm:postcss-css-variables@0.3.1/index", ["npm:postcss@4.1.9", "
1937319412
var mimicDecl = cloneSpliceParentOntoNodeWhen(decl, varDeclAtRule, function(ancestor) {
1937419413
return ancestor === currentNodeToSpliceParentOnto;
1937519414
});
19376-
if (isUnderScope(mimicDecl.parent, varDeclMapItem.parent)) {
19415+
if (isNodeUnderNode(mimicDecl.parent, varDeclMapItem.parent)) {
1937719416
var atRuleNode = varDeclMapItem.parent.parent.clone().removeAll();
1937819417
var ruleClone = decl.parent.clone().removeAll();
1937919418
var declClone = decl.clone();
@@ -21116,11 +21155,11 @@ System.register("npm:postcss@4.1.9/lib/input", ["npm:postcss@4.1.9/lib/css-synta
2111621155
return module.exports;
2111721156
});
2111821157

21119-
System.register("npm:postcss-css-variables@0.3.1", ["npm:postcss-css-variables@0.3.1/index"], true, function(require, exports, module) {
21158+
System.register("npm:postcss-css-variables@0.3.3", ["npm:postcss-css-variables@0.3.3/index"], true, function(require, exports, module) {
2112021159
var global = System.global,
2112121160
__define = global.define;
2112221161
global.define = undefined;
21123-
module.exports = require("npm:postcss-css-variables@0.3.1/index");
21162+
module.exports = require("npm:postcss-css-variables@0.3.3/index");
2112421163
global.define = __define;
2112521164
return module.exports;
2112621165
});
@@ -25303,7 +25342,7 @@ System.register('src/js/components/PlaygroundHeader', ['npm:babel-runtime@5.2.6/
2530325342
}
2530425343
};
2530525344
});
25306-
System.register('src/js/stores/PlaygroundStore', ['src/js/dispatcher/AppDispatcher', 'src/js/constants/PlaygroundConstants', 'src/js/stores/PlaygroundSettingsStore', 'npm:object-assign@2.0.0', 'npm:immutable@3.7.2', 'npm:events@1.0.2', 'npm:postcss@4.1.9', 'npm:postcss-css-variables@0.3.1'], function (_export) {
25345+
System.register('src/js/stores/PlaygroundStore', ['src/js/dispatcher/AppDispatcher', 'src/js/constants/PlaygroundConstants', 'src/js/stores/PlaygroundSettingsStore', 'npm:object-assign@2.0.0', 'npm:immutable@3.7.2', 'npm:events@1.0.2', 'npm:postcss@4.1.9', 'npm:postcss-css-variables@0.3.3'], function (_export) {
2530725346
var AppDispatcher, PlaygroundConstants, PlaygroundSettingsStore, assign, Immutable, events, postcss, cssvariables, EventEmitter, CHANGE_EVENT, keyboardActionStream, playgroundProcessor, postcssUnprocessedInputText, processingResult, PlaygroundStore;
2530825347

2530925348
function updateProcessor(settings) {
@@ -25349,8 +25388,8 @@ System.register('src/js/stores/PlaygroundStore', ['src/js/dispatcher/AppDispatch
2534925388
events = _npmEvents102['default'];
2535025389
}, function (_npmPostcss419) {
2535125390
postcss = _npmPostcss419['default'];
25352-
}, function (_npmPostcssCssVariables031) {
25353-
cssvariables = _npmPostcssCssVariables031['default'];
25391+
}, function (_npmPostcssCssVariables033) {
25392+
cssvariables = _npmPostcssCssVariables033['default'];
2535425393
}],
2535525394
execute: function () {
2535625395
'use strict';

0 commit comments

Comments
 (0)