Give SassScriptException a name parameter (#1798)

This avoids the need to copy around the same `_exception()` helper all
over the place.
This commit is contained in:
Natalie Weizenbaum 2022-09-13 16:09:56 -07:00 committed by GitHub
parent e2f97055db
commit 5466dd76a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 56 additions and 51 deletions

View File

@ -1,3 +1,10 @@
## 1.55.0
### Dart API
* Add an optional `argumentName` parameter to `SassScriptException()` to make it
easier to throw exceptions associated with particular argument names.
## 1.54.9
* Fix an incorrect span in certain `@media` query deprecation warnings.

View File

@ -165,7 +165,13 @@ class SassScriptException {
/// The error message.
final String message;
SassScriptException(this.message);
/// Creates a [SassScriptException] with the given [message].
///
/// The [argumentName] is the name of the Sass function argument that
/// triggered this exception. If it's not null, it's automatically included in
/// [message].
SassScriptException(String message, [String? argumentName])
: message = argumentName == null ? message : "\$$argumentName: $message";
String toString() => "$message\n\nBUG: This should include a source span!";
}

View File

@ -121,9 +121,9 @@ abstract class Value {
/// argument name (without the `$`). It's used for error reporting.
int sassIndexToListIndex(Value sassIndex, [String? name]) {
var index = sassIndex.assertNumber(name).assertInt(name);
if (index == 0) throw _exception("List index may not be 0.", name);
if (index == 0) throw SassScriptException("List index may not be 0.", name);
if (index.abs() > lengthAsList) {
throw _exception(
throw SassScriptException(
"Invalid index $sassIndex for a list with $lengthAsList elements.",
name);
}
@ -139,35 +139,35 @@ abstract class Value {
/// 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);
throw SassScriptException("$this is not a boolean.", name);
/// Throws a [SassScriptException] if [this] isn't a calculation.
///
/// If this came from a function argument, [name] is the argument name
/// (without the `$`). It's used for error reporting.
SassCalculation assertCalculation([String? name]) =>
throw _exception("$this is not a calculation.", name);
throw SassScriptException("$this is not a calculation.", 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);
throw SassScriptException("$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);
throw SassScriptException("$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);
throw SassScriptException("$this is not a map.", name);
/// Returns [this] as a [SassMap] if it is one (including empty lists, which
/// count as empty maps) or returns `null` if it's not.
@ -178,14 +178,14 @@ abstract class Value {
/// 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);
throw SassScriptException("$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);
throw SassScriptException("$this is not a string.", name);
/// Converts a `selector-parse()`-style input into a string that can be
/// parsed.
@ -196,7 +196,7 @@ abstract class Value {
var string = _selectorStringOrNull();
if (string != null) return string;
throw _exception(
throw SassScriptException(
"$this is not a valid selector: it must be a string,\n"
"a list of strings, or a list of lists of strings.",
name);
@ -384,10 +384,6 @@ abstract class Value {
/// 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].
SassScriptException _exception(String message, [String? name]) =>
SassScriptException(name == null ? message : "\$$name: $message");
}
/// Extension methods that are only visible through the `sass_api` package.
@ -414,7 +410,7 @@ extension SassApiValue on Value {
// TODO(nweiz): colorize this if we're running in an environment where
// that works.
throwWithTrace(
_exception(error.toString().replaceFirst("Error: ", ""), name),
SassScriptException(error.toString().replaceFirst("Error: ", ""), name),
stackTrace);
}
}
@ -437,7 +433,7 @@ extension SassApiValue on Value {
// TODO(nweiz): colorize this if we're running in an environment where
// that works.
throwWithTrace(
_exception(error.toString().replaceFirst("Error: ", ""), name),
SassScriptException(error.toString().replaceFirst("Error: ", ""), name),
stackTrace);
}
}
@ -460,7 +456,7 @@ extension SassApiValue on Value {
// TODO(nweiz): colorize this if we're running in an environment where
// that works.
throwWithTrace(
_exception(error.toString().replaceFirst("Error: ", ""), name),
SassScriptException(error.toString().replaceFirst("Error: ", ""), name),
stackTrace);
}
}
@ -483,7 +479,7 @@ extension SassApiValue on Value {
// TODO(nweiz): colorize this if we're running in an environment where
// that works.
throwWithTrace(
_exception(error.toString().replaceFirst("Error: ", ""), name),
SassScriptException(error.toString().replaceFirst("Error: ", ""), name),
stackTrace);
}
}

View File

@ -235,11 +235,11 @@ class SassCalculation extends Value {
return arg;
} else if (arg is SassString) {
if (!arg.hasQuotes) return arg;
throw _exception("Quoted string $arg can't be used in a calculation.");
throw SassScriptException("Quoted string $arg can't be used in a calculation.");
} else if (arg is SassCalculation) {
return arg.name == 'calc' ? arg.arguments[0] : arg;
} else if (arg is Value) {
throw _exception("Value $arg can't be used in a calculation.");
throw SassScriptException("Value $arg can't be used in a calculation.");
} else {
throw ArgumentError("Unexpected calculation argument $arg.");
}
@ -255,7 +255,7 @@ class SassCalculation extends Value {
for (var arg in args) {
if (arg is! SassNumber) continue;
if (arg.numeratorUnits.length > 1 || arg.denominatorUnits.isNotEmpty) {
throw _exception("Number $arg isn't compatible with CSS calculations.");
throw SassScriptException("Number $arg isn't compatible with CSS calculations.");
}
}
@ -267,7 +267,7 @@ class SassCalculation extends Value {
var number2 = args[j];
if (number2 is! SassNumber) continue;
if (number1.hasPossiblyCompatibleUnits(number2)) continue;
throw _exception("$number1 and $number2 are incompatible.");
throw SassScriptException("$number1 and $number2 are incompatible.");
}
}
}
@ -280,7 +280,7 @@ class SassCalculation extends Value {
.any((arg) => arg is SassString || arg is CalculationInterpolation)) {
return;
}
throw _exception(
throw SassScriptException(
"$expectedLength arguments required, but only ${args.length} "
"${pluralize('was', args.length, plural: 'were')} passed.");
}
@ -319,10 +319,6 @@ class SassCalculation extends Value {
listEquals(arguments, other.arguments);
int get hashCode => name.hashCode ^ listHash(arguments);
/// Throws a [SassScriptException] with the given [message].
static SassScriptException _exception(String message, [String? name]) =>
SassScriptException(name == null ? message : "\$$name: $message");
}
/// A binary operation that can appear in a [SassCalculation].

View File

@ -332,7 +332,7 @@ abstract class SassNumber extends Value {
int assertInt([String? name]) {
var integer = fuzzyAsInt(value);
if (integer != null) return integer;
throw _exception("$this is not an int.", name);
throw SassScriptException("$this is not an int.", name);
}
/// If [value] is between [min] and [max], returns it.
@ -344,7 +344,7 @@ abstract class SassNumber extends Value {
num valueInRange(num min, num max, [String? name]) {
var result = fuzzyCheckRange(value, min, max);
if (result != null) return result;
throw _exception(
throw SassScriptException(
"Expected $this to be within $min$unitString and $max$unitString.",
name);
}
@ -361,7 +361,7 @@ abstract class SassNumber extends Value {
num valueInRangeWithUnit(num min, num max, String name, String unit) {
var result = fuzzyCheckRange(value, min, max);
if (result != null) return result;
throw _exception(
throw SassScriptException(
"Expected $this to be within $min$unit and $max$unit.", name);
}
@ -395,7 +395,7 @@ abstract class SassNumber extends Value {
/// (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);
throw SassScriptException('Expected $this to have unit "$unit".', name);
}
/// Throws a [SassScriptException] unless [this] has no units.
@ -404,7 +404,7 @@ abstract class SassNumber extends Value {
/// (without the `$`). It's used for error reporting.
void assertNoUnits([String? name]) {
if (!hasUnits) return;
throw _exception('Expected $this to have no units.', name);
throw SassScriptException('Expected $this to have no units.', name);
}
/// Returns a copy of this number, converted to the units represented by
@ -601,16 +601,16 @@ abstract class SassNumber extends Value {
if (!hasUnits || !otherHasUnits) {
message.write(" (one has units and the other doesn't)");
}
return _exception("$message.", name);
return SassScriptException("$message.", name);
} else if (!otherHasUnits) {
return _exception("Expected $this to have no units.", name);
return SassScriptException("Expected $this to have no units.", name);
} else {
if (newNumerators.length == 1 && newDenominators.isEmpty) {
var type = _typesByUnit[newNumerators.first];
if (type != null) {
// If we're converting to a unit of a named type, use that type name
// and make it clear exactly which units are convertible.
return _exception(
return SassScriptException(
"Expected $this to have ${a(type)} unit "
"(${_unitsByType[type]!.join(', ')}).",
name);
@ -619,7 +619,7 @@ abstract class SassNumber extends Value {
var unit =
pluralize('unit', newNumerators.length + newDenominators.length);
return _exception(
return SassScriptException(
"Expected $this to have $unit "
"${_unitString(newNumerators, newDenominators)}.",
name);
@ -946,8 +946,4 @@ abstract class SassNumber extends Value {
var innerMap = _conversions[unit];
return innerMap == null ? 1 : 1 / innerMap.values.first;
}
/// Throws a [SassScriptException] with the given [message].
SassScriptException _exception(String message, [String? name]) =>
SassScriptException(name == null ? message : "\$$name: $message");
}

View File

@ -170,9 +170,10 @@ class SassString extends Value {
/// argument name (without the `$`). It's used for error reporting.
int sassIndexToRuneIndex(Value sassIndex, [String? name]) {
var index = sassIndex.assertNumber(name).assertInt(name);
if (index == 0) throw _exception("String index may not be 0.", name);
if (index.abs() > sassLength) {
throw _exception(
if (index == 0) {
throw SassScriptException("String index may not be 0.", name);
} else if (index.abs() > sassLength) {
throw SassScriptException(
"Invalid index $sassIndex for a string with $sassLength characters.",
name);
}
@ -199,8 +200,4 @@ class SassString extends Value {
bool operator ==(Object other) => other is SassString && text == other.text;
int get hashCode => _hashCache ??= text.hashCode;
/// Throws a [SassScriptException] with the given [message].
SassScriptException _exception(String message, [String? name]) =>
SassScriptException(name == null ? message : "\$$name: $message");
}

View File

@ -1,3 +1,10 @@
## 3.1.0
### Dart API
* Add an optional `argumentName` parameter to `SassScriptException()` to make it
easier to throw exceptions associated with particular argument names.
## 3.0.4
* `UnaryOperationExpression`s with operator `not` now include a correct span,

View File

@ -2,7 +2,7 @@ name: sass_api
# Note: Every time we add a new Sass AST node, we need to bump the *major*
# version because it's a breaking change for anyone who's implementing the
# visitor interface(s).
version: 3.0.4
version: 3.1.0
description: Additional APIs for Dart Sass.
homepage: https://github.com/sass/dart-sass
@ -10,7 +10,7 @@ environment:
sdk: ">=2.17.0 <3.0.0"
dependencies:
sass: 1.54.9
sass: 1.55.0
dev_dependencies:
dartdoc: ^5.0.0

View File

@ -1,5 +1,5 @@
name: sass
version: 1.54.9
version: 1.55.0
description: A Sass implementation in Dart.
homepage: https://github.com/sass/dart-sass