Skip to content

Commit

Permalink
Replace VAR_MATCH regex with a simple state machine / callback
Browse files Browse the repository at this point in the history
Fixes #3190
  • Loading branch information
dfreedm committed Jun 21, 2016
1 parent b78e5af commit 4ebec15
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 27 deletions.
21 changes: 8 additions & 13 deletions src/lib/apply-shim.html
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@

var MIXIN_MATCH = styleUtil.rx.MIXIN_MATCH;
var VAR_ASSIGN = styleUtil.rx.VAR_ASSIGN;
var VAR_MATCH = styleUtil.rx.VAR_MATCH;
// match var(--a, --b) to make var(--a, var(--b));
var BAD_VAR = /var\(\s*(--[^,]*),\s*(--[^)]*)\)/g;
var APPLY_NAME_CLEAN = /;\s*/m;

// separator used between mixin-name and mixin-property-name when producing properties
Expand Down Expand Up @@ -120,14 +121,11 @@
function produceCssProperties(matchText, propertyName, valueProperty, valueMixin) {
// handle case where property value is a mixin
if (valueProperty) {
VAR_MATCH.lastIndex = 0;
var m = VAR_MATCH.exec(valueProperty);
if (m) {
var value = m[2];
if (mapGet(value)){
styleUtil.processVariableAndFallback(valueProperty, function(prefix, value) {
if (value && mapGet(value)) {
valueMixin = '@apply ' + value + ';';
}
}
});
}
if (!valueMixin) {
return matchText;
Expand Down Expand Up @@ -160,12 +158,9 @@

// fix shim'd var syntax
// var(--a, --b) -> var(--a, var(--b));
function fixVars(matchText, prefix, value, fallback) {
function fixVars(matchText, varA, varB) {
// if fallback doesn't exist, or isn't a broken variable, abort
if (!fallback || fallback.indexOf('--') !== 0) {
return matchText;
}
return [prefix, 'var(', value, ', var(', fallback, '));'].join('');
return 'var(' + varA + ',' + 'var(' + varB + '));';
}

// produce variable consumption at the site of mixin consumption
Expand Down Expand Up @@ -233,7 +228,7 @@
},
transformCssText: function(cssText) {
// fix shim variables
cssText = cssText.replace(VAR_MATCH, fixVars);
cssText = cssText.replace(BAD_VAR, fixVars);
// produce variables
cssText = cssText.replace(VAR_ASSIGN, produceCssProperties);
// consume mixins
Expand Down
6 changes: 3 additions & 3 deletions src/lib/style-properties.html
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,14 @@
} else {
// case (2) variable
var self = this;
var fn = function(all, prefix, value, fallback) {
var fn = function(prefix, value, fallback, suffix) {
var propertyValue = (self.valueForProperty(props[value], props) ||
// fallback may be --a or var(--a) or literal
self.valueForProperty(props[fallback] || fallback, props) ||
fallback);
return prefix + (propertyValue || '');
return prefix + (propertyValue || '') + suffix;
};
property = property.replace(this.rx.VAR_MATCH, fn);
property = styleUtil.processVariableAndFallback(property, fn);
}
}
return property && property.trim() || '';
Expand Down
55 changes: 44 additions & 11 deletions src/lib/style-util.html
Original file line number Diff line number Diff line change
Expand Up @@ -235,20 +235,53 @@
return element.getAttribute('css-build');
},

// Walk from text[start] matching parens
// returns position of the outer end paren
_findMatchingParen: function(text, start) {
var level = 0;
for (var i=start, l=text.length; i < l; i++) {
switch (text[i]) {
case '(':
level++;
break;
case ')':
if (--level === 0) {
return i;
}
break;
}
}
return -1;
},

processVariableAndFallback: function(str, callback) {
// find 'var('
var start = str.indexOf('var(');
if (start === -1) {
// no var?, everything is prefix
return callback(str, '', '', '');
}
//${prefix}var(${inner})${suffix}
var end = this._findMatchingParen(str, start + 3);
var inner = str.substring(start + 4, end);
var prefix = str.substring(0, start);
// suffix may have other variables
var suffix = this.processVariableAndFallback(str.substring(end + 1), callback);
var comma = inner.indexOf(',');
// value and fallback args should be trimmed to match in property lookup
if (comma === -1) {
// variable, no fallback
return callback(prefix, inner.trim(), '', suffix);
}
// var(${value},${fallback})
var value = inner.substring(0, comma).trim();
var fallback = inner.substring(comma + 1).trim();
return callback(prefix, value, fallback, suffix);
},

rx: {
VAR_ASSIGN: /(?:^|[;\s{]\s*)(--[\w-]*?)\s*:\s*(?:([^;{]*)|{([^}]*)})(?:(?=[;\s}])|$)/gi,
MIXIN_MATCH: /(?:^|\W+)@apply\s*\(?([^);\n]*)\)?/gi,
// note, this supports:
// var(--a)
// var(--a, --b)
// var(--a, fallback-literal)
// var(--a, fallback-literal(with-one-nested-parentheses))
// var(--a, var(--b))
// var(--a, var(--b, fallback-literal))
// var(--a, var(--b, fallback-literal(with-one-nested-parentheses)))
// var(--a, var(--b, var(--c, fallback-literal)))
// var(--a, var(--b, var(--c, fallback-literal(with-one-nested-parentheses))))
VAR_MATCH: /(^|\W+)var\([\s]*([^,)]*)[\s]*,?[\s]*((?:[^,()]*)|(?:[^;()]*\([^;)]*\)+))[\s]*?\)/gi,
VAR_CONSUMED: /(--[\w-]+)\s*([:,;)]|$)/gi,
ANIMATION_MATCH: /(animation\s*:)|(animation-name\s*:)/,
MEDIA_MATCH: /@media[^(]*(\([^)]*\))/,
Expand Down
42 changes: 42 additions & 0 deletions test/smoke/css-gradient-var.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Gradient in variable</title>
<script>Polymer={useNativeCSSProperties: true, lazyRegister: true}</script>
<link rel="import" href="../../polymer.html">
</head>
<body>
<style is="custom-style">
:root {
--a: 10px;
--b: 20px;
--default1: 10px;
}
</style>
<dom-module id="var-el">
<template>
<style>
:host {
display: block;
height: 100px;
width: 100px;
color: var(--undefined, rgb(123, 321, 231));
background: var(--fx-webkit-background, -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,0,0,.65)), color-stop(100%,rgba(0,0,255,.65))));
border-width: calc(var(--a) + var(--b));
border-color: brown;
border-style: solid;
padding-bottom: var(--undefined, --default1);
}
</style>
<div>Hi!</div>
</template>
<script>
Polymer({
is: 'var-el'
})
</script>
</dom-module>
<var-el></var-el>
</body>
</html>

0 comments on commit 4ebec15

Please sign in to comment.