Skip to content

Commit

Permalink
Implement deprecations for strict function units (#1817)
Browse files Browse the repository at this point in the history
  • Loading branch information
nex3 committed Oct 28, 2022
1 parent 655b55c commit dd9e3cc
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 25 deletions.
22 changes: 22 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,28 @@

* Fix indentation for selectors that span multiple lines in a `@media` query.

* Emit a deprecation warning when passing `$alpha` values with units to
`color.adjust()` or `color.change()`. This will be an error in Dart Sass
2.0.0.

* Emit a deprecation warning when passing a `$weight` value with no units or
with units other than `%` to `color.mix()`. This will be an error in Dart Sass
2.0.0.

* Emit a deprecation warning when passing `$n` values with units to `list.nth()`
or `list.set-nth()`. This will be an error in Dart Sass 2.0.0.

* Improve existing deprecation warnings to wrap `/`-as-division suggestions in
`calc()` expressions.

* Properly mark the warning for passing numbers with units to `random()` as a
deprecation warning.

### Dart API

* Emit a deprecation warning when passing a `sassIndex` with units to
`Value.sassIndexToListIndex()`. This will be an error in Dart Sass 2.0.0.

## 1.55.0

* **Potentially breaking bug fix:** Sass numbers are now universally stored as
Expand Down
37 changes: 24 additions & 13 deletions lib/src/functions/color.dart
Expand Up @@ -453,9 +453,23 @@ SassColor _updateComponents(List<Value> arguments,
/// [max] should be 255 for RGB channels, 1 for the alpha channel, and 100
/// for saturation, lightness, whiteness, and blackness.
double? getParam(String name, num max,
{bool checkPercent = false, bool assertPercent = false}) {
{bool checkPercent = false,
bool assertPercent = false,
bool checkUnitless = false}) {
var number = keywords.remove(name)?.assertNumber(name);
if (number == null) return null;
if (!scale && checkUnitless) {
if (number.hasUnits) {
warn(
"\$$name: Passing a number with unit ${number.unitString} is "
"deprecated.\n"
"\n"
"To preserve current behavior: ${number.unitSuggestion(name)}\n"
"\n"
"More info: https://sass-lang.com/d/function-units",
deprecation: true);
}
}
if (!scale && checkPercent) _checkPercent(number, name);
if (scale || assertPercent) number.assertUnit("%", name);
if (scale) max = 100;
Expand All @@ -465,7 +479,7 @@ SassColor _updateComponents(List<Value> arguments,
change ? 0 : -max, max, name, checkPercent ? '%' : '');
}

var alpha = getParam("alpha", 1);
var alpha = getParam("alpha", 1, checkUnitless: true);
var red = getParam("red", 255);
var green = getParam("green", 255);
var blue = getParam("blue", 255);
Expand Down Expand Up @@ -656,12 +670,13 @@ void _checkAngle(SassNumber angle, String name) {

var actualUnit = angle.numeratorUnits.first;
message
..writeln("To preserve current behavior: \$$name * 1deg/1$actualUnit")
..writeln(
"To preserve current behavior: calc(\$$name * 1deg/1$actualUnit)")
..writeln("To migrate to new behavior: 0deg + \$$name")
..writeln();
} else {
message
..writeln("To preserve current behavior: \$$name${_removeUnits(angle)}")
..writeln("To preserve current behavior: ${angle.unitSuggestion(name)}")
..writeln();
}

Expand All @@ -676,18 +691,12 @@ void _checkPercent(SassNumber number, String name) {
warn(
"\$$name: Passing a number without unit % ($number) is deprecated.\n"
"\n"
"To preserve current behavior: \$$name${_removeUnits(number)} * 1%",
"To preserve current behavior: ${number.unitSuggestion(name, '%')}\n"
"\n"
"More info: https://sass-lang.com/d/function-units",
deprecation: true);
}

/// Returns the right-hand side of an expression that would remove all units
/// from `$number` but leaves the value the same.
///
/// Used for constructing deprecation messages.
String _removeUnits(SassNumber number) =>
number.denominatorUnits.map((unit) => " * 1$unit").join() +
number.numeratorUnits.map((unit) => " / 1$unit").join();

/// Create an HWB color from the given [arguments].
Value _hwb(List<Value> arguments) {
var alpha = arguments.length > 3 ? arguments[3] : null;
Expand Down Expand Up @@ -805,6 +814,8 @@ double _percentageOrUnitless(SassNumber number, num max, String name) {

/// Returns [color1] and [color2], mixed together and weighted by [weight].
SassColor _mixColors(SassColor color1, SassColor color2, SassNumber weight) {
_checkPercent(weight, 'weight');

// This algorithm factors in both the user-provided weight (w) and the
// difference between the alpha values of the two colors (a) to decide how
// to perform the weighted average of the two RGB values.
Expand Down
22 changes: 11 additions & 11 deletions lib/src/functions/math.dart
Expand Up @@ -251,17 +251,17 @@ final _randomFunction = _function("random", r"$limit: null", (arguments) {

if (limit.hasUnits) {
warn(
"math.random() will no longer ignore \$limit units ($limit) in a "
"future release.\n"
"\n"
"Recommendation: "
"math.random(math.div(\$limit, 1${limit.unitString})) * 1${limit.unitString}\n"
"\n"
"To preserve current behavior: "
"math.random(math.div(\$limit, 1${limit.unitString}))\n"
"\n"
"More info: https://sass-lang.com/d/random-with-units",
);
"math.random() will no longer ignore \$limit units ($limit) in a "
"future release.\n"
"\n"
"Recommendation: "
"math.random(math.div(\$limit, 1${limit.unitString})) * 1${limit.unitString}\n"
"\n"
"To preserve current behavior: "
"math.random(math.div(\$limit, 1${limit.unitString}))\n"
"\n"
"More info: https://sass-lang.com/d/function-units",
deprecation: true);
}

var limitScalar = limit.assertInt("limit");
Expand Down
16 changes: 15 additions & 1 deletion lib/src/value.dart
Expand Up @@ -5,6 +5,7 @@
import 'package:meta/meta.dart';

import 'ast/selector.dart';
import 'evaluation_context.dart';
import 'exception.dart';
import 'utils.dart';
import 'value/boolean.dart';
Expand Down Expand Up @@ -120,7 +121,20 @@ abstract class Value {
/// [asList]. If [sassIndex] came from a function argument, [name] is the
/// argument name (without the `$`). It's used for error reporting.
int sassIndexToListIndex(Value sassIndex, [String? name]) {
var index = sassIndex.assertNumber(name).assertInt(name);
var indexValue = sassIndex.assertNumber(name);
if (indexValue.hasUnits) {
warn(
"\$$name: Passing a number with unit ${indexValue.unitString} is "
"deprecated.\n"
"\n"
"To preserve current behavior: "
"${indexValue.unitSuggestion(name ?? 'index')}\n"
"\n"
"More info: https://sass-lang.com/d/function-units",
deprecation: true);
}

var index = indexValue.assertInt(name);
if (index == 0) throw SassScriptException("List index may not be 0.", name);
if (index.abs() > lengthAsList) {
throw SassScriptException(
Expand Down
17 changes: 17 additions & 0 deletions lib/src/value/number.dart
Expand Up @@ -933,4 +933,21 @@ abstract class SassNumber extends Value {
var innerMap = _conversions[unit];
return innerMap == null ? 1 : 1 / innerMap.values.first;
}

/// Returns a suggested Sass snippet for converting a variable named [name]
/// (without `%`) containing this number into a number with the same value and
/// the given [unit].
///
/// If [unit] is null, this forces the number to be unitless.
///
/// This is used for deprecation warnings when restricting which units are
/// allowed for a given function.
@internal
String unitSuggestion(String name, [String? unit]) {
var result = "\$$name" +
denominatorUnits.map((unit) => " * 1$unit").join() +
numeratorUnits.map((unit) => " / 1$unit").join() +
(unit == null ? "" : " * 1$unit");
return numeratorUnits.isEmpty ? result : "calc($result)";
}
}

0 comments on commit dd9e3cc

Please sign in to comment.