Skip to content

Commit

Permalink
Address review
Browse files Browse the repository at this point in the history
  • Loading branch information
jerivas committed Jul 18, 2023
1 parent d30acbd commit cd06089
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 57 deletions.
46 changes: 20 additions & 26 deletions lib/src/node/compile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -225,15 +225,17 @@ Importer _parseImporter(Object? importer) {
}
}

/// Implements the simplification algorithm for custom function return values.
/// Implements the simplification algorithm for custom function return Values.
/// {@link https://github.com/sass/sass/blob/main/spec/types/calculation.md#simplifying-a-calculationvalue}
Object simplify(Object value) => switch (value) {
Value _simplifyValue(Value value) => switch (value) {
SassCalculation() => switch ((
// Match against...
value.name, // ...the calculation name
value.arguments.map(simplify).toList() // ...and simplified arguments
value.arguments // ...and simplified arguments
.map(_simplifyCalcArg)
.toList()
)) {
('calc', [var first]) => first,
('calc', [var first]) => first as Value,
('calc', _) =>
throw ArgumentError('calc() requires exactly one argument.'),
('clamp', [var min, var value, var max]) =>
Expand All @@ -245,8 +247,15 @@ Object simplify(Object value) => switch (value) {
(var name, _) => throw ArgumentError(
'"$name" is not a recognized calculation type.'),
},
CalculationOperation() => SassCalculation.operate(
value.operator, simplify(value.left), simplify(value.right)),
_ => value,
};

/// Handles simplifying calculation arguments, which are not guaranteed to be
/// Value instances.
Object _simplifyCalcArg(Object value) => switch (value) {
SassCalculation() => _simplifyValue(value),
CalculationOperation() => SassCalculation.operate(value.operator,
_simplifyCalcArg(value.left), _simplifyCalcArg(value.right)),
_ => value,
};

Expand All @@ -264,23 +273,16 @@ List<AsyncCallable> _parseFunctions(Object? functions, {bool asynch = false}) {
late Callable callable;
callable = Callable.fromSignature(signature, (arguments) {
var result = (callback as Function)(toJSArray(arguments));
if (result is Value) return _simplifyValue(result);
if (isPromise(result)) {
throw 'Invalid return value for custom function '
'"${callable.name}":\n'
'Promises may only be returned for sass.compileAsync() and '
'sass.compileStringAsync().';
} else {
throw 'Invalid return value for custom function '
'"${callable.name}": $result is not a sass.Value.';
}
if (result is Value) {
var simplified = simplify(result);
if (simplified is! Value) {
throw 'Custom function "${callable.name}" '
'returned an object that cannot be simplified to a '
'sass.Value.';
}
return simplified;
}
throw 'Invalid return value for custom function '
'"${callable.name}": $result is not a sass.Value.';
});
result.add(callable);
} else {
Expand All @@ -290,15 +292,7 @@ List<AsyncCallable> _parseFunctions(Object? functions, {bool asynch = false}) {
if (isPromise(result)) {
result = await promiseToFuture<Object>(result as Promise);
}
if (result is Value) {
var simplified = simplify(result);
if (simplified is! Value) {
throw 'Custom function "${callable.name}" '
'returned an object that cannot be simplified to a '
'sass.Value.';
}
return simplified;
}
if (result is Value) return _simplifyValue(result);
throw 'Invalid return value for custom function '
'"${callable.name}": $result is not a sass.Value.';
});
Expand Down
30 changes: 15 additions & 15 deletions lib/src/node/value/calculation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@ import '../../value.dart';
import '../reflection.dart';

/// Check that [arg] is a valid argument to a calculation function.
void assertCalculationValue(Object arg) => switch (arg) {
(SassNumber() ||
SassString(hasQuotes: false) ||
SassCalculation() ||
CalculationOperation() ||
CalculationInterpolation()) =>
void _assertCalculationValue(Object arg) => switch (arg) {
SassNumber() ||
SassString(hasQuotes: false) ||
SassCalculation() ||
CalculationOperation() ||
CalculationInterpolation() =>
null,
_ => jsThrow(JsError(
'Argument `$arg` must be one of SassNumber, unquoted SassString, '
'SassCalculation, CalculationOperation, CalculationInterpolation')),
};

/// Check that [arg] is an unquoted string or interpolation.
bool isValidClampArg(Object? arg) => switch (arg) {
bool _isValidClampArg(Object? arg) => switch (arg) {
(CalculationInterpolation() || SassString(hasQuotes: false)) => true,
_ => false,
};
Expand All @@ -38,30 +38,30 @@ final JSClass calculationClass = () {

jsClass.defineStaticMethods({
'calc': (Object argument) {
assertCalculationValue(argument);
_assertCalculationValue(argument);
return SassCalculation.unsimplified('calc', [argument]);
},
'min': (Object arguments) {
var argList = jsToDartList(arguments).cast<Object>();
argList.forEach(assertCalculationValue);
argList.forEach(_assertCalculationValue);
return SassCalculation.unsimplified('min', argList);
},
'max': (Object arguments) {
var argList = jsToDartList(arguments).cast<Object>();
argList.forEach(assertCalculationValue);
argList.forEach(_assertCalculationValue);
return SassCalculation.unsimplified('max', argList);
},
'clamp': (Object min, [Object? value, Object? max]) {
if ((value == null && !isValidClampArg(min)) ||
(max == null) && !([min, value].any(isValidClampArg))) {
if ((value == null && !_isValidClampArg(min)) ||
(max == null && ![min, value].any(_isValidClampArg))) {
jsThrow(JsError('Expected at least one SassString or '
'CalculationInterpolation in `${[
min,
value,
max
].whereNotNull()}`'));
}
[min, value, max].whereNotNull().forEach(assertCalculationValue);
[min, value, max].whereNotNull().forEach(_assertCalculationValue);
return SassCalculation.unsimplified(
'clamp', [min, value, max].whereNotNull());
}
Expand Down Expand Up @@ -90,8 +90,8 @@ final JSClass calculationOperationClass = () {
if (operator == null) {
jsThrow(JsError('Invalid operator: $strOperator'));
}
assertCalculationValue(left);
assertCalculationValue(right);
_assertCalculationValue(left);
_assertCalculationValue(right);
return SassCalculation.operateInternal(operator, left, right,
inMinMax: false, simplify: false);
});
Expand Down
20 changes: 4 additions & 16 deletions lib/src/value/calculation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -332,30 +332,21 @@ class CalculationOperation {
/// implementation.
/// The operator.
CalculationOperator get operator {
return _operator;
}

CalculationOperator get operator => _operator;
final CalculationOperator _operator;

/// The left-hand operand.
///
/// This is either a [SassNumber], a [SassCalculation], an unquoted
/// [SassString], a [CalculationOperation], or a [CalculationInterpolation].
Object get left {
return _left;
}

Object get left => _left;
final Object _left;

/// The right-hand operand.
///
/// This is either a [SassNumber], a [SassCalculation], an unquoted
/// [SassString], a [CalculationOperation], or a [CalculationInterpolation].
Object get right {
return _right;
}

Object get right => _right;
final Object _right;

CalculationOperation._(this._operator, this._left, this._right);
Expand Down Expand Up @@ -421,10 +412,7 @@ class CalculationInterpolation {
/// We use a getters to allow overriding the logic in the JS API
/// implementation.
String get value {
return _value;
}

String get value => _value;
final String _value;

CalculationInterpolation(this._value);
Expand Down

0 comments on commit cd06089

Please sign in to comment.