@@ -37,15 +37,12 @@ String shimCssText(String css, String tag) =>
37
37
* * `:host`
38
38
* * `:host(.x)`
39
39
*
40
- * When the shim is not powerful enough, you can fall back on the polyfill-next-selector
41
- * directive .
40
+ * When the shim is not powerful enough, you can fall back on the polyfill-next-selector,
41
+ * polyfill-unscoped-next-selector, and polyfill-non-strict directives .
42
42
*
43
- * polyfill-next-selector {content: 'x > y'}
44
- * z {}
45
- *
46
- * Becomes:
47
- *
48
- * x[tag] > y[tag]
43
+ * * `polyfill-next-selector {content: 'x > y'}` z {} becomes `x[tag] > y[tag] {}`
44
+ * * `polyfill-unscoped-next-selector {content: 'x > y'} z {}` becomes `x > y {}`
45
+ * * `polyfill-non-strict {} z {}` becomes `tag z {}`
49
46
*
50
47
* See http://www.polymer-project.org/docs/polymer/styling.html#at-polyfill
51
48
*
@@ -54,17 +51,15 @@ String shimCssText(String css, String tag) =>
54
51
*/
55
52
class _CssShim {
56
53
static final List SELECTOR_SPLITS = const [' ' , '>' , '+' , '~' ];
57
- static final RegExp POLYFILL_NEXT_SELECTOR_DIRECTIVE = new RegExp (
58
- r"polyfill-next-selector"
54
+
55
+ static final RegExp CONTENT = new RegExp (
59
56
r"[^}]*"
60
57
r"content\:[\s]*"
61
58
r"'([^']*)'"
62
- r"[^}]*}"
63
- r"([^{]*)" ,
59
+ r"[^}]*}" ,
64
60
caseSensitive: false ,
65
61
multiLine: true
66
62
);
67
- static final int NEXT_SELECTOR_CONTENT = 1 ;
68
63
69
64
static final String HOST_TOKEN = '-host-element' ;
70
65
static final RegExp COLON_SELECTORS = new RegExp (r'(' + HOST_TOKEN + r')(\(.*\)){0,1}(.*)' ,
@@ -79,21 +74,29 @@ class _CssShim {
79
74
static final RegExp COLON_HOST = new RegExp ('($HOST_TOKEN $PAREN_SUFFIX ' ,
80
75
caseSensitive: false , multiLine: true );
81
76
77
+ static final String POLYFILL_NON_STRICT = "polyfill-non-strict" ;
78
+ static final String POLYFILL_UNSCOPED_NEXT_SELECTOR = "polyfill-unscoped-next-selector" ;
79
+ static final String POLYFILL_NEXT_SELECTOR = "polyfill-next-selector" ;
80
+
81
+ static final List <RegExp > COMBINATORS = [
82
+ new RegExp (r'/shadow/' , caseSensitive: false ),
83
+ new RegExp (r'/shadow-deep/' , caseSensitive: false ),
84
+ new RegExp (r'::shadow' , caseSensitive: false ),
85
+ new RegExp (r'/deep/' , caseSensitive: false )
86
+ ];
87
+
82
88
final String tag;
83
89
final String attr;
84
90
85
91
_CssShim (String tag)
86
92
: tag = tag, attr = "[$tag ]" ;
87
93
88
94
String shimCssText (String css) {
89
- final preprocessed = convertColonHost (applyPolyfillNextSelectorDirective ( css) );
95
+ final preprocessed = convertColonHost (css);
90
96
final rules = cssToRules (preprocessed);
91
97
return scopeRules (rules);
92
98
}
93
99
94
- String applyPolyfillNextSelectorDirective (String css) =>
95
- css.replaceAllMapped (POLYFILL_NEXT_SELECTOR_DIRECTIVE , (m) => m[NEXT_SELECTOR_CONTENT ]);
96
-
97
100
String convertColonHost (String css) {
98
101
css = css.replaceAll (":host" , HOST_TOKEN );
99
102
@@ -120,35 +123,82 @@ class _CssShim {
120
123
List <_Rule > cssToRules (String css) =>
121
124
new _Parser (css).parse ();
122
125
123
- String scopeRules (List <_Rule > rules) =>
124
- rules.map (scopeRule).join ("\n " );
126
+ String scopeRules (List <_Rule > rules) {
127
+ final scopedRules = [];
128
+
129
+ var prevRule;
130
+ rules.forEach ((rule) {
131
+ if (prevRule != null && prevRule.selectorText == POLYFILL_NON_STRICT ) {
132
+ scopedRules.add (scopeNonStrictMode (rule));
133
+
134
+ } else if (prevRule != null && prevRule.selectorText == POLYFILL_UNSCOPED_NEXT_SELECTOR ) {
135
+ final content = extractContent (prevRule);
136
+ scopedRules.add (ruleToString (new _Rule (content, body: rule.body)));
137
+
138
+ } else if (prevRule != null && prevRule.selectorText == POLYFILL_NEXT_SELECTOR ) {
139
+ final content = extractContent (prevRule);
140
+ scopedRules.add (scopeStrictMode (new _Rule (content, body: rule.body)));
141
+
142
+ } else if (rule.selectorText != POLYFILL_NON_STRICT &&
143
+ rule.selectorText != POLYFILL_UNSCOPED_NEXT_SELECTOR &&
144
+ rule.selectorText != POLYFILL_NEXT_SELECTOR ) {
145
+ scopedRules.add (scopeStrictMode (rule));
146
+ }
147
+
148
+ prevRule = rule;
149
+ });
150
+
151
+ return scopedRules.join ("\n " );
152
+ }
153
+
154
+ String extractContent (_Rule rule) {
155
+ return CONTENT .firstMatch (rule.body)[1 ];
156
+ }
157
+
158
+ String ruleToString (_Rule rule) {
159
+ return "${rule .selectorText } ${rule .body }" ;
160
+ }
125
161
126
- String scopeRule (_Rule rule) {
162
+ String scopeStrictMode (_Rule rule) {
127
163
if (rule.hasNestedRules) {
128
164
final selector = rule.selectorText;
129
165
final rules = scopeRules (rule.rules);
130
166
return '$selector {\n $rules \n }' ;
131
167
} else {
132
- final scopedSelector = scopeSelector (rule.selectorText);
168
+ final scopedSelector = scopeSelector (rule.selectorText, strict : true );
133
169
final scopedBody = cssText (rule);
134
170
return "$scopedSelector $scopedBody " ;
135
171
}
136
172
}
137
173
138
- String scopeSelector (String selector) {
139
- final parts = selector.split ("," );
174
+ String scopeNonStrictMode (_Rule rule) {
175
+ final scopedBody = cssText (rule);
176
+ final scopedSelector = scopeSelector (rule.selectorText, strict: false );
177
+ return "${scopedSelector } $scopedBody " ;
178
+ }
179
+
180
+ String scopeSelector (String selector, {bool strict}) {
181
+ final parts = replaceCombinators (selector).split ("," );
140
182
final scopedParts = parts.fold ([], (res, p) {
141
- res.add (scopeSimpleSelector (p.trim ()));
183
+ res.add (scopeSimpleSelector (p.trim (), strict : strict ));
142
184
return res;
143
185
});
144
186
return scopedParts.join (", " );
145
187
}
146
188
147
- String scopeSimpleSelector (String selector) {
189
+ String replaceCombinators (String selector) {
190
+ return COMBINATORS .fold (selector, (sel, combinator) {
191
+ return sel.replaceAll (combinator, ' ' );
192
+ });
193
+ }
194
+
195
+ String scopeSimpleSelector (String selector, {bool strict}) {
148
196
if (selector.contains (HOST_TOKEN )) {
149
197
return replaceColonSelectors (selector);
198
+ } else if (strict) {
199
+ return insertTagToEverySelectorPart (selector);
150
200
} else {
151
- return insertTag ( selector) ;
201
+ return "$ tag $ selector " ;
152
202
}
153
203
}
154
204
@@ -162,7 +212,7 @@ class _CssShim {
162
212
});
163
213
}
164
214
165
- String insertTag (String selector) {
215
+ String insertTagToEverySelectorPart (String selector) {
166
216
selector = handleIsSelector (selector);
167
217
168
218
SELECTOR_SPLITS .forEach ((split) {
@@ -258,7 +308,7 @@ class _Lexer {
258
308
int start = index;
259
309
advance ();
260
310
while (isSelector (peek)) advance ();
261
- String string = input.substring (start, index);
311
+ String string = input.substring (start, index). trim () ;
262
312
return new _Token (string, "selector" );
263
313
}
264
314
0 commit comments