Skip to content

Commit f63659b

Browse files
committed
@Keyframes parsing: Use RegExp.lastIndex trick to avoid extracting a substring before matching.
1 parent 01ced44 commit f63659b

2 files changed

Lines changed: 40 additions & 5 deletions

File tree

lib/parse.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ CSSOM.parse = function parse(token) {
5252

5353
var selector, name, value, priority="", styleRule, mediaRule, importRule, keyframesRule, keyframeRule;
5454

55+
var atKeyframesRegExp = /@(-(?:\w+-)+)?keyframes/g;
56+
5557
for (var character; character = token.charAt(i); i++) {
5658

5759
switch (character) {
@@ -135,11 +137,9 @@ CSSOM.parse = function parse(token) {
135137
buffer += "@import";
136138
break;
137139
} else {
138-
// A @keyframes rule can have an arbitrary vendor prefix, but unfortunately we cannot match a regular expression
139-
// against 'token' starting at index 'i'. Extract a substring and match against that:
140-
var nextBraceIndex = token.indexOf('{', i);
141-
var matchKeyframes = token.substring(i, nextBraceIndex === -1 ? token.length : nextBraceIndex).match(/@((?:-\w+)+-)?keyframes/);
142-
if (matchKeyframes) {
140+
atKeyframesRegExp.lastIndex = i;
141+
var matchKeyframes = atKeyframesRegExp.exec(token);
142+
if (matchKeyframes && matchKeyframes.index === i) {
143143
state = "keyframesRule-begin";
144144
keyframesRule = new CSSOM.CSSKeyframesRule;
145145
keyframesRule.__starts = i;

spec/parse.spec.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,41 @@ var TESTS = [
746746
return result;
747747
})()
748748
},
749+
{
750+
// @keyframes with invalid vendor prefix followed by a valid one (make sure that the RegExp.lastIndex trick works as expected):
751+
input: '@-moz-keyframes foo {} @--keyframes bar {} @-webkit-keyframes quux {}',
752+
result: (function () {
753+
var result = {
754+
cssRules: [
755+
{
756+
name: "foo",
757+
_vendorPrefix: "-moz-",
758+
cssRules: [],
759+
parentRule: null
760+
},
761+
{
762+
selectorText: "@--keyframes bar",
763+
style: {
764+
length: 0
765+
},
766+
parentRule: null,
767+
__starts: 0,
768+
__ends: 14
769+
},
770+
{
771+
name: "quux",
772+
_vendorPrefix: "-webkit-",
773+
cssRules: [],
774+
parentRule: null
775+
}
776+
],
777+
parentStyleSheet: null
778+
};
779+
result.cssRules[0].parentStyleSheet = result.cssRules[1].parentStyleSheet = result.cssRules[2].parentStyleSheet = result;
780+
result.cssRules[1].style.parentRule = result.cssRules[1];
781+
return result;
782+
})()
783+
},
749784
{
750785
input: "@-some-ridiculously-long-vendor-prefix-that-must-be-supported-keyframes therulename /*comment*/{0%{top:0px; left:0px; background:red;}100% {top:4em; left:40px; background:maroon;}}",
751786
result: (function() {

0 commit comments

Comments
 (0)