Supports at-rules nested within at-rules (#52)
* Supports at-rules nested within at-rules
Fixes #50.
* Rename `processRuleSet()` to `processRule()`
diff --git a/lib/parser.dart b/lib/parser.dart
index cd4f6c0..6688507 100644
--- a/lib/parser.dart
+++ b/lib/parser.dart
@@ -211,17 +211,11 @@
var start = _peekToken.span;
while (!_maybeEat(TokenKind.END_OF_FILE) && !_peekKind(TokenKind.RBRACE)) {
// TODO(terry): Need to handle charset.
- var directive = processDirective();
- if (directive != null) {
- productions.add(directive);
- _maybeEat(TokenKind.SEMICOLON);
+ final rule = processRule();
+ if (rule != null) {
+ productions.add(rule);
} else {
- RuleSet ruleset = processRuleSet();
- if (ruleset != null) {
- productions.add(ruleset);
- } else {
- break;
- }
+ break;
}
}
@@ -523,12 +517,12 @@
// Any medias?
var media = processMediaQueryList();
- List<TreeNode> rulesets = [];
+ List<TreeNode> rules = [];
if (_maybeEat(TokenKind.LBRACE)) {
while (!_maybeEat(TokenKind.END_OF_FILE)) {
- RuleSet ruleset = processRuleSet();
- if (ruleset == null) break;
- rulesets.add(ruleset);
+ final rule = processRule();
+ if (rule == null) break;
+ rules.add(rule);
}
if (!_maybeEat(TokenKind.RBRACE)) {
@@ -537,17 +531,17 @@
} else {
_error('expected { after media before ruleset', _peekToken.span);
}
- return new MediaDirective(media, rulesets, _makeSpan(start));
+ return new MediaDirective(media, rules, _makeSpan(start));
case TokenKind.DIRECTIVE_HOST:
_next();
- List<TreeNode> rulesets = [];
+ List<TreeNode> rules = [];
if (_maybeEat(TokenKind.LBRACE)) {
while (!_maybeEat(TokenKind.END_OF_FILE)) {
- RuleSet ruleset = processRuleSet();
- if (ruleset == null) break;
- rulesets.add(ruleset);
+ final rule = processRule();
+ if (rule == null) break;
+ rules.add(rule);
}
if (!_maybeEat(TokenKind.RBRACE)) {
@@ -556,7 +550,7 @@
} else {
_error('expected { after host before ruleset', _peekToken.span);
}
- return new HostDirective(rulesets, _makeSpan(start));
+ return new HostDirective(rules, _makeSpan(start));
case TokenKind.DIRECTIVE_PAGE:
/*
@@ -708,11 +702,11 @@
start = _peekToken.span;
while (!_maybeEat(TokenKind.END_OF_FILE)) {
- RuleSet ruleset = processRuleSet();
- if (ruleset == null) {
+ final rule = processRule();
+ if (rule == null) {
break;
}
- productions.add(ruleset);
+ productions.add(rule);
}
_eat(TokenKind.RBRACE);
@@ -1121,8 +1115,13 @@
return new ViewportDirective(name, declarations, _makeSpan(start));
}
- RuleSet processRuleSet([SelectorGroup selectorGroup]) {
+ TreeNode processRule([SelectorGroup selectorGroup]) {
if (selectorGroup == null) {
+ final directive = processDirective();
+ if (directive != null) {
+ _maybeEat(TokenKind.SEMICOLON);
+ return directive;
+ }
selectorGroup = processSelectorGroup();
}
if (selectorGroup != null) {
@@ -1135,14 +1134,9 @@
List<TreeNode> processGroupRuleBody() {
var nodes = <TreeNode>[];
while (!(_peekKind(TokenKind.RBRACE) || _peekKind(TokenKind.END_OF_FILE))) {
- var directive = processDirective();
- if (directive != null) {
- nodes.add(directive);
- continue;
- }
- var ruleSet = processRuleSet();
- if (ruleSet != null) {
- nodes.add(ruleSet);
+ var rule = processRule();
+ if (rule != null) {
+ nodes.add(rule);
continue;
}
break;
@@ -1211,7 +1205,7 @@
var selectorGroup = _nestedSelector();
while (selectorGroup != null) {
// Nested selector so process as a ruleset.
- var ruleset = processRuleSet(selectorGroup);
+ var ruleset = processRule(selectorGroup);
decls.add(ruleset);
selectorGroup = _nestedSelector();
}
diff --git a/lib/src/analyzer.dart b/lib/src/analyzer.dart
index 7c7372c..6c6ba6d 100644
--- a/lib/src/analyzer.dart
+++ b/lib/src/analyzer.dart
@@ -415,9 +415,9 @@
_MediaRulesReplacer(this._ruleSet, this._newRules);
visitMediaDirective(MediaDirective node) {
- var index = node.rulesets.indexOf(_ruleSet);
+ var index = node.rules.indexOf(_ruleSet);
if (index != -1) {
- node.rulesets.insertAll(index + 1, _newRules);
+ node.rules.insertAll(index + 1, _newRules);
_foundAndReplaced = true;
}
}
diff --git a/lib/src/css_printer.dart b/lib/src/css_printer.dart
index ac26acb..91c2861 100644
--- a/lib/src/css_printer.dart
+++ b/lib/src/css_printer.dart
@@ -141,7 +141,7 @@
emit('$_newLine@media');
emitMediaQueries(node.mediaQueries);
emit('$_sp{');
- for (var ruleset in node.rulesets) {
+ for (var ruleset in node.rules) {
ruleset.visit(this);
}
emit('$_newLine}');
@@ -149,7 +149,7 @@
void visitHostDirective(HostDirective node) {
emit('$_newLine@host$_sp{');
- for (var ruleset in node.rulesets) {
+ for (var ruleset in node.rules) {
ruleset.visit(this);
}
emit('$_newLine}');
diff --git a/lib/src/tree.dart b/lib/src/tree.dart
index 509e708..7e68473 100644
--- a/lib/src/tree.dart
+++ b/lib/src/tree.dart
@@ -638,9 +638,9 @@
class MediaDirective extends Directive {
final List<MediaQuery> mediaQueries;
- final List<RuleSet> rulesets;
+ final List<TreeNode> rules;
- MediaDirective(this.mediaQueries, this.rulesets, SourceSpan span)
+ MediaDirective(this.mediaQueries, this.rules, SourceSpan span)
: super(span);
MediaDirective clone() {
@@ -648,27 +648,27 @@
for (var mediaQuery in mediaQueries) {
cloneQueries.add(mediaQuery.clone());
}
- var cloneRulesets = <RuleSet>[];
- for (var ruleset in rulesets) {
- cloneRulesets.add(ruleset.clone());
+ var cloneRules = <TreeNode>[];
+ for (var rule in rules) {
+ cloneRules.add(rule.clone());
}
- return new MediaDirective(cloneQueries, cloneRulesets, span);
+ return new MediaDirective(cloneQueries, cloneRules, span);
}
visit(VisitorBase visitor) => visitor.visitMediaDirective(this);
}
class HostDirective extends Directive {
- final List<RuleSet> rulesets;
+ final List<TreeNode> rules;
- HostDirective(this.rulesets, SourceSpan span) : super(span);
+ HostDirective(this.rules, SourceSpan span) : super(span);
HostDirective clone() {
- var cloneRulesets = <RuleSet>[];
- for (var ruleset in rulesets) {
- cloneRulesets.add(ruleset.clone());
+ var cloneRules = <TreeNode>[];
+ for (var rule in rules) {
+ cloneRules.add(rule.clone());
}
- return new HostDirective(cloneRulesets, span);
+ return new HostDirective(cloneRules, span);
}
visit(VisitorBase visitor) => visitor.visitHostDirective(this);
@@ -771,20 +771,20 @@
class StyletDirective extends Directive {
final String dartClassName;
- final List<RuleSet> rulesets;
+ final List<TreeNode> rules;
- StyletDirective(this.dartClassName, this.rulesets, SourceSpan span)
+ StyletDirective(this.dartClassName, this.rules, SourceSpan span)
: super(span);
bool get isBuiltIn => false;
bool get isExtension => true;
StyletDirective clone() {
- var cloneRulesets = <RuleSet>[];
- for (var ruleset in rulesets) {
- cloneRulesets.add(ruleset.clone());
+ var cloneRules = <TreeNode>[];
+ for (var rule in rules) {
+ cloneRules.add(rule.clone());
}
- return new StyletDirective(dartClassName, cloneRulesets, span);
+ return new StyletDirective(dartClassName, cloneRules, span);
}
visit(VisitorBase visitor) => visitor.visitStyletDirective(this);
diff --git a/lib/src/tree_printer.dart b/lib/src/tree_printer.dart
index ba35dec..4f196c0 100644
--- a/lib/src/tree_printer.dart
+++ b/lib/src/tree_printer.dart
@@ -85,7 +85,7 @@
heading('MediaDirective', node);
output.depth++;
output.writeNodeList('media queries', node.mediaQueries);
- output.writeNodeList('rule sets', node.rulesets);
+ output.writeNodeList('rule sets', node.rules);
super.visitMediaDirective(node);
output.depth--;
}
@@ -191,7 +191,7 @@
heading('StyletDirective', node);
output.writeValue('dartClassName', node.dartClassName);
output.depth++;
- output.writeNodeList('rulesets', node.rulesets);
+ output.writeNodeList('rulesets', node.rules);
output.depth--;
}
diff --git a/lib/visitor.dart b/lib/visitor.dart
index eff9e7b..6e3af18 100644
--- a/lib/visitor.dart
+++ b/lib/visitor.dart
@@ -190,18 +190,12 @@
}
visitMediaDirective(MediaDirective node) {
- for (var mediaQuery in node.mediaQueries) {
- visitMediaQuery(mediaQuery);
- }
- for (var ruleset in node.rulesets) {
- visitRuleSet(ruleset);
- }
+ _visitNodeList(node.mediaQueries);
+ _visitNodeList(node.rules);
}
visitHostDirective(HostDirective node) {
- for (var ruleset in node.rulesets) {
- visitRuleSet(ruleset);
- }
+ _visitNodeList(node.rules);
}
visitPageDirective(PageDirective node) {
@@ -237,7 +231,7 @@
}
visitStyletDirective(StyletDirective node) {
- _visitNodeList(node.rulesets);
+ _visitNodeList(node.rules);
}
visitNamespaceDirective(NamespaceDirective node) {}
diff --git a/test/declaration_test.dart b/test/declaration_test.dart
index 782c33c..ab1f70d 100644
--- a/test/declaration_test.dart
+++ b/test/declaration_test.dart
@@ -478,6 +478,30 @@
expect(
errors.first.message, contains('expected { after media before ruleset'));
expect(errors.first.span.text, '(');
+
+ // Test nested at-rules.
+ input = '''
+@media (min-width: 840px) {
+ .cell {
+ width: calc(33% - 16px);
+ }
+ @supports (display: grid) {
+ .cell {
+ grid-column-end: span 4;
+ }
+ }
+}''';
+ generated = '''@media (min-width:840px) {
+.cell {
+ width: calc(33% - 16px);
+}
+@supports (display: grid) {
+.cell {
+ grid-column-end: span 4;
+}
+}
+}''';
+ expectCss(input, generated);
}
void testMozDocument() {