mirror of
https://github.com/danog/dart-sass.git
synced 2024-11-27 04:34:59 +01:00
Support @each
This commit is contained in:
parent
e873242ac4
commit
1832879845
@ -28,6 +28,7 @@ export 'sass/statement/comment.dart';
|
||||
export 'sass/statement/content_rule.dart';
|
||||
export 'sass/statement/debug_rule.dart';
|
||||
export 'sass/statement/declaration.dart';
|
||||
export 'sass/statement/each_rule.dart';
|
||||
export 'sass/statement/error_rule.dart';
|
||||
export 'sass/statement/extend_rule.dart';
|
||||
export 'sass/statement/for_rule.dart';
|
||||
|
31
lib/src/ast/sass/statement/each_rule.dart
Normal file
31
lib/src/ast/sass/statement/each_rule.dart
Normal file
@ -0,0 +1,31 @@
|
||||
// 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 'package:source_span/source_span.dart';
|
||||
|
||||
import '../../../visitor/interface/statement.dart';
|
||||
import '../expression.dart';
|
||||
import '../statement.dart';
|
||||
|
||||
class EachRule implements Statement {
|
||||
final List<String> variables;
|
||||
|
||||
final Expression list;
|
||||
|
||||
final List<Statement> children;
|
||||
|
||||
final FileSpan span;
|
||||
|
||||
EachRule(Iterable<String> variables, this.list, Iterable<Statement> children,
|
||||
this.span)
|
||||
: variables = new List.unmodifiable(variables),
|
||||
children = new List.unmodifiable(children);
|
||||
|
||||
/*=T*/ accept/*<T>*/(StatementVisitor/*<T>*/ visitor) =>
|
||||
visitor.visitEachRule(this);
|
||||
|
||||
String toString() =>
|
||||
"@each ${variables.map((variable) => '\$' + variable).join(', ')} in "
|
||||
"$list {${children.join(" ")}}";
|
||||
}
|
@ -327,6 +327,8 @@ class Parser {
|
||||
return _contentRule(start);
|
||||
case "debug":
|
||||
return _debugRule(start);
|
||||
case "each":
|
||||
return _eachRule(start, child);
|
||||
case "error":
|
||||
return _errorRule(start);
|
||||
case "extend":
|
||||
@ -367,6 +369,8 @@ class Parser {
|
||||
return _contentRule(start);
|
||||
case "debug":
|
||||
return _debugRule(start);
|
||||
case "each":
|
||||
return _eachRule(start, _declarationChild);
|
||||
case "error":
|
||||
return _errorRule(start);
|
||||
case "for":
|
||||
@ -389,6 +393,8 @@ class Parser {
|
||||
switch (_atRuleName()) {
|
||||
case "debug":
|
||||
return _debugRule(start);
|
||||
case "each":
|
||||
return _eachRule(start, _functionAtRule);
|
||||
case "error":
|
||||
return _errorRule(start);
|
||||
case "for":
|
||||
@ -436,6 +442,28 @@ class Parser {
|
||||
DebugRule _debugRule(LineScannerState start) =>
|
||||
new DebugRule(_expression(), _scanner.spanFrom(start));
|
||||
|
||||
EachRule _eachRule(LineScannerState start, Statement child()) {
|
||||
var wasInControlDirective = _inControlDirective;
|
||||
_inControlDirective = true;
|
||||
|
||||
var variables = [_variableName()];
|
||||
_ignoreComments();
|
||||
while (_scanner.scanChar($comma)) {
|
||||
_ignoreComments();
|
||||
variables.add(_variableName());
|
||||
_ignoreComments();
|
||||
}
|
||||
|
||||
_scanner.expect("in");
|
||||
_ignoreComments();
|
||||
|
||||
var list = _expression();
|
||||
var children = _children(child);
|
||||
_inControlDirective = wasInControlDirective;
|
||||
|
||||
return new EachRule(variables, list, children, _scanner.spanFrom(start));
|
||||
}
|
||||
|
||||
ErrorRule _errorRule(LineScannerState start) =>
|
||||
new ErrorRule(_expression(), _scanner.spanFrom(start));
|
||||
|
||||
@ -1938,6 +1966,7 @@ class Parser {
|
||||
/// [the CSS algorithm]: https://drafts.csswg.org/css-syntax-3/#would-start-an-identifier
|
||||
bool _lookingAtInterpolatedIdentifier() {
|
||||
var first = _scanner.peekChar();
|
||||
if (first == null) return false;
|
||||
if (isNameStart(first) || first == $backslash) return true;
|
||||
if (first == $hash) return _scanner.peekChar(1) == $lbrace;
|
||||
|
||||
|
@ -24,12 +24,12 @@ abstract class Value {
|
||||
|
||||
int get asInt => throw new InternalException("$this is not an int.");
|
||||
|
||||
List<Value> get asList => [this];
|
||||
|
||||
const Value();
|
||||
|
||||
/*=T*/ accept/*<T>*/(ValueVisitor/*<T>*/ visitor);
|
||||
|
||||
List<Value> asList() => [this];
|
||||
|
||||
Value unaryPlus() => new SassIdentifier("+${valueToCss(this)}");
|
||||
|
||||
Value unaryMinus() => new SassIdentifier("-${valueToCss(this)}");
|
||||
|
@ -15,6 +15,8 @@ class SassList extends Value {
|
||||
|
||||
bool get isBlank => contents.every((element) => element.isBlank);
|
||||
|
||||
List<Value> get asList => contents;
|
||||
|
||||
SassList(Iterable<Value> contents, this.separator, {bool bracketed: false})
|
||||
: contents = new List.unmodifiable(contents),
|
||||
isBracketed = bracketed;
|
||||
|
@ -10,6 +10,14 @@ import '../value.dart';
|
||||
class SassMap extends Value {
|
||||
final Map<Value, Value> contents;
|
||||
|
||||
List<SassList> get asList {
|
||||
var result = <SassList>[];
|
||||
contents.forEach((key, value) {
|
||||
result.add(new SassList([key, value], ListSeparator.space));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
SassMap(Map<Value, Value> contents)
|
||||
: contents = new Map.unmodifiable(contents);
|
||||
|
||||
|
@ -11,6 +11,7 @@ abstract class StatementVisitor<T> {
|
||||
T visitContentRule(ContentRule node);
|
||||
T visitDebugRule(DebugRule node);
|
||||
T visitDeclaration(Declaration node);
|
||||
T visitEachRule(EachRule node);
|
||||
T visitErrorRule(ErrorRule node);
|
||||
T visitExtendRule(ExtendRule node);
|
||||
T visitForRule(ForRule node);
|
||||
|
@ -211,6 +211,33 @@ class PerformVisitor implements StatementVisitor, ExpressionVisitor<Value> {
|
||||
}
|
||||
}
|
||||
|
||||
void visitEachRule(EachRule node) {
|
||||
var list = node.list.accept(this);
|
||||
var setVariables = node.variables.length == 1
|
||||
? (value) => _environment.setLocalVariable(node.variables.first, value)
|
||||
: (value) => _setMultipleVariables(node.variables, value);
|
||||
_environment.scope(() {
|
||||
for (var element in list.asList) {
|
||||
setVariables(element);
|
||||
for (var child in node.children) {
|
||||
child.accept(this);
|
||||
}
|
||||
}
|
||||
}, semiGlobal: true);
|
||||
}
|
||||
|
||||
void _setMultipleVariables(List<String> variables, Value value) {
|
||||
var list = value.asList;
|
||||
var minLength = math.min(variables.length, list.length);
|
||||
for (var i = 0; i < minLength; i++) {
|
||||
_environment.setLocalVariable(variables[i], list[i]);
|
||||
}
|
||||
for (var i = minLength; i < variables.length; i++) {
|
||||
// TODO: Sass null
|
||||
_environment.setLocalVariable(variables[i], null);
|
||||
}
|
||||
}
|
||||
|
||||
void visitErrorRule(ErrorRule node) {
|
||||
throw _exception(node.expression.accept(this).toString(), node.span);
|
||||
}
|
||||
@ -720,7 +747,7 @@ class PerformVisitor implements StatementVisitor, ExpressionVisitor<Value> {
|
||||
if (rest is SassMap) {
|
||||
_addRestMap(named, rest, invocation.span);
|
||||
} else if (rest is SassList) {
|
||||
positional.addAll(rest.asList());
|
||||
positional.addAll(rest.asList);
|
||||
} else {
|
||||
positional.add(rest);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user