mirror of
https://github.com/danog/dart-sass.git
synced 2025-01-22 05:41:14 +01:00
Split Value and its subtypes into public and private interfaces (#210)
This commit is contained in:
parent
8e57a0635d
commit
1e09cec5aa
@ -12,7 +12,8 @@ import 'src/sync_package_resolver.dart';
|
||||
|
||||
export 'src/callable.dart' show Callable, AsyncCallable;
|
||||
export 'src/importer.dart';
|
||||
export 'src/value.dart' hide SassNull;
|
||||
export 'src/value.dart' show ListSeparator;
|
||||
export 'src/value/external/value.dart';
|
||||
|
||||
/// Loads the Sass file at [path], compiles it to CSS, and returns the result.
|
||||
///
|
||||
|
@ -13,9 +13,9 @@ class ColorExpression implements Expression {
|
||||
/// The value of this color.
|
||||
final SassColor value;
|
||||
|
||||
final FileSpan span;
|
||||
FileSpan get span => value.originalSpan;
|
||||
|
||||
ColorExpression(this.value, this.span);
|
||||
ColorExpression(this.value);
|
||||
|
||||
T accept<T>(ExpressionVisitor<T> visitor) =>
|
||||
visitor.visitColorExpression(this);
|
||||
|
@ -5,6 +5,7 @@
|
||||
import 'callable/async.dart';
|
||||
import 'callable/built_in.dart';
|
||||
import 'value.dart';
|
||||
import 'value/external/value.dart' as ext;
|
||||
|
||||
export 'callable/async.dart';
|
||||
export 'callable/async_built_in.dart';
|
||||
@ -87,5 +88,7 @@ abstract class Callable extends AsyncCallable {
|
||||
/// which provides access to keyword arguments using
|
||||
/// [SassArgumentList.keywords].
|
||||
factory Callable(String name, String arguments,
|
||||
Value callback(List<Value> arguments)) = BuiltInCallable;
|
||||
ext.Value callback(List<ext.Value> arguments)) =>
|
||||
new BuiltInCallable(
|
||||
name, arguments, (arguments) => callback(arguments) as Value);
|
||||
}
|
||||
|
@ -4,7 +4,10 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:async/async.dart';
|
||||
|
||||
import '../value.dart';
|
||||
import '../value/external/value.dart' as ext;
|
||||
import 'async_built_in.dart';
|
||||
|
||||
/// An interface functions and mixins that can be invoked from Sass by passing
|
||||
@ -27,5 +30,10 @@ abstract class AsyncCallable {
|
||||
///
|
||||
/// See [new Callable] for more details.
|
||||
factory AsyncCallable(String name, String arguments,
|
||||
FutureOr<Value> callback(List<Value> arguments)) = AsyncBuiltInCallable;
|
||||
FutureOr<ext.Value> callback(List<ext.Value> arguments)) =>
|
||||
new AsyncBuiltInCallable(name, arguments, (arguments) {
|
||||
var result = callback(arguments);
|
||||
if (result is ext.Value) return result as Value;
|
||||
return DelegatingFuture.typed(result as Future);
|
||||
});
|
||||
}
|
||||
|
@ -1704,20 +1704,14 @@ abstract class StylesheetParser extends Parser {
|
||||
|
||||
var first = scanner.peekChar();
|
||||
if (first != null && isDigit(first)) {
|
||||
var color = _hexColorContents();
|
||||
var span = scanner.spanFrom(start);
|
||||
setOriginalSpan(color, span);
|
||||
return new ColorExpression(color, span);
|
||||
return new ColorExpression(_hexColorContents(start));
|
||||
}
|
||||
|
||||
var afterHash = scanner.state;
|
||||
var identifier = _interpolatedIdentifier();
|
||||
if (_isHexColor(identifier)) {
|
||||
scanner.state = afterHash;
|
||||
var color = _hexColorContents();
|
||||
var span = scanner.spanFrom(start);
|
||||
setOriginalSpan(color, span);
|
||||
return new ColorExpression(color, span);
|
||||
return new ColorExpression(_hexColorContents(start));
|
||||
}
|
||||
|
||||
var buffer = new InterpolationBuffer();
|
||||
@ -1727,7 +1721,7 @@ abstract class StylesheetParser extends Parser {
|
||||
}
|
||||
|
||||
/// Consumes the contents of a hex color, after the `#`.
|
||||
SassColor _hexColorContents() {
|
||||
SassColor _hexColorContents(LineScannerState start) {
|
||||
var red = _hexDigit();
|
||||
var green = _hexDigit();
|
||||
var blue = _hexDigit();
|
||||
@ -1743,7 +1737,7 @@ abstract class StylesheetParser extends Parser {
|
||||
blue = (blue << 4) + blue;
|
||||
}
|
||||
|
||||
return new SassColor.rgb(red, green, blue);
|
||||
return new SassColor.rgb(red, green, blue, 1, scanner.spanFrom(start));
|
||||
}
|
||||
|
||||
/// Returns whether [interpolation] is a plain string that can be parsed as a
|
||||
@ -2034,9 +2028,8 @@ abstract class StylesheetParser extends Parser {
|
||||
var color = colorsByName[lower];
|
||||
if (color != null) {
|
||||
color = new SassColor.rgb(
|
||||
color.red, color.green, color.blue, color.alpha);
|
||||
setOriginalSpan(color, identifier.span);
|
||||
return new ColorExpression(color, identifier.span);
|
||||
color.red, color.green, color.blue, color.alpha, identifier.span);
|
||||
return new ColorExpression(color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import 'ast/selector.dart';
|
||||
import 'exception.dart';
|
||||
import 'value/boolean.dart';
|
||||
import 'value/color.dart';
|
||||
import 'value/external/value.dart' as ext;
|
||||
import 'value/function.dart';
|
||||
import 'value/list.dart';
|
||||
import 'value/map.dart';
|
||||
@ -16,7 +17,7 @@ import 'visitor/serialize.dart';
|
||||
|
||||
export 'value/argument_list.dart';
|
||||
export 'value/boolean.dart';
|
||||
export 'value/color.dart' hide setOriginalSpan;
|
||||
export 'value/color.dart';
|
||||
export 'value/function.dart';
|
||||
export 'value/list.dart';
|
||||
export 'value/map.dart';
|
||||
@ -24,38 +25,20 @@ export 'value/null.dart';
|
||||
export 'value/number.dart';
|
||||
export 'value/string.dart';
|
||||
|
||||
/// A SassScript value.
|
||||
// TODO(nweiz): Just mark members as @internal when sdk#28066 is fixed.
|
||||
/// The implementation of [ext.Value].
|
||||
///
|
||||
/// All SassScript values are unmodifiable. New values can be constructed using
|
||||
/// subclass constructors like [new SassString]. Untyped values can be cast to
|
||||
/// particular types using `assert*()` functions like [assertString], which
|
||||
/// throw user-friendly error messages if they fail.
|
||||
abstract class Value {
|
||||
/// This is a separate class to avoid exposing more API surface than necessary
|
||||
/// to users outside this package.
|
||||
abstract class Value implements ext.Value {
|
||||
bool get isTruthy => true;
|
||||
ListSeparator get separator => ListSeparator.undecided;
|
||||
bool get hasBrackets => false;
|
||||
List<Value> get asList => [this];
|
||||
|
||||
/// Whether the value will be represented in CSS as the empty string.
|
||||
bool get isBlank => false;
|
||||
|
||||
/// Whether the value counts as `true` in an `@if` statement and other
|
||||
/// contexts.
|
||||
bool get isTruthy => true;
|
||||
|
||||
/// The separator for this value as a list.
|
||||
///
|
||||
/// All SassScript values can be used as lists. Maps count as lists of pairs,
|
||||
/// and all other values count as single-value lists.
|
||||
ListSeparator get separator => ListSeparator.undecided;
|
||||
|
||||
/// Whether this value as a list has brackets.
|
||||
///
|
||||
/// All SassScript values can be used as lists. Maps count as lists of pairs,
|
||||
/// and all other values count as single-value lists.
|
||||
bool get hasBrackets => false;
|
||||
|
||||
/// This value as a list.
|
||||
///
|
||||
/// All SassScript values can be used as lists. Maps count as lists of pairs,
|
||||
/// and all other values count as single-value lists.
|
||||
List<Value> get asList => [this];
|
||||
|
||||
/// Whether this is a value that CSS may treat as a number, such as `calc()`
|
||||
/// or `var()`.
|
||||
///
|
||||
@ -78,48 +61,21 @@ abstract class Value {
|
||||
/// It's not guaranteed to be stable across versions.
|
||||
T accept<T>(ValueVisitor<T> visitor);
|
||||
|
||||
/// Throws a [SassScriptException] if [this] isn't a boolean.
|
||||
///
|
||||
/// Note that generally, functions should use [isTruthy] rather than requiring
|
||||
/// a literal boolean.
|
||||
///
|
||||
/// If this came from a function argument, [name] is the argument name
|
||||
/// (without the `$`). It's used for error reporting.
|
||||
SassBoolean assertBoolean([String name]) =>
|
||||
throw _exception("$this is not a boolean.", name);
|
||||
|
||||
/// Throws a [SassScriptException] if [this] isn't a color.
|
||||
///
|
||||
/// If this came from a function argument, [name] is the argument name
|
||||
/// (without the `$`). It's used for error reporting.
|
||||
SassColor assertColor([String name]) =>
|
||||
throw _exception("$this is not a color.", name);
|
||||
|
||||
/// Throws a [SassScriptException] if [this] isn't a function reference.
|
||||
///
|
||||
/// If this came from a function argument, [name] is the argument name
|
||||
/// (without the `$`). It's used for error reporting.
|
||||
SassFunction assertFunction([String name]) =>
|
||||
throw _exception("$this is not a function reference.", name);
|
||||
|
||||
/// Throws a [SassScriptException] if [this] isn't a map.
|
||||
///
|
||||
/// If this came from a function argument, [name] is the argument name
|
||||
/// (without the `$`). It's used for error reporting.
|
||||
SassMap assertMap([String name]) =>
|
||||
throw _exception("$this is not a map.", name);
|
||||
|
||||
/// Throws a [SassScriptException] if [this] isn't a number.
|
||||
///
|
||||
/// If this came from a function argument, [name] is the argument name
|
||||
/// (without the `$`). It's used for error reporting.
|
||||
SassNumber assertNumber([String name]) =>
|
||||
throw _exception("$this is not a number.", name);
|
||||
|
||||
/// Throws a [SassScriptException] if [this] isn't a string.
|
||||
///
|
||||
/// If this came from a function argument, [name] is the argument name
|
||||
/// (without the `$`). It's used for error reporting.
|
||||
SassString assertString([String name]) =>
|
||||
throw _exception("$this is not a string.", name);
|
||||
|
||||
@ -132,8 +88,6 @@ abstract class Value {
|
||||
///
|
||||
/// If this came from a function argument, [name] is the argument name
|
||||
/// (without the `$`). It's used for error reporting.
|
||||
///
|
||||
/// **Note:** this function should not be called outside the `sass` package.
|
||||
SelectorList assertSelector({String name, bool allowParent: false}) {
|
||||
var string = _selectorString(name);
|
||||
try {
|
||||
@ -154,9 +108,6 @@ abstract class Value {
|
||||
///
|
||||
/// If this came from a function argument, [name] is the argument name
|
||||
/// (without the `$`). It's used for error reporting.
|
||||
///
|
||||
/// **Note:** this function should not be called outside the `sass` package.
|
||||
/// It's not guaranteed to be stable across versions.
|
||||
SimpleSelector assertSimpleSelector({String name, bool allowParent: false}) {
|
||||
var string = _selectorString(name);
|
||||
try {
|
||||
@ -177,9 +128,6 @@ abstract class Value {
|
||||
///
|
||||
/// If this came from a function argument, [name] is the argument name
|
||||
/// (without the `$`). It's used for error reporting.
|
||||
///
|
||||
/// **Note:** this function should not be called outside the `sass` package.
|
||||
/// It's not guaranteed to be stable across versions.
|
||||
CompoundSelector assertCompoundSelector(
|
||||
{String name, bool allowParent: false}) {
|
||||
var string = _selectorString(name);
|
||||
@ -369,11 +317,6 @@ abstract class Value {
|
||||
/// If [quote] is `false`, quoted strings are emitted without quotes.
|
||||
String toCssString({bool quote: true}) => serializeValue(this, quote: quote);
|
||||
|
||||
/// Returns a string representation of [this].
|
||||
///
|
||||
/// Note that this is equivalent to calling `inspect()` on the value, and thus
|
||||
/// won't reflect the user's output settings. [toCssString] should be used
|
||||
/// instead to convert [this] to CSS.
|
||||
String toString() => serializeValue(this, inspect: true);
|
||||
|
||||
/// Throws a [SassScriptException] with the given [message].
|
||||
|
@ -4,18 +4,13 @@
|
||||
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
import '../utils.dart';
|
||||
import '../value.dart';
|
||||
import 'external/value.dart' as ext;
|
||||
|
||||
/// A SassScript argument list.
|
||||
///
|
||||
/// An argument list comes from a rest argument. It's distinct from a normal
|
||||
/// [SassList] in that it may contain a keyword map as well as the positional
|
||||
/// arguments.
|
||||
class SassArgumentList extends SassList {
|
||||
/// The keyword arguments attached to this argument list.
|
||||
///
|
||||
/// The argument names don't include `$`.
|
||||
class SassArgumentList extends SassList implements ext.SassArgumentList {
|
||||
Map<String, Value> get keywords {
|
||||
_wereKeywordsAccessed = true;
|
||||
return _keywords;
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
import '../visitor/interface/value.dart';
|
||||
import '../value.dart';
|
||||
import 'external/value.dart' as ext;
|
||||
|
||||
/// The SassScript `true` value.
|
||||
const sassTrue = const SassBoolean._(true);
|
||||
@ -11,17 +12,11 @@ const sassTrue = const SassBoolean._(true);
|
||||
/// The SassScript `false` value.
|
||||
const sassFalse = const SassBoolean._(false);
|
||||
|
||||
/// A SassScript boolean value.
|
||||
class SassBoolean extends Value {
|
||||
/// Whether this value is `true` or `false`.
|
||||
class SassBoolean extends Value implements ext.SassBoolean {
|
||||
final bool value;
|
||||
|
||||
bool get isTruthy => value;
|
||||
|
||||
/// Returns a [SassBoolean] corresponding to [value].
|
||||
///
|
||||
/// This just returns [sassTrue] or [sassFalse]; it doesn't allocate a new
|
||||
/// value.
|
||||
factory SassBoolean(bool value) => value ? sassTrue : sassFalse;
|
||||
|
||||
const SassBoolean._(this.value);
|
||||
|
@ -10,17 +10,9 @@ import '../exception.dart';
|
||||
import '../util/number.dart';
|
||||
import '../value.dart';
|
||||
import '../visitor/interface/value.dart';
|
||||
import 'external/value.dart' as ext;
|
||||
|
||||
/// Sets the span for [SassColor.original] to [span].
|
||||
///
|
||||
/// This is a separate function so it can be hidden in most exports.
|
||||
void setOriginalSpan(SassColor color, SourceSpan span) {
|
||||
color._originalSpan = span;
|
||||
}
|
||||
|
||||
/// A SassScript color.
|
||||
class SassColor extends Value {
|
||||
/// This color's red channel, between `0` and `255`.
|
||||
class SassColor extends Value implements ext.SassColor {
|
||||
int get red {
|
||||
if (_red == null) _hslToRgb();
|
||||
return _red;
|
||||
@ -28,7 +20,6 @@ class SassColor extends Value {
|
||||
|
||||
int _red;
|
||||
|
||||
/// This color's green channel, between `0` and `255`.
|
||||
int get green {
|
||||
if (_green == null) _hslToRgb();
|
||||
return _green;
|
||||
@ -36,7 +27,6 @@ class SassColor extends Value {
|
||||
|
||||
int _green;
|
||||
|
||||
/// This color's blue channel, between `0` and `255`.
|
||||
int get blue {
|
||||
if (_blue == null) _hslToRgb();
|
||||
return _blue;
|
||||
@ -44,7 +34,6 @@ class SassColor extends Value {
|
||||
|
||||
int _blue;
|
||||
|
||||
/// This color's hue, between `0` and `360`.
|
||||
num get hue {
|
||||
if (_hue == null) _rgbToHsl();
|
||||
return _hue;
|
||||
@ -52,7 +41,6 @@ class SassColor extends Value {
|
||||
|
||||
num _hue;
|
||||
|
||||
/// This color's saturation, a percentage between `0` and `100`.
|
||||
num get saturation {
|
||||
if (_saturation == null) _rgbToHsl();
|
||||
return _saturation;
|
||||
@ -60,7 +48,6 @@ class SassColor extends Value {
|
||||
|
||||
num _saturation;
|
||||
|
||||
/// This color's lightness, a percentage between `0` and `100`.
|
||||
num get lightness {
|
||||
if (_lightness == null) _rgbToHsl();
|
||||
return _lightness;
|
||||
@ -68,57 +55,48 @@ class SassColor extends Value {
|
||||
|
||||
num _lightness;
|
||||
|
||||
/// This color's alpha channel, between `0` and `1`.
|
||||
final num alpha;
|
||||
|
||||
/// The original string representation of this color, or `null` if one is
|
||||
/// unavailable.
|
||||
String get original => _originalSpan?.text;
|
||||
String get original => originalSpan?.text;
|
||||
|
||||
/// The span tracking the location in which this color was originally defined.
|
||||
///
|
||||
/// This is tracked as a span to avoid extra substring allocations.
|
||||
SourceSpan _originalSpan;
|
||||
final FileSpan originalSpan;
|
||||
|
||||
/// Creates an RGB color.
|
||||
///
|
||||
/// Throws a [RangeError] if [red], [green], and [blue] aren't between `0` and
|
||||
/// `255`, or if [alpha] isn't between `0` and `1`.
|
||||
SassColor.rgb(this._red, this._green, this._blue, [num alpha])
|
||||
SassColor.rgb(this._red, this._green, this._blue,
|
||||
[num alpha, this.originalSpan])
|
||||
: alpha = alpha == null ? 1 : fuzzyAssertRange(alpha, 0, 1, "alpha") {
|
||||
RangeError.checkValueInInterval(red, 0, 255, "red");
|
||||
RangeError.checkValueInInterval(green, 0, 255, "green");
|
||||
RangeError.checkValueInInterval(blue, 0, 255, "blue");
|
||||
}
|
||||
|
||||
/// Creates an HSL color.
|
||||
///
|
||||
/// Throws a [RangeError] if [saturation] or [lightness] aren't between `0`
|
||||
/// and `100`, or if [alpha] isn't between `0` and `1`.
|
||||
SassColor.hsl(num hue, num saturation, num lightness, [num alpha])
|
||||
: _hue = hue % 360,
|
||||
_saturation = fuzzyAssertRange(saturation, 0, 100, "saturation"),
|
||||
_lightness = fuzzyAssertRange(lightness, 0, 100, "lightness"),
|
||||
alpha = alpha == null ? 1 : fuzzyAssertRange(alpha, 0, 1, "alpha");
|
||||
alpha = alpha == null ? 1 : fuzzyAssertRange(alpha, 0, 1, "alpha"),
|
||||
originalSpan = null;
|
||||
|
||||
SassColor._(this._red, this._green, this._blue, this._hue, this._saturation,
|
||||
this._lightness, this.alpha);
|
||||
this._lightness, this.alpha)
|
||||
: originalSpan = null;
|
||||
|
||||
T accept<T>(ValueVisitor<T> visitor) => visitor.visitColor(this);
|
||||
|
||||
SassColor assertColor([String name]) => this;
|
||||
|
||||
/// Changes one or more of this color's RGB channels and returns the result.
|
||||
SassColor changeRgb({int red, int green, int blue, num alpha}) =>
|
||||
new SassColor.rgb(red ?? this.red, green ?? this.green, blue ?? this.blue,
|
||||
alpha ?? this.alpha);
|
||||
|
||||
/// Changes one or more of this color's HSL channels and returns the result.
|
||||
SassColor changeHsl({num hue, num saturation, num lightness, num alpha}) =>
|
||||
new SassColor.hsl(hue ?? this.hue, saturation ?? this.saturation,
|
||||
lightness ?? this.lightness, alpha ?? this.alpha);
|
||||
|
||||
/// Returns a new copy of this color with the alpha channel set to [alpha].
|
||||
SassColor changeAlpha(num alpha) => new SassColor._(_red, _green, _blue, _hue,
|
||||
_saturation, _lightness, fuzzyAssertRange(alpha, 0, 1, "alpha"));
|
||||
|
||||
|
26
lib/src/value/external/argument_list.dart
vendored
Normal file
26
lib/src/value/external/argument_list.dart
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2018 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:collection/collection.dart';
|
||||
|
||||
import '../../value.dart' as internal;
|
||||
import '../../value.dart' show ListSeparator;
|
||||
import 'value.dart';
|
||||
|
||||
/// A SassScript argument list.
|
||||
///
|
||||
/// An argument list comes from a rest argument. It's distinct from a normal
|
||||
/// [SassList] in that it may contain a keyword map as well as the positional
|
||||
/// arguments.
|
||||
abstract class SassArgumentList extends SassList {
|
||||
/// The keyword arguments attached to this argument list.
|
||||
///
|
||||
/// The argument names don't include `$`.
|
||||
Map<String, Value> get keywords;
|
||||
|
||||
factory SassArgumentList(Iterable<Value> contents,
|
||||
Map<String, Value> keywords, ListSeparator separator) =>
|
||||
new internal.SassArgumentList(DelegatingIterable.typed(contents),
|
||||
DelegatingMap.typed(keywords), separator);
|
||||
}
|
24
lib/src/value/external/boolean.dart
vendored
Normal file
24
lib/src/value/external/boolean.dart
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2018 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 '../../value.dart' as internal;
|
||||
import 'value.dart';
|
||||
|
||||
/// The SassScript `true` value.
|
||||
SassBoolean get sassTrue => internal.sassTrue;
|
||||
|
||||
/// The SassScript `false` value.
|
||||
SassBoolean get sassFalse => internal.sassFalse;
|
||||
|
||||
/// A SassScript boolean value.
|
||||
abstract class SassBoolean extends Value {
|
||||
/// Whether this value is `true` or `false`.
|
||||
bool get value;
|
||||
|
||||
/// Returns a [SassBoolean] corresponding to [value].
|
||||
///
|
||||
/// This just returns [sassTrue] or [sassFalse]; it doesn't allocate a new
|
||||
/// value.
|
||||
factory SassBoolean(bool value) = internal.SassBoolean;
|
||||
}
|
53
lib/src/value/external/color.dart
vendored
Normal file
53
lib/src/value/external/color.dart
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright 2018 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 '../../value.dart' as internal;
|
||||
import 'value.dart';
|
||||
|
||||
/// A SassScript color.
|
||||
abstract class SassColor extends Value {
|
||||
/// This color's red channel, between `0` and `255`.
|
||||
int get red;
|
||||
|
||||
/// This color's green channel, between `0` and `255`.
|
||||
int get green;
|
||||
|
||||
/// This color's blue channel, between `0` and `255`.
|
||||
int get blue;
|
||||
|
||||
/// This color's hue, between `0` and `360`.
|
||||
num get hue;
|
||||
|
||||
/// This color's saturation, a percentage between `0` and `100`.
|
||||
num get saturation;
|
||||
|
||||
/// This color's lightness, a percentage between `0` and `100`.
|
||||
num get lightness;
|
||||
|
||||
/// This color's alpha channel, between `0` and `1`.
|
||||
num get alpha;
|
||||
|
||||
/// Creates an RGB color.
|
||||
///
|
||||
/// Throws a [RangeError] if [red], [green], and [blue] aren't between `0` and
|
||||
/// `255`, or if [alpha] isn't between `0` and `1`.
|
||||
factory SassColor.rgb(int red, int green, int blue, [num alpha]) =
|
||||
internal.SassColor.rgb;
|
||||
|
||||
/// Creates an HSL color.
|
||||
///
|
||||
/// Throws a [RangeError] if [saturation] or [lightness] aren't between `0`
|
||||
/// and `100`, or if [alpha] isn't between `0` and `1`.
|
||||
factory SassColor.hsl(num hue, num saturation, num lightness, [num alpha]) =
|
||||
internal.SassColor.hsl;
|
||||
|
||||
/// Changes one or more of this color's RGB channels and returns the result.
|
||||
SassColor changeRgb({int red, int green, int blue, num alpha});
|
||||
|
||||
/// Changes one or more of this color's HSL channels and returns the result.
|
||||
SassColor changeHsl({num hue, num saturation, num lightness, num alpha});
|
||||
|
||||
/// Returns a new copy of this color with the alpha channel set to [alpha].
|
||||
SassColor changeAlpha(num alpha);
|
||||
}
|
22
lib/src/value/external/function.dart
vendored
Normal file
22
lib/src/value/external/function.dart
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2018 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 '../../callable.dart';
|
||||
import '../../value.dart' as internal;
|
||||
import 'value.dart';
|
||||
|
||||
/// A SassScript function reference.
|
||||
///
|
||||
/// A function reference captures a function from the local environment so that
|
||||
/// it may be passed between modules.
|
||||
abstract class SassFunction extends Value {
|
||||
/// The callable that this function invokes.
|
||||
///
|
||||
/// Note that this is typed as an [AsyncCallback] so that it will work with
|
||||
/// both synchronous and asynchronous evaluate visitors, but in practice the
|
||||
/// synchronous evaluate visitor will crash if this isn't a [Callback].
|
||||
AsyncCallable get callable;
|
||||
|
||||
factory SassFunction(AsyncCallable callable) = internal.SassFunction;
|
||||
}
|
36
lib/src/value/external/list.dart
vendored
Normal file
36
lib/src/value/external/list.dart
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2018 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:collection/collection.dart';
|
||||
|
||||
import '../../value.dart' as internal;
|
||||
import '../../value.dart' show ListSeparator;
|
||||
import 'value.dart';
|
||||
|
||||
/// A SassScript list.
|
||||
abstract class SassList extends Value {
|
||||
// TODO(nweiz): Use persistent data structures rather than copying here. An
|
||||
// RRB vector should fit our use-cases well.
|
||||
//
|
||||
// We may also want to fall back to a plain unmodifiable List for small lists
|
||||
// (<32 items?).
|
||||
/// The contents of the list.
|
||||
List<Value> get contents;
|
||||
|
||||
ListSeparator get separator;
|
||||
|
||||
bool get hasBrackets;
|
||||
|
||||
/// Returns an empty list with the given [separator] and [brackets].
|
||||
///
|
||||
/// The [separator] defaults to [ListSeparator.undecided], and [brackets] defaults to `false`.
|
||||
const factory SassList.empty({ListSeparator separator, bool brackets}) =
|
||||
internal.SassList.empty;
|
||||
|
||||
/// Returns an empty list with the given [separator] and [brackets].
|
||||
factory SassList(Iterable<Value> contents, ListSeparator separator,
|
||||
{bool brackets: false}) =>
|
||||
new internal.SassList(DelegatingIterable.typed(contents), separator,
|
||||
brackets: brackets);
|
||||
}
|
26
lib/src/value/external/map.dart
vendored
Normal file
26
lib/src/value/external/map.dart
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2018 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:collection/collection.dart';
|
||||
|
||||
import '../../value.dart' as internal;
|
||||
import 'value.dart';
|
||||
|
||||
/// A SassScript map.
|
||||
abstract class SassMap extends Value {
|
||||
// TODO(nweiz): Use persistent data structures rather than copying here. We
|
||||
// need to preserve the order, which can be done by tracking an RRB vector of
|
||||
// keys along with the hash-mapped array trie representing the map.
|
||||
//
|
||||
// We may also want to fall back to a plain unmodifiable Map for small maps
|
||||
// (<32 items?).
|
||||
/// The contents of the map.
|
||||
Map<Value, Value> get contents;
|
||||
|
||||
/// Returns an empty map.
|
||||
const factory SassMap.empty() = internal.SassMap.empty;
|
||||
|
||||
factory SassMap(Map<Value, Value> contents) =>
|
||||
new internal.SassMap(DelegatingMap.typed(contents));
|
||||
}
|
123
lib/src/value/external/number.dart
vendored
Normal file
123
lib/src/value/external/number.dart
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
// 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 '../../value.dart' as internal;
|
||||
import 'value.dart';
|
||||
|
||||
/// A SassScript number.
|
||||
///
|
||||
/// Numbers can have units. Although there's no literal syntax for it, numbers
|
||||
/// support scientific-style numerator and denominator units (for example,
|
||||
/// `miles/hour`). These are expected to be resolved before being emitted to
|
||||
/// CSS.
|
||||
abstract class SassNumber extends Value {
|
||||
/// The number of distinct digits that are emitted when converting a number to
|
||||
/// CSS.
|
||||
static const precision = 10;
|
||||
|
||||
/// The value of this number.
|
||||
///
|
||||
/// Note that due to details of floating-point arithmetic, this may be a
|
||||
/// [double] even if [this] represents an int from Sass's perspective. Use
|
||||
/// [isInt] to determine whether this is an integer, [asInt] to get its
|
||||
/// integer value, or [assertInt] to do both at once.
|
||||
num get value;
|
||||
|
||||
/// This number's numerator units.
|
||||
List<String> get numeratorUnits;
|
||||
|
||||
/// This number's denominator units.
|
||||
List<String> get denominatorUnits;
|
||||
|
||||
/// Whether [this] has any units.
|
||||
///
|
||||
/// If a function expects a number to have no units, it should use
|
||||
/// [assertNoUnits]. If it expects the number to have a particular unit, it
|
||||
/// should use [assertUnit].
|
||||
bool get hasUnits;
|
||||
|
||||
/// Whether [this] is an integer, according to [fuzzyEquals].
|
||||
///
|
||||
/// The [int] value can be accessed using [asInt] or [assertInt]. Note that
|
||||
/// this may return `false` for very large doubles even though they may be
|
||||
/// mathematically integers, because not all platforms have a valid
|
||||
/// representation for integers that large.
|
||||
bool get isInt;
|
||||
|
||||
/// If [this] is an integer according to [isInt], returns [value] as an [int].
|
||||
///
|
||||
/// Otherwise, returns `null`.
|
||||
int get asInt;
|
||||
|
||||
/// Creates a number, optionally with a single numerator unit.
|
||||
///
|
||||
/// This matches the numbers that can be written as literals.
|
||||
/// [SassNumber.withUnits] can be used to construct more complex units.
|
||||
factory SassNumber(num value, [String unit]) = internal.SassNumber;
|
||||
|
||||
/// Creates a number with full [numeratorUnits] and [denominatorUnits].
|
||||
factory SassNumber.withUnits(num value,
|
||||
{Iterable<String> numeratorUnits,
|
||||
Iterable<String> denominatorUnits}) = internal.SassNumber.withUnits;
|
||||
|
||||
/// Returns [value] as an [int], if it's an integer value according to
|
||||
/// [isInt].
|
||||
///
|
||||
/// Throws a [SassScriptException] if [value] isn't an integer. If this came
|
||||
/// from a function argument, [name] is the argument name (without the `$`).
|
||||
/// It's used for error reporting.
|
||||
int assertInt([String name]);
|
||||
|
||||
/// Asserts that this is a valid Sass-style index for [list], and returns the
|
||||
/// Dart-style index.
|
||||
///
|
||||
/// A Sass-style index is one-based, and uses negative numbers to count
|
||||
/// backwards from the end of the list.
|
||||
///
|
||||
/// Throws a [SassScriptException] if this isn't an integer or if it isn't a
|
||||
/// valid index for [list]. If this came from a function argument, [name] is
|
||||
/// the argument name (without the `$`). It's used for error reporting.
|
||||
int assertIndexFor(List list, [String name]);
|
||||
|
||||
/// If [value] is between [min] and [max], returns it.
|
||||
///
|
||||
/// If [value] is [fuzzyEquals] to [min] or [max], it's clamped to the
|
||||
/// appropriate value. Otherwise, this throws a [SassScriptException]. If this
|
||||
/// came from a function argument, [name] is the argument name (without the
|
||||
/// `$`). It's used for error reporting.
|
||||
num valueInRange(num min, num max, [String name]);
|
||||
|
||||
/// Returns whether [this] has [unit] as its only unit (and as a numerator).
|
||||
bool hasUnit(String unit);
|
||||
|
||||
/// Throws a [SassScriptException] unless [this] has [unit] as its only unit
|
||||
/// (and as a numerator).
|
||||
///
|
||||
/// If this came from a function argument, [name] is the argument name
|
||||
/// (without the `$`). It's used for error reporting.
|
||||
void assertUnit(String unit, [String name]);
|
||||
|
||||
/// Throws a [SassScriptException] unless [this] has no units.
|
||||
///
|
||||
/// If this came from a function argument, [name] is the argument name
|
||||
/// (without the `$`). It's used for error reporting.
|
||||
void assertNoUnits([String name]);
|
||||
|
||||
/// Returns a copy of this number, converted to the units represented by
|
||||
/// [newNumerators] and [newDenominators].
|
||||
///
|
||||
/// Note that [valueInUnits] is generally more efficient if the value is going
|
||||
/// to be accessed directly.
|
||||
///
|
||||
/// Throws a [SassScriptException] if this number's units aren't compatible
|
||||
/// with [newNumerators] and [newDenominators].
|
||||
SassNumber coerce(List<String> newNumerators, List<String> newDenominators);
|
||||
|
||||
/// Returns [value], converted to the units represented by [newNumerators] and
|
||||
/// [newDenominators].
|
||||
///
|
||||
/// Throws a [SassScriptException] if this number's units aren't compatible
|
||||
/// with [newNumerators] and [newDenominators].
|
||||
num valueInUnits(List<String> newNumerators, List<String> newDenominators);
|
||||
}
|
39
lib/src/value/external/string.dart
vendored
Normal file
39
lib/src/value/external/string.dart
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2018 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 '../../value.dart' as internal;
|
||||
import 'value.dart';
|
||||
|
||||
/// A SassScript string.
|
||||
///
|
||||
/// Strings can either be quoted or unquoted. Unquoted strings are usually CSS
|
||||
/// identifiers, but they may contain any text.
|
||||
abstract class SassString extends Value {
|
||||
/// The contents of the string.
|
||||
///
|
||||
/// For quoted strings, this is the semantic content—any escape sequences that
|
||||
/// were been written in the source text are resolved to their Unicode values.
|
||||
/// For unquoted strings, though, escape sequences are preserved as literal
|
||||
/// backslashes.
|
||||
///
|
||||
/// This difference allows us to distinguish between identifiers with escapes,
|
||||
/// such as `url\u28 http://example.com\u29`, and unquoted strings that
|
||||
/// contain characters that aren't valid in identifiers, such as
|
||||
/// `url(http://example.com)`. Unfortunately, it also means that we don't
|
||||
/// consider `foo` and `f\6F\6F` the same string.
|
||||
String get text;
|
||||
|
||||
/// Whether this string has quotes.
|
||||
bool get hasQuotes;
|
||||
|
||||
/// Creates an empty string.
|
||||
///
|
||||
/// The [quotes] argument defaults to `false`.
|
||||
factory SassString.empty({bool quotes}) = internal.SassString.empty;
|
||||
|
||||
/// Creates a string with the given [text].
|
||||
///
|
||||
/// The [quotes] argument defaults to `false`.
|
||||
factory SassString(String text, {bool quotes}) = internal.SassString;
|
||||
}
|
113
lib/src/value/external/value.dart
vendored
Normal file
113
lib/src/value/external/value.dart
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
// Copyright 2018 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 '../../value.dart' as internal;
|
||||
import '../../value.dart' show ListSeparator;
|
||||
import 'boolean.dart';
|
||||
import 'color.dart';
|
||||
import 'function.dart';
|
||||
import 'map.dart';
|
||||
import 'number.dart';
|
||||
import 'string.dart';
|
||||
|
||||
export 'argument_list.dart';
|
||||
export 'boolean.dart';
|
||||
export 'color.dart';
|
||||
export 'function.dart';
|
||||
export 'list.dart';
|
||||
export 'map.dart';
|
||||
export 'number.dart';
|
||||
export 'string.dart';
|
||||
|
||||
/// The SassScript `null` value.
|
||||
Value get sassNull => internal.sassNull;
|
||||
|
||||
// TODO(nweiz): Just mark members as @internal when sdk#28066 is fixed.
|
||||
//
|
||||
// We separate out the externally-visible Value type and subtypes (in this
|
||||
// directory) from the internally-visible types (in the parent directory) so
|
||||
// that we can add members that are only accessible from within this package.
|
||||
|
||||
/// A SassScript value.
|
||||
///
|
||||
/// All SassScript values are unmodifiable. New values can be constructed using
|
||||
/// subclass constructors like [new SassString]. Untyped values can be cast to
|
||||
/// particular types using `assert*()` functions like [assertString], which
|
||||
/// throw user-friendly error messages if they fail.
|
||||
abstract class Value {
|
||||
/// Whether the value counts as `true` in an `@if` statement and other
|
||||
/// contexts.
|
||||
bool get isTruthy;
|
||||
|
||||
/// The separator for this value as a list.
|
||||
///
|
||||
/// All SassScript values can be used as lists. Maps count as lists of pairs,
|
||||
/// and all other values count as single-value lists.
|
||||
ListSeparator get separator;
|
||||
|
||||
/// Whether this value as a list has brackets.
|
||||
///
|
||||
/// All SassScript values can be used as lists. Maps count as lists of pairs,
|
||||
/// and all other values count as single-value lists.
|
||||
bool get hasBrackets;
|
||||
|
||||
/// This value as a list.
|
||||
///
|
||||
/// All SassScript values can be used as lists. Maps count as lists of pairs,
|
||||
/// and all other values count as single-value lists.
|
||||
List<Value> get asList;
|
||||
|
||||
/// Throws a [SassScriptException] if [this] isn't a boolean.
|
||||
///
|
||||
/// Note that generally, functions should use [isTruthy] rather than requiring
|
||||
/// a literal boolean.
|
||||
///
|
||||
/// If this came from a function argument, [name] is the argument name
|
||||
/// (without the `$`). It's used for error reporting.
|
||||
SassBoolean assertBoolean([String name]);
|
||||
|
||||
/// Throws a [SassScriptException] if [this] isn't a color.
|
||||
///
|
||||
/// If this came from a function argument, [name] is the argument name
|
||||
/// (without the `$`). It's used for error reporting.
|
||||
SassColor assertColor([String name]);
|
||||
|
||||
/// Throws a [SassScriptException] if [this] isn't a function reference.
|
||||
///
|
||||
/// If this came from a function argument, [name] is the argument name
|
||||
/// (without the `$`). It's used for error reporting.
|
||||
SassFunction assertFunction([String name]);
|
||||
|
||||
/// Throws a [SassScriptException] if [this] isn't a map.
|
||||
///
|
||||
/// If this came from a function argument, [name] is the argument name
|
||||
/// (without the `$`). It's used for error reporting.
|
||||
SassMap assertMap([String name]);
|
||||
|
||||
/// Throws a [SassScriptException] if [this] isn't a number.
|
||||
///
|
||||
/// If this came from a function argument, [name] is the argument name
|
||||
/// (without the `$`). It's used for error reporting.
|
||||
SassNumber assertNumber([String name]);
|
||||
|
||||
/// Throws a [SassScriptException] if [this] isn't a string.
|
||||
///
|
||||
/// If this came from a function argument, [name] is the argument name
|
||||
/// (without the `$`). It's used for error reporting.
|
||||
SassString assertString([String name]);
|
||||
|
||||
/// 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();
|
||||
|
||||
/// Returns a string representation of [this].
|
||||
///
|
||||
/// Note that this is equivalent to calling `inspect()` on the value, and thus
|
||||
/// won't reflect the user's output settings. [toCssString] should be used
|
||||
/// instead to convert [this] to CSS.
|
||||
String toString();
|
||||
}
|
@ -5,17 +5,9 @@
|
||||
import '../callable.dart';
|
||||
import '../visitor/interface/value.dart';
|
||||
import '../value.dart';
|
||||
import 'external/value.dart' as internal;
|
||||
|
||||
/// A SassScript function reference.
|
||||
///
|
||||
/// A function reference captures a function from the local environment so that
|
||||
/// it may be passed between modules.
|
||||
class SassFunction extends Value {
|
||||
/// The callable that this function invokes.
|
||||
///
|
||||
/// Note that this is typed as an [AsyncCallback] so that it will work with
|
||||
/// both synchronous and asynchronous evaluate visitors, but in practice the
|
||||
/// synchronous evaluate visitor will crash if this isn't a [Callback].
|
||||
class SassFunction extends Value implements internal.SassFunction {
|
||||
final AsyncCallable callable;
|
||||
|
||||
SassFunction(this.callable);
|
||||
|
@ -5,15 +5,9 @@
|
||||
import '../utils.dart';
|
||||
import '../visitor/interface/value.dart';
|
||||
import '../value.dart';
|
||||
import 'external/value.dart' as ext;
|
||||
|
||||
/// A SassScript list.
|
||||
class SassList extends Value {
|
||||
// TODO(nweiz): Use persistent data structures rather than copying here. An
|
||||
// RRB vector should fit our use-cases well.
|
||||
//
|
||||
// We may also want to fall back to a plain unmodifiable List for small lists
|
||||
// (<32 items?).
|
||||
/// The contents of the list.
|
||||
class SassList extends Value implements ext.SassList {
|
||||
final List<Value> contents;
|
||||
|
||||
final ListSeparator separator;
|
||||
@ -24,7 +18,6 @@ class SassList extends Value {
|
||||
|
||||
List<Value> get asList => contents;
|
||||
|
||||
/// Returns an empty list with the given [separator] and [brackets].
|
||||
const SassList.empty({ListSeparator separator, bool brackets: false})
|
||||
: contents = const [],
|
||||
separator = separator ?? ListSeparator.undecided,
|
||||
|
@ -6,16 +6,9 @@ import 'package:collection/collection.dart';
|
||||
|
||||
import '../visitor/interface/value.dart';
|
||||
import '../value.dart';
|
||||
import 'external/value.dart' as ext;
|
||||
|
||||
/// A SassScript map.
|
||||
class SassMap extends Value {
|
||||
// TODO(nweiz): Use persistent data structures rather than copying here. We
|
||||
// need to preserve the order, which can be done by tracking an RRB vector of
|
||||
// keys along with the hash-mapped array trie representing the map.
|
||||
//
|
||||
// We may also want to fall back to a plain unmodifiable Map for small maps
|
||||
// (<32 items?).
|
||||
/// The contents of the map.
|
||||
class SassMap extends Value implements ext.SassMap {
|
||||
final Map<Value, Value> contents;
|
||||
|
||||
ListSeparator get separator => ListSeparator.comma;
|
||||
|
@ -9,6 +9,7 @@ import '../util/number.dart';
|
||||
import '../utils.dart';
|
||||
import '../value.dart';
|
||||
import '../visitor/interface/value.dart';
|
||||
import 'external/value.dart' as ext;
|
||||
|
||||
/// A nested map containing unit conversion rates.
|
||||
///
|
||||
@ -141,66 +142,31 @@ final _conversions = {
|
||||
// and numbers with only a single numerator unit. These should be opaque to
|
||||
// users of SassNumber.
|
||||
|
||||
/// A SassScript number.
|
||||
///
|
||||
/// Numbers can have units. Although there's no literal syntax for it, numbers
|
||||
/// support scientific-style numerator and denominator units (for example,
|
||||
/// `miles/hour`). These are expected to be resolved before being emitted to
|
||||
/// CSS.
|
||||
class SassNumber extends Value {
|
||||
/// The number of distinct digits that are emitted when converting a number to
|
||||
/// CSS.
|
||||
static const precision = 10;
|
||||
class SassNumber extends Value implements ext.SassNumber {
|
||||
static const precision = ext.SassNumber.precision;
|
||||
|
||||
/// The value of this number.
|
||||
///
|
||||
/// Note that due to details of floating-point arithmetic, this may be a
|
||||
/// [double] even if [this] represents an int from Sass's perspective. Use
|
||||
/// [isInt] to determine whether this is an integer, [asInt] to get its
|
||||
/// integer value, or [assertInt] to do both at once.
|
||||
final num value;
|
||||
|
||||
/// This number's numerator units.
|
||||
final List<String> numeratorUnits;
|
||||
|
||||
/// This number's denominator units.
|
||||
final List<String> denominatorUnits;
|
||||
|
||||
/// The slash-separated representation of this number, if it has one.
|
||||
final String asSlash;
|
||||
|
||||
/// Whether [this] has any units.
|
||||
///
|
||||
/// If a function expects a number to have no units, it should use
|
||||
/// [assertNoUnits]. If it expects the number to have a particular unit, it
|
||||
/// should use [assertUnit].
|
||||
bool get hasUnits => numeratorUnits.isNotEmpty || denominatorUnits.isNotEmpty;
|
||||
|
||||
/// Whether [this] is an integer, according to [fuzzyEquals].
|
||||
///
|
||||
/// The [int] value can be accessed using [asInt] or [assertInt]. Note that
|
||||
/// this may return `false` for very large doubles even though they may be
|
||||
/// mathematically integers, because not all platforms have a valid
|
||||
/// representation for integers that large.
|
||||
bool get isInt => fuzzyIsInt(value);
|
||||
|
||||
/// If [this] is an integer according to [isInt], returns [value] as an [int].
|
||||
///
|
||||
/// Otherwise, returns `null`.
|
||||
int get asInt => fuzzyAsInt(value);
|
||||
|
||||
/// Returns a human readable string representation of this number's units.
|
||||
String get unitString =>
|
||||
hasUnits ? _unitString(numeratorUnits, denominatorUnits) : '';
|
||||
|
||||
/// Creates a number, optionally with a single numerator unit.
|
||||
///
|
||||
/// This matches the numbers that can be written as literals.
|
||||
/// [SassNumber.withUnits] can be used to construct more complex units.
|
||||
SassNumber(num value, [String unit])
|
||||
: this.withUnits(value, numeratorUnits: unit == null ? null : [unit]);
|
||||
|
||||
/// Creates a number with full [numeratorUnits] and [denominatorUnits].
|
||||
SassNumber.withUnits(this.value,
|
||||
{Iterable<String> numeratorUnits, Iterable<String> denominatorUnits})
|
||||
: numeratorUnits = numeratorUnits == null
|
||||
@ -228,27 +194,12 @@ class SassNumber extends Value {
|
||||
|
||||
SassNumber assertNumber([String name]) => this;
|
||||
|
||||
/// Returns [value] as an [int], if it's an integer value according to
|
||||
/// [isInt].
|
||||
///
|
||||
/// Throws a [SassScriptException] if [value] isn't an integer. If this came
|
||||
/// from a function argument, [name] is the argument name (without the `$`).
|
||||
/// It's used for error reporting.
|
||||
int assertInt([String name]) {
|
||||
var integer = fuzzyAsInt(value);
|
||||
if (integer != null) return integer;
|
||||
throw _exception("$this is not an int.", name);
|
||||
}
|
||||
|
||||
/// Asserts that this is a valid Sass-style index for [list], and returns the
|
||||
/// Dart-style index.
|
||||
///
|
||||
/// A Sass-style index is one-based, and uses negative numbers to count
|
||||
/// backwards from the end of the list.
|
||||
///
|
||||
/// Throws a [SassScriptException] if this isn't an integer or if it isn't a
|
||||
/// valid index for [list]. If this came from a function argument, [name] is
|
||||
/// the argument name (without the `$`). It's used for error reporting.
|
||||
int assertIndexFor(List list, [String name]) {
|
||||
var sassIndex = assertInt(name);
|
||||
if (sassIndex == 0) throw _exception("List index may not be 0.");
|
||||
@ -260,12 +211,6 @@ class SassNumber extends Value {
|
||||
return sassIndex < 0 ? list.length + sassIndex : sassIndex - 1;
|
||||
}
|
||||
|
||||
/// If [value] is between [min] and [max], returns it.
|
||||
///
|
||||
/// If [value] is [fuzzyEquals] to [min] or [max], it's clamped to the
|
||||
/// appropriate value. Otherwise, this throws a [SassScriptException]. If this
|
||||
/// came from a function argument, [name] is the argument name (without the
|
||||
/// `$`). It's used for error reporting.
|
||||
num valueInRange(num min, num max, [String name]) {
|
||||
var result = fuzzyCheckRange(value, min, max);
|
||||
if (result != null) return result;
|
||||
@ -273,48 +218,25 @@ class SassNumber extends Value {
|
||||
"Expected $this to be within $min$unitString and $max$unitString.");
|
||||
}
|
||||
|
||||
/// Returns whether [this] has [unit] as its only unit (and as a numerator).
|
||||
bool hasUnit(String unit) =>
|
||||
numeratorUnits.length == 1 &&
|
||||
denominatorUnits.isEmpty &&
|
||||
numeratorUnits.first == unit;
|
||||
|
||||
/// Throws a [SassScriptException] unless [this] has [unit] as its only unit
|
||||
/// (and as a numerator).
|
||||
///
|
||||
/// If this came from a function argument, [name] is the argument name
|
||||
/// (without the `$`). It's used for error reporting.
|
||||
void assertUnit(String unit, [String name]) {
|
||||
if (hasUnit(unit)) return;
|
||||
throw _exception('Expected $this to have unit "$unit".', name);
|
||||
}
|
||||
|
||||
/// Throws a [SassScriptException] unless [this] has no units.
|
||||
///
|
||||
/// If this came from a function argument, [name] is the argument name
|
||||
/// (without the `$`). It's used for error reporting.
|
||||
void assertNoUnits([String name]) {
|
||||
if (!hasUnits) return;
|
||||
throw _exception('Expected $this to have no units.', name);
|
||||
}
|
||||
|
||||
/// Returns a copy of this number, converted to the units represented by
|
||||
/// [newNumerators] and [newDenominators].
|
||||
///
|
||||
/// Note that [valueInUnits] is generally more efficient if the value is going
|
||||
/// to be accessed directly.
|
||||
///
|
||||
/// Throws a [SassScriptException] if this number's units aren't compatible
|
||||
/// with [newNumerators] and [newDenominators].
|
||||
SassNumber coerce(List<String> newNumerators, List<String> newDenominators) =>
|
||||
new SassNumber.withUnits(valueInUnits(newNumerators, newDenominators),
|
||||
numeratorUnits: newNumerators, denominatorUnits: newDenominators);
|
||||
|
||||
/// Returns [value], converted to the units represented by [newNumerators] and
|
||||
/// [newDenominators].
|
||||
///
|
||||
/// Throws a [SassScriptException] if this number's units aren't compatible
|
||||
/// with [newNumerators] and [newDenominators].
|
||||
num valueInUnits(List<String> newNumerators, List<String> newDenominators) {
|
||||
if ((newNumerators.isEmpty && newDenominators.isEmpty) ||
|
||||
(numeratorUnits.isEmpty && denominatorUnits.isEmpty) ||
|
||||
|
@ -7,6 +7,7 @@ import 'package:charcode/charcode.dart';
|
||||
import '../util/character.dart';
|
||||
import '../visitor/interface/value.dart';
|
||||
import '../value.dart';
|
||||
import 'external/value.dart' as ext;
|
||||
|
||||
/// A quoted empty string, returned by [SassString.empty].
|
||||
final _emptyQuoted = new SassString("", quotes: true);
|
||||
@ -14,26 +15,9 @@ final _emptyQuoted = new SassString("", quotes: true);
|
||||
/// An unquoted empty string, returned by [SassString.empty].
|
||||
final _emptyUnquoted = new SassString("", quotes: false);
|
||||
|
||||
/// A SassScript string.
|
||||
///
|
||||
/// Strings can either be quoted or unquoted. Unquoted strings are usually CSS
|
||||
/// identifiers, but they may contain any text.
|
||||
class SassString extends Value {
|
||||
/// The contents of the string.
|
||||
///
|
||||
/// For quoted strings, this is the semantic content—any escape sequences that
|
||||
/// were been written in the source text are resolved to their Unicode values.
|
||||
/// For unquoted strings, though, escape sequences are preserved as literal
|
||||
/// backslashes.
|
||||
///
|
||||
/// This difference allows us to distinguish between identifiers with escapes,
|
||||
/// such as `url\u28 http://example.com\u29`, and unquoted strings that
|
||||
/// contain characters that aren't valid in identifiers, such as
|
||||
/// `url(http://example.com)`. Unfortunately, it also means that we don't
|
||||
/// consider `foo` and `f\6F\6F` the same string.
|
||||
class SassString extends Value implements ext.SassString {
|
||||
final String text;
|
||||
|
||||
/// Whether this string has quotes.
|
||||
final bool hasQuotes;
|
||||
|
||||
bool get isSpecialNumber {
|
||||
|
@ -12,6 +12,7 @@ environment:
|
||||
|
||||
dependencies:
|
||||
args: "^0.13.0"
|
||||
async: ">=1.10.0 <3.0.0"
|
||||
charcode: "^1.1.0"
|
||||
collection: "^1.8.0"
|
||||
convert: "^2.0.1"
|
||||
|
Loading…
x
Reference in New Issue
Block a user