Skip to content

Commit

Permalink
Give SassScriptException a name parameter (#1798)
Browse files Browse the repository at this point in the history
This avoids the need to copy around the same `_exception()` helper all
over the place.
  • Loading branch information
nex3 authored Sep 13, 2022
1 parent e2f9705 commit 5466dd7
Show file tree
Hide file tree
Showing 9 changed files with 56 additions and 51 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
8 changes: 7 additions & 1 deletion lib/src/exception.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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!";
}
Expand Down
32 changes: 14 additions & 18 deletions lib/src/value.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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);
Expand Down Expand Up @@ -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.
Expand All @@ -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);
}
}
Expand All @@ -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);
}
}
Expand All @@ -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);
}
}
Expand All @@ -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);
}
}
Expand Down
14 changes: 5 additions & 9 deletions lib/src/value/calculation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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.");
}
Expand All @@ -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.");
}
}

Expand All @@ -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.");
}
}
}
Expand All @@ -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.");
}
Expand Down Expand Up @@ -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].
Expand Down
22 changes: 9 additions & 13 deletions lib/src/value/number.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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);
}
Expand All @@ -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);
}

Expand Down Expand Up @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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");
}
11 changes: 4 additions & 7 deletions lib/src/value/string.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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");
}
7 changes: 7 additions & 0 deletions pkg/sass_api/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
4 changes: 2 additions & 2 deletions pkg/sass_api/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ 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

environment:
sdk: ">=2.17.0 <3.0.0"

dependencies:
sass: 1.54.9
sass: 1.55.0

dev_dependencies:
dartdoc: ^5.0.0
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -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

Expand Down

0 comments on commit 5466dd7

Please sign in to comment.