Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Give SassScriptException a name parameter #1798

Merged
merged 2 commits into from Sep 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
@@ -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
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
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
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
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
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
@@ -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
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
@@ -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