Simple perform.

This commit is contained in:
Natalie Weizenbaum 2016-05-24 14:01:41 -07:00
parent 5543201398
commit 34b365c8c6
7 changed files with 145 additions and 4 deletions

View File

@ -6,9 +6,10 @@ import 'dart:io';
import 'package:path/path.dart' as p;
import 'package:sass/src/parser.dart';
import 'package:sass/src/visitor/statement/perform.dart';
void main(List<String> args) {
var parser = new Parser(new File(args.first).readAsStringSync(),
url: p.toUri(args.first));
print(parser.parse());
print(new PerformVisitor().visitStylesheet(parser.parse()));
}

View File

@ -4,7 +4,7 @@
import 'package:source_span/source_span.dart';
import '../../value/identifier.dart';
import '../../value.dart';
import 'node.dart';
import 'value.dart';

View File

@ -4,7 +4,6 @@
import 'package:source_span/source_span.dart';
import '../../value/identifier.dart';
import 'node.dart';
import 'value.dart';

View File

@ -5,7 +5,6 @@
import 'package:source_span/source_span.dart';
import 'node.dart';
import '../../value.dart';
class CssValue<T> implements CssNode {
final T value;

View File

@ -2,6 +2,8 @@
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import 'dart:collection';
import 'package:source_span/source_span.dart';
import 'ast/node.dart';
@ -13,3 +15,9 @@ SourceSpan spanForList(List<AstNode> nodes) {
var last = nodes.last.span;
return first is FileSpan && last is FileSpan ? first.expand(last) : null;
}
class LinkedListValue<T> extends LinkedListEntry<LinkedListValue<T>> {
final T value;
LinkedListValue(this.value);
}

View File

@ -0,0 +1,35 @@
// Copyright 2016 Google Inc. Use of this source code is governed by an
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import '../../ast/sass/expression.dart';
import '../../ast/sass/expression/identifier.dart';
import '../../ast/sass/expression/interpolation.dart';
import '../../ast/sass/expression/list.dart';
import '../../ast/sass/expression/string.dart';
import '../../value.dart';
import '../../value/identifier.dart';
import '../../value/list.dart';
import '../../value/string.dart';
import '../expression.dart';
class PerformExpressionVisitor extends ExpressionVisitor<Value> {
Value visit(Expression expression) => expression.visit(this);
Identifier visitIdentifierExpression(IdentifierExpression node) =>
new Identifier(visitInterpolationExpression(node.text).text);
SassString visitInterpolationExpression(InterpolationExpression node) {
return new SassString(node.contents.map((value) {
if (value is String) return value;
return (value as Expression).visit(this);
}).join());
}
SassList visitListExpression(ListExpression node) => new SassList(
node.contents.map((expression) => expression.visit(this)),
node.separator);
SassString visitStringExpression(StringExpression node) =>
visitInterpolationExpression(node.text);
}

View File

@ -0,0 +1,99 @@
// Copyright 2016 Google Inc. Use of this source code is governed by an
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import 'dart:collection';
import '../../ast/css/comment.dart';
import '../../ast/css/declaration.dart';
import '../../ast/css/node.dart';
import '../../ast/css/style_rule.dart';
import '../../ast/css/stylesheet.dart';
import '../../ast/css/value.dart';
import '../../ast/sass/comment.dart';
import '../../ast/sass/declaration.dart';
import '../../ast/sass/expression.dart';
import '../../ast/sass/expression/interpolation.dart';
import '../../ast/sass/statement.dart';
import '../../ast/sass/style_rule.dart';
import '../../ast/sass/stylesheet.dart';
import '../../ast/sass/variable_declaration.dart';
import '../../utils.dart';
import '../../value.dart';
import '../expression/perform.dart';
import '../statement.dart';
class PerformVisitor extends StatementVisitor {
final _expressionVisitor = new PerformExpressionVisitor();
final _styleRules = <CssStyleRule>[];
/// These are linked lists so that we can efficiently insert the style rules
/// before their nested children.
final _children = [new LinkedList<LinkedListValue<CssNode>>()];
void visit(Statement node) => node.visit(this);
CssStylesheet visitStylesheet(Stylesheet node) {
super.visitStylesheet(node);
return new CssStylesheet(_children.single.map((entry) => entry.value),
span: node.span);
}
void visitComment(Comment node) {
if (node.isSilent) return;
_addChild(new CssComment(node.text, span: node.span));
}
void visitDeclaration(Declaration node) {
_addChild(new CssDeclaration(
_performInterpolation(node.name),
_performExpression(node.value),
span: node.span));
}
void visitStyleRule(StyleRule node) {
var selector = _performInterpolation(node.selector);
if (_styleRules.isNotEmpty) {
selector = new CssValue(
"${_styleRules.last.selector.value} ${selector.value}",
span: node.selector.span);
}
// This allows us to follow Ruby Sass's behavior of always putting the style
// rule before any of its children.
var insertionPoint = _children.first.isEmpty ? null : _children.first.last;
_styleRules.add(new CssStyleRule(selector, [], span: node.span));
var children = _collectChildren(() => super.visitStyleRule(node));
_styleRules.removeLast();
if (children.isEmpty) return;
var rule = new CssStyleRule(selector, children, span: node.span);
if (insertionPoint == null) {
_children.first.addFirst(new LinkedListValue(rule));
} else {
insertionPoint.insertAfter(new LinkedListValue(rule));
}
}
void visitVariableDeclaration(VariableDeclaration node) {}
CssValue<String> _performInterpolation(
InterpolationExpression interpolation) {
return new CssValue(
_expressionVisitor.visitInterpolationExpression(interpolation).text);
}
CssValue<Value> _performExpression(Expression expression) =>
new CssValue(expression.visit(_expressionVisitor));
void _addChild(CssNode node) {
_children.last.add(new LinkedListValue(node));
}
Iterable<CssNode> _collectChildren(void callback()) {
_children.add(new LinkedList<LinkedListValue<CssNode>>());
callback();
return _children.removeLast().map((entry) => entry.value);
}
}