Add Value.toCssString().

This commit is contained in:
Natalie Weizenbaum 2016-10-16 19:01:23 -07:00
parent 604fa597e5
commit 7f6c70f821
4 changed files with 40 additions and 35 deletions

View File

@ -14,7 +14,6 @@ import 'extend/extender.dart';
import 'util/number.dart'; import 'util/number.dart';
import 'utils.dart'; import 'utils.dart';
import 'value.dart'; import 'value.dart';
import 'visitor/serialize.dart';
/// A regular expression matching the beginning of a proprietary Microsoft /// A regular expression matching the beginning of a proprietary Microsoft
/// filter declaration. /// filter declaration.
@ -42,9 +41,7 @@ void defineCoreFunctions(Environment environment) {
environment.defineFunction("rgb", r"$red, $green, $blue", (arguments) { environment.defineFunction("rgb", r"$red, $green, $blue", (arguments) {
if (arguments[0].isCalc || arguments[1].isCalc || arguments[2].isCalc) { if (arguments[0].isCalc || arguments[1].isCalc || arguments[2].isCalc) {
return new SassString( return _functionString('rgb', arguments);
"rgb(${valueToCss(arguments[0])}, ${valueToCss(arguments[0])}, "
"${valueToCss(arguments[0])})");
} }
var red = arguments[0].assertNumber("red"); var red = arguments[0].assertNumber("red");
@ -66,9 +63,7 @@ void defineCoreFunctions(Environment environment) {
arguments[1].isCalc || arguments[1].isCalc ||
arguments[2].isCalc || arguments[2].isCalc ||
arguments[3].isCalc) { arguments[3].isCalc) {
return new SassString( return _functionString('rgba', arguments);
"rgba(${valueToCss(arguments[0])}, ${valueToCss(arguments[1])}, "
"${valueToCss(arguments[2])}, ${valueToCss(arguments[3])})");
} }
var red = arguments[0].assertNumber("red"); var red = arguments[0].assertNumber("red");
@ -88,7 +83,7 @@ void defineCoreFunctions(Environment environment) {
if (arguments[1].isCalc) { if (arguments[1].isCalc) {
return new SassString( return new SassString(
"rgba(${color.red}, ${color.green}, ${color.blue}, " "rgba(${color.red}, ${color.green}, ${color.blue}, "
"${valueToCss(arguments[1])})"); "${arguments[1].toCssString()})");
} }
var alpha = arguments[0].assertNumber("alpha"); var alpha = arguments[0].assertNumber("alpha");
@ -121,9 +116,7 @@ void defineCoreFunctions(Environment environment) {
environment.defineFunction("hsl", r"$hue, $saturation, $lightness", environment.defineFunction("hsl", r"$hue, $saturation, $lightness",
(arguments) { (arguments) {
if (arguments[0].isCalc || arguments[1].isCalc || arguments[2].isCalc) { if (arguments[0].isCalc || arguments[1].isCalc || arguments[2].isCalc) {
return new SassString( return _functionString("hsl", arguments);
"rgb(${valueToCss(arguments[0])}, ${valueToCss(arguments[0])}, "
"${valueToCss(arguments[0])})");
} }
var hue = arguments[0].assertNumber("hue"); var hue = arguments[0].assertNumber("hue");
@ -139,9 +132,7 @@ void defineCoreFunctions(Environment environment) {
arguments[1].isCalc || arguments[1].isCalc ||
arguments[2].isCalc || arguments[2].isCalc ||
arguments[3].isCalc) { arguments[3].isCalc) {
return new SassString( return _functionString("hsla", arguments);
"rgba(${valueToCss(arguments[0])}, ${valueToCss(arguments[1])}, "
"${valueToCss(arguments[2])}, ${valueToCss(arguments[3])})");
} }
var hue = arguments[0].assertNumber("hue"); var hue = arguments[0].assertNumber("hue");
@ -207,7 +198,7 @@ void defineCoreFunctions(Environment environment) {
environment.defineFunction("grayscale", r"$color", (arguments) { environment.defineFunction("grayscale", r"$color", (arguments) {
if (arguments[0] is SassNumber) { if (arguments[0] is SassNumber) {
return new SassString("grayscale(${valueToCss(arguments[0])})"); return _functionString('grayscale', arguments);
} }
var color = arguments[0].assertColor("color"); var color = arguments[0].assertColor("color");
@ -223,7 +214,7 @@ void defineCoreFunctions(Environment environment) {
if (arguments[0] is SassNumber) { if (arguments[0] is SassNumber) {
// TODO: find some way of ensuring this is stringified using the right // TODO: find some way of ensuring this is stringified using the right
// options. We may need to resort to zones. // options. We may need to resort to zones.
return new SassString("invert(${valueToCss(arguments[0])})"); return _functionString("invert", arguments);
} }
var color = arguments[0].assertColor("color"); var color = arguments[0].assertColor("color");
@ -247,7 +238,7 @@ void defineCoreFunctions(Environment environment) {
!argument.hasQuotes && !argument.hasQuotes &&
argument.text.contains(_microsoftFilterStart)) { argument.text.contains(_microsoftFilterStart)) {
// Suport the proprietary Microsoft alpha() function. // Suport the proprietary Microsoft alpha() function.
return new SassString("alpha(${valueToCss(argument)})"); return _functionString("alpha", arguments);
} }
var color = argument.assertColor("color"); var color = argument.assertColor("color");
@ -259,7 +250,7 @@ void defineCoreFunctions(Environment environment) {
!argument.hasQuotes && !argument.hasQuotes &&
argument.text.contains(_microsoftFilterStart))) { argument.text.contains(_microsoftFilterStart))) {
// Suport the proprietary Microsoft alpha() function. // Suport the proprietary Microsoft alpha() function.
return new SassString("alpha(${arguments.map(valueToCss).join(', ')})"); return _functionString("alpha", arguments);
} }
assert(arguments.length != 1); assert(arguments.length != 1);
@ -270,7 +261,7 @@ void defineCoreFunctions(Environment environment) {
environment.defineFunction("opacity", r"$color", (arguments) { environment.defineFunction("opacity", r"$color", (arguments) {
if (arguments[0] is SassNumber) { if (arguments[0] is SassNumber) {
return new SassString("opacity(${valueToCss(arguments[0])})"); return _functionString("opacity", arguments);
} }
var color = arguments[0].assertColor("color"); var color = arguments[0].assertColor("color");
@ -894,6 +885,13 @@ void defineCoreFunctions(Environment environment) {
}); });
} }
/// Returns a string representation of [name] called with [arguments], as though
/// it were a plain CSS function.
SassString _functionString(String name, List<Value> arguments) =>
new SassString("$name(" +
arguments.map((argument) => argument.toCssString()).join(', ') +
")");
/// Asserts that [number] is a percentage or has no units, and normalizes the /// Asserts that [number] is a percentage or has no units, and normalizes the
/// value. /// value.
/// ///

View File

@ -254,37 +254,44 @@ abstract class Value {
/// The SassScript `+` operation. /// The SassScript `+` operation.
Value plus(Value other) { Value plus(Value other) {
if (other is SassString) { if (other is SassString) {
return new SassString(valueToCss(this) + other.text, return new SassString(toCssString() + other.text,
quotes: other.hasQuotes); quotes: other.hasQuotes);
} else { } else {
return new SassString(valueToCss(this) + valueToCss(other)); return new SassString(toCssString() + other.toCssString());
} }
} }
/// The SassScript `-` operation. /// The SassScript `-` operation.
Value minus(Value other) => Value minus(Value other) =>
new SassString("${valueToCss(this)}-${valueToCss(other)}"); new SassString("${toCssString()}-${other.toCssString()}");
/// The SassScript `/` operation. /// The SassScript `/` operation.
Value dividedBy(Value other) => Value dividedBy(Value other) =>
new SassString("${valueToCss(this)}/${valueToCss(other)}"); new SassString("${toCssString()}/${other.toCssString()}");
/// The SassScript unary `+` operation. /// The SassScript unary `+` operation.
Value unaryPlus() => new SassString("+${valueToCss(this)}"); Value unaryPlus() => new SassString("+${toCssString()}");
/// The SassScript unary `-` operation. /// The SassScript unary `-` operation.
Value unaryMinus() => new SassString("-${valueToCss(this)}"); Value unaryMinus() => new SassString("-${toCssString()}");
/// The SassScript unary `/` operation. /// The SassScript unary `/` operation.
Value unaryDivide() => new SassString("/${valueToCss(this)}"); Value unaryDivide() => new SassString("/${toCssString()}");
/// The SassScript unary `not` operation. /// The SassScript unary `not` operation.
Value unaryNot() => sassFalse; Value unaryNot() => sassFalse;
/// Returns a valid CSS representation of [this].
///
/// Throws a [SassScriptException] if [this] can't be represented in plain
/// CSS. Use [toString] instead to get a string representation even if this
/// isn't valid CSS.
String toCssString() => valueToCss(this);
/// Returns a string representation of [this]. /// Returns a string representation of [this].
/// ///
/// Note that this is equivalent to calling `inspect()` on the value, and thus /// Note that this is equivalent to calling `inspect()` on the value, and thus
/// won't reflect the user's output settings. [valueToCss] should be used /// won't reflect the user's output settings. [toCssString] should be used
/// instead to convert [this] to CSS. /// instead to convert [this] to CSS.
String toString() => valueToCss(this, inspect: true); String toString() => valueToCss(this, inspect: true);

View File

@ -5,7 +5,6 @@
import 'package:charcode/charcode.dart'; import 'package:charcode/charcode.dart';
import '../visitor/interface/value.dart'; import '../visitor/interface/value.dart';
import '../visitor/serialize.dart';
import '../value.dart'; import '../value.dart';
/// A SassScript string. /// A SassScript string.
@ -44,7 +43,7 @@ class SassString extends Value {
return new SassString(text + other.text, return new SassString(text + other.text,
quotes: hasQuotes || other.hasQuotes); quotes: hasQuotes || other.hasQuotes);
} else { } else {
return new SassString(text + valueToCss(other), quotes: hasQuotes); return new SassString(text + other.toCssString(), quotes: hasQuotes);
} }
} }

View File

@ -21,7 +21,6 @@ import '../utils.dart';
import '../value.dart'; import '../value.dart';
import 'interface/statement.dart'; import 'interface/statement.dart';
import 'interface/expression.dart'; import 'interface/expression.dart';
import 'serialize.dart';
/// A function that takes a callback with no arguments. /// A function that takes a callback with no arguments.
typedef _ScopeCallback(callback()); typedef _ScopeCallback(callback());
@ -597,10 +596,10 @@ class _PerformVisitor implements StatementVisitor, ExpressionVisitor<Value> {
} else if (condition is SupportsNegation) { } else if (condition is SupportsNegation) {
return "not ${_parenthesize(condition.condition)}"; return "not ${_parenthesize(condition.condition)}";
} else if (condition is SupportsInterpolation) { } else if (condition is SupportsInterpolation) {
return valueToCss(condition.expression.accept(this)); return condition.expression.accept(this).toCssString();
} else if (condition is SupportsDeclaration) { } else if (condition is SupportsDeclaration) {
return "(${valueToCss(condition.name.accept(this))}: " return "(${condition.name.accept(this).toCssString()}: "
"${valueToCss(condition.value.accept(this))})"; "${condition.value.accept(this).toCssString()})";
} else { } else {
return null; return null;
} }
@ -631,7 +630,7 @@ class _PerformVisitor implements StatementVisitor, ExpressionVisitor<Value> {
_addExceptionSpan( _addExceptionSpan(
node.span, node.span,
() => stderr () => stderr
.writeln("WARNING: ${valueToCss(node.expression.accept(this))}")); .writeln("WARNING: ${node.expression.accept(this).toCssString()}"));
for (var line in _stackTrace(node.span).toString().split("\n")) { for (var line in _stackTrace(node.span).toString().split("\n")) {
stderr.writeln(" $line"); stderr.writeln(" $line");
} }
@ -789,7 +788,9 @@ class _PerformVisitor implements StatementVisitor, ExpressionVisitor<Value> {
// TODO: if rest is an arglist that has keywords, error out. // TODO: if rest is an arglist that has keywords, error out.
var rest = node.arguments.rest?.accept(this); var rest = node.arguments.rest?.accept(this);
if (rest != null) arguments.add(rest); if (rest != null) arguments.add(rest);
return new SassString("$name(${arguments.map(valueToCss).join(', ')})"); return new SassString("$name(" +
arguments.map((argument) => argument.toCssString()).join(', ') +
")");
} }
/// Evaluates the arguments in [invocation] as applied to [callable], and /// Evaluates the arguments in [invocation] as applied to [callable], and