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

Deprecate explicitly passing null as an alpha value #2049

Merged
merged 4 commits into from
Aug 7, 2023
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,27 @@

### Dart API

* Deprecate explicitly passing `null` as the alpha channel for
`SassColor.rgb()`, `SassColor.hsl()`, and `SassColor.hwb()`. Omitting the
`alpha` channel is still allowed. In future releases, `null` will be used to
indicate a [missing component]. This deprecation is named `null-alpha`.

[missing component]: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#missing_color_components

* Include protocol buffer definitions when uploading the `sass` package to pub.

### JS API

* Deprecate explicitly passing `null` as the alpha channel for `new
SassColor()`. Omitting the `alpha` channel or passing `undefined` for it is
still allowed. In future releases, `null` will be used to indicate a [missing
component]. This deprecation is named `null-alpha`.

[missing component]: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#missing_color_components

(Note that this was already prohibited by the TypeScript types, but in
practice prior to this `null` was treated as `1`.)

## 1.64.2

* No user-visible changes.
Expand Down
5 changes: 5 additions & 0 deletions lib/src/deprecation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'package:collection/collection.dart';
import 'package:pub_semver/pub_semver.dart';

import 'io.dart';
import 'util/nullable.dart';

/// A deprecated feature in the language.
Expand Down Expand Up @@ -59,6 +60,10 @@ enum Deprecation {
description:
'Using !default or !global multiple times for one variable.'),

nullAlpha('null-alpha',
deprecatedIn: '1.62.3',
description: 'Passing null as alpha in the ${isJS ? 'JS' : 'Dart'} API.'),

/// Deprecation for `@import` rules.
import.future('import', description: '@import rules.'),

Expand Down
9 changes: 6 additions & 3 deletions lib/src/functions/color.dart
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,8 @@ Value _rgb(String name, List<Value> arguments) {
fuzzyRound(_percentageOrUnitless(green, 255, "green")),
fuzzyRound(_percentageOrUnitless(blue, 255, "blue")),
alpha.andThen((alpha) =>
_percentageOrUnitless(alpha.assertNumber("alpha"), 1, "alpha")),
_percentageOrUnitless(alpha.assertNumber("alpha"), 1, "alpha")) ??
1,
ColorFormat.rgbFunction);
}

Expand Down Expand Up @@ -644,7 +645,8 @@ Value _hsl(String name, List<Value> arguments) {
saturation.value.clamp(0, 100),
lightness.value.clamp(0, 100),
alpha.andThen((alpha) =>
_percentageOrUnitless(alpha.assertNumber("alpha"), 1, "alpha")),
_percentageOrUnitless(alpha.assertNumber("alpha"), 1, "alpha")) ??
1,
ColorFormat.hslFunction);
}

Expand Down Expand Up @@ -693,7 +695,8 @@ Value _hwb(List<Value> arguments) {
whiteness.valueInRange(0, 100, "whiteness"),
blackness.valueInRange(0, 100, "blackness"),
alpha.andThen((alpha) =>
_percentageOrUnitless(alpha.assertNumber("alpha"), 1, "alpha")));
_percentageOrUnitless(alpha.assertNumber("alpha"), 1, "alpha")) ??
1);
}

Object /* SassString | List<Value> */ _parseChannels(
Expand Down
2 changes: 1 addition & 1 deletion lib/src/io/interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ bool get isMacOS => throw '';
bool get hasTerminal => throw '';

/// Whether we're running as JS (browser or Node.js).
bool get isJS => throw '';
const bool isJS = false;

/// Whether we're running as Node.js (not browser or Dart VM).
bool get isNode => throw '';
Expand Down
2 changes: 1 addition & 1 deletion lib/src/io/js.dart
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ bool get isWindows => process?.platform == 'win32';

bool get isMacOS => process?.platform == 'darwin';

bool get isJS => true;
const bool isJS = true;

/// The fs module object, used to check whether this has been loaded as Node.
///
Expand Down
2 changes: 1 addition & 1 deletion lib/src/io/vm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ bool get isMacOS => io.Platform.isMacOS;

bool get hasTerminal => io.stdout.hasTerminal;

bool get isJS => false;
const bool isJS = false;

bool get isNode => false;

Expand Down
17 changes: 12 additions & 5 deletions lib/src/js/value/color.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,20 @@ import '../../util/nullable.dart';
import '../../util/number.dart';
import '../../value.dart';
import '../reflection.dart';
import '../utils.dart';

/// The JavaScript `SassColor` class.
final JSClass colorClass = () {
var jsClass = createJSClass('sass.SassColor', (Object self, _Channels color) {
if (color.red != null) {
return SassColor.rgb(fuzzyRound(color.red!), fuzzyRound(color.green!),
fuzzyRound(color.blue!), color.alpha);
fuzzyRound(color.blue!), _handleNullAlpha(color.alpha));
} else if (color.saturation != null) {
return SassColor.hsl(
color.hue!, color.saturation!, color.lightness!, color.alpha);
return SassColor.hsl(color.hue!, color.saturation!, color.lightness!,
_handleNullAlpha(color.alpha));
} else {
return SassColor.hwb(
color.hue!, color.whiteness!, color.blackness!, color.alpha);
return SassColor.hwb(color.hue!, color.whiteness!, color.blackness!,
_handleNullAlpha(color.alpha));
}
});

Expand Down Expand Up @@ -68,6 +69,12 @@ final JSClass colorClass = () {
return jsClass;
}();

/// Converts an undefined [alpha] to 1.
///
/// This ensures that an explicitly null alpha will produce a deprecation
/// warning when passed to the Dart API.
num? _handleNullAlpha(num? alpha) => isUndefined(alpha) ? 1 : alpha;

@JS()
@anonymous
class _Channels {
Expand Down
2 changes: 1 addition & 1 deletion lib/src/parse/stylesheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2232,7 +2232,7 @@ abstract class StylesheetParser extends Parser {
red,
green,
blue,
alpha,
alpha ?? 1,
// Don't emit four- or eight-digit hex colors as hex, since that's not
// yet well-supported in browsers.
alpha == null ? SpanColorFormat(scanner.spanFrom(start)) : null);
Expand Down
55 changes: 42 additions & 13 deletions lib/src/value/color.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import 'dart:math' as math;
import 'package:meta/meta.dart';
import 'package:source_span/source_span.dart';

import '../deprecation.dart';
import '../evaluation_context.dart';
import '../exception.dart';
import '../io.dart';
import '../util/number.dart';
import '../value.dart';
import '../visitor/interface/value.dart';
Expand Down Expand Up @@ -98,52 +101,63 @@ class SassColor extends Value {

/// Creates an RGB color.
///
/// Passing `null` to [alpha] is deprecated, and will change behavior in
/// future versions of Dart Sass to represent a [missing component] instead of
/// being equivalent to `1`. Callers who want to create opaque colors should
/// explicitly pass `1` or not pass [alpha] at all.
///
/// [missing component]: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#missing_color_components
///
/// Throws a [RangeError] if [red], [green], and [blue] aren't between `0` and
/// `255`, or if [alpha] isn't between `0` and `1`.
SassColor.rgb(int red, int green, int blue, [num? alpha])
: this.rgbInternal(red, green, blue, alpha);
SassColor.rgb(int red, int green, int blue, [num? alpha = 1])
: this.rgbInternal(red, green, blue, _handleNullAlpha(alpha));

/// Like [SassColor.rgb], but also takes a [format] parameter.
///
/// @nodoc
@internal
SassColor.rgbInternal(this._red, this._green, this._blue,
[num? alpha, this.format])
: _alpha = alpha == null
? 1
: fuzzyAssertRange(alpha.toDouble(), 0, 1, "alpha") {
[num alpha = 1, this.format])
: _alpha = fuzzyAssertRange(alpha.toDouble(), 0, 1, "alpha") {
RangeError.checkValueInInterval(red, 0, 255, "red");
RangeError.checkValueInInterval(green, 0, 255, "green");
RangeError.checkValueInInterval(blue, 0, 255, "blue");
}

/// Creates an HSL color.
///
/// Passing `null` to [alpha] is deprecated, and will change behavior in
/// future versions of Dart Sass to represent a [missing component] instead of
/// being equivalent to `1`. Callers who want to create opaque colors should
/// explicitly pass `1` or not pass [alpha] at all.
///
/// [missing component]: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#missing_color_components
///
/// Throws a [RangeError] if [saturation] or [lightness] aren't between `0`
/// and `100`, or if [alpha] isn't between `0` and `1`.
SassColor.hsl(num hue, num saturation, num lightness, [num? alpha])
: this.hslInternal(hue, saturation, lightness, alpha);
SassColor.hsl(num hue, num saturation, num lightness, [num? alpha = 1])
: this.hslInternal(hue, saturation, lightness, _handleNullAlpha(alpha));

/// Like [SassColor.hsl], but also takes a [format] parameter.
///
/// @nodoc
@internal
SassColor.hslInternal(num hue, num saturation, num lightness,
[num? alpha, this.format])
[num alpha = 1, this.format])
: _hue = hue % 360,
_saturation =
fuzzyAssertRange(saturation.toDouble(), 0, 100, "saturation"),
_lightness =
fuzzyAssertRange(lightness.toDouble(), 0, 100, "lightness"),
_alpha = alpha == null
? 1
: fuzzyAssertRange(alpha.toDouble(), 0, 1, "alpha");
_alpha = fuzzyAssertRange(alpha.toDouble(), 0, 1, "alpha");

/// Creates an HWB color.
///
/// Throws a [RangeError] if [whiteness] or [blackness] aren't between `0` and
/// `100`, or if [alpha] isn't between `0` and `1`.
factory SassColor.hwb(num hue, num whiteness, num blackness, [num? alpha]) {
factory SassColor.hwb(num hue, num whiteness, num blackness,
[num? alpha = 1]) {
// From https://www.w3.org/TR/css-color-4/#hwb-to-rgb
var scaledHue = hue % 360 / 360;
var scaledWhiteness =
Expand Down Expand Up @@ -171,6 +185,21 @@ class SassColor extends Value {
toRgb(scaledHue - 1 / 3), alpha);
}

/// Prints a deprecation warning if [alpha] is explicitly `null`.
static num _handleNullAlpha(num? alpha) {
if (alpha != null) return alpha;

warnForDeprecation(
'Passing null for alpha in the ${isJS ? 'JS' : 'Dart'} API is '
'deprecated.\n'
'To preserve current behavior, pass 1${isJS ? ' or undefined' : ''} '
'instead.'
'\n'
'More info: https://sass-lang.com/d/null-alpha',
Deprecation.nullAlpha);
return 1;
}

SassColor._(this._red, this._green, this._blue, this._hue, this._saturation,
this._lightness, this._alpha)
: format = null;
Expand Down
4 changes: 4 additions & 0 deletions pkg/sass_api/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

* All uses of classes from the `tuple` package have been replaced by record
types.

## 7.2.2

* No user-visible changes.
Comment on lines +10 to +13
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it got accidentally deleted in a previous CL but we did release 7.2.2 so it should have a changelog entry.


## 7.2.1

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: 8.0.0-dev
version: 8.0.0
description: Additional APIs for Dart Sass.
homepage: https://github.com/sass/dart-sass

environment:
sdk: ">=3.0.0 <4.0.0"

dependencies:
sass: 1.64.2
sass: 1.64.3

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.64.3-dev
version: 1.64.3
description: A Sass implementation in Dart.
homepage: https://github.com/sass/dart-sass

Expand Down