Skip to content
This repository was archived by the owner on Feb 22, 2018. It is now read-only.

Commit 4bed785

Browse files
committed
fix(css_shim): escape keyframes from shimming.
@Keyframes declaration changes the CSS syntax expected in ways, which make it harder to shim. For now we just skip shimming the keyframe names, as to keep valid CSS.
1 parent 6959dd3 commit 4bed785

File tree

2 files changed

+39
-19
lines changed

2 files changed

+39
-19
lines changed

lib/core_dom/css_shim.dart

+27-19
Original file line numberDiff line numberDiff line change
@@ -123,26 +123,28 @@ class _CssShim {
123123
List<_Rule> cssToRules(String css) =>
124124
new _Parser(css).parse();
125125

126-
String scopeRules(List<_Rule> rules) {
127-
final scopedRules = [];
126+
String scopeRules(List<_Rule> rules, {bool emitMode: false}) {
127+
if (emitMode) {
128+
return rules.map(ruleToString).join("\n");
129+
}
128130

131+
final scopedRules = [];
129132
var prevRule;
130133
rules.forEach((rule) {
131134
if (prevRule != null && prevRule.selectorText == POLYFILL_NON_STRICT) {
132-
scopedRules.add(scopeNonStrictMode(rule));
133-
135+
scopedRules.add(scopeNonStrictMode(rule, emitMode));
134136
} else if (prevRule != null && prevRule.selectorText == POLYFILL_UNSCOPED_NEXT_SELECTOR) {
135137
final content = extractContent(prevRule);
136138
scopedRules.add(ruleToString(new _Rule(content, body: rule.body)));
137139

138140
} else if (prevRule != null && prevRule.selectorText == POLYFILL_NEXT_SELECTOR) {
139141
final content = extractContent(prevRule);
140-
scopedRules.add(scopeStrictMode(new _Rule(content, body: rule.body)));
142+
scopedRules.add(scopeStrictMode(new _Rule(content, body: rule.body), false));
141143

142144
} else if (rule.selectorText != POLYFILL_NON_STRICT &&
143145
rule.selectorText != POLYFILL_UNSCOPED_NEXT_SELECTOR &&
144146
rule.selectorText != POLYFILL_NEXT_SELECTOR) {
145-
scopedRules.add(scopeStrictMode(rule));
147+
scopedRules.add(scopeStrictMode(rule, false));
146148
}
147149

148150
prevRule = rule;
@@ -159,19 +161,22 @@ class _CssShim {
159161
return "${rule.selectorText} ${rule.body}";
160162
}
161163

162-
String scopeStrictMode(_Rule rule) {
164+
String scopeStrictMode(_Rule rule, bool emitMode) {
163165
if (rule.hasNestedRules) {
164-
final selector = rule.selectorText;
165-
final rules = scopeRules(rule.rules);
166-
return '$selector {\n$rules\n}';
166+
final rules = scopeRules(rule.rules, emitMode: rule.selectorText.contains("keyframes"));
167+
return "${rule.selectorText} {\n$rules\n}";
167168
} else {
168169
final scopedSelector = scopeSelector(rule.selectorText, strict: true);
169170
final scopedBody = cssText(rule);
170171
return "$scopedSelector $scopedBody";
171172
}
172173
}
173174

174-
String scopeNonStrictMode(_Rule rule) {
175+
String scopeNonStrictMode(_Rule rule, bool emitMode) {
176+
if (rule.hasNestedRules && rule.selectorText == "keyframes") {
177+
final rules = scopeRules(rule.rules, emitMode: true);
178+
return '${rule.selectorText} {\n$rules\n}';
179+
}
175180
final scopedBody = cssText(rule);
176181
final scopedSelector = scopeSelector(rule.selectorText, strict: false);
177182
return "${scopedSelector} $scopedBody";
@@ -281,7 +286,7 @@ class _Lexer {
281286
advance();
282287
return new _Token("}", "rparen");
283288
}
284-
if (isMedia(peek)) return scanMedia();
289+
if (isDeclaration(peek)) return scanDeclaration();
285290
if (isSelector(peek)) return scanSelector();
286291
if (isBodyStart(peek)) return scanBody();
287292

@@ -291,7 +296,7 @@ class _Lexer {
291296
bool isSelector(int v) => !isBodyStart(v) && v != $EOF;
292297
bool isBodyStart(int v) => v == $LBRACE;
293298
bool isBodyEnd(int v) => v == $RBRACE;
294-
bool isMedia(int v) => v == 64; //@ = 64
299+
bool isDeclaration(int v) => v == 64; //@ = 64
295300

296301
void skipWhitespace() {
297302
while (isWhitespace(peek)) {
@@ -321,7 +326,7 @@ class _Lexer {
321326
return new _Token(string, "body");
322327
}
323328

324-
_Token scanMedia() {
329+
_Token scanDeclaration() {
325330
int start = index;
326331
advance();
327332

@@ -330,7 +335,10 @@ class _Lexer {
330335

331336
advance(); //skip {
332337

333-
return new _Token(string, "media");
338+
// we assume that declaration cannot start with media and contain keyframes.
339+
String type = string.contains("keyframes") ? "keyframes" :
340+
(string.startsWith("@media") ? "media" : string);
341+
return new _Token(string, type);
334342
}
335343

336344
void advance() {
@@ -370,8 +378,8 @@ class _Parser {
370378

371379
_Rule parseRule() {
372380
try {
373-
if (next.type == "media") {
374-
return parseMedia();
381+
if (next.type == "media" || next.type == "keyframes") {
382+
return parseMedia(next.type);
375383
} else {
376384
return parseCssRule();
377385
}
@@ -380,8 +388,8 @@ class _Parser {
380388
}
381389
}
382390

383-
_Rule parseMedia() {
384-
advance("media");
391+
_Rule parseMedia(type) {
392+
advance(type);
385393
final media = current.string;
386394

387395
final rules = [];

test/core_dom/css_shim_spec.dart

+12
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,18 @@ main() {
5252
expect(s(css, "a")).toEqual(expected);
5353
});
5454

55+
it("should handle keyframe rules", () {
56+
final css = "@keyframes foo {0% {transform: translate(-50%) scaleX(0)}}";
57+
58+
expect(s(css, "a")).toEqual(css);
59+
});
60+
61+
it("should handle -webkit-keyframe rules", () {
62+
final css = "@-webkit-keyframes foo {0% {transform: translate(-50% scaleX(0)}}";
63+
64+
expect(s(css, "a")).toEqual(css);
65+
});
66+
5567
it("should handle complicated selectors", () {
5668
expect(s('one::before {}', "a")).toEqual('one[a]::before {}');
5769
expect(s('one two {}', "a")).toEqual('one[a] two[a] {}');

0 commit comments

Comments
 (0)