mirror of
https://github.com/danog/dart-sass.git
synced 2024-11-26 20:24:42 +01:00
Make visitor interfaces wholly abstract.
This commit is contained in:
parent
ffb85921cb
commit
cdc3065dfb
@ -22,6 +22,4 @@ class PlaceholderSelector extends SimpleSelector {
|
||||
bool operator ==(other) => other is PlaceholderSelector && other.name == name;
|
||||
|
||||
int get hashCode => name.hashCode;
|
||||
|
||||
String toString() => "%$name";
|
||||
}
|
||||
|
@ -3,41 +3,13 @@
|
||||
// https://opensource.org/licenses/MIT.
|
||||
|
||||
import '../../ast/css.dart';
|
||||
import 'selector.dart';
|
||||
import 'value.dart';
|
||||
|
||||
abstract class CssVisitor<T> extends SelectorVisitor<T>
|
||||
implements ValueVisitor<T> {
|
||||
T visitComment(CssComment node) => null;
|
||||
T visitDeclaration(CssDeclaration node) => null;
|
||||
T visitImport(CssImport node) => null;
|
||||
|
||||
T visitAtRule(CssAtRule node) {
|
||||
if (node.children == null) return null;
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitMediaRule(CssMediaRule node) {
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitStyleRule(CssStyleRule node) {
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitStylesheet(CssStylesheet node) {
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
abstract class CssVisitor<T> {
|
||||
T visitAtRule(CssAtRule node);
|
||||
T visitComment(CssComment node);
|
||||
T visitDeclaration(CssDeclaration node);
|
||||
T visitImport(CssImport node);
|
||||
T visitMediaRule(CssMediaRule node);
|
||||
T visitStyleRule(CssStyleRule node);
|
||||
T visitStylesheet(CssStylesheet node);
|
||||
}
|
||||
|
@ -5,56 +5,14 @@
|
||||
import '../../ast/sass.dart';
|
||||
|
||||
abstract class ExpressionVisitor<T> {
|
||||
T visitVariableExpression(VariableExpression node) => null;
|
||||
T visitBooleanExpression(BooleanExpression node) => null;
|
||||
T visitNumberExpression(NumberExpression node) => null;
|
||||
T visitColorExpression(ColorExpression node) => null;
|
||||
|
||||
T visitUnaryOperatorExpression(UnaryOperatorExpression node) {
|
||||
node.operand.accept(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitIdentifierExpression(IdentifierExpression node) {
|
||||
_visitInterpolation(node.text);
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitListExpression(ListExpression node) {
|
||||
for (var expression in node.contents) {
|
||||
expression.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitMapExpression(MapExpression node) {
|
||||
for (var pair in node.pairs) {
|
||||
pair.first.accept(this);
|
||||
pair.last.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitFunctionExpression(FunctionExpression node) {
|
||||
for (var expression in node.arguments.positional) {
|
||||
expression.accept(this);
|
||||
}
|
||||
for (var expression in node.arguments.named.values) {
|
||||
expression.accept(this);
|
||||
}
|
||||
node.arguments.rest?.accept(this);
|
||||
node.arguments.keywordRest?.accept(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitStringExpression(StringExpression node) {
|
||||
_visitInterpolation(node.text);
|
||||
return null;
|
||||
}
|
||||
|
||||
void _visitInterpolation(Interpolation node) {
|
||||
for (var value in node.contents) {
|
||||
if (value is Expression) value.accept(this);
|
||||
}
|
||||
}
|
||||
T visitBooleanExpression(BooleanExpression node);
|
||||
T visitColorExpression(ColorExpression node);
|
||||
T visitFunctionExpression(FunctionExpression node);
|
||||
T visitIdentifierExpression(IdentifierExpression node);
|
||||
T visitListExpression(ListExpression node);
|
||||
T visitMapExpression(MapExpression node);
|
||||
T visitNumberExpression(NumberExpression node);
|
||||
T visitStringExpression(StringExpression node);
|
||||
T visitUnaryOperatorExpression(UnaryOperatorExpression node);
|
||||
T visitVariableExpression(VariableExpression node);
|
||||
}
|
||||
|
@ -5,37 +5,15 @@
|
||||
import '../../ast/selector.dart';
|
||||
|
||||
abstract class SelectorVisitor<T> {
|
||||
T visitAttributeSelector(AttributeSelector attribute) => null;
|
||||
T visitClassSelector(ClassSelector klass) => null;
|
||||
T visitIDSelector(IDSelector id) => null;
|
||||
T visitParentSelector(ParentSelector placeholder) => null;
|
||||
T visitPlaceholderSelector(PlaceholderSelector placeholder) => null;
|
||||
T visitTypeSelector(TypeSelector type) => null;
|
||||
T visitUniversalSelector(UniversalSelector universal) => null;
|
||||
|
||||
T visitComplexSelector(ComplexSelector complex) {
|
||||
for (var component in complex.components) {
|
||||
if (component is CompoundSelector) component.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitCompoundSelector(CompoundSelector compound) {
|
||||
for (var simple in compound.components) {
|
||||
simple.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitSelectorList(SelectorList list) {
|
||||
for (var complex in list.components) {
|
||||
complex.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitPseudoSelector(PseudoSelector pseudo) {
|
||||
if (pseudo.selector != null) visitSelectorList(pseudo.selector);
|
||||
return null;
|
||||
}
|
||||
T visitAttributeSelector(AttributeSelector attribute);
|
||||
T visitClassSelector(ClassSelector klass);
|
||||
T visitComplexSelector(ComplexSelector complex);
|
||||
T visitCompoundSelector(CompoundSelector compound);
|
||||
T visitIDSelector(IDSelector id);
|
||||
T visitParentSelector(ParentSelector placeholder);
|
||||
T visitPlaceholderSelector(PlaceholderSelector placeholder);
|
||||
T visitPseudoSelector(PseudoSelector pseudo);
|
||||
T visitSelectorList(SelectorList list);
|
||||
T visitTypeSelector(TypeSelector type);
|
||||
T visitUniversalSelector(UniversalSelector universal);
|
||||
}
|
||||
|
@ -5,77 +5,20 @@
|
||||
import '../../ast/sass.dart';
|
||||
|
||||
abstract class StatementVisitor<T> {
|
||||
T visitComment(Comment node) => null;
|
||||
T visitContent(Content node) => null;
|
||||
T visitExtendRule(ExtendRule node) => null;
|
||||
T visitImport(Import node) => null;
|
||||
T visitPlainImport(PlainImport node) => null;
|
||||
T visitReturn(Return node) => null;
|
||||
T visitVariableDeclaration(VariableDeclaration node) => null;
|
||||
|
||||
T visitDeclaration(Declaration node) {
|
||||
if (node.children == null) return null;
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitAtRule(AtRule node) {
|
||||
if (node.children == null) return null;
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitFunctionDeclaration(FunctionDeclaration node) {
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitIf(If node) {
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitInclude(Include node) {
|
||||
if (node.children == null) return null;
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitMixinDeclaration(MixinDeclaration node) {
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitMediaRule(MediaRule node) {
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitStyleRule(StyleRule node) {
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitStylesheet(Stylesheet node) {
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
T visitAtRule(AtRule node);
|
||||
T visitComment(Comment node);
|
||||
T visitContent(Content node);
|
||||
T visitDeclaration(Declaration node);
|
||||
T visitExtendRule(ExtendRule node);
|
||||
T visitFunctionDeclaration(FunctionDeclaration node);
|
||||
T visitIf(If node);
|
||||
T visitImport(Import node);
|
||||
T visitInclude(Include node);
|
||||
T visitMediaRule(MediaRule node);
|
||||
T visitMixinDeclaration(MixinDeclaration node);
|
||||
T visitPlainImport(PlainImport node);
|
||||
T visitReturn(Return node);
|
||||
T visitStyleRule(StyleRule node);
|
||||
T visitStylesheet(Stylesheet node);
|
||||
T visitVariableDeclaration(VariableDeclaration node);
|
||||
}
|
||||
|
@ -5,24 +5,11 @@
|
||||
import '../../value.dart';
|
||||
|
||||
abstract class ValueVisitor<T> {
|
||||
T visitBoolean(SassBoolean value) => null;
|
||||
T visitIdentifier(SassIdentifier value) => null;
|
||||
T visitNumber(SassNumber value) => null;
|
||||
T visitString(SassString value) => null;
|
||||
T visitColor(SassColor value) => null;
|
||||
|
||||
T visitList(SassList value) {
|
||||
for (var element in value.contents) {
|
||||
element.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
T visitMap(SassMap value) {
|
||||
value.contents.forEach((key, value) {
|
||||
key.accept(this);
|
||||
value.accept(this);
|
||||
});
|
||||
return null;
|
||||
}
|
||||
T visitBoolean(SassBoolean value);
|
||||
T visitColor(SassColor value);
|
||||
T visitIdentifier(SassIdentifier value);
|
||||
T visitList(SassList value);
|
||||
T visitMap(SassMap value);
|
||||
T visitNumber(SassNumber value);
|
||||
T visitString(SassString value);
|
||||
}
|
||||
|
@ -20,8 +20,7 @@ import '../value.dart';
|
||||
import 'interface/statement.dart';
|
||||
import 'interface/expression.dart';
|
||||
|
||||
class PerformVisitor extends StatementVisitor
|
||||
implements ExpressionVisitor<Value> {
|
||||
class PerformVisitor implements StatementVisitor, ExpressionVisitor<Value> {
|
||||
final List<String> _loadPaths;
|
||||
|
||||
Environment _environment;
|
||||
@ -64,7 +63,9 @@ class PerformVisitor extends StatementVisitor
|
||||
CssStylesheet visitStylesheet(Stylesheet node) {
|
||||
_root = new CssStylesheet(node.span);
|
||||
_parent = _root;
|
||||
super.visitStylesheet(node);
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
return _root;
|
||||
}
|
||||
|
||||
@ -101,7 +102,9 @@ class PerformVisitor extends StatementVisitor
|
||||
if (node.children != null) {
|
||||
var oldDeclarationName = _declarationName;
|
||||
_declarationName = name.value;
|
||||
super.visitDeclaration(node);
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
_declarationName = oldDeclarationName;
|
||||
}
|
||||
}
|
||||
@ -137,15 +140,19 @@ class PerformVisitor extends StatementVisitor
|
||||
|
||||
_withParent(new CssAtRule(node.name, node.span, value: value), () {
|
||||
if (_selector == null) {
|
||||
super.visitAtRule(node);
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
} else {
|
||||
// If we're in a style rule, copy it into the at-rule so that
|
||||
// declarations immediately inside it have somewhere to go.
|
||||
//
|
||||
// For example, "a {@foo {b: c}}" should produce "@foo {a {b: c}}".
|
||||
_withParent(new CssStyleRule(_selector, _selector.span),
|
||||
() => super.visitAtRule(node),
|
||||
removeIfEmpty: true);
|
||||
_withParent(new CssStyleRule(_selector, _selector.span), () {
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
}, removeIfEmpty: true);
|
||||
}
|
||||
}, through: (node) => node is CssStyleRule);
|
||||
}
|
||||
@ -158,7 +165,11 @@ class PerformVisitor extends StatementVisitor
|
||||
void visitIf(If node) {
|
||||
var condition = node.expression.accept(this);
|
||||
if (!condition.isTruthy) return;
|
||||
_environment.scope(() => super.visitIf(node), semiGlobal: true);
|
||||
_environment.scope(() {
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
}, semiGlobal: true);
|
||||
}
|
||||
|
||||
void visitImport(Import node) {
|
||||
@ -254,16 +265,20 @@ class PerformVisitor extends StatementVisitor
|
||||
_withParent(new CssMediaRule(queries, node.span), () {
|
||||
_withMediaQueries(queries, () {
|
||||
if (_selector == null) {
|
||||
super.visitMediaRule(node);
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
} else {
|
||||
// If we're in a style rule, copy it into the media query so that
|
||||
// declarations immediately inside @media have somewhere to go.
|
||||
//
|
||||
// For example, "a {@media screen {b: c}}" should produce
|
||||
// "@media screen {a {b: c}}".
|
||||
_withParent(new CssStyleRule(_selector, _selector.span),
|
||||
() => super.visitMediaRule(node),
|
||||
removeIfEmpty: true);
|
||||
_withParent(new CssStyleRule(_selector, _selector.span), () {
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
}, removeIfEmpty: true);
|
||||
}
|
||||
});
|
||||
},
|
||||
@ -313,9 +328,13 @@ class PerformVisitor extends StatementVisitor
|
||||
var selector =
|
||||
new CssValue<SelectorList>(parsedSelector, node.selector.span);
|
||||
|
||||
_withParent(_extender.addSelector(selector, node.span),
|
||||
() => _withSelector(selector, () => super.visitStyleRule(node)),
|
||||
through: (node) => node is CssStyleRule, removeIfEmpty: true);
|
||||
_withParent(_extender.addSelector(selector, node.span), () {
|
||||
_withSelector(selector, () {
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
});
|
||||
}, through: (node) => node is CssStyleRule, removeIfEmpty: true);
|
||||
}
|
||||
|
||||
void visitVariableDeclaration(VariableDeclaration node) {
|
||||
|
@ -12,6 +12,8 @@ import '../ast/selector.dart';
|
||||
import '../util/character.dart';
|
||||
import '../value.dart';
|
||||
import 'interface/css.dart';
|
||||
import 'interface/selector.dart';
|
||||
import 'interface/value.dart';
|
||||
|
||||
String toCss(CssNode node) {
|
||||
var visitor = new _SerializeCssVisitor();
|
||||
@ -38,7 +40,8 @@ String selectorToCss(Selector selector) {
|
||||
return visitor._buffer.toString();
|
||||
}
|
||||
|
||||
class _SerializeCssVisitor extends CssVisitor {
|
||||
class _SerializeCssVisitor
|
||||
implements CssVisitor, ValueVisitor, SelectorVisitor {
|
||||
final _buffer = new StringBuffer();
|
||||
|
||||
var _indentation = 0;
|
||||
@ -311,6 +314,12 @@ class _SerializeCssVisitor extends CssVisitor {
|
||||
});
|
||||
}
|
||||
|
||||
void visitCompoundSelector(CompoundSelector compound) {
|
||||
for (var simple in compound.components) {
|
||||
simple.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void visitIDSelector(IDSelector id) {
|
||||
_buffer.writeCharCode($hash);
|
||||
_buffer.write(id.name);
|
||||
@ -326,6 +335,11 @@ class _SerializeCssVisitor extends CssVisitor {
|
||||
if (parent.suffix != null) _buffer.write(parent.suffix);
|
||||
}
|
||||
|
||||
void visitPlaceholderSelector(PlaceholderSelector placeholder) {
|
||||
_buffer.writeCharCode($percent);
|
||||
_buffer.write(placeholder.name);
|
||||
}
|
||||
|
||||
void visitPseudoSelector(PseudoSelector pseudo) {
|
||||
_buffer.writeCharCode($colon);
|
||||
if (pseudo.type == PseudoType.element) _buffer.writeCharCode($colon);
|
||||
|
Loading…
Reference in New Issue
Block a user